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 { 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.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 { 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 { 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 { if(type_filter & (1<
{ 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 { kzero_memory(&context.graphics_command_buffers[i],sizeof(vulkan_command_buffer)); } } for(u32 i = 0;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 { //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.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 { vulkan_command_buffer_free(&context,context.device.graphics_command_pool,&context.graphics_command_buffers[i]); } //Framebuffers for(u32 i = 0;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); }