1.vulkan_backend.h
#pragma once
#include "renderer/renderer_backend.h"
#include "resources/resource_types.h"
b8 vulkan_renderer_backend_initialize(renderer_backend* backend,const char* application_name,struct platform_state* plat_state);
void vulkan_renderer_backend_shutdown(renderer_backend* backend);
void vulkan_renderer_backend_on_resized(renderer_backend* backend,u16 width,u16 height);
b8 vulkan_renderer_backend_begin_frame(renderer_backend*backend,f32 delta_time);
void vulkan_renderer_update_global_state(mat4 projection,mat4 view,vec3 view_position,vec4 ambient_colour,i32 mode);
b8 vulkan_renderer_backend_end_frame(renderer_backend* backend,f32 delta_time);
void vulkan_backend_update_object(mat4 model);
void vulkan_renderer_create_texture(
const char* name,
b8 auto_release,
i32 width,
i32 height,
i32 channel_count,
const u8* pixels,
b8 has_transparency,
texture* out_texture
);
void vulkan_renderer_destroy_texture(texture* texture);
2.vulkan_backend.c
#include "vulkan_backend.h"
#include "vulkan_swapchain.h"
#include "vulkan_renderpass.h"
#include "vulkan_command_buffer.h"
#include "vulkan_framebuffer.h"
#include "vulkan_fence.h"
#include "vulkan_utils.h"
#include "vulkan_types.inl"
#include "core/logger.h"
#include "containers/darray.h"
#include "core/kstring.h"
#include "vulkan_platform.h"
#include "core/kmemory.h"
#include "core/application.h"
#include "platform/platform.h"
#include "vulkan_device.h"
#include "vulkan_platform.h"
#include "shaders/vulkan_object_shader.h"
#include "math/math_types.h"
#include "vulkan_buffer.h"
//static vulkan context
static vulkan_context context;
static u32 cached_framebuffer_width = 0;
static u32 cached_framebuffer_height = 0;
static vulkan_context context;
VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
VkDebugUtilsMessageTypeFlagsEXT message_types,
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
void* user_data
);
i32 find_memory_index(u32 type_filter,u32 property_flags);
b8 create_buffers(vulkan_context* context);
void create_command_buffers(renderer_backend* backend);
void regenerate_framebuffers(renderer_backend* backend,vulkan_swapchain* swapchain,vulkan_renderpass* renderpass);
b8 recreate_swapchain(renderer_backend* backend);
void upload_data_range(vulkan_context* context,VkCommandPool pool,VkFence fence,VkQueue queue,vulkan_buffer* buffer,u64 offset,u64 size,void* data)
{
VkBufferUsageFlags flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
vulkan_buffer staging;
vulkan_buffer_create(context,size,VK_BUFFER_USAGE_TRANSFER_SRC_BIT,flags,true,&staging);
vulkan_buffer_load_data(context,&staging,0,size,0,data);
vulkan_buffer_copy_to(context,pool,fence,queue,staging.handle,0,buffer->handle,offset,size);
vulkan_buffer_destroy(context,&staging);
}
b8 vulkan_renderer_backend_initialize(renderer_backend* backend,const char* application_name,struct platform_state* plat_state)
{
context.find_memory_index = find_memory_index;
context.allocator = 0;
application_get_framebuffer_size(&cached_framebuffer_width,&cached_framebuffer_height);
context.framebuffer_width = (cached_framebuffer_width != 0)? cached_framebuffer_width : 800;
context.framebuffer_height = (cached_framebuffer_height != 0) ? cached_framebuffer_height : 600;
cached_framebuffer_width = 0;
cached_framebuffer_height = 0;
//Setup vulkan instance
VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO};
app_info.apiVersion = VK_API_VERSION_1_2;
app_info.pApplicationName = application_name;
app_info.applicationVersion = VK_MAKE_VERSION(1,0,0);
app_info.pEngineName = "Apophis Engine";
app_info.engineVersion = VK_MAKE_VERSION(1,0,0);
VkInstanceCreateInfo create_info = {VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO};
create_info.pApplicationInfo = &app_info;
create_info.enabledExtensionCount= 0;
create_info.ppEnabledExtensionNames = 0;
create_info.enabledLayerCount = 0;
create_info.ppEnabledLayerNames = 0;
//Obtain a list of required extensions
const char** required_extensions = darray_create(const char*);
darray_push(required_extensions,&VK_KHR_SURFACE_EXTENSION_NAME);
platform_get_required_extension_names(&required_extensions);
#if defined(_DEBUG)
darray_push(required_extensions,&VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
KDEBUG("Required extensions");
u32 length = darray_length(required_extensions);
for (u32 i = 0; i < length; ++i) {
KDEBUG(required_extensions[i]);
}
#endif
create_info.enabledExtensionCount = darray_length(required_extensions);
create_info.ppEnabledExtensionNames = required_extensions;
const char** required_validation_layer_names = 0;
u32 required_validation_layer_count = 0;
#if defined(_DEBUG)
KINFO("Validation layers enabled. Enumerating...");
required_validation_layer_names = darray_create(const char*);
darray_push(required_validation_layer_names,&"VK_LAYER_KHRONOS_validation");
required_validation_layer_count = darray_length(required_validation_layer_names);
u32 available_layer_count = 0;
VK_CHECK(vkEnumerateInstanceLayerProperties(&available_layer_count, 0));
VkLayerProperties* available_layers = darray_reserve(VkLayerProperties, available_layer_count);
VK_CHECK(vkEnumerateInstanceLayerProperties(&available_layer_count, available_layers));
// Verify all required layers are available.
for (u32 i = 0; i < required_validation_layer_count; ++i) {
b8 found = false;
for (u32 j = 0; j < available_layer_count; ++j) {
if (strings_equal(required_validation_layer_names[i], available_layers[j].layerName)) {
found = true;
KINFO("Found validation layer: %s...", required_validation_layer_names[i]);
break;
}
}
if (!found) {
KFATAL("Required validation layer is missing: %s", required_validation_layer_names[i]);
return false;
}
}
// Clean up.
//darray_destroy(available_extensions);
//darray_destroy(available_layers);
KINFO("All required validation layers are present.");
#endif
create_info.enabledLayerCount = required_validation_layer_count;
create_info.ppEnabledLayerNames = required_validation_layer_names;
//Validation layers
VK_CHECK(vkCreateInstance(&create_info,context.allocator,&context.instance));
KINFO("Vulkan Instance created!");
//Debugger
#if defined(_DEBUG)
KDEBUG("Creating Vulkan debugger...");
u32 log_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT};
debug_create_info.messageSeverity = log_severity;
debug_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
debug_create_info.pfnUserCallback = vk_debug_callback;
//debug_create_info.pUserData = 0;
PFN_vkCreateDebugUtilsMessengerEXT func =
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance,"vkCreateDebugUtilsMessengerEXT");
KASSERT_MSG(func,"Failed to create debug messenger!");
VK_CHECK(func(context.instance,&debug_create_info,context.allocator,&context.debug_messenger));
KDEBUG("Vulkan debugger created");
KDEBUG("Creating Vulkan surface...");
if(!platform_create_vulkan_surface(plat_state,&context))
{
KERROR("Failed to create platform surface!");
return false;
}
KDEBUG("Vulkan surface created.");
#endif
//Device creation
if(!vulkan_device_create(&context))
{
KERROR("Failed to create device.");
return false;
}
//Swapchain
vulkan_swapchain_create(
&context,
context.framebuffer_height,
context.framebuffer_width,
&context.swapchain);
vulkan_renderpass_create(
&context,
&context.main_renderpass,
0,0,context.framebuffer_width,context.framebuffer_height,
0.0f,0.0f,0.2f,1.0f,
1.0f,
0
);
//Swapchain framebuffers
context.swapchain.framebuffers = darray_reserve(vulkan_framebuffer,context.swapchain.image_count);
regenerate_framebuffers(backend,&context.swapchain,&context.main_renderpass);
//Create command buffers
create_command_buffers(backend);
//Create command buffers
context.image_available_semaphores = darray_reserve(VkSemaphore,context.swapchain.max_frames_in_flight);
context.queue_complete_semaphores = darray_reserve(VkSemaphore,context.swapchain.max_frames_in_flight);
context.in_flight_fences = darray_reserve(vulkan_fence,context.swapchain.max_frames_in_flight);
for(u8 i =0;i<context.swapchain.max_frames_in_flight;++i)
{
VkSemaphoreCreateInfo semaphore_create_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
vkCreateSemaphore(context.device.logical_device,&semaphore_create_info,context.allocator,&context.image_available_semaphores[i]);
vkCreateSemaphore(context.device.logical_device,&semaphore_create_info,context.allocator,&context.queue_complete_semaphores[i]);
vulkan_fence_create(&context,true,&context.in_flight_fences[i]);
}
//by list
context.images_in_flight = darray_reserve(vulkan_fence,context.swapchain.image_count);
for(u32 i = 0;i<context.swapchain.image_count;++i)
{
context.images_in_flight[i] = 0;
}
if(!vulkan_object_shader_create(&context,&context.object_shader))
{
KERROR("Error loading built-in basic_lighting shader.");
return false;
}
create_buffers(&context);
//TODO:compary test code
const u32 vert_count = 4;
vertex_3d verts[vert_count];
kzero_memory(verts,sizeof(vertex_3d)*vert_count);
const f32 f = 10.0f;
verts[0].position.x = 0.5 * f;
verts[0].position.y = -0.5*f;
verts[1].position.x = 0.5*f;
verts[1].position.y = 0.5*f;
verts[2].position.x = -0.5*f;
verts[2].position.y = 0.5*f;
verts[3].position.x = 0.5*f;
verts[3].position.y = -0.5*f;
const u32 index_count = 6;
u32 indices[index_count] = {0,1,2,0,3,1};
upload_data_range(&context,context.device.graphics_command_pool,0,context.device.graphics_queue,&context.object_vertex_buffer,0,sizeof(vertex_3d)*vert_count,verts);
upload_data_range(&context,context.device.graphics_command_pool,0,context.device.graphics_queue,&context.object_index_buffer,0,sizeof(u32)*index_count,indices);
KINFO("Vulkan renderer initialize successfully.");
return true;
}
void vulkan_renderer_backend_shutdown(renderer_backend* backend)
{
vkDeviceWaitIdle(context.device.logical_device);
vulkan_buffer_destroy(&context,&context.object_vertex_buffer);
vulkan_buffer_destroy(&context,&context.object_index_buffer);
vulkan_object_shader_destroy(&context,&context.object_shader);
//Sync objects
for(u8 i = 0;i<context.swapchain.max_frames_in_flight;++i)
{
if(context.image_available_semaphores[i])
{
vkDestroySemaphore(
context.device.logical_device,
context.image_available_semaphores[i],
context.allocator
);
context.image_available_semaphores[i] = 0;
}
if(context.queue_complete_semaphores[i])
{
vkDestroySemaphore(
context.device.logical_device,
context.queue_complete_semaphores[i],
context.allocator
);
context.queue_complete_semaphores[i] = 0;
}
vulkan_fence_destroy(&context,&context.in_flight_fences[i]);
}
darray_destroy(context.image_available_semaphores);
context.image_available_semaphores = 0;
darray_destroy(context.queue_complete_semaphores);
context.queue_complete_semaphores = 0;
darray_destroy(context.in_flight_fences);
context.in_flight_fences = 0;
darray_destroy(context.images_in_flight);
context.images_in_flight = 0;
//Command buffers
for(u32 i = 0;i<context.swapchain.image_count;++i)
{
if(context.graphics_command_buffers[i].handle)
{
vulkan_command_buffer_free(
&context,
context.device.graphics_command_pool,
&context.graphics_command_buffers[i]
);
context.graphics_command_buffers[i].handle = 0;
}
}
darray_destroy(context.graphics_command_buffers);
context.graphics_command_buffers = 0;
vulkan_renderpass_destroy(&context,&context.main_renderpass);
vulkan_swapchain_destroy(&context,&context.swapchain);
KDEBUG("Destroying vulkan device...");
vulkan_device_destroy(&context);
KDEBUG("Destroying Vulkan surface...");
if(context.surface)
{
vkDestroySurfaceKHR(context.instance,context.surface,context.allocator);
context.surface = 0;
}
KDEBUG("Destroying Vulkan debugger...");
if(context.debug_messenger)
{
PFN_vkDestroyDebugUtilsMessengerEXT func =
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context.instance,"vkDestroyDebugUtilsMessengerEXT");
func(context.instance,context.debug_messenger,context.allocator);
}
KDEBUG("Destroying Vulkan instance...");
vkDestroyInstance(context.instance,context.allocator);
}
void vulkan_renderer_backend_on_resized(renderer_backend* backend,u16 width,u16 height)
{
cached_framebuffer_width = width;
cached_framebuffer_height = height;
context.framebuffer_size_generation++;
KINFO("Vulkan renderer backend->resized: %i/%i/%ilu",width,height,context.framebuffer_size_generation);
}
b8 vulkan_renderer_backend_begin_frame(renderer_backend*backend,f32 delta_time)
{
vulkan_device* device = &context.device;
//Check if recreating swap chain add boot out
if(context.recreating_swapchain)
{
VkResult result = vkDeviceWaitIdle(device->logical_device);
if(!vulkan_result_is_success(result))
{
KERROR("vulkan_renderer_backend_begin_frame vkDeviceWaitIdle (1) failed: '%s",vulkan_result_string(result,true));
return false;
}
KINFO("Recreating swapchain,booting.");
return false;
}
//Check if the framebuffer
if(context.framebuffer_size_generation != context.framebuffer_size_last_generation)
{
VkResult result = vkDeviceWaitIdle(device->logical_device);
if(!vulkan_result_is_success(result))
{
KERROR("vulkan_renderer_backend_begin_frame vkDeviceWaitIdle (2) failed: '%s'",vulkan_result_string(result,true));
return false;
}
if(!recreate_swapchain(backend))
{
return false;
}
KINFO("Resized , booting");
return false;
}
if(!vulkan_fence_wait(
&context,
&context.in_flight_fences[context.current_frame],
UINT64_MAX
))
{
KWARN("In flight fence wait failure!");
return false;
}
if(
!vulkan_swapchain_acquire_next_image_index(
&context,
&context.swapchain,
UINT64_MAX,
context.image_available_semaphores[context.current_frame],
0,
&context.image_index
))
{
return false;
}
//Begin recording commands
vulkan_command_buffer* command_buffer = &context.graphics_command_buffers[context.image_index];
vulkan_command_buffer_reset(command_buffer);
vulkan_command_buffer_begin(command_buffer,false,false,false);
//Dynamic state
VkViewport viewport;
viewport.x = 0.0f;
viewport.y = (f32)context.framebuffer_height;
viewport.width = (f32)context.framebuffer_width;
viewport.height = -(f32)context.framebuffer_height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
//Scissor
VkRect2D scissor;
scissor.offset.x = scissor.offset.y = 0;
scissor.extent.width = context.framebuffer_width;
scissor.extent.height = context.framebuffer_height;
vkCmdSetViewport(command_buffer->handle,0,1,&viewport);
vkCmdSetScissor(command_buffer->handle,0,1,&scissor);
context.main_renderpass.w = context.framebuffer_width;
context.main_renderpass.h = context.framebuffer_height;
//Begin the render pass/
vulkan_renderpass_begin(
command_buffer,
&context.main_renderpass,
context.swapchain.framebuffers[context.image_index].handle
);
//temporary test code
return true;
}
/*
void vulkan_renderer_update_global_state(mat4 projection,mat4 view,vec3 view_position,vec4 ambient_colour,i32 mode)
{
vulkan_command_buffer* command_buffer = &context.graphics_command_buffers[context.image_index];
vulkan_object_shader_use(&context,&context.object_shader);
context.object_shader.global_ubo.projection = projection;
context.object_shader.global_ubo.view = view;
//TODO: other ubo properties
vulkan_object_shader_update_global_state(&context,&context.object_shader);
vulkan_object_shader_use(&context,&context.object_shader);
VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(command_buffer->handle,0,1,&context.object_vertex_buffer.handle,(VkDeviceSize*)offsets);
vkCmdBindIndexBuffer(command_buffer->handle,context.object_index_buffer.handle,0,VK_INDEX_TYPE_UINT32);
//Draw
vkCmdDrawIndexed(command_buffer->handle,6,1,0,0,0);
}
*/
void vulkan_renderer_update_global_state(mat4 projection, mat4 view, vec3 view_position, vec4 ambient_colour, i32 mode)
{
vulkan_command_buffer* command_buffer = &context.graphics_command_buffers[context.image_index];
vulkan_object_shader_use(&context, &context.object_shader);
context.object_shader.global_ubo.projection = projection;
context.object_shader.global_ubo.view = view;
//TODO: other ubo properties
vulkan_object_shader_update_global_state(&context, &context.object_shader);
}
b8 vulkan_renderer_backend_end_frame(renderer_backend* backend,f32 delta_time)
{
vulkan_command_buffer* command_buffer = &context.graphics_command_buffers[context.image_index];
//End renderpass
vulkan_renderpass_end(command_buffer,&context.main_renderpass);
vulkan_command_buffer_end(command_buffer);
//Make sure the previous frame is not using this image
if(context.images_in_flight[context.image_index] != VK_NULL_HANDLE)
{
vulkan_fence_wait(
&context,
context.images_in_flight[context.image_index],
UINT64_MAX);
}
context.images_in_flight[context.image_index] = &context.in_flight_fences[context.current_frame];
vulkan_fence_reset(&context,&context.in_flight_fences[context.current_frame]);
VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
//Command buffers to be executed
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer->handle;
//The semaphores to be signaled when the queue is complete
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &context.queue_complete_semaphores[context.current_frame];
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &context.image_available_semaphores[context.current_frame];
VkPipelineStageFlags flags[1] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
submit_info.pWaitDstStageMask=flags;
VkResult result = vkQueueSubmit(
context.device.graphics_queue,
1,
&submit_info,
context.in_flight_fences[context.current_frame].handle);
if(result!=VK_SUCCESS)
{
KERROR("vkQueueSubmit failed with result: %s",vulkan_result_string(result,true));
return false;
}
vulkan_command_buffer_update_submitted(command_buffer);
//Give the image back to the swapchain
vulkan_swapchain_present(
&context,
&context.swapchain,
context.device.graphics_queue,
context.device.present_queue,
context.queue_complete_semaphores[context.current_frame],
context.image_index
);
return true;
}
void vulkan_backend_update_object(mat4 model)
{
vulkan_command_buffer* command_buffer = &context.graphics_command_buffers[context.image_index];
vulkan_object_shader_update_object(&context,&context.object_shader,model);
vulkan_object_shader_use(&context, &context.object_shader);
VkDeviceSize offsets[1] = {0};
vkCmdBindVertexBuffers(command_buffer->handle, 0, 1, &context.object_vertex_buffer.handle, offsets);
// 确保 context.object_index_buffer.handle 是有效的 VkBuffer 句柄
if (context.object_index_buffer.handle != VK_NULL_HANDLE) {
vkCmdBindIndexBuffer(command_buffer->handle, context.object_index_buffer.handle, 0, VK_INDEX_TYPE_UINT32);
} else {
KERROR("Invalid index buffer handle!");
return; // 或者根据需要进行错误处理
}
//Draw
vkCmdDrawIndexed(command_buffer->handle, 6, 1, 0, 0, 0);
}
VKAPI_ATTR VkBool32 VKAPI_CALL vk_debug_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
VkDebugUtilsMessageTypeFlagsEXT message_types,
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
void* user_data
)
{
switch(message_severity)
{
default:
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
KERROR(callback_data->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
KWARN(callback_data->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
KINFO(callback_data->pMessage);
break;
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
KTRACE(callback_data->pMessage);
break;
}
return VK_FALSE;
}
i32 find_memory_index(u32 type_filter,u32 property_flags)
{
VkPhysicalDeviceMemoryProperties memory_properties;
vkGetPhysicalDeviceMemoryProperties(context.device.physical_device,&memory_properties);
for(u32 i = 0; i<memory_properties.memoryTypeCount;++i)
{
if(type_filter & (1<<i) && (memory_properties.memoryTypes[i].propertyFlags & property_flags) == property_flags)
{
return i;
}
}
KWARN("Unable to find suitable memory type!");
return -1;
}
void create_command_buffers(renderer_backend* backend)
{
if(!context.graphics_command_buffers)
{
context.graphics_command_buffers = darray_reserve(vulkan_command_buffer,context.swapchain.image_count);
for(u32 i = 0;i<context.swapchain.image_count;++i)
{
kzero_memory(&context.graphics_command_buffers[i],sizeof(vulkan_command_buffer));
}
}
for(u32 i = 0;i<context.swapchain.image_count;++i)
{
if(context.graphics_command_buffers[i].handle)
{
vulkan_command_buffer_free(
&context,
context.device.graphics_command_pool,
&context.graphics_command_buffers[i]
);
}
kzero_memory(&context.graphics_command_buffers[i],sizeof(vulkan_command_buffer));
vulkan_command_buffer_allocate(
&context,
context.device.graphics_command_pool,
true,
&context.graphics_command_buffers[i]
);
}
KDEBUG("Vulkan command buffers created");
}
void regenerate_framebuffers(renderer_backend* backend,vulkan_swapchain* swapchain,vulkan_renderpass* renderpass)
{
for(u32 i = 0;i<swapchain->image_count;++i)
{
//make this dynamic based on the currently configured attachemnts
u32 attachment_count =2;
VkImageView attachments[] = {
swapchain->views[i],
swapchain->depth_attachment.view
};
vulkan_framebuffer_create(
&context,
renderpass,
context.framebuffer_width,
context.framebuffer_height,
attachment_count,
attachments,
&context.swapchain.framebuffers[i]
);
}
}
b8 recreate_swapchain(renderer_backend* backend)
{
if(context.recreating_swapchain)
{
KDEBUG("recreating swapchain called when already recreating .Booting.");
return false;
}
if(context.framebuffer_width == 0 || context.framebuffer_height == 0)
{
KDEBUG("recreate_swapchain called when window is <1 in a dimension.Booting.");
return false;
}
//Marking
context.recreating_swapchain = true;
//Wait for any operations to complete
vkDeviceWaitIdle(context.device.logical_device);
for(u32 i = 0;i<context.swapchain.image_count;++i){
context.images_in_flight[i] = 0;
}
//Requery support
vulkan_device_query_swapchain_support(
context.device.physical_device,
context.surface,
&context.device.swapchain_support
);
vulkan_device_detect_depth_format(&context.device);
vulkan_swapchain_recreate(
&context,
cached_framebuffer_width,
cached_framebuffer_height,
&context.swapchain
);
//Sync the framebuffer size with the cached sizes
context.framebuffer_width = cached_framebuffer_width;
context.framebuffer_height = cached_framebuffer_height;
context.main_renderpass.w = context.framebuffer_width;
context.main_renderpass.h = context.framebuffer_height;
cached_framebuffer_width=0;
cached_framebuffer_height=0;
//Update framebuffer size geneartion
context.framebuffer_size_last_generation = context.framebuffer_size_generation;
//cleanup swapchain
for(u32 i = 0;i<context.swapchain.image_count;++i)
{
vulkan_command_buffer_free(&context,context.device.graphics_command_pool,&context.graphics_command_buffers[i]);
}
//Framebuffers
for(u32 i = 0;i <context.swapchain.image_count;++i)
{
vulkan_framebuffer_destroy(&context,&context.swapchain.framebuffers[i]);
}
context.main_renderpass.x = 0;
context.main_renderpass.y = 0;
context.main_renderpass.w = context.framebuffer_width;
context.main_renderpass.h = context.framebuffer_height;
regenerate_framebuffers(backend,&context.swapchain,&context.main_renderpass);
create_command_buffers(backend);
//Clear the recreating flag
context.recreating_swapchain = false;
return true;
}
b8 create_buffers(vulkan_context* context)
{
VkMemoryPropertyFlagBits memory_property_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
const u64 vertex_buffer_size = sizeof(vertex_3d)*1024*1024;
if(!vulkan_buffer_create(
context,
vertex_buffer_size,
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
memory_property_flags,
true,
&context->object_vertex_buffer
))
{
KERROR("Error creating vertex buffer.");
return false;
}
context->geometry_vertex_offset= 0;
const u64 index_buffer_size = sizeof(u32) * 1024 * 1204;
if(!vulkan_buffer_create(
context,
index_buffer_size,
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
memory_property_flags,
true,
&context->object_index_buffer
))
{
KERROR("Error creating index buffer.");
return false;
}
context->geometry_index_offset = 0;
return true;
}
void vulkan_renderer_create_texture(
const char* name,
b8 auto_release,
i32 width,
i32 height,
i32 channel_count,
const u8* pixels,
b8 has_transparency,
texture* out_texture
)
{
out_texture->width = width;
out_texture->height= height;
out_texture->channel_count = channel_count;
out_texture->generation = 0;
out_texture->internal_data = (vulkan_texture_data*)kallocate(sizeof(vulkan_texture_data),MEMORY_TAG_TEXTURE);
vulkan_texture_data* data = (vulkan_texture_data*)out_texture->internal_data;
VkDeviceSize image_size = width * height * channel_count;
//Assume bits a channel
VkFormat image_format = VK_FORMAT_R8G8B8A8_UNORM;
//Create a staging buffer and load data info it
VkBufferUsageFlags usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VkMemoryPropertyFlags memory_prop_flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
vulkan_buffer staging;
vulkan_buffer_create(&context,image_size,usage,memory_prop_flags,true,&staging);
}