2024-01-07 16:34:09 -07:00
|
|
|
#define VK_USE_PLATFORM_MACOS_MVK
|
2024-01-07 03:04:12 -07:00
|
|
|
#include "vulkan/vulkan_core.h"
|
2024-01-07 01:01:57 -07:00
|
|
|
#define GLFW_INCLUDE_VULKAN
|
|
|
|
#include <GLFW/glfw3.h>
|
2024-01-07 16:34:09 -07:00
|
|
|
#define GLFW_EXPOSE_NATIVE_COCOA
|
|
|
|
#include <GLFW/glfw3native.h>
|
2024-01-07 01:01:57 -07:00
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
#define GLM_FORCE_RADIANS
|
|
|
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
2024-01-08 12:42:59 -07:00
|
|
|
#include <cglm/types.h>
|
|
|
|
#include <cglm/mat4.h>
|
2024-01-08 17:45:10 -07:00
|
|
|
#include <cglm/vec3.h>
|
2024-01-08 13:10:54 -07:00
|
|
|
#include <cglm/affine.h>
|
2024-01-09 10:32:22 -07:00
|
|
|
#include <cglm/quat.h>
|
2024-01-08 17:37:52 -07:00
|
|
|
#include <cglm/cam.h>
|
2024-01-07 03:04:12 -07:00
|
|
|
#include <stdio.h>
|
2024-01-11 12:09:54 -07:00
|
|
|
#include <stdlib.h>
|
2024-01-07 16:34:09 -07:00
|
|
|
#include <string.h>
|
|
|
|
|
2024-01-11 12:09:54 -07:00
|
|
|
#include <ply.h>
|
2024-01-11 16:16:10 -07:00
|
|
|
#include <map.h>
|
|
|
|
|
|
|
|
typedef struct AllocatedBufferStruct {
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
VkBuffer buffer;
|
|
|
|
} AllocatedBuffer;
|
|
|
|
|
|
|
|
typedef struct AllocatedImageStruct {
|
|
|
|
VkDeviceMemory memory;
|
|
|
|
VkImage image;
|
|
|
|
} AllocatedImage;
|
2024-01-11 12:09:54 -07:00
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
typedef struct QueueIndicesStruct {
|
|
|
|
uint32_t graphics_family;
|
|
|
|
uint32_t graphics_index;
|
|
|
|
|
|
|
|
uint32_t present_family;
|
|
|
|
uint32_t present_index;
|
2024-01-08 11:59:58 -07:00
|
|
|
|
|
|
|
uint32_t transfer_family;
|
|
|
|
uint32_t transfer_index;
|
2024-01-07 16:34:09 -07:00
|
|
|
} QueueIndices;
|
|
|
|
|
|
|
|
typedef struct QueuesStruct {
|
|
|
|
VkQueue graphics;
|
|
|
|
VkQueue present;
|
2024-01-08 11:59:58 -07:00
|
|
|
VkQueue transfer;
|
2024-01-07 16:34:09 -07:00
|
|
|
} Queues;
|
|
|
|
|
|
|
|
typedef struct SwapchainDetailsStruct {
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
|
|
|
|
|
|
|
VkSurfaceFormatKHR* formats;
|
|
|
|
uint32_t formats_count;
|
|
|
|
|
|
|
|
VkPresentModeKHR* present_modes;
|
|
|
|
uint32_t present_modes_count;
|
|
|
|
} SwapchainDetails;
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
typedef struct SwapchainImagesStruct {
|
|
|
|
VkImage* images;
|
|
|
|
uint32_t count;
|
|
|
|
} SwapchainImages;
|
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
typedef struct TextureStruct {
|
|
|
|
AllocatedImage image;
|
|
|
|
VkImageView view;
|
|
|
|
VkSampler sampler;
|
|
|
|
} Texture;
|
|
|
|
|
2024-01-10 11:27:04 -07:00
|
|
|
typedef struct PositionStruct {
|
2024-01-10 13:19:41 -07:00
|
|
|
vec3 position;
|
|
|
|
vec3 scale;
|
2024-01-10 11:27:04 -07:00
|
|
|
versor rotation;
|
|
|
|
} Position;
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
typedef void(*MappingFunc)(void*,void*);
|
|
|
|
|
|
|
|
void attribute_mapping_position_to_matrix(void* dest, void* source) {
|
|
|
|
Position* position = source;
|
|
|
|
glm_translate_make(dest, position->position);
|
|
|
|
glm_quat_rotate(dest, position->rotation, dest);
|
|
|
|
glm_scale(dest, position->scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MAPPING_POSITION_TO_MATRIX 0
|
|
|
|
|
|
|
|
MappingFunc mapping_functions[] = {
|
|
|
|
attribute_mapping_position_to_matrix,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct MappingStruct {
|
2024-01-10 11:27:04 -07:00
|
|
|
uint32_t mapping_type; // What function to use to map it
|
2024-01-10 13:19:41 -07:00
|
|
|
uint32_t index; // Which index to use in the ATTRIBUTE_ID_DESCRIPTORS array
|
|
|
|
} Mapping;
|
2024-01-10 11:27:04 -07:00
|
|
|
|
2024-01-10 11:31:32 -07:00
|
|
|
#define ATTRIBUTE_ID_MESH 0x00000001 // Mesh*
|
|
|
|
#define ATTRIBUTE_ID_MATERIAL 0x00000002 // Material*
|
|
|
|
#define ATTRIBUTE_ID_DESCRIPTORS 0x00000003 // void***(array of array of data pointers)
|
|
|
|
#define ATTRIBUTE_ID_DESCRIPTOR_SETS 0x00000004 // VkDescriptorSet*
|
|
|
|
#define ATTRIBUTE_ID_POSITION 0x00000005 // Position*
|
2024-01-09 21:28:57 -07:00
|
|
|
|
2024-01-09 20:41:31 -07:00
|
|
|
typedef struct ObjectStruct {
|
2024-01-09 21:28:57 -07:00
|
|
|
Map attributes;
|
2024-01-09 20:41:31 -07:00
|
|
|
} Object;
|
|
|
|
|
2024-01-09 18:36:40 -07:00
|
|
|
// Defines how a mesh is read from a buffer into a graphics pipeline
|
|
|
|
typedef struct MeshTypeStruct {
|
|
|
|
uint32_t bindings_count;
|
|
|
|
VkVertexInputBindingDescription* bindings;
|
|
|
|
|
|
|
|
uint32_t attributes_count;
|
|
|
|
VkVertexInputAttributeDescription* attributes;
|
|
|
|
} MeshType;
|
|
|
|
|
|
|
|
// Defines what descriptors are bound at two different upate rates for the pipeline
|
|
|
|
typedef struct PipelineLayoutStruct {
|
2024-01-10 11:31:32 -07:00
|
|
|
uint32_t object_bindings_count;
|
|
|
|
VkDescriptorSetLayoutBinding* object_bindings;
|
2024-01-09 18:36:40 -07:00
|
|
|
|
|
|
|
uint32_t material_bindings_count;
|
|
|
|
VkDescriptorSetLayoutBinding* material_bindings;
|
|
|
|
} PipelineLayout;
|
|
|
|
|
2024-01-08 13:04:45 -07:00
|
|
|
typedef struct MeshStruct {
|
2024-01-11 23:28:59 -07:00
|
|
|
uint32_t vertex_count;
|
|
|
|
VkBuffer vertex_buffer;
|
2024-01-08 19:48:09 -07:00
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
uint32_t index_count;
|
|
|
|
VkBuffer index_buffer;
|
2024-01-08 13:04:45 -07:00
|
|
|
} Mesh;
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
typedef struct MaterialStruct {
|
2024-01-09 12:33:38 -07:00
|
|
|
VkDescriptorSetLayout material_set_layout;
|
2024-01-10 11:31:32 -07:00
|
|
|
VkDescriptorSetLayout object_set_layout;
|
2024-01-09 12:33:38 -07:00
|
|
|
|
2024-01-09 18:36:40 -07:00
|
|
|
VkPipelineLayout layout;
|
2024-01-08 19:48:09 -07:00
|
|
|
VkPipeline pipeline;
|
2024-01-09 21:28:57 -07:00
|
|
|
|
|
|
|
VkDescriptorPool material_descriptor_pool;
|
|
|
|
VkDescriptorSet* material_descriptors;
|
|
|
|
uint32_t material_descriptors_count;
|
2024-01-10 11:31:32 -07:00
|
|
|
|
|
|
|
Map object_descriptor_mappings;
|
2024-01-08 19:48:09 -07:00
|
|
|
} Material;
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
typedef struct VulkanContextStruct {
|
|
|
|
VkInstance instance;
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
|
VkPhysicalDevice physical_device;
|
|
|
|
|
|
|
|
QueueIndices queue_indices;
|
|
|
|
VkDevice device;
|
|
|
|
Queues queues;
|
|
|
|
|
|
|
|
VkSurfaceKHR surface;
|
|
|
|
|
|
|
|
SwapchainDetails swapchain_details;
|
|
|
|
VkSwapchainKHR swapchain;
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkSurfaceFormatKHR swapchain_format;
|
|
|
|
VkPresentModeKHR swapchain_present_mode;
|
|
|
|
VkExtent2D swapchain_extent;
|
|
|
|
|
|
|
|
uint32_t swapchain_image_count;
|
2024-01-07 22:55:36 -07:00
|
|
|
// Per image objects
|
2024-01-07 22:27:53 -07:00
|
|
|
VkImage* swapchain_images;
|
|
|
|
VkImageView* swapchain_image_views;
|
|
|
|
VkFramebuffer* swapchain_framebuffers;
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkDeviceMemory depth_image_memory;
|
|
|
|
VkImage depth_image;
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFormat depth_format;
|
|
|
|
VkImageView depth_image_view;
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
uint32_t max_frames_in_flight;
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
// Per frame objects
|
|
|
|
VkCommandBuffer* swapchain_command_buffers;
|
|
|
|
VkSemaphore* image_available_semaphores;
|
|
|
|
VkSemaphore* render_finished_semaphores;
|
|
|
|
VkFence* in_flight_fences;
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
VkRenderPass render_pass;
|
|
|
|
|
|
|
|
VkCommandPool graphics_command_pool;
|
2024-01-08 11:59:58 -07:00
|
|
|
VkCommandPool transfer_command_pool;
|
2024-01-07 22:27:53 -07:00
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
uint32_t current_frame;
|
2024-01-11 16:16:10 -07:00
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
VkPhysicalDeviceMemoryProperties memories;
|
|
|
|
VkCommandPool extra_graphics_pool;
|
2024-01-07 16:34:09 -07:00
|
|
|
} VulkanContext;
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
typedef struct SceneContextStruct {
|
|
|
|
VkDescriptorPool pool;
|
|
|
|
VkDescriptorSetLayout descriptor_layout;
|
|
|
|
VkDescriptorSet* descriptors;
|
|
|
|
AllocatedBuffer* ubos;
|
|
|
|
void** ubo_ptrs;
|
|
|
|
} SceneContext;
|
|
|
|
|
2024-01-08 20:32:47 -07:00
|
|
|
struct TextureVertex {
|
|
|
|
vec3 pos;
|
|
|
|
vec3 color;
|
|
|
|
vec2 tex;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Vertex {
|
2024-01-08 17:37:52 -07:00
|
|
|
vec3 pos;
|
2024-01-08 09:44:47 -07:00
|
|
|
vec3 color;
|
|
|
|
};
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
struct ModelUBO {
|
|
|
|
mat4 model;
|
|
|
|
};
|
|
|
|
|
2024-01-08 16:44:14 -07:00
|
|
|
struct SceneUBO {
|
2024-01-08 12:42:59 -07:00
|
|
|
mat4 view;
|
|
|
|
mat4 proj;
|
|
|
|
};
|
|
|
|
|
2024-01-08 09:44:47 -07:00
|
|
|
const struct Vertex vertices[] = {
|
2024-01-10 13:19:41 -07:00
|
|
|
{.pos = {-1.f, -1.f, 0.f}, .color = {1.0f, 0.0f, 0.0f}},
|
|
|
|
{.pos = { 1.f, -1.f, 0.f}, .color = {0.0f, 1.0f, 0.0f}},
|
|
|
|
{.pos = { 1.f, 1.f, 0.f}, .color = {0.0f, 0.0f, 1.0f}},
|
|
|
|
{.pos = {-1.f, 1.f, 0.f}, .color = {1.0f, 1.0f, 1.0f}},
|
2024-01-08 20:32:47 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const struct TextureVertex texture_vertices[] = {
|
2024-01-10 13:19:41 -07:00
|
|
|
{.pos = {-1.f, -1.f, 0.f}, .color = {1.0f, 0.0f, 0.0f}, .tex = {1.0f, 1.0f}},
|
|
|
|
{.pos = { 1.f, -1.f, 0.f}, .color = {0.0f, 1.0f, 0.0f}, .tex = {0.0f, 1.0f}},
|
|
|
|
{.pos = { 1.f, 1.f, 0.f}, .color = {0.0f, 0.0f, 1.0f}, .tex = {0.0f, 0.0f}},
|
|
|
|
{.pos = {-1.f, 1.f, 0.f}, .color = {1.0f, 1.0f, 1.0f}, .tex = {1.0f, 0.0f}},
|
2024-01-08 11:59:58 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
const uint16_t indices[] = {
|
2024-01-08 20:32:47 -07:00
|
|
|
2, 1, 0, 0, 3, 2,
|
2024-01-08 09:44:47 -07:00
|
|
|
};
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
const char * validation_layers[] = {
|
|
|
|
"VK_LAYER_KHRONOS_validation",
|
2024-01-08 11:59:58 -07:00
|
|
|
//"VK_LAYER_LUNARG_api_dump",
|
2024-01-09 23:06:08 -07:00
|
|
|
"VK_LAYER_KHRONOS_synchronization2",
|
2024-01-08 11:59:58 -07:00
|
|
|
"VK_LAYER_KHRONOS_shader_object",
|
2024-01-07 16:34:09 -07:00
|
|
|
};
|
|
|
|
uint32_t validation_layer_count = sizeof(validation_layers) / sizeof(const char *);
|
|
|
|
|
|
|
|
const char * instance_extensions[] = {
|
|
|
|
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
|
|
|
|
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
|
2024-01-11 16:16:10 -07:00
|
|
|
"VK_EXT_metal_surface",
|
2024-01-07 16:34:09 -07:00
|
|
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
|
|
|
};
|
|
|
|
uint32_t instance_extension_count = sizeof(instance_extensions) / sizeof(const char *);
|
|
|
|
|
|
|
|
const char * device_extensions[] = {
|
|
|
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
2024-01-11 16:16:10 -07:00
|
|
|
"VK_KHR_portability_subset",
|
2024-01-07 16:34:09 -07:00
|
|
|
};
|
|
|
|
uint32_t device_extension_count = sizeof(device_extensions) / sizeof(const char *);
|
2024-01-07 03:04:12 -07:00
|
|
|
|
|
|
|
void glfw_error(int error, const char* description) {
|
|
|
|
fprintf(stderr, "GLFW_ERR: 0x%02x - %s\n", error, description);
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
uint32_t pick_memory(VkPhysicalDeviceMemoryProperties properties, uint32_t filter, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude) {
|
|
|
|
for(uint32_t i = 0; i < properties.memoryTypeCount; i++){
|
|
|
|
if((filter & (1 << i))
|
|
|
|
&& ((include & properties.memoryTypes[i].propertyFlags) == include)
|
|
|
|
&& ((exclude & properties.memoryTypes[i].propertyFlags) == 0)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
GLFWwindow* init_window(int width, int height) {
|
|
|
|
glfwInit();
|
|
|
|
glfwSetErrorCallback(glfw_error);
|
|
|
|
|
|
|
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
2024-01-08 19:48:09 -07:00
|
|
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
2024-01-07 03:04:12 -07:00
|
|
|
GLFWwindow* window = glfwCreateWindow(width, height, "Vulkan window", 0, 0);
|
|
|
|
|
|
|
|
|
|
|
|
return window;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
void object_update_mappings(Material material, Object object, uint32_t frame_num) {
|
|
|
|
if(material.object_descriptor_mappings.buckets == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MaybeValue maybe_descriptors = map_lookup(object.attributes, ATTRIBUTE_ID_DESCRIPTORS);
|
|
|
|
if(maybe_descriptors.has_value == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void** descriptors = ((void***)(maybe_descriptors.value))[frame_num];
|
|
|
|
|
|
|
|
MapIterator mapping_iterator = map_iterator_create(material.object_descriptor_mappings);
|
|
|
|
for(uint32_t i = 0; i < mapping_iterator.count; i++) {
|
|
|
|
MaybeValue maybe_attribute = map_lookup(object.attributes, mapping_iterator.keys[i]);
|
|
|
|
if(maybe_attribute.has_value == true) {
|
|
|
|
Mapping* mapping = mapping_iterator.vals[i];
|
|
|
|
if(mapping->mapping_type > sizeof(mapping_functions)/sizeof(MappingFunc)) {
|
|
|
|
fprintf(stderr, "material requested mapping_function 0x%02x which does not exist\n", mapping->mapping_type);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
mapping_functions[mapping->mapping_type](descriptors[mapping->index], maybe_attribute.value);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "material requested attribute 0x%02x from object, but it does not have it\n", mapping_iterator.keys[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
map_iterator_free(mapping_iterator);
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
VkSemaphore* create_semaphores(VkDevice device, VkSemaphoreCreateFlags flags, uint32_t count) {
|
|
|
|
VkSemaphore* semaphores = malloc(sizeof(VkSemaphore)*count);
|
|
|
|
if(semaphores == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkSemaphoreCreateInfo semaphore_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
|
|
|
.flags = flags,
|
|
|
|
};
|
2024-01-11 18:06:20 -07:00
|
|
|
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
|
|
|
VkResult result = vkCreateSemaphore(device, &semaphore_info, 0, &semaphores[i]);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(semaphores);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return semaphores;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFormat find_depth_format(VkPhysicalDevice physical_device, uint32_t num_requested, VkFormat* requested, VkImageTiling tiling, VkFormatFeatureFlags features) {
|
|
|
|
for(uint32_t i = 0; i < num_requested; i++) {
|
|
|
|
VkFormatProperties properties;
|
|
|
|
vkGetPhysicalDeviceFormatProperties(physical_device, requested[i], &properties);
|
|
|
|
|
|
|
|
if(tiling == VK_IMAGE_TILING_LINEAR && (properties.linearTilingFeatures & features) == features) {
|
|
|
|
return requested[i];
|
|
|
|
} else if (tiling == VK_IMAGE_TILING_OPTIMAL && (properties.optimalTilingFeatures & features) == features) {
|
|
|
|
return requested[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return VK_FORMAT_MAX_ENUM;
|
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
bool check_validation_layers(const char ** layers, uint32_t num_layers) {
|
|
|
|
uint32_t layer_count;
|
|
|
|
VkResult result;
|
|
|
|
|
|
|
|
result = vkEnumerateInstanceLayerProperties(&layer_count, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkLayerProperties* available_layers = malloc(sizeof(VkLayerProperties)*layer_count);
|
|
|
|
|
|
|
|
result = vkEnumerateInstanceLayerProperties(&layer_count, available_layers);
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < num_layers; i++) {
|
|
|
|
bool found = false;
|
|
|
|
for(uint32_t j = 0; j < layer_count; j++) {
|
|
|
|
if(strcmp(layers[i], available_layers[j].layerName) == 0) {
|
|
|
|
found = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(found == false) {
|
|
|
|
free(available_layers);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(available_layers);
|
|
|
|
return true;
|
2024-01-08 12:42:59 -07:00
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback(
|
|
|
|
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT type,
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* callback_data,
|
|
|
|
void* user_data) {
|
|
|
|
|
|
|
|
(void)severity;
|
|
|
|
(void)type;
|
|
|
|
(void)user_data;
|
|
|
|
|
|
|
|
fprintf(stderr, "Validation layer: %s\n", callback_data->pMessage);
|
|
|
|
|
|
|
|
return VK_FALSE;
|
2024-01-08 12:42:59 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 15:23:23 -07:00
|
|
|
VkDescriptorSet* create_descriptor_sets(VkDevice device, VkDescriptorSetLayout layout, VkDescriptorPool pool, uint32_t count) {
|
2024-01-08 12:42:59 -07:00
|
|
|
VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*count);
|
|
|
|
if(layouts == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSet* sets = malloc(sizeof(VkDescriptorSet)*count);
|
|
|
|
if(sets == 0) {
|
|
|
|
free(layouts);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
|
|
|
layouts[i] = layout;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkDescriptorSetAllocateInfo alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
|
|
.descriptorPool = pool,
|
|
|
|
.descriptorSetCount = count,
|
|
|
|
.pSetLayouts = layouts,
|
|
|
|
};
|
2024-01-08 12:42:59 -07:00
|
|
|
|
|
|
|
VkResult result = vkAllocateDescriptorSets(device, &alloc_info, sets);
|
|
|
|
free(layouts);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(sets);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sets;
|
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
VkPhysicalDevice get_best_physical_device(VkInstance instance) {
|
|
|
|
VkPhysicalDevice device = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
uint32_t device_count = 0;
|
|
|
|
VkResult result;
|
|
|
|
result = vkEnumeratePhysicalDevices(instance, &device_count, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPhysicalDevice* devices = malloc(sizeof(VkPhysicalDevice)*device_count);
|
|
|
|
result = vkEnumeratePhysicalDevices(instance, &device_count, devices);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(devices);
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int top_score = -1;
|
|
|
|
for(uint32_t i = 0; i < device_count; i++) {
|
|
|
|
int score = 0;
|
|
|
|
|
|
|
|
VkPhysicalDeviceProperties properties;
|
|
|
|
vkGetPhysicalDeviceProperties(devices[i], &properties);
|
|
|
|
|
|
|
|
VkPhysicalDeviceFeatures features;
|
|
|
|
vkGetPhysicalDeviceFeatures(devices[i], &features);
|
|
|
|
|
|
|
|
switch(properties.deviceType) {
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
|
|
|
|
score += 100;
|
|
|
|
break;
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
|
|
|
|
score += 50;
|
|
|
|
break;
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
|
|
|
|
score += 25;
|
|
|
|
break;
|
|
|
|
case VK_PHYSICAL_DEVICE_TYPE_CPU:
|
|
|
|
score += 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(score > top_score) {
|
|
|
|
top_score = score;
|
|
|
|
device = devices[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(devices);
|
|
|
|
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
bool check_queue_indices(QueueIndices indices) {
|
|
|
|
return ((indices.graphics_family != 0xFFFFFFFF)
|
|
|
|
&& (indices.present_family != 0xFFFFFFFF)
|
|
|
|
&& (indices.transfer_family != 0xFFFFFFFF));
|
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
QueueIndices get_queue_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
2024-01-11 21:13:30 -07:00
|
|
|
QueueIndices indices = {
|
|
|
|
.graphics_family = 0xFFFFFFFF,
|
|
|
|
.graphics_index = 0xFFFFFFFF,
|
|
|
|
.present_family = 0xFFFFFFFF,
|
|
|
|
.present_index = 0xFFFFFFFF,
|
|
|
|
.transfer_family = 0xFFFFFFFF,
|
|
|
|
.transfer_index = 0xFFFFFFFF,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
uint32_t queue_family_count;
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, 0);
|
|
|
|
|
|
|
|
VkQueueFamilyProperties* queue_families = malloc(sizeof(VkQueueFamilyProperties)*queue_family_count);
|
|
|
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
for(uint32_t family_idx = 0; family_idx < queue_family_count; family_idx++) {
|
|
|
|
VkBool32 present_support;
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, family_idx, surface, &present_support);
|
|
|
|
for(uint32_t queue_idx = 0; queue_idx < queue_families[family_idx].queueCount; queue_idx++) {
|
|
|
|
if(((indices.graphics_family == 0xFFFFFFFF)
|
|
|
|
|| (indices.present_family == 0xFFFFFFFF)
|
|
|
|
|| (indices.present_family != indices.graphics_family))
|
|
|
|
&& (queue_families[family_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
|
|
&& (present_support == VK_TRUE)) {
|
|
|
|
fprintf(stderr, "Selected %d:%d for graphics and present queues\n", family_idx, queue_idx);
|
|
|
|
indices.graphics_family = family_idx;
|
|
|
|
indices.graphics_index = queue_idx;
|
|
|
|
|
|
|
|
indices.present_family = family_idx;
|
|
|
|
indices.present_index = queue_idx;
|
|
|
|
} else if((indices.graphics_family == 0xFFFFFFFF)
|
|
|
|
&& (queue_families[family_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT)) {
|
|
|
|
fprintf(stderr, "Selected %d:%d for graphics queue\n", family_idx, queue_idx);
|
|
|
|
indices.graphics_family = family_idx;
|
|
|
|
indices.graphics_index = queue_idx;
|
|
|
|
} else if((indices.present_family == 0xFFFFFFFF)
|
|
|
|
&& (present_support == VK_TRUE)) {
|
|
|
|
fprintf(stderr, "Selected %d:%d for present queue\n", family_idx, queue_idx);
|
|
|
|
indices.present_family = family_idx;
|
|
|
|
indices.present_index = queue_idx;
|
|
|
|
} else if((indices.transfer_family == 0xFFFFFFFF)
|
|
|
|
&& (queue_families[family_idx].queueFlags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT))) {
|
|
|
|
fprintf(stderr, "Selected %d:%d for transfer queue\n", family_idx, queue_idx);
|
|
|
|
indices.transfer_family = family_idx;
|
|
|
|
indices.transfer_index = queue_idx;
|
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(queue_families);
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
return indices;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
|
|
|
|
VkDebugUtilsMessengerEXT debug_messenger;
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
|
|
|
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_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,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
PFN_vkCreateDebugUtilsMessengerEXT func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
result = func(instance, &messenger_info, 0, &debug_messenger);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to create debug messenger\n");
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return debug_messenger;
|
|
|
|
}
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
VkInstance create_instance() {
|
|
|
|
VkInstance instance;
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
if(check_validation_layers(validation_layers, validation_layer_count) == false) {
|
|
|
|
fprintf(stderr, "requested validation layers not supported");
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkApplicationInfo app_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
|
|
|
.pApplicationName = "spacegame",
|
|
|
|
.applicationVersion = VK_MAKE_VERSION(0, 0, 1),
|
|
|
|
.pEngineName = "spacegame",
|
|
|
|
.engineVersion = VK_MAKE_VERSION(0, 0, 1),
|
|
|
|
.apiVersion = VK_API_VERSION_1_2,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
uint32_t glfwExtensionCount = 0;
|
|
|
|
const char** glfwExtensions;
|
|
|
|
|
|
|
|
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
const char** requested_extensions = malloc(sizeof(char*)*(glfwExtensionCount + instance_extension_count));
|
2024-01-07 03:13:49 -07:00
|
|
|
for (uint32_t i = 0; i < glfwExtensionCount; i++) {
|
|
|
|
requested_extensions[i] = glfwExtensions[i];
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
for (uint32_t i = 0; i < instance_extension_count; i++) {
|
|
|
|
requested_extensions[glfwExtensionCount + i] = instance_extensions[i];
|
|
|
|
}
|
2024-01-07 03:13:49 -07:00
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkInstanceCreateInfo instance_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
|
|
|
.pApplicationInfo = &app_info,
|
|
|
|
.enabledLayerCount = validation_layer_count,
|
|
|
|
.ppEnabledLayerNames = validation_layers,
|
|
|
|
.enabledExtensionCount = glfwExtensionCount + instance_extension_count,
|
|
|
|
.ppEnabledExtensionNames = requested_extensions,
|
|
|
|
.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR,
|
|
|
|
};
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
|
2024-01-07 03:13:49 -07:00
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
VkResult result = vkCreateInstance(&instance_info, 0, &instance);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "vkCreateInstance: 0x%02x\n", result);
|
2024-01-07 16:34:09 -07:00
|
|
|
return VK_NULL_HANDLE;
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 03:13:49 -07:00
|
|
|
free(requested_extensions);
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices queue_indices) {
|
|
|
|
VkDevice device;
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
uint32_t unique_families[3] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
|
|
|
|
uint32_t unique_family_queues[3] = {0, 0, 0};
|
|
|
|
uint32_t unique_family_count = 0;
|
|
|
|
|
|
|
|
uint32_t queue_family[] = {queue_indices.transfer_family, queue_indices.graphics_family, queue_indices.present_family};
|
|
|
|
uint32_t unique_queue_count = 3;
|
|
|
|
if((queue_indices.graphics_family == queue_indices.present_family)
|
|
|
|
&& (queue_indices.graphics_index == queue_indices.present_index)) {
|
|
|
|
unique_queue_count = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t queue_idx = 0; queue_idx < unique_queue_count; queue_idx++) {
|
|
|
|
uint32_t idx = 0xFFFFFFFF;
|
|
|
|
for(uint32_t check_idx = 0; check_idx < unique_family_count; check_idx++) {
|
|
|
|
if(queue_family[queue_idx] == unique_families[check_idx]) {
|
|
|
|
idx = check_idx;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
if(idx == 0xFFFFFFFF) {
|
|
|
|
unique_families[unique_family_count] = queue_family[queue_idx];
|
|
|
|
unique_family_queues[unique_family_count] += 1;
|
|
|
|
unique_family_count += 1;
|
|
|
|
} else {
|
|
|
|
unique_family_queues[idx] += 1;
|
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
VkDeviceQueueCreateInfo queue_create_info[3] = {};
|
|
|
|
float default_queue_priority = 1.0f;
|
|
|
|
for(uint32_t i = 0; i < unique_family_count; i++) {
|
|
|
|
queue_create_info[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
queue_create_info[i].queueFamilyIndex = unique_families[i];
|
|
|
|
queue_create_info[i].queueCount = unique_family_queues[i];
|
|
|
|
queue_create_info[i].pQueuePriorities = &default_queue_priority;
|
|
|
|
}
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
VkPhysicalDeviceFeatures device_features = {
|
|
|
|
.samplerAnisotropy = VK_TRUE,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkDeviceCreateInfo device_create_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
|
|
|
.pQueueCreateInfos = queue_create_info,
|
|
|
|
.queueCreateInfoCount = unique_family_count,
|
|
|
|
.pEnabledFeatures = &device_features,
|
|
|
|
.enabledExtensionCount = device_extension_count,
|
|
|
|
.ppEnabledExtensionNames = device_extensions,
|
|
|
|
.enabledLayerCount = validation_layer_count,
|
|
|
|
.ppEnabledLayerNames = validation_layers,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
VkResult result = vkCreateDevice(physical_device, &device_create_info, 0, &device);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
SwapchainDetails get_swapchain_details(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
|
|
|
SwapchainDetails details = {};
|
|
|
|
details.formats = 0;
|
|
|
|
details.present_modes = 0;
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device, surface, &details.capabilities);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 17:37:52 -07:00
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.formats_count, 0);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 17:37:52 -07:00
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
2024-01-08 17:37:52 -07:00
|
|
|
details.formats = malloc(sizeof(VkSurfaceFormatKHR)*details.formats_count);
|
|
|
|
result = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device, surface, &details.formats_count, details.formats);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 17:37:52 -07:00
|
|
|
free(details.formats);
|
|
|
|
details.formats = 0;
|
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_modes_count, 0);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 17:37:52 -07:00
|
|
|
free(details.formats);
|
|
|
|
details.formats = 0;
|
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
2024-01-08 17:37:52 -07:00
|
|
|
details.present_modes = malloc(sizeof(VkPresentModeKHR)*details.present_modes_count);
|
|
|
|
result = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device, surface, &details.present_modes_count, details.present_modes);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 17:37:52 -07:00
|
|
|
free(details.formats);
|
|
|
|
free(details.present_modes);
|
|
|
|
details.formats = 0;
|
|
|
|
details.present_modes = 0;
|
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
return details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkSurfaceFormatKHR choose_swapchain_format(SwapchainDetails swapchain_details) {
|
|
|
|
for(uint32_t i = 0; i < swapchain_details.formats_count; i++) {
|
|
|
|
VkSurfaceFormatKHR format = swapchain_details.formats[i];
|
|
|
|
if(format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
|
return format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return swapchain_details.formats[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPresentModeKHR choose_present_mode(SwapchainDetails swapchain_details) {
|
|
|
|
for(uint32_t i = 0; i < swapchain_details.present_modes_count; i++) {
|
|
|
|
if(swapchain_details.present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
|
|
return VK_PRESENT_MODE_MAILBOX_KHR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return VK_PRESENT_MODE_FIFO_KHR;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkExtent2D choose_swapchain_extent(SwapchainDetails swapchain_details) {
|
|
|
|
return swapchain_details.capabilities.currentExtent;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
VkSwapchainKHR create_swapchain(VkDevice device, VkSurfaceFormatKHR format, VkPresentModeKHR present_mode, VkExtent2D extent, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR capabilities, QueueIndices indices, VkSwapchainKHR old_swapchain) {
|
|
|
|
uint32_t image_count = capabilities.minImageCount + 1;
|
|
|
|
uint32_t max_images = capabilities.maxImageCount;
|
2024-01-07 16:34:09 -07:00
|
|
|
if((max_images > 0) && (image_count > max_images)) {
|
|
|
|
image_count = max_images;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkSwapchainCreateInfoKHR swapchain_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
|
|
.surface = surface,
|
|
|
|
.minImageCount = image_count,
|
|
|
|
.imageFormat = format.format,
|
|
|
|
.imageColorSpace = format.colorSpace,
|
|
|
|
.imageExtent = extent,
|
|
|
|
.imageArrayLayers = 1,
|
|
|
|
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
|
|
.preTransform = capabilities.currentTransform,
|
|
|
|
.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
|
|
|
|
.presentMode = present_mode,
|
|
|
|
.clipped = VK_TRUE,
|
|
|
|
.oldSwapchain = old_swapchain,
|
|
|
|
};
|
2024-01-07 16:34:09 -07:00
|
|
|
|
|
|
|
uint32_t queue_families[2] = {indices.graphics_family, indices.present_index};
|
|
|
|
if(indices.graphics_family != indices.present_family) {
|
|
|
|
swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
|
|
swapchain_info.queueFamilyIndexCount = 2;
|
|
|
|
swapchain_info.pQueueFamilyIndices = queue_families;
|
|
|
|
} else {
|
|
|
|
swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
swapchain_info.queueFamilyIndexCount = 0;
|
|
|
|
swapchain_info.pQueueFamilyIndices = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkSwapchainKHR swapchain;
|
|
|
|
VkResult result;
|
|
|
|
result = vkCreateSwapchainKHR(device, &swapchain_info, 0, &swapchain);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return swapchain;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
SwapchainImages get_swapchain_images(VkDevice device, VkSwapchainKHR swapchain) {
|
2024-01-11 21:13:30 -07:00
|
|
|
SwapchainImages images = {
|
|
|
|
.images = NULL,
|
|
|
|
.count = 0,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkResult result;
|
|
|
|
result = vkGetSwapchainImagesKHR(device, swapchain, &images.count, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
images.count = 0;
|
|
|
|
return images;
|
|
|
|
}
|
|
|
|
|
|
|
|
images.images = malloc(sizeof(VkImage)*images.count);
|
|
|
|
if(images.images == 0) {
|
|
|
|
images.count = 0;
|
|
|
|
return images;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkGetSwapchainImagesKHR(device, swapchain, &images.count, images.images);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
images.count = 0;
|
|
|
|
return images;
|
|
|
|
}
|
|
|
|
|
|
|
|
return images;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkImageView* create_image_views(VkDevice device, uint32_t image_count, VkImage* images, VkSurfaceFormatKHR format) {
|
|
|
|
VkImageView* image_views = malloc(sizeof(VkImageView)*image_count);
|
|
|
|
if(image_views == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < image_count; i++) {
|
2024-01-11 21:13:30 -07:00
|
|
|
VkImageViewCreateInfo view_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
.image = images[i],
|
|
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
|
|
.format = format.format,
|
|
|
|
.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,
|
|
|
|
},
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkResult result = vkCreateImageView(device, &view_info, 0, &image_views[i]);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(image_views);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return image_views;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFramebuffer* create_swapchain_framebuffers(VkDevice device, uint32_t image_count, VkImageView* image_views, VkImageView depth_image_view, VkRenderPass render_pass, VkExtent2D extent) {
|
2024-01-07 22:27:53 -07:00
|
|
|
VkFramebuffer* framebuffers = malloc(sizeof(VkFramebuffer)*image_count);
|
|
|
|
if(framebuffers == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < image_count; i++) {
|
|
|
|
VkImageView attachments[] = {
|
|
|
|
image_views[i],
|
2024-01-09 13:12:05 -07:00
|
|
|
depth_image_view,
|
2024-01-07 22:27:53 -07:00
|
|
|
};
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkFramebufferCreateInfo framebuffer_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
|
|
.renderPass = render_pass,
|
|
|
|
.attachmentCount = 2,
|
|
|
|
.pAttachments = attachments,
|
|
|
|
.width = extent.width,
|
|
|
|
.height = extent.height,
|
|
|
|
.layers = 1,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkResult result = vkCreateFramebuffer(device, &framebuffer_info, 0, &framebuffers[i]);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(framebuffers);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return framebuffers;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkShaderModule create_shader_module(VkDevice device, const char * code, uint32_t code_size) {
|
2024-01-11 21:13:30 -07:00
|
|
|
VkShaderModuleCreateInfo shader_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
|
|
.codeSize = code_size,
|
|
|
|
.pCode = (uint32_t*)code,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkShaderModule shader;
|
|
|
|
VkResult result;
|
|
|
|
result = vkCreateShaderModule(device, &shader_info, 0, &shader);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkShaderModule load_shader_file(uint32_t buffer_size, const char* path, VkDevice device) {
|
|
|
|
FILE* file;
|
|
|
|
file = fopen(path, "r");
|
|
|
|
if(file == 0) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
char * buffer = malloc(buffer_size);
|
|
|
|
if(buffer == 0) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t read = fread(buffer, 1, buffer_size, file);
|
|
|
|
|
|
|
|
VkShaderModule shader = create_shader_module(device, buffer, read);
|
|
|
|
free(buffer);
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkRenderPass create_render_pass(VkDevice device, VkSurfaceFormatKHR format, VkFormat depth_format) {
|
|
|
|
VkAttachmentDescription attachments[] = {
|
|
|
|
{
|
|
|
|
.format = format.format,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.format = depth_format,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
2024-01-11 18:31:14 -07:00
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
2024-01-09 13:12:05 -07:00
|
|
|
.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkAttachmentReference color_attachment_refs[] = {
|
|
|
|
{
|
|
|
|
.attachment = 0,
|
|
|
|
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkAttachmentReference depth_attachment_ref = {
|
|
|
|
.attachment = 1,
|
|
|
|
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkSubpassDescription subpass = {
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
.colorAttachmentCount = sizeof(color_attachment_refs)/sizeof(VkAttachmentReference),
|
|
|
|
.pColorAttachments = color_attachment_refs,
|
|
|
|
.pDepthStencilAttachment = &depth_attachment_ref,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkSubpassDependency dependency = {
|
|
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
|
|
.dstSubpass = 0,
|
|
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
|
|
.srcAccessMask = 0,
|
|
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
|
|
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkRenderPassCreateInfo render_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
|
.attachmentCount = sizeof(attachments)/sizeof(VkAttachmentDescription),
|
|
|
|
.pAttachments = attachments,
|
|
|
|
.subpassCount = 1,
|
|
|
|
.pSubpasses = &subpass,
|
|
|
|
.dependencyCount = 1,
|
|
|
|
.pDependencies = &dependency,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkRenderPass render_pass;
|
|
|
|
VkResult result = vkCreateRenderPass(device, &render_info, 0, &render_pass);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return render_pass;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedImage allocate_image(VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkImageType type, VkFormat format, VkExtent3D size, VkImageUsageFlags usage, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude) {
|
2024-01-08 21:36:45 -07:00
|
|
|
VkImageCreateInfo image_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
.imageType = type,
|
|
|
|
.extent = size,
|
|
|
|
.mipLevels = 1,
|
|
|
|
.arrayLayers = 1,
|
|
|
|
.format = format,
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.usage = usage,
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
2024-01-09 13:12:05 -07:00
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
2024-01-08 21:36:45 -07:00
|
|
|
.flags = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
AllocatedImage allocated = {
|
|
|
|
.memory = VK_NULL_HANDLE,
|
|
|
|
.image = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
VkResult result = vkCreateImage(device, &image_info, 0, &allocated.image);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetImageMemoryRequirements(device, allocated.image, &memory_requirements);
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo memory_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
.allocationSize = memory_requirements.size,
|
2024-01-11 17:32:10 -07:00
|
|
|
.memoryTypeIndex = pick_memory(memories, memory_requirements.memoryTypeBits, include, exclude),
|
2024-01-08 21:36:45 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
result = vkAllocateMemory(device, &memory_info, 0, &allocated.memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyImage(device, allocated.image, 0);
|
|
|
|
allocated.image = VK_NULL_HANDLE;
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkBindImageMemory(device, allocated.image, allocated.memory, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkFreeMemory(device, allocated.memory, 0);
|
|
|
|
vkDestroyImage(device, allocated.image, 0);
|
|
|
|
allocated.memory = VK_NULL_HANDLE;
|
|
|
|
allocated.image = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer allocate_buffer(VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude) {
|
2024-01-11 21:13:30 -07:00
|
|
|
AllocatedBuffer ret = {
|
|
|
|
.memory = VK_NULL_HANDLE,
|
|
|
|
.buffer = VK_NULL_HANDLE,
|
|
|
|
};
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkBufferCreateInfo buffer_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
|
|
.size = size,
|
|
|
|
.usage = usage,
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
};
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
VkResult result = vkCreateBuffer(device, &buffer_info, 0, &ret.buffer);
|
2024-01-08 09:44:47 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 11:59:58 -07:00
|
|
|
ret.buffer = VK_NULL_HANDLE;
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
return ret;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
2024-01-08 11:59:58 -07:00
|
|
|
vkGetBufferMemoryRequirements(device, ret.buffer, &memory_requirements);
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkMemoryAllocateInfo alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
.allocationSize = memory_requirements.size,
|
|
|
|
.memoryTypeIndex = pick_memory(memories, memory_requirements.memoryTypeBits, include, exclude),
|
|
|
|
};
|
2024-01-08 11:59:58 -07:00
|
|
|
|
|
|
|
result = vkAllocateMemory(device, &alloc_info, 0, &ret.memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyBuffer(device, ret.buffer, 0);
|
|
|
|
ret.buffer = VK_NULL_HANDLE;
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkBindBufferMemory(device, ret.buffer, ret.memory, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyBuffer(device, ret.buffer, 0);
|
|
|
|
ret.buffer = VK_NULL_HANDLE;
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void deallocate_buffer(VkDevice device, AllocatedBuffer buffer) {
|
|
|
|
vkDestroyBuffer(device, buffer.buffer, 0);
|
|
|
|
vkFreeMemory(device, buffer.memory, 0);
|
|
|
|
};
|
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
void deallocate_image(VkDevice device, AllocatedImage image) {
|
|
|
|
vkDestroyImage(device, image.image, 0);
|
|
|
|
vkFreeMemory(device, image.memory, 0);
|
|
|
|
};
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer* allocate_buffers(VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, uint32_t count, VkMemoryPropertyFlags include, VkMemoryPropertyFlags exclude) {
|
2024-01-08 12:42:59 -07:00
|
|
|
AllocatedBuffer* buffers = malloc(sizeof(AllocatedBuffer)*count);
|
|
|
|
if(buffers == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
2024-01-11 17:32:10 -07:00
|
|
|
buffers[i] = allocate_buffer(memories, device, size, usage, include, exclude);
|
2024-01-08 12:42:59 -07:00
|
|
|
if(buffers[i].memory == VK_NULL_HANDLE) {
|
|
|
|
for(uint32_t j = 0; j < i; j++) {
|
|
|
|
deallocate_buffer(device, buffers[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(buffers);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buffers;
|
|
|
|
}
|
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
VkCommandBuffer command_begin_single(VkDevice device, VkCommandPool transfer_pool) {
|
2024-01-11 21:13:30 -07:00
|
|
|
VkCommandBufferAllocateInfo command_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
|
.commandPool = transfer_pool,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
};
|
2024-01-08 11:59:58 -07:00
|
|
|
|
|
|
|
VkCommandBuffer command_buffer;
|
|
|
|
VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 21:36:45 -07:00
|
|
|
return VK_NULL_HANDLE;
|
2024-01-08 11:59:58 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkCommandBufferBeginInfo begin_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
|
|
|
};
|
2024-01-08 11:59:58 -07:00
|
|
|
|
|
|
|
result = vkBeginCommandBuffer(command_buffer, &begin_info);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
2024-01-08 21:36:45 -07:00
|
|
|
return VK_NULL_HANDLE;
|
2024-01-08 11:59:58 -07:00
|
|
|
}
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
return command_buffer;
|
|
|
|
}
|
2024-01-08 11:59:58 -07:00
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
VkResult command_end_single(VkDevice device, VkCommandBuffer command_buffer, VkCommandPool transfer_pool, VkQueue transfer_queue) {
|
2024-01-11 17:32:10 -07:00
|
|
|
VkResult result = vkEndCommandBuffer(command_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkSubmitInfo submit_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
.pCommandBuffers = &command_buffer,
|
|
|
|
};
|
2024-01-08 11:59:58 -07:00
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0);
|
2024-01-08 09:44:47 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 11:59:58 -07:00
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
return result;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
result = vkQueueWaitIdle(transfer_queue);
|
2024-01-08 21:36:45 -07:00
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) {
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkBufferCopy copy_region = {
|
|
|
|
.srcOffset = 0,
|
|
|
|
.dstOffset = 0,
|
|
|
|
.size = size,
|
|
|
|
};
|
2024-01-08 21:36:45 -07:00
|
|
|
|
|
|
|
vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region);
|
2024-01-08 11:59:58 -07:00
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
|
|
}
|
2024-01-08 11:59:58 -07:00
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
VkResult command_transition_image_layout(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkImageLayout old_layout, VkImageLayout new_layout, VkImage image, VkAccessFlags src_mask, VkAccessFlags dst_mask, VkPipelineStageFlags source, VkPipelineStageFlags dest, uint32_t source_family, uint32_t dest_family, VkImageAspectFlags aspect_flags) {
|
2024-01-08 21:36:45 -07:00
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
|
|
|
VkImageMemoryBarrier barrier = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
|
|
|
.oldLayout = old_layout,
|
|
|
|
.newLayout = new_layout,
|
2024-01-11 17:32:10 -07:00
|
|
|
.srcQueueFamilyIndex = source_family,
|
|
|
|
.dstQueueFamilyIndex = dest_family,
|
2024-01-08 21:36:45 -07:00
|
|
|
.image = image,
|
|
|
|
.subresourceRange = {
|
2024-01-11 18:06:20 -07:00
|
|
|
.aspectMask = aspect_flags,
|
2024-01-08 21:36:45 -07:00
|
|
|
.levelCount = 1,
|
|
|
|
.layerCount = 1,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
},
|
2024-01-11 17:32:10 -07:00
|
|
|
.srcAccessMask = src_mask,
|
|
|
|
.dstAccessMask = dst_mask,
|
2024-01-08 21:36:45 -07:00
|
|
|
};
|
2024-01-11 17:32:10 -07:00
|
|
|
vkCmdPipelineBarrier(command_buffer, source, dest, 0, 0, 0, 0, 0, 1, &barrier);
|
2024-01-08 21:36:45 -07:00
|
|
|
|
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult command_copy_buffer_to_image(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkExtent3D image_size, VkBuffer source, VkImage dest) {
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, transfer_pool);
|
|
|
|
|
|
|
|
VkBufferImageCopy region = {
|
|
|
|
.bufferOffset = 0,
|
|
|
|
.bufferRowLength = 0,
|
|
|
|
.bufferImageHeight = 0,
|
|
|
|
.imageSubresource = {
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = 1,
|
|
|
|
.mipLevel = 0,
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
},
|
|
|
|
.imageOffset = {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
.imageExtent = image_size,
|
|
|
|
};
|
|
|
|
|
|
|
|
vkCmdCopyBufferToImage(command_buffer, source, dest, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
|
|
|
|
|
|
return command_end_single(device, command_buffer, transfer_pool, transfer_queue);
|
2024-01-08 11:59:58 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer create_populated_buffer(VkPhysicalDeviceMemoryProperties memories, VkDevice device, void* data, VkDeviceSize size, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBufferUsageFlags usage) {
|
2024-01-08 11:59:58 -07:00
|
|
|
AllocatedBuffer staging_buffer = {};
|
|
|
|
AllocatedBuffer vertex_buffer = {};
|
2024-01-11 17:32:10 -07:00
|
|
|
staging_buffer = allocate_buffer(memories, device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
2024-01-08 11:59:58 -07:00
|
|
|
if(staging_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
return vertex_buffer;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
|
2024-01-08 09:44:47 -07:00
|
|
|
void* buffer_data;
|
2024-01-08 11:59:58 -07:00
|
|
|
VkResult result = vkMapMemory(device, staging_buffer.memory, 0, size, 0, &buffer_data);
|
2024-01-08 09:44:47 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 11:59:58 -07:00
|
|
|
deallocate_buffer(device, staging_buffer);
|
|
|
|
return vertex_buffer;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(buffer_data, data, size);
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
vkUnmapMemory(device, staging_buffer.memory);
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
vertex_buffer = allocate_buffer(memories, device, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT);
|
2024-01-08 11:59:58 -07:00
|
|
|
if(vertex_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
deallocate_buffer(device, staging_buffer);
|
|
|
|
return vertex_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = command_copy_buffers(device, transfer_pool, transfer_queue, staging_buffer.buffer, vertex_buffer.buffer, size);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging_buffer);
|
|
|
|
deallocate_buffer(device, vertex_buffer);
|
|
|
|
vertex_buffer.buffer = VK_NULL_HANDLE;
|
|
|
|
vertex_buffer.memory = VK_NULL_HANDLE;
|
|
|
|
return vertex_buffer;
|
|
|
|
}
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
return vertex_buffer;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Texture load_texture(VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkCommandPool graphics_pool, VkQueue graphics_queue, VkExtent2D size, uint32_t stride, VkFormat format, void* image_data, uint32_t transfer_family, uint32_t graphics_family){
|
2024-01-08 21:36:45 -07:00
|
|
|
Texture ret = {
|
|
|
|
.image.image = VK_NULL_HANDLE,
|
|
|
|
.image.memory = VK_NULL_HANDLE,
|
|
|
|
.view = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
|
|
|
|
uint32_t image_size = size.width * size.height * stride;
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer staging = allocate_buffer(memories, device, image_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
2024-01-08 21:36:45 -07:00
|
|
|
if(staging.memory == VK_NULL_HANDLE) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void* staging_ptr;
|
|
|
|
VkResult result = vkMapMemory(device, staging.memory, 0, image_size, 0, &staging_ptr);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(staging_ptr, image_data, image_size);
|
|
|
|
|
|
|
|
vkUnmapMemory(device, staging.memory);
|
|
|
|
|
|
|
|
VkExtent3D full_extent = {
|
|
|
|
.width = size.width,
|
|
|
|
.height = size.height,
|
|
|
|
.depth = 1,
|
|
|
|
};
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedImage image = allocate_image(memories, device, VK_IMAGE_TYPE_2D, format, full_extent, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
|
2024-01-08 21:36:45 -07:00
|
|
|
if(image.memory == VK_NULL_HANDLE) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, image.image, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, transfer_family, transfer_family, VK_IMAGE_ASPECT_COLOR_BIT);
|
2024-01-08 21:36:45 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = command_copy_buffer_to_image(device, transfer_pool, transfer_queue, full_extent, staging.buffer, image.image);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
result = command_transition_image_layout(device, transfer_pool, transfer_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family, VK_IMAGE_ASPECT_COLOR_BIT);
|
2024-01-11 17:32:10 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
result = command_transition_image_layout(device, graphics_pool, graphics_queue, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, image.image, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, transfer_family, graphics_family, VK_IMAGE_ASPECT_COLOR_BIT);
|
2024-01-11 17:32:10 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-08 21:36:45 -07:00
|
|
|
VkImageView view;
|
|
|
|
VkImageViewCreateInfo view_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
|
|
.image = image.image,
|
|
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
|
|
.components = {
|
|
|
|
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
|
|
},
|
|
|
|
.format = format,
|
|
|
|
.subresourceRange = {
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
.layerCount = 1,
|
|
|
|
.levelCount = 1,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkCreateImageView(device, &view_info, 0, &view);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_buffer(device, staging);
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkSampler sampler;
|
|
|
|
VkSamplerCreateInfo sampler_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
|
|
.magFilter = VK_FILTER_NEAREST,
|
|
|
|
.minFilter = VK_FILTER_NEAREST,
|
|
|
|
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
|
|
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
|
|
|
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
2024-01-09 23:06:08 -07:00
|
|
|
.anisotropyEnable = VK_FALSE,
|
2024-01-09 10:32:22 -07:00
|
|
|
.maxAnisotropy = 2.0f,
|
2024-01-08 21:36:45 -07:00
|
|
|
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
|
|
|
|
.unnormalizedCoordinates = VK_FALSE,
|
|
|
|
.compareEnable = VK_FALSE,
|
|
|
|
.compareOp = VK_COMPARE_OP_ALWAYS,
|
|
|
|
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
|
|
|
|
.mipLodBias = 0.0f,
|
|
|
|
.minLod = 0.0f,
|
|
|
|
.maxLod = 0.0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkCreateSampler(device, &sampler_info, 0, &sampler);
|
2024-01-09 23:06:08 -07:00
|
|
|
deallocate_buffer(device, staging);
|
2024-01-08 21:36:45 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
deallocate_image(device, image);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret.image = image;
|
|
|
|
ret.view = view;
|
|
|
|
ret.sampler = sampler;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-08 20:14:07 -07:00
|
|
|
VkPipeline create_graphics_pipeline(
|
|
|
|
VkDevice device,
|
|
|
|
VkExtent2D extent,
|
|
|
|
VkPipelineLayout layout,
|
|
|
|
VkRenderPass render_pass,
|
|
|
|
uint32_t shader_stage_count,
|
|
|
|
VkPipelineShaderStageCreateInfo* shader_stages,
|
2024-01-09 18:36:40 -07:00
|
|
|
MeshType mesh_type
|
2024-01-08 20:14:07 -07:00
|
|
|
) {
|
2024-01-07 22:27:53 -07:00
|
|
|
VkDynamicState dynamic_states[] = {
|
|
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
|
|
VK_DYNAMIC_STATE_SCISSOR,
|
|
|
|
};
|
|
|
|
uint32_t dynamic_state_count = sizeof(dynamic_states)/sizeof(VkDynamicState);
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkPipelineDynamicStateCreateInfo dynamic_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
|
|
.dynamicStateCount = dynamic_state_count,
|
|
|
|
.pDynamicStates = dynamic_states,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
|
|
.vertexBindingDescriptionCount = mesh_type.bindings_count,
|
|
|
|
.pVertexBindingDescriptions = mesh_type.bindings,
|
|
|
|
.vertexAttributeDescriptionCount = mesh_type.attributes_count,
|
|
|
|
.pVertexAttributeDescriptions = mesh_type.attributes,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkViewport viewport = {
|
|
|
|
.x = 0.0f,
|
|
|
|
.y = 0.0f,
|
|
|
|
.width = (float)(extent.width),
|
|
|
|
.height = (float)(extent.height),
|
|
|
|
.minDepth = 0.0f,
|
|
|
|
.maxDepth = 1.0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkRect2D scissor = {
|
|
|
|
.offset = {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
},
|
|
|
|
.extent = extent,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_state = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
|
|
.viewportCount = 1,
|
|
|
|
.pViewports = &viewport,
|
|
|
|
.scissorCount = 1,
|
|
|
|
.pScissors = &scissor,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineRasterizationStateCreateInfo raster_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
|
|
.depthClampEnable = VK_FALSE,
|
|
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
|
|
.lineWidth = 1.0f,
|
|
|
|
.cullMode = VK_CULL_MODE_NONE,
|
|
|
|
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
|
|
.depthBiasEnable = VK_FALSE,
|
|
|
|
.depthBiasConstantFactor = 0.0f,
|
|
|
|
.depthBiasClamp = 0.0f,
|
|
|
|
.depthBiasSlopeFactor = 0.0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisample_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
|
|
.sampleShadingEnable = VK_FALSE,
|
|
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.minSampleShading = 1.0f,
|
|
|
|
.pSampleMask = 0,
|
|
|
|
.alphaToCoverageEnable = VK_FALSE,
|
|
|
|
.alphaToOneEnable = VK_FALSE,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkPipelineDepthStencilStateCreateInfo depth_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
|
|
|
.depthTestEnable = VK_TRUE,
|
|
|
|
.depthWriteEnable = VK_TRUE,
|
|
|
|
.depthCompareOp = VK_COMPARE_OP_LESS,
|
|
|
|
.depthBoundsTestEnable = VK_FALSE,
|
|
|
|
.maxDepthBounds = 1.0f,
|
|
|
|
.minDepthBounds = 0.0f,
|
|
|
|
.stencilTestEnable = VK_FALSE,
|
|
|
|
.front = {},
|
|
|
|
.back = {},
|
|
|
|
};
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment = {
|
|
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
|
|
.blendEnable = VK_TRUE,
|
|
|
|
.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,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blend_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
|
|
.logicOpEnable = VK_FALSE,
|
|
|
|
.logicOp = VK_LOGIC_OP_COPY,
|
|
|
|
.attachmentCount = 1,
|
|
|
|
.pAttachments = &color_blend_attachment,
|
|
|
|
.blendConstants[0] = 0.0f,
|
|
|
|
.blendConstants[1] = 0.0f,
|
|
|
|
.blendConstants[2] = 0.0f,
|
|
|
|
.blendConstants[3] = 0.0f,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkGraphicsPipelineCreateInfo pipeline_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
|
|
.stageCount = shader_stage_count,
|
|
|
|
.pStages = shader_stages,
|
|
|
|
.pVertexInputState = &vertex_input_info,
|
|
|
|
.pInputAssemblyState = &input_assembly_info,
|
|
|
|
.pViewportState = &viewport_state,
|
|
|
|
.pRasterizationState = &raster_info,
|
|
|
|
.pColorBlendState = &color_blend_info,
|
|
|
|
.pDynamicState = &dynamic_info,
|
|
|
|
.pDepthStencilState = &depth_info,
|
|
|
|
.pMultisampleState = &multisample_info,
|
|
|
|
.layout = layout,
|
|
|
|
.renderPass = render_pass,
|
|
|
|
.subpass = 0,
|
|
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
|
|
.basePipelineIndex = -1,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkPipeline pipeline;
|
|
|
|
VkResult result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, 0, &pipeline);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
int create_depth_image(VulkanContext* context) {
|
|
|
|
VkExtent3D depth_extent = {
|
|
|
|
.width = context->swapchain_extent.width,
|
|
|
|
.height = context->swapchain_extent.height,
|
|
|
|
.depth = 1,
|
|
|
|
};
|
2024-01-08 19:48:09 -07:00
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkImageCreateInfo depth_image_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
|
|
.extent = depth_extent,
|
|
|
|
.mipLevels = 1,
|
|
|
|
.arrayLayers = 1,
|
|
|
|
.format = context->depth_format,
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
2024-01-11 17:32:10 -07:00
|
|
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT,
|
2024-01-11 16:16:10 -07:00
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.flags = 0,
|
|
|
|
};
|
2024-01-08 19:48:09 -07:00
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkImage depth_image;
|
|
|
|
VkResult result = vkCreateImage(context->device, &depth_image_info, 0, &depth_image);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to create depth image\n");
|
|
|
|
return 1;
|
2024-01-08 19:48:09 -07:00
|
|
|
} else {
|
2024-01-11 16:16:10 -07:00
|
|
|
context->depth_image = depth_image;
|
2024-01-08 19:48:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkMemoryRequirements depth_image_requirements;
|
|
|
|
vkGetImageMemoryRequirements(context->device, context->depth_image, &depth_image_requirements);
|
2024-01-08 19:48:09 -07:00
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkMemoryAllocateInfo depth_memory_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
.allocationSize = depth_image_requirements.size,
|
2024-01-11 17:32:10 -07:00
|
|
|
.memoryTypeIndex = pick_memory(context->memories, depth_image_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, 0),
|
2024-01-09 23:19:04 -07:00
|
|
|
};
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
VkDeviceMemory depth_image_memory;
|
|
|
|
result = vkAllocateMemory(context->device, &depth_memory_info, 0, &depth_image_memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to allocate memory for depth image\n");
|
|
|
|
return 2;
|
2024-01-09 23:19:04 -07:00
|
|
|
} else {
|
2024-01-11 16:16:10 -07:00
|
|
|
context->depth_image_memory = depth_image_memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkBindImageMemory(context->device, context->depth_image, context->depth_image_memory, 0);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to bind memory for depth image\n");
|
|
|
|
return 3;
|
2024-01-09 23:19:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkImageViewCreateInfo depth_view_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
2024-01-11 16:16:10 -07:00
|
|
|
.image = context->depth_image,
|
2024-01-09 23:19:04 -07:00
|
|
|
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
|
|
.format = context->depth_format,
|
|
|
|
.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_DEPTH_BIT,
|
|
|
|
.baseMipLevel = 0,
|
|
|
|
.levelCount = 1,
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = 1,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkImageView depth_image_view;
|
2024-01-11 16:16:10 -07:00
|
|
|
result = vkCreateImageView(context->device, &depth_view_info, 0, &depth_image_view);
|
2024-01-09 23:19:04 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-11 16:16:10 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan depth image view\n");
|
|
|
|
return 4;
|
2024-01-09 23:19:04 -07:00
|
|
|
} else {
|
|
|
|
context->depth_image_view = depth_image_view;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:31:14 -07:00
|
|
|
result = command_transition_image_layout(context->device, context->extra_graphics_pool, context->queues.graphics, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, context->depth_image, 0, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, VK_IMAGE_ASPECT_DEPTH_BIT);
|
2024-01-11 18:06:20 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to transition depth image\n");
|
|
|
|
return 5;
|
|
|
|
}
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
VkResult recreate_swapchain(VulkanContext* context) {
|
2024-01-11 16:16:10 -07:00
|
|
|
for(uint32_t i = 0; i < context->swapchain_image_count; i++) {
|
|
|
|
vkDestroyFramebuffer(context->device, context->swapchain_framebuffers[i], 0);
|
|
|
|
vkDestroyImageView(context->device, context->swapchain_image_views[i], 0);
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
for(uint32_t i = 0; i < context->max_frames_in_flight; i++) {
|
|
|
|
vkDestroySemaphore(context->device, context->image_available_semaphores[i], 0);
|
|
|
|
}
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
free(context->swapchain_image_views);
|
|
|
|
free(context->swapchain_framebuffers);
|
|
|
|
free(context->swapchain_details.formats);
|
|
|
|
free(context->swapchain_details.present_modes);
|
|
|
|
|
|
|
|
vkDestroyImageView(context->device, context->depth_image_view, 0);
|
|
|
|
vkDestroyImage(context->device, context->depth_image, 0);
|
|
|
|
vkFreeMemory(context->device, context->depth_image_memory, 0);
|
|
|
|
|
|
|
|
SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
if(swapchain_details.formats == 0) {
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
} else {
|
|
|
|
context->swapchain_details = swapchain_details;
|
|
|
|
}
|
|
|
|
|
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
|
|
context->swapchain_present_mode = choose_present_mode(context->swapchain_details);
|
|
|
|
context->swapchain_extent = choose_swapchain_extent(context->swapchain_details);
|
|
|
|
|
|
|
|
create_depth_image(context);
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
VkSwapchainKHR swapchain = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->queue_indices, context->swapchain);
|
|
|
|
if(swapchain == VK_NULL_HANDLE) {
|
|
|
|
context->swapchain = VK_NULL_HANDLE;
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
} else {
|
|
|
|
context->swapchain = swapchain;
|
|
|
|
}
|
|
|
|
|
|
|
|
SwapchainImages swapchain_images = get_swapchain_images(context->device, context->swapchain);
|
|
|
|
if(swapchain_images.count == 0) {
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
} else {
|
|
|
|
context->swapchain_images = swapchain_images.images;
|
|
|
|
context->swapchain_image_count = swapchain_images.count;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkImageView* image_views = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format);
|
|
|
|
if(image_views == 0) {
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
} else {
|
|
|
|
context->swapchain_image_views = image_views;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFramebuffer* framebuffers = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->render_pass, context->swapchain_extent);
|
2024-01-08 19:48:09 -07:00
|
|
|
if(framebuffers == 0) {
|
|
|
|
return VK_ERROR_INITIALIZATION_FAILED;
|
|
|
|
} else {
|
|
|
|
context->swapchain_framebuffers = framebuffers;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
VkSemaphore* ia_semaphores = create_semaphores(context->device, 0, context->max_frames_in_flight);
|
|
|
|
if(ia_semaphores == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan image available semaphores\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->image_available_semaphores = ia_semaphores;
|
|
|
|
}
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-01-09 21:56:56 -07:00
|
|
|
void command_draw_object(Material material, Object object, uint32_t frame_num, VkCommandBuffer command_buffer) {
|
2024-01-09 21:28:57 -07:00
|
|
|
MaybeValue maybe_mesh = map_lookup(object.attributes, ATTRIBUTE_ID_MESH);
|
|
|
|
if(maybe_mesh.has_value == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
object_update_mappings(material, object, frame_num);
|
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
Mesh* mesh = maybe_mesh.value;
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
VkBuffer vertex_buffers[] = {mesh->vertex_buffer};
|
2024-01-08 20:14:07 -07:00
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
|
|
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
|
2024-01-11 23:28:59 -07:00
|
|
|
vkCmdBindIndexBuffer(command_buffer, mesh->index_buffer, 0, VK_INDEX_TYPE_UINT16);
|
2024-01-08 20:14:07 -07:00
|
|
|
|
2024-01-10 11:31:32 -07:00
|
|
|
if(material.object_set_layout != VK_NULL_HANDLE) {
|
2024-01-10 11:27:04 -07:00
|
|
|
MaybeValue maybe_descriptors = map_lookup(object.attributes, ATTRIBUTE_ID_DESCRIPTOR_SETS);
|
2024-01-09 21:56:56 -07:00
|
|
|
if(maybe_descriptors.has_value == false) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSet* descriptor_sets = maybe_descriptors.value;
|
|
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 2, 1, &descriptor_sets[frame_num], 0, 0);
|
2024-01-10 19:32:01 -07:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "test\n");
|
2024-01-09 21:56:56 -07:00
|
|
|
}
|
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
vkCmdDrawIndexed(command_buffer, mesh->index_count, 1, 0, 0, 0);
|
2024-01-08 20:14:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 11:31:32 -07:00
|
|
|
void command_draw_material(Material material, uint32_t object_count, Object* objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, VkCommandBuffer command_buffer) {
|
2024-01-08 16:44:14 -07:00
|
|
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.pipeline);
|
2024-01-09 21:28:57 -07:00
|
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 0, 1, &scene_descriptors[frame_num], 0, 0);
|
|
|
|
if(material.material_descriptors != 0) {
|
|
|
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material.layout, 1, 1, &material.material_descriptors[frame_num], 0, 0);
|
|
|
|
}
|
2024-01-10 11:31:32 -07:00
|
|
|
for(uint32_t i = 0; i < object_count; i++) {
|
2024-01-09 21:56:56 -07:00
|
|
|
command_draw_object(material, objects[i], frame_num, command_buffer);
|
2024-01-08 16:44:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-10 11:31:32 -07:00
|
|
|
VkResult command_draw_scene(uint32_t materials_count, Material* materials, uint32_t* object_counts, Object** objects, uint32_t frame_num, VkDescriptorSet* scene_descriptors, VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer framebuffer, VkExtent2D extent) {
|
2024-01-11 21:13:30 -07:00
|
|
|
VkCommandBufferBeginInfo begin_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
|
|
|
.flags = 0,
|
|
|
|
.pInheritanceInfo = 0,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
VkResult result = vkBeginCommandBuffer(command_buffer, &begin_info);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkClearValue clear_colors[] = {
|
|
|
|
{
|
|
|
|
.color = {
|
|
|
|
{0.0f, 0.0f, 0.0f, 1.0f}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.depthStencil = {1.0f, 0.0f},
|
|
|
|
},
|
|
|
|
};
|
2024-01-11 21:13:30 -07:00
|
|
|
|
|
|
|
VkRenderPassBeginInfo render_pass_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
|
|
.renderPass = render_pass,
|
|
|
|
.framebuffer = framebuffer,
|
|
|
|
.renderArea = {
|
|
|
|
.offset = {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
},
|
|
|
|
.extent = extent,
|
|
|
|
},
|
|
|
|
.clearValueCount = sizeof(clear_colors)/sizeof(VkClearValue),
|
|
|
|
.pClearValues = clear_colors,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
vkCmdBeginRenderPass(command_buffer, &render_pass_info, VK_SUBPASS_CONTENTS_INLINE);
|
2024-01-08 09:44:47 -07:00
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkViewport viewport = {
|
|
|
|
.x = 0.0f,
|
|
|
|
.y = 0.0f,
|
|
|
|
.width = (float)(extent.width),
|
|
|
|
.height = (float)(extent.height),
|
|
|
|
.minDepth = 0.0f,
|
|
|
|
.maxDepth = 1.0f,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkRect2D scissor = {
|
|
|
|
.offset = {
|
|
|
|
.x = 0.0f,
|
|
|
|
.y = 0.0f,
|
|
|
|
},
|
|
|
|
.extent = extent,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
|
2024-01-08 16:44:14 -07:00
|
|
|
for(uint i = 0; i < materials_count; i++) {
|
2024-01-10 11:31:32 -07:00
|
|
|
command_draw_material(materials[i], object_counts[i], objects[i], frame_num, scene_descriptors, command_buffer);
|
2024-01-08 16:44:14 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
|
|
|
|
return vkEndCommandBuffer(command_buffer);
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VkCommandBuffer* create_command_buffers(VkDevice device, VkCommandPool command_pool, uint32_t image_count) {
|
2024-01-11 21:13:30 -07:00
|
|
|
VkCommandBufferAllocateInfo alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
|
|
.commandPool = command_pool,
|
|
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
|
|
.commandBufferCount = image_count,
|
|
|
|
};
|
2024-01-07 22:55:36 -07:00
|
|
|
|
|
|
|
VkCommandBuffer* command_buffers = malloc(sizeof(VkCommandBuffer)*image_count);
|
|
|
|
if(command_buffers == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
2024-01-07 22:27:53 -07:00
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VkResult result = vkAllocateCommandBuffers(device, &alloc_info, command_buffers);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
return command_buffers;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VkFence* create_fences(VkDevice device, VkFenceCreateFlags flags, uint32_t count) {
|
|
|
|
VkFence* fences = malloc(sizeof(VkFence)*count);
|
|
|
|
if(fences == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkFenceCreateInfo fence_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
|
|
|
.flags = flags,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
|
|
|
VkResult result = vkCreateFence(device, &fence_info, 0, &fences[i]);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
free(fences);
|
|
|
|
return 0;
|
|
|
|
}
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
2024-01-07 22:55:36 -07:00
|
|
|
return fences;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
Object create_object(uint32_t max_frames_in_flight, uint32_t descriptor_count) {
|
2024-01-09 21:28:57 -07:00
|
|
|
Object ret = {
|
|
|
|
.attributes = {
|
|
|
|
.buckets = 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
Map attributes = map_create(8, 2);
|
|
|
|
if(attributes.buckets == 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
if(descriptor_count > 0) {
|
|
|
|
void*** descriptor_arrays = malloc(sizeof(void**)*max_frames_in_flight);
|
|
|
|
if(descriptor_arrays == 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
descriptor_arrays[i] = malloc(sizeof(void*)*descriptor_count);
|
|
|
|
|
|
|
|
if(descriptor_arrays[i] == 0) {
|
|
|
|
for(uint32_t j = 0; j < i; j++) {
|
|
|
|
free(descriptor_arrays[j]);
|
|
|
|
}
|
|
|
|
free(descriptor_arrays);
|
|
|
|
map_destroy(attributes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool result = map_add(&attributes, ATTRIBUTE_ID_DESCRIPTORS, descriptor_arrays);
|
|
|
|
if(result == false) {
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
free(descriptor_arrays[i]);
|
|
|
|
}
|
|
|
|
free(descriptor_arrays);
|
|
|
|
map_destroy(attributes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
ret.attributes = attributes;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2024-01-10 16:27:21 -07:00
|
|
|
Object create_renderable(Mesh* mesh, Material* material, uint32_t descriptor_sets_count, VkDescriptorSet* descriptor_sets, uint32_t max_frames_in_flight) {
|
2024-01-09 21:28:57 -07:00
|
|
|
Object zero = {
|
|
|
|
.attributes = {
|
|
|
|
.buckets = 0,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-01-10 16:27:21 -07:00
|
|
|
Object object = create_object(max_frames_in_flight, descriptor_sets_count);
|
2024-01-10 13:19:41 -07:00
|
|
|
if(object.attributes.buckets == 0) {
|
2024-01-09 21:28:57 -07:00
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
if(mesh == 0 || material == 0) {
|
2024-01-09 21:28:57 -07:00
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
bool result = map_add(&object.attributes, ATTRIBUTE_ID_MESH, mesh);
|
2024-01-09 21:28:57 -07:00
|
|
|
if(result == false) {
|
2024-01-10 13:19:41 -07:00
|
|
|
map_destroy(object.attributes);
|
2024-01-09 21:28:57 -07:00
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
result = map_add(&object.attributes, ATTRIBUTE_ID_MATERIAL, material);
|
2024-01-09 21:28:57 -07:00
|
|
|
if(result == false) {
|
2024-01-10 13:19:41 -07:00
|
|
|
map_destroy(object.attributes);
|
2024-01-09 21:28:57 -07:00
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
result = map_add(&object.attributes, ATTRIBUTE_ID_DESCRIPTOR_SETS, descriptor_sets);
|
2024-01-10 11:27:04 -07:00
|
|
|
if(result == false) {
|
2024-01-10 13:19:41 -07:00
|
|
|
map_destroy(object.attributes);
|
2024-01-10 11:27:04 -07:00
|
|
|
return zero;
|
|
|
|
}
|
2024-01-10 13:19:41 -07:00
|
|
|
return object;
|
2024-01-09 21:28:57 -07:00
|
|
|
}
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
Material create_material(
|
|
|
|
VkDevice device,
|
|
|
|
VkExtent2D extent,
|
|
|
|
VkRenderPass render_pass,
|
|
|
|
uint32_t shader_stage_count,
|
|
|
|
VkPipelineShaderStageCreateInfo* shader_stages,
|
|
|
|
VkDescriptorSetLayout scene_ubo_layout,
|
2024-01-09 18:36:40 -07:00
|
|
|
PipelineLayout pipeline_layout,
|
2024-01-09 21:28:57 -07:00
|
|
|
MeshType mesh_type,
|
2024-01-10 13:19:41 -07:00
|
|
|
uint32_t max_frames_in_flight,
|
|
|
|
Map object_descriptor_mappings
|
2024-01-08 19:48:09 -07:00
|
|
|
) {
|
2024-01-08 15:23:23 -07:00
|
|
|
Material zero_material = {
|
|
|
|
.pipeline = VK_NULL_HANDLE,
|
|
|
|
};
|
|
|
|
|
2024-01-09 12:33:38 -07:00
|
|
|
VkDescriptorSetLayout material_set_layout;
|
2024-01-10 11:31:32 -07:00
|
|
|
VkDescriptorSetLayout object_set_layout;
|
2024-01-09 12:33:38 -07:00
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
VkDescriptorPool material_descriptor_pool = VK_NULL_HANDLE;
|
|
|
|
VkDescriptorSet* material_descriptors = 0;
|
|
|
|
|
2024-01-09 23:06:08 -07:00
|
|
|
VkDescriptorSetLayoutCreateInfo material_layout_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
|
|
.bindingCount = pipeline_layout.material_bindings_count,
|
|
|
|
.pBindings = pipeline_layout.material_bindings,
|
|
|
|
};
|
2024-01-09 12:33:38 -07:00
|
|
|
|
2024-01-09 23:06:08 -07:00
|
|
|
VkResult result = vkCreateDescriptorSetLayout(device, &material_layout_info, 0, &material_set_layout);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero_material;
|
|
|
|
}
|
2024-01-09 12:33:38 -07:00
|
|
|
|
2024-01-09 23:06:08 -07:00
|
|
|
if(pipeline_layout.material_bindings_count > 0) {
|
2024-01-09 21:28:57 -07:00
|
|
|
material_descriptors = malloc(sizeof(VkDescriptorSet)*max_frames_in_flight);
|
|
|
|
if(material_descriptors == 0) {
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorPoolSize* pool_sizes = malloc(sizeof(VkDescriptorPool)*pipeline_layout.material_bindings_count);
|
|
|
|
if(pool_sizes == 0) {
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < pipeline_layout.material_bindings_count; i++) {
|
|
|
|
VkDescriptorPoolSize pool_size = {
|
|
|
|
.type = pipeline_layout.material_bindings[i].descriptorType,
|
|
|
|
.descriptorCount = pipeline_layout.material_bindings[i].descriptorCount,
|
|
|
|
};
|
|
|
|
pool_sizes[i] = pool_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorPoolCreateInfo pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
|
|
.poolSizeCount = pipeline_layout.material_bindings_count,
|
|
|
|
.maxSets = max_frames_in_flight,
|
|
|
|
.pPoolSizes = pool_sizes,
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkCreateDescriptorPool(device, &pool_info, 0, &material_descriptor_pool);
|
|
|
|
free(pool_sizes);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSetLayout* set_layouts = malloc(sizeof(VkDescriptorSetLayout)*max_frames_in_flight);
|
|
|
|
if(set_layouts == 0) {
|
|
|
|
vkDestroyDescriptorPool(device, material_descriptor_pool, 0);
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
set_layouts[i] = material_set_layout;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSetAllocateInfo alloc_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
|
|
.descriptorSetCount = max_frames_in_flight,
|
|
|
|
.descriptorPool = material_descriptor_pool,
|
|
|
|
.pSetLayouts = set_layouts,
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkAllocateDescriptorSets(device, &alloc_info, material_descriptors);
|
|
|
|
free(set_layouts);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyDescriptorPool(device, material_descriptor_pool, 0);
|
|
|
|
return zero_material;
|
|
|
|
}
|
2024-01-08 15:23:23 -07:00
|
|
|
}
|
|
|
|
|
2024-01-09 23:06:08 -07:00
|
|
|
VkDescriptorSetLayoutCreateInfo mesh_layout_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
2024-01-10 11:31:32 -07:00
|
|
|
.bindingCount = pipeline_layout.object_bindings_count,
|
|
|
|
.pBindings = pipeline_layout.object_bindings,
|
2024-01-09 23:06:08 -07:00
|
|
|
};
|
2024-01-09 12:33:38 -07:00
|
|
|
|
2024-01-10 11:31:32 -07:00
|
|
|
result = vkCreateDescriptorSetLayout(device, &mesh_layout_info, 0, &object_set_layout);
|
2024-01-09 23:06:08 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero_material;
|
2024-01-08 15:23:23 -07:00
|
|
|
}
|
2024-01-10 11:31:32 -07:00
|
|
|
VkDescriptorSetLayout all_layouts[3] = {scene_ubo_layout, material_set_layout, object_set_layout};
|
2024-01-08 15:23:23 -07:00
|
|
|
|
2024-01-09 20:41:31 -07:00
|
|
|
VkPipelineLayout layout;
|
2024-01-09 23:06:08 -07:00
|
|
|
VkPipelineLayoutCreateInfo layout_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
|
|
.setLayoutCount = 3,
|
|
|
|
.pSetLayouts = all_layouts,
|
|
|
|
.pushConstantRangeCount = 0,
|
|
|
|
.pPushConstantRanges = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkCreatePipelineLayout(device, &layout_info, 0, &layout);
|
2024-01-09 20:41:31 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 15:23:23 -07:00
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
2024-01-09 18:36:40 -07:00
|
|
|
VkPipeline pipeline = create_graphics_pipeline(device, extent, layout, render_pass, shader_stage_count, shader_stages, mesh_type);
|
2024-01-08 15:23:23 -07:00
|
|
|
if(pipeline == VK_NULL_HANDLE) {
|
|
|
|
return zero_material;
|
|
|
|
}
|
|
|
|
|
|
|
|
Material material = {
|
2024-01-09 18:36:40 -07:00
|
|
|
.layout = layout,
|
2024-01-08 15:23:23 -07:00
|
|
|
.pipeline = pipeline,
|
2024-01-09 12:33:38 -07:00
|
|
|
|
|
|
|
.material_set_layout = material_set_layout,
|
2024-01-10 11:31:32 -07:00
|
|
|
.object_set_layout = object_set_layout,
|
2024-01-09 21:28:57 -07:00
|
|
|
|
|
|
|
.material_descriptors = material_descriptors,
|
|
|
|
.material_descriptor_pool = material_descriptor_pool,
|
|
|
|
.material_descriptors_count = max_frames_in_flight,
|
2024-01-10 13:19:41 -07:00
|
|
|
.object_descriptor_mappings = object_descriptor_mappings,
|
2024-01-08 15:23:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return material;
|
|
|
|
}
|
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
Material create_simple_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout, uint32_t max_frames_in_flight) {
|
2024-01-08 20:32:47 -07:00
|
|
|
VkShaderModule vert_shader = load_shader_file(2048, "shader_src/basic.vert.spv", device);
|
|
|
|
VkShaderModule frag_shader = load_shader_file(2048, "shader_src/basic.frag.spv", device);
|
2024-01-11 17:32:10 -07:00
|
|
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
.module = vert_shader,
|
|
|
|
.pName = "main",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
.module = frag_shader,
|
|
|
|
.pName = "main",
|
|
|
|
},
|
|
|
|
};
|
2024-01-08 20:32:47 -07:00
|
|
|
|
|
|
|
|
|
|
|
VkVertexInputBindingDescription bindings[1] = {
|
|
|
|
{
|
2024-01-09 18:36:40 -07:00
|
|
|
.binding = 0, // Which buffer 'binding' to use
|
|
|
|
.stride = sizeof(struct Vertex), // How many bytes to increase the index between instance
|
|
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX, // Whether an instance is a vertex or an index
|
2024-01-08 20:32:47 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkVertexInputAttributeDescription attributes[2] = {
|
|
|
|
{
|
2024-01-09 18:36:40 -07:00
|
|
|
.binding = 0, // Which buffer 'binding' to use
|
|
|
|
.location = 0, // Which 'location' to export as to shader
|
|
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT, // What format to interpret as for shader
|
|
|
|
.offset = offsetof(struct Vertex, pos), // What offset from instance start
|
2024-01-08 20:32:47 -07:00
|
|
|
},
|
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.location = 1,
|
|
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
.offset = offsetof(struct Vertex, color),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-01-09 18:36:40 -07:00
|
|
|
MeshType simple_mesh_type = {
|
|
|
|
.bindings = bindings,
|
|
|
|
.bindings_count = sizeof(bindings)/sizeof(VkVertexInputBindingDescription),
|
|
|
|
.attributes = attributes,
|
|
|
|
.attributes_count = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
|
|
|
|
};
|
|
|
|
|
2024-01-10 16:27:21 -07:00
|
|
|
VkDescriptorSetLayoutBinding object_set_bindings[] = {
|
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.pImmutableSamplers = 0,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
},
|
2024-01-09 18:36:40 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 16:27:21 -07:00
|
|
|
PipelineLayout simple_layout = {
|
|
|
|
.object_bindings = object_set_bindings,
|
2024-01-10 19:32:01 -07:00
|
|
|
.object_bindings_count = sizeof(object_set_bindings)/sizeof(VkDescriptorSetLayoutBinding),
|
2024-01-10 13:19:41 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 16:27:21 -07:00
|
|
|
Map object_descriptor_mappings = map_create(8, 2);
|
|
|
|
if(object_descriptor_mappings.buckets == 0) {
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mapping* position_mapping = malloc(sizeof(Mapping));
|
|
|
|
if(position_mapping == 0) {
|
|
|
|
map_destroy(object_descriptor_mappings);
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
position_mapping->mapping_type = MAPPING_POSITION_TO_MATRIX;
|
|
|
|
position_mapping->index = 0;
|
|
|
|
|
|
|
|
bool map_result = map_add(&object_descriptor_mappings, ATTRIBUTE_ID_POSITION, position_mapping);
|
|
|
|
if(map_result != true) {
|
|
|
|
map_destroy(object_descriptor_mappings);
|
|
|
|
free(position_mapping);
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, simple_layout, simple_mesh_type, max_frames_in_flight, object_descriptor_mappings);
|
2024-01-08 20:32:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-09 21:28:57 -07:00
|
|
|
Material create_texture_mesh_material(VkDevice device, VkExtent2D extent, VkRenderPass render_pass, VkDescriptorSetLayout scene_ubo_layout, uint32_t max_frames_in_flight) {
|
2024-01-08 20:32:47 -07:00
|
|
|
VkShaderModule vert_shader = load_shader_file(2048, "shader_src/texture.vert.spv", device);
|
|
|
|
if(vert_shader == VK_NULL_HANDLE) {
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
VkShaderModule frag_shader = load_shader_file(2048, "shader_src/texture.frag.spv", device);
|
|
|
|
if(frag_shader == VK_NULL_HANDLE) {
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
2024-01-10 19:32:01 -07:00
|
|
|
VkPipelineShaderStageCreateInfo shader_stages[2] = {
|
|
|
|
{
|
2024-01-11 17:32:10 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
2024-01-10 19:32:01 -07:00
|
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
.module = vert_shader,
|
|
|
|
.pName = "main",
|
|
|
|
},
|
|
|
|
{
|
2024-01-11 17:32:10 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
2024-01-10 19:32:01 -07:00
|
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
.module = frag_shader,
|
|
|
|
.pName = "main",
|
|
|
|
},
|
|
|
|
};
|
2024-01-08 20:32:47 -07:00
|
|
|
|
|
|
|
|
2024-01-09 12:33:38 -07:00
|
|
|
VkVertexInputBindingDescription bindings[] = {
|
2024-01-08 20:32:47 -07:00
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.stride = sizeof(struct TextureVertex),
|
|
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-01-09 12:33:38 -07:00
|
|
|
VkVertexInputAttributeDescription attributes[] = {
|
2024-01-08 20:32:47 -07:00
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.location = 0,
|
|
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
.offset = offsetof(struct TextureVertex, pos),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.location = 1,
|
|
|
|
.format = VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
.offset = offsetof(struct TextureVertex, color),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.binding = 0,
|
|
|
|
.location = 2,
|
|
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
|
|
.offset = offsetof(struct TextureVertex, tex),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2024-01-09 12:33:38 -07:00
|
|
|
VkDescriptorSetLayoutBinding mesh_set_bindings[] = {
|
|
|
|
{
|
2024-01-09 21:56:56 -07:00
|
|
|
.binding = 0,
|
2024-01-09 12:33:38 -07:00
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
.pImmutableSamplers = 0,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
|
|
},
|
2024-01-10 13:19:41 -07:00
|
|
|
{
|
|
|
|
.binding = 1,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.pImmutableSamplers = 0,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
},
|
2024-01-09 12:33:38 -07:00
|
|
|
};
|
|
|
|
|
2024-01-09 18:36:40 -07:00
|
|
|
MeshType textured_mesh_type = {
|
|
|
|
.bindings = bindings,
|
|
|
|
.bindings_count = sizeof(bindings)/sizeof(VkVertexInputBindingDescription),
|
|
|
|
.attributes = attributes,
|
|
|
|
.attributes_count = sizeof(attributes)/sizeof(VkVertexInputAttributeDescription),
|
|
|
|
};
|
|
|
|
|
|
|
|
PipelineLayout texture_layout = {
|
2024-01-10 11:31:32 -07:00
|
|
|
.object_bindings_count = sizeof(mesh_set_bindings)/sizeof(VkDescriptorSetLayoutBinding),
|
|
|
|
.object_bindings = mesh_set_bindings,
|
2024-01-09 18:36:40 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
Map object_descriptor_mappings = map_create(8, 2);
|
|
|
|
if(object_descriptor_mappings.buckets == 0) {
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mapping* position_mapping = malloc(sizeof(Mapping));
|
|
|
|
if(position_mapping == 0) {
|
|
|
|
map_destroy(object_descriptor_mappings);
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
position_mapping->mapping_type = MAPPING_POSITION_TO_MATRIX;
|
|
|
|
position_mapping->index = 0;
|
|
|
|
|
|
|
|
bool map_result = map_add(&object_descriptor_mappings, ATTRIBUTE_ID_POSITION, position_mapping);
|
|
|
|
if(map_result != true) {
|
|
|
|
map_destroy(object_descriptor_mappings);
|
|
|
|
free(position_mapping);
|
|
|
|
Material tmp = {};
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return create_material(device, extent, render_pass, 2, shader_stages, scene_ubo_layout, texture_layout, textured_mesh_type, max_frames_in_flight, object_descriptor_mappings);
|
2024-01-08 20:32:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 22:49:53 -07:00
|
|
|
typedef struct MemoryChunkStruct {
|
|
|
|
VkDeviceMemory memory;
|
2024-01-11 23:28:59 -07:00
|
|
|
VkDeviceSize used;
|
|
|
|
VkDeviceSize allocated;
|
2024-01-11 22:49:53 -07:00
|
|
|
} MemoryChunk;
|
|
|
|
|
|
|
|
VkResult allocate_memory_chunk(uint32_t memory_type, VkDevice device, VkDeviceSize size, MemoryChunk* allocated) {
|
|
|
|
if(allocated == NULL) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo allocate_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
|
|
.memoryTypeIndex = memory_type,
|
|
|
|
.allocationSize = size,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkResult result = vkAllocateMemory(device, &allocate_info, 0, &allocated->memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
allocated->used = 0;
|
|
|
|
allocated->allocated = size;
|
2024-01-11 22:49:53 -07:00
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult create_image(MemoryChunk* memory, VkDevice device, VkDeviceSize offset, VkImageType type, VkFormat format, VkExtent3D extent, VkImageUsageFlags usage, VkImage* image) {
|
|
|
|
if(image == NULL) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
} else if (*image != VK_NULL_HANDLE) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
} else if (memory == NULL) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkImageCreateInfo image_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
.imageType = type,
|
|
|
|
.extent = extent,
|
|
|
|
.mipLevels = 1,
|
|
|
|
.arrayLayers = 1,
|
|
|
|
.format = format,
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
|
|
.usage = usage,
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
.flags = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkResult result = vkCreateImage(device, &image_info, 0, image);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = vkBindImageMemory(device, *image, memory->memory, offset);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyImage(device, *image, 0);
|
|
|
|
*image = VK_NULL_HANDLE;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetImageMemoryRequirements(device, *image, &memory_requirements);
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
memory->used += memory_requirements.size;
|
2024-01-11 22:49:53 -07:00
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
VkResult create_buffer(MemoryChunk* memory, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer* buffer) {
|
2024-01-11 22:49:53 -07:00
|
|
|
if(buffer == NULL) {
|
2024-01-11 23:28:59 -07:00
|
|
|
fprintf(stderr, "buffer is null\n");
|
2024-01-11 22:49:53 -07:00
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
} else if (*buffer != VK_NULL_HANDLE) {
|
2024-01-11 23:28:59 -07:00
|
|
|
fprintf(stderr, "buffer has value\n");
|
2024-01-11 22:49:53 -07:00
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
} else if (memory == NULL) {
|
2024-01-11 23:28:59 -07:00
|
|
|
fprintf(stderr, "memory is null\n");
|
2024-01-11 22:49:53 -07:00
|
|
|
return VK_ERROR_UNKNOWN;
|
2024-01-11 23:28:59 -07:00
|
|
|
} else if ((memory->allocated - memory->used) < size) {
|
|
|
|
fprintf(stderr, "memory has not enough space\n");
|
2024-01-11 22:49:53 -07:00
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBufferCreateInfo buffer_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
|
|
.size = size,
|
|
|
|
.usage = usage,
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkResult result = vkCreateBuffer(device, &buffer_info, 0, buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-11 23:28:59 -07:00
|
|
|
fprintf(stderr, "vkCreateBuffer returned %d\n", result);
|
2024-01-11 22:49:53 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetBufferMemoryRequirements(device, *buffer, &memory_requirements);
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
result = vkBindBufferMemory(device, *buffer, memory->memory, memory->used);
|
2024-01-11 22:49:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyBuffer(device, *buffer, 0);
|
|
|
|
*buffer = VK_NULL_HANDLE;
|
2024-01-11 23:28:59 -07:00
|
|
|
fprintf(stderr, "vkBindBufferMemory returned %d\n", result);
|
2024-01-11 22:49:53 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
memory->used += size;
|
2024-01-11 22:49:53 -07:00
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
VkResult create_buffers(MemoryChunk* memory, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkBuffer** buffers, uint32_t count) {
|
2024-01-11 22:49:53 -07:00
|
|
|
if(buffers == NULL) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
} else if(*buffers == NULL) {
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
*buffers = malloc(sizeof(VkBuffer)*count);
|
|
|
|
if(*buffers == NULL) {
|
|
|
|
return VK_ERROR_OUT_OF_HOST_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < count; i++) {
|
2024-01-11 23:28:59 -07:00
|
|
|
VkResult result = create_buffer(memory, device, size, usage, &(*buffers)[i]);
|
2024-01-11 22:49:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
for(uint32_t j = 0; j < i; j++) {
|
|
|
|
vkDestroyBuffer(device, *buffers[j], 0);
|
|
|
|
}
|
|
|
|
free(buffers);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult command_copy_to_image(VkDevice device, VkBuffer staging_buffer, VkDeviceMemory staging_memory, VkImage destination, void* data, VkExtent3D size, VkDeviceSize stride, VkCommandPool pool, VkQueue queue) {
|
|
|
|
VkDeviceSize data_size = size.height * size.width * stride;
|
|
|
|
|
|
|
|
void* mapped_ptr = NULL;
|
|
|
|
VkResult result = vkMapMemory(device, staging_memory, 0, data_size, 0, &mapped_ptr);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyBuffer(device, staging_buffer, 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(mapped_ptr, data, data_size);
|
|
|
|
|
|
|
|
vkUnmapMemory(device, staging_memory);
|
|
|
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, pool);
|
|
|
|
if(command_buffer == VK_NULL_HANDLE) {
|
|
|
|
vkDestroyBuffer(device, staging_buffer, 0);
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBufferImageCopy region = {
|
|
|
|
.bufferOffset = 0,
|
|
|
|
.bufferRowLength = 0,
|
|
|
|
.bufferImageHeight = 0,
|
|
|
|
.imageSubresource = {
|
|
|
|
.baseArrayLayer = 0,
|
|
|
|
.layerCount = 1,
|
|
|
|
.mipLevel = 0,
|
|
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
|
|
},
|
|
|
|
.imageOffset = {
|
|
|
|
.x = 0,
|
|
|
|
.y = 0,
|
|
|
|
.z = 0,
|
|
|
|
},
|
|
|
|
.imageExtent = size,
|
|
|
|
};
|
|
|
|
|
|
|
|
vkCmdCopyBufferToImage(command_buffer, staging_buffer, destination, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
|
|
|
|
|
|
result = command_end_single(device, command_buffer, pool, queue);
|
|
|
|
vkDestroyBuffer(device, staging_buffer, 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkResult command_copy_to_buffer(VkDevice device, VkBuffer staging_buffer, VkDeviceMemory staging_memory, VkBuffer destination, void* data, VkDeviceSize size, VkDeviceSize offset, VkCommandPool pool, VkQueue queue) {
|
|
|
|
void* mapped_ptr = NULL;
|
|
|
|
VkResult result = vkMapMemory(device, staging_memory, 0, size, 0, &mapped_ptr);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
vkDestroyBuffer(device, staging_buffer, 0);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(mapped_ptr, data, size);
|
|
|
|
|
|
|
|
vkUnmapMemory(device, staging_memory);
|
|
|
|
|
|
|
|
VkCommandBuffer command_buffer = command_begin_single(device, pool);
|
|
|
|
if(command_buffer == VK_NULL_HANDLE) {
|
|
|
|
vkDestroyBuffer(device, staging_buffer, 0);
|
|
|
|
return VK_ERROR_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBufferCopy region = {
|
|
|
|
.srcOffset = 0,
|
|
|
|
.dstOffset = offset,
|
|
|
|
.size = size,
|
|
|
|
};
|
|
|
|
|
|
|
|
vkCmdCopyBuffer(command_buffer, staging_buffer, destination, 1, ®ion);
|
|
|
|
|
|
|
|
result = command_end_single(device, command_buffer, pool, queue);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
Mesh* load_mesh_to_buffer(VkDevice device, MemoryChunk* memory, VkBuffer staging_buffer, VkDeviceMemory staging_memory, uint32_t vertex_count, uint32_t vertex_stride, void* vertex_data, uint32_t index_count, uint32_t index_stride, void* index_data, VkCommandPool pool, VkQueue queue) {
|
|
|
|
VkBuffer vertex_buffer = VK_NULL_HANDLE;
|
|
|
|
VkBuffer index_buffer = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
VkResult result = create_buffer(memory, device, vertex_count*vertex_stride, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, &vertex_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to create vertex buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = create_buffer(memory, device, sizeof(uint16_t)*index_count, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, &index_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to create index buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = command_copy_to_buffer(device, staging_buffer, staging_memory, vertex_buffer, vertex_data, vertex_count*vertex_stride, 0, pool, queue);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to copy to vertex buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
result = command_copy_to_buffer(device, staging_buffer, staging_memory, index_buffer, index_data, index_stride*index_count, 0, pool, queue);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "Failed to copy to index buffer\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh* mesh = malloc(sizeof(Mesh));
|
|
|
|
if(mesh == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh->vertex_buffer = vertex_buffer;
|
|
|
|
mesh->vertex_count = vertex_count;
|
|
|
|
mesh->index_buffer = index_buffer;
|
|
|
|
mesh->index_count = index_count;
|
|
|
|
|
|
|
|
return mesh;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
2024-01-07 16:34:09 -07:00
|
|
|
VulkanContext* context = (VulkanContext*)malloc(sizeof(VulkanContext));
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
VkInstance instance = create_instance();
|
2024-01-07 16:34:09 -07:00
|
|
|
if(instance == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to initialize vulkan instance\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->instance = instance;
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
VkDebugUtilsMessengerEXT debug_messenger = create_debug_messenger(context->instance);
|
|
|
|
if(debug_messenger == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to initialize vulkan debug messenger\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->debug_messenger = debug_messenger;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPhysicalDevice physical_device = get_best_physical_device(context->instance);
|
|
|
|
if(physical_device == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to pick vulkan physical device\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->physical_device = physical_device;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
vkGetPhysicalDeviceMemoryProperties(context->physical_device, &context->memories);
|
2024-01-10 17:18:07 -07:00
|
|
|
|
|
|
|
VkSurfaceKHR surface;
|
|
|
|
VkResult result = glfwCreateWindowSurface(instance, window, 0, &surface);
|
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-07 16:34:09 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan surface\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->surface = surface;
|
|
|
|
}
|
|
|
|
|
2024-01-08 11:59:58 -07:00
|
|
|
QueueIndices queue_indices = get_queue_indices(context->physical_device, context->surface);
|
|
|
|
if(check_queue_indices(queue_indices) == false) {
|
2024-01-07 16:34:09 -07:00
|
|
|
fprintf(stderr, "failed to get vulkan queue indices\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-08 11:59:58 -07:00
|
|
|
context->queue_indices = queue_indices;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDevice device = create_logical_device(context->physical_device, context->queue_indices);
|
|
|
|
if(device == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create vulkan logical device\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->device = device;
|
|
|
|
}
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.graphics_family, context->queue_indices.graphics_index, &context->queues.graphics);
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.present_family, context->queue_indices.present_index, &context->queues.present);
|
2024-01-08 11:59:58 -07:00
|
|
|
vkGetDeviceQueue(device, context->queue_indices.transfer_family, context->queue_indices.transfer_index, &context->queues.transfer);
|
2024-01-07 16:34:09 -07:00
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
SwapchainDetails swapchain_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
if(swapchain_details.formats == 0) {
|
2024-01-07 16:34:09 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan logical device\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-08 17:37:52 -07:00
|
|
|
context->swapchain_details = swapchain_details;
|
2024-01-07 16:34:09 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
context->swapchain_format = choose_swapchain_format(context->swapchain_details);
|
|
|
|
context->swapchain_present_mode = choose_present_mode(context->swapchain_details);
|
|
|
|
context->swapchain_extent = choose_swapchain_extent(context->swapchain_details);
|
|
|
|
|
|
|
|
VkSwapchainKHR swapchain = create_swapchain(context->device, context->swapchain_format, context->swapchain_present_mode, context->swapchain_extent, context->surface, context->swapchain_details.capabilities, context->queue_indices, VK_NULL_HANDLE);
|
2024-01-07 16:34:09 -07:00
|
|
|
if(swapchain == VK_NULL_HANDLE) {
|
2024-01-07 22:27:53 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan swapchain\n");
|
2024-01-07 16:34:09 -07:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->swapchain = swapchain;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
SwapchainImages swapchain_images = get_swapchain_images(context->device, context->swapchain);
|
|
|
|
if(swapchain_images.count == 0) {
|
|
|
|
fprintf(stderr, "failed to get vulkan swapchain images\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->swapchain_image_count = swapchain_images.count;
|
|
|
|
context->swapchain_images = swapchain_images.images;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkImageView* image_views = create_image_views(context->device, context->swapchain_image_count, context->swapchain_images, context->swapchain_format);
|
|
|
|
if(image_views == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan image views\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->swapchain_image_views = image_views;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFormat requested[] = {
|
|
|
|
VK_FORMAT_D32_SFLOAT,
|
|
|
|
VK_FORMAT_D32_SFLOAT_S8_UINT,
|
|
|
|
VK_FORMAT_D24_UNORM_S8_UINT
|
|
|
|
};
|
|
|
|
VkFormat depth_format = find_depth_format(context->physical_device, 3, requested, VK_IMAGE_TILING_OPTIMAL, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
|
|
|
if(depth_format == VK_FORMAT_MAX_ENUM) {
|
|
|
|
fprintf(stderr, "failed to find a suitable depth image format\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->depth_format = depth_format;
|
|
|
|
}
|
|
|
|
|
2024-01-11 18:06:20 -07:00
|
|
|
VkCommandPoolCreateInfo extra_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
|
.queueFamilyIndex = context->queue_indices.graphics_family,
|
|
|
|
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
|
|
|
};
|
|
|
|
|
|
|
|
result = vkCreateCommandPool(context->device, &extra_pool_info, 0, &context->extra_graphics_pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to create extra graphics command pool\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-11 16:16:10 -07:00
|
|
|
if(create_depth_image(context) != 0) {
|
|
|
|
fprintf(stderr, "failed to create depth image\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkRenderPass render_pass = create_render_pass(context->device, context->swapchain_format, context->depth_format);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(render_pass == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create vulkan render pass\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->render_pass = render_pass;
|
|
|
|
}
|
|
|
|
|
2024-01-09 13:12:05 -07:00
|
|
|
VkFramebuffer* framebuffers = create_swapchain_framebuffers(context->device, context->swapchain_image_count, context->swapchain_image_views, context->depth_image_view, context->render_pass, context->swapchain_extent);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(framebuffers == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan framebuffers\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->swapchain_framebuffers = framebuffers;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
VkCommandPoolCreateInfo graphics_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
|
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
|
|
|
.queueFamilyIndex = context->queue_indices.graphics_family,
|
|
|
|
};
|
|
|
|
VkCommandPool graphics_command_pool;
|
|
|
|
result = vkCreateCommandPool(context->device, &graphics_pool_info, 0, &graphics_command_pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-07 22:55:36 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan graphics command pool");
|
2024-01-07 22:27:53 -07:00
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-08 11:59:58 -07:00
|
|
|
context->graphics_command_pool = graphics_command_pool;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
VkCommandPoolCreateInfo transfer_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
|
|
|
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
|
|
|
|
.queueFamilyIndex = context->queue_indices.transfer_family,
|
|
|
|
};
|
|
|
|
VkCommandPool transfer_command_pool;
|
|
|
|
result = vkCreateCommandPool(context->device, &transfer_pool_info, 0, &transfer_command_pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-08 11:59:58 -07:00
|
|
|
fprintf(stderr, "failed to create vulkan transfer command pool");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->transfer_command_pool = transfer_command_pool;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
context->max_frames_in_flight = max_frames_in_flight;
|
|
|
|
|
|
|
|
VkCommandBuffer* swapchain_command_buffers = create_command_buffers(context->device, context->graphics_command_pool, max_frames_in_flight);
|
|
|
|
if(swapchain_command_buffers == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create vulkan swapchain command buffer\n");
|
2024-01-07 22:27:53 -07:00
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-07 22:55:36 -07:00
|
|
|
context->swapchain_command_buffers = swapchain_command_buffers;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VkSemaphore* ia_semaphores = create_semaphores(context->device, 0, max_frames_in_flight);
|
|
|
|
if(ia_semaphores == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan image available semaphores\n");
|
2024-01-07 22:27:53 -07:00
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-07 22:55:36 -07:00
|
|
|
context->image_available_semaphores = ia_semaphores;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VkSemaphore* rf_semaphores = create_semaphores(context->device, 0, max_frames_in_flight);
|
|
|
|
if(rf_semaphores == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan render finished semaphores\n");
|
2024-01-07 22:27:53 -07:00
|
|
|
return 0;
|
|
|
|
} else {
|
2024-01-07 22:55:36 -07:00
|
|
|
context->render_finished_semaphores = rf_semaphores;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkFence* if_fences = create_fences(context->device, VK_FENCE_CREATE_SIGNALED_BIT, max_frames_in_flight);
|
|
|
|
if(if_fences == 0) {
|
|
|
|
fprintf(stderr, "failed to create vulkan in flight fence\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
context->in_flight_fences = if_fences;
|
2024-01-07 22:27:53 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
SceneContext create_scene_context(VkDevice device, VkPhysicalDeviceMemoryProperties memories, uint32_t max_frames_in_flight) {
|
2024-01-10 17:18:07 -07:00
|
|
|
SceneContext ret = {
|
|
|
|
.pool = VK_NULL_HANDLE,
|
|
|
|
.descriptor_layout = VK_NULL_HANDLE,
|
|
|
|
.descriptors = 0,
|
|
|
|
.ubos = 0,
|
|
|
|
.ubo_ptrs = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkDescriptorPoolSize pool_sizes[] = {
|
2024-01-09 12:33:38 -07:00
|
|
|
{
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.descriptorCount = max_frames_in_flight,
|
|
|
|
}
|
|
|
|
};
|
2024-01-08 16:44:14 -07:00
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorPoolCreateInfo pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
|
|
.poolSizeCount = 1,
|
|
|
|
.pPoolSizes = pool_sizes,
|
|
|
|
.maxSets = max_frames_in_flight,
|
2024-01-08 16:44:14 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorPool pool;
|
|
|
|
VkResult result = vkCreateDescriptorPool(device, &pool_info, 0, &pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return ret;
|
2024-01-08 09:44:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorSetLayoutBinding layout_bindings[] = {
|
2024-01-10 16:27:21 -07:00
|
|
|
{
|
2024-01-10 17:18:07 -07:00
|
|
|
.binding = 0,
|
|
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.pImmutableSamplers = 0,
|
|
|
|
}
|
2024-01-10 16:27:21 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorSetLayoutCreateInfo layout_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
|
|
.bindingCount = 1,
|
|
|
|
.pBindings = layout_bindings,
|
2024-01-10 16:27:21 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorSetLayout layout;
|
|
|
|
result = vkCreateDescriptorSetLayout(device, &layout_info, 0, &layout);
|
2024-01-10 16:27:21 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 17:18:07 -07:00
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
return ret;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*max_frames_in_flight);
|
|
|
|
if(layouts == 0) {
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
return ret;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
2024-01-10 17:18:07 -07:00
|
|
|
layouts[i] = layout;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorSet* sets = malloc(sizeof(VkDescriptorSet)*max_frames_in_flight);
|
|
|
|
if(sets == 0) {
|
|
|
|
free(layouts);
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSetAllocateInfo set_alloc_info = {
|
2024-01-11 17:32:10 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
2024-01-10 17:18:07 -07:00
|
|
|
.descriptorPool = pool,
|
2024-01-10 16:27:21 -07:00
|
|
|
.descriptorSetCount = max_frames_in_flight,
|
2024-01-10 17:18:07 -07:00
|
|
|
.pSetLayouts = layouts,
|
2024-01-10 16:27:21 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
result = vkAllocateDescriptorSets(device, &set_alloc_info, sets);
|
2024-01-10 16:27:21 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 17:18:07 -07:00
|
|
|
free(layouts);
|
|
|
|
free(sets);
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
return ret;
|
2024-01-09 21:28:57 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer* ubos = allocate_buffers(memories, device, sizeof(struct SceneUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, max_frames_in_flight, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(ubos == 0) {
|
|
|
|
free(layouts);
|
|
|
|
free(sets);
|
|
|
|
vkFreeDescriptorSets(device, pool, max_frames_in_flight, sets);
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
return ret;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
void** ubo_ptrs = malloc(sizeof(void*)*max_frames_in_flight);
|
|
|
|
if(ubo_ptrs == 0) {
|
|
|
|
free(layouts);
|
|
|
|
free(sets);
|
|
|
|
vkFreeDescriptorSets(device, pool, max_frames_in_flight, sets);
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
deallocate_buffer(device, ubos[i]);
|
|
|
|
}
|
|
|
|
free(ubos);
|
|
|
|
return ret;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
2024-01-10 17:18:07 -07:00
|
|
|
VkResult result = vkMapMemory(device, ubos[i].memory, 0, sizeof(struct SceneUBO), 0, &ubo_ptrs[i]);
|
2024-01-10 16:27:21 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 17:18:07 -07:00
|
|
|
for(uint32_t j = 0; j < i; j++) {
|
|
|
|
vkUnmapMemory(device, ubos[j].memory);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(layouts);
|
|
|
|
free(sets);
|
|
|
|
vkFreeDescriptorSets(device, pool, max_frames_in_flight, sets);
|
|
|
|
vkDestroyDescriptorPool(device, pool, 0);
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
deallocate_buffer(device, ubos[i]);
|
|
|
|
}
|
|
|
|
free(ubos);
|
|
|
|
|
|
|
|
return ret;
|
2024-01-10 16:27:21 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorBufferInfo buffer_info = {
|
2024-01-10 17:18:07 -07:00
|
|
|
.buffer = ubos[i].buffer,
|
2024-01-10 16:27:21 -07:00
|
|
|
.offset = 0,
|
2024-01-10 17:18:07 -07:00
|
|
|
.range = sizeof(struct SceneUBO),
|
2024-01-10 16:27:21 -07:00
|
|
|
};
|
2024-01-10 17:18:07 -07:00
|
|
|
VkWriteDescriptorSet write = {
|
2024-01-10 16:27:21 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
2024-01-10 17:18:07 -07:00
|
|
|
.dstSet = sets[i],
|
2024-01-10 16:27:21 -07:00
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
2024-01-10 17:18:07 -07:00
|
|
|
.descriptorCount = 1,
|
2024-01-10 16:27:21 -07:00
|
|
|
.pBufferInfo = &buffer_info,
|
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
vkUpdateDescriptorSets(device, 1, &write, 0, 0);
|
2024-01-08 20:32:47 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
SceneContext scene = {
|
|
|
|
.pool = pool,
|
|
|
|
.descriptor_layout = layout,
|
|
|
|
.descriptors = sets,
|
|
|
|
.ubos = ubos,
|
|
|
|
.ubo_ptrs = ubo_ptrs,
|
2024-01-09 21:56:56 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
return scene;
|
|
|
|
}
|
2024-01-09 21:56:56 -07:00
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
struct {
|
|
|
|
bool forward;
|
|
|
|
bool backward;
|
|
|
|
bool left;
|
|
|
|
bool right;
|
|
|
|
bool up;
|
|
|
|
bool down;
|
|
|
|
bool turn_left;
|
|
|
|
bool turn_right;
|
|
|
|
bool turn_up;
|
|
|
|
bool turn_down;
|
|
|
|
bool roll_left;
|
|
|
|
bool roll_right;
|
|
|
|
} key_flags = {
|
|
|
|
.forward = false,
|
|
|
|
.backward = false,
|
|
|
|
.left = false,
|
|
|
|
.right = false,
|
2024-01-08 19:48:09 -07:00
|
|
|
|
|
|
|
.turn_left = false,
|
|
|
|
.turn_right = false,
|
|
|
|
.turn_up = false,
|
|
|
|
.turn_down = false,
|
2024-01-09 10:32:22 -07:00
|
|
|
.roll_left = false,
|
|
|
|
.roll_right = false,
|
2024-01-08 17:37:52 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
|
|
|
|
(void)scancode;
|
|
|
|
(void)window;
|
|
|
|
(void)mods;
|
|
|
|
|
|
|
|
switch(key) {
|
|
|
|
case GLFW_KEY_W:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.forward = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.forward = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_A:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.left = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.left = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_S:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.backward = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.backward = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_D:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.right = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.right = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2024-01-08 17:50:24 -07:00
|
|
|
case GLFW_KEY_SPACE:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.up = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.up = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_LEFT_SHIFT:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.down = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.down = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
case GLFW_KEY_RIGHT:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.turn_right = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.turn_right = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_LEFT:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.turn_left = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.turn_left = false;
|
|
|
|
}
|
|
|
|
break;
|
2024-01-08 19:48:09 -07:00
|
|
|
|
|
|
|
case GLFW_KEY_UP:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.turn_up = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.turn_up = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_DOWN:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.turn_down = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.turn_down = false;
|
|
|
|
}
|
|
|
|
break;
|
2024-01-09 10:32:22 -07:00
|
|
|
|
|
|
|
case GLFW_KEY_Q:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.roll_left = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.roll_left = false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GLFW_KEY_E:
|
|
|
|
if(action == GLFW_PRESS) {
|
|
|
|
key_flags.roll_right = true;
|
|
|
|
} else if(action == GLFW_RELEASE) {
|
|
|
|
key_flags.roll_right = false;
|
|
|
|
}
|
|
|
|
break;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-09 10:32:22 -07:00
|
|
|
vec3 world_position = {0.0f, 0.0f, 0.0f};
|
|
|
|
versor world_rotation = {-1.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
|
2024-01-10 11:27:04 -07:00
|
|
|
VkResult update_scene_descriptor(void** buffers, uint32_t frame_index, vec3 world_position, versor world_rotation, float aspect_ratio, float time_delta) {
|
2024-01-08 17:45:10 -07:00
|
|
|
vec3 movement_sum = {0.0f, 0.0f, 0.0f};
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
if(key_flags.forward) {
|
2024-01-09 10:32:22 -07:00
|
|
|
movement_sum[2] -= 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.backward) {
|
2024-01-09 10:32:22 -07:00
|
|
|
movement_sum[2] += 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
if(key_flags.right) {
|
2024-01-10 11:27:04 -07:00
|
|
|
movement_sum[0] += 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
if(key_flags.left) {
|
2024-01-10 11:27:04 -07:00
|
|
|
movement_sum[0] -= 1 * time_delta;
|
2024-01-08 17:50:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.up) {
|
2024-01-10 13:19:41 -07:00
|
|
|
movement_sum[1] -= 1 * time_delta;
|
2024-01-08 17:50:24 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.down) {
|
2024-01-10 13:19:41 -07:00
|
|
|
movement_sum[1] += 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
2024-01-09 10:32:22 -07:00
|
|
|
|
|
|
|
vec3 eular_rotation = {0.0f, 0.0f, 0.0f};
|
2024-01-08 17:37:52 -07:00
|
|
|
if(key_flags.turn_right) {
|
2024-01-10 11:27:04 -07:00
|
|
|
eular_rotation[0] -= 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.turn_left) {
|
2024-01-10 11:27:04 -07:00
|
|
|
eular_rotation[0] += 1 * time_delta;
|
2024-01-08 17:37:52 -07:00
|
|
|
}
|
|
|
|
|
2024-01-09 10:32:22 -07:00
|
|
|
if(key_flags.turn_up) {
|
2024-01-10 13:19:41 -07:00
|
|
|
eular_rotation[1] -= 1 * time_delta;
|
2024-01-09 10:32:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.turn_down) {
|
2024-01-10 13:19:41 -07:00
|
|
|
eular_rotation[1] += 1 * time_delta;
|
2024-01-09 10:32:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.roll_right) {
|
|
|
|
eular_rotation[2] += 1 * time_delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(key_flags.roll_left) {
|
|
|
|
eular_rotation[2] -= 1 * time_delta;
|
|
|
|
}
|
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
vec3 right = {1.0f, 0.0f, 0.0f};
|
|
|
|
vec3 up = {0.0f, 1.0f, 0.0f};
|
2024-01-09 10:32:22 -07:00
|
|
|
vec3 forward = {0.0f, 0.0f, 1.0f};
|
2024-01-10 13:19:41 -07:00
|
|
|
glm_quat_rotatev(world_rotation, right, right);
|
2024-01-09 10:32:22 -07:00
|
|
|
glm_quat_rotatev(world_rotation, up, up);
|
|
|
|
glm_quat_rotatev(world_rotation, forward, forward);
|
2024-01-08 17:37:52 -07:00
|
|
|
|
2024-01-09 10:32:22 -07:00
|
|
|
versor relative_rotation_y;
|
2024-01-10 13:19:41 -07:00
|
|
|
glm_quatv(relative_rotation_y, eular_rotation[1], right);
|
2024-01-09 10:32:22 -07:00
|
|
|
|
|
|
|
versor relative_rotation_x;
|
|
|
|
glm_quatv(relative_rotation_x, eular_rotation[0], up);
|
|
|
|
|
|
|
|
versor relative_rotation_z;
|
|
|
|
glm_quatv(relative_rotation_z, eular_rotation[2], forward);
|
|
|
|
|
|
|
|
glm_quat_mul(relative_rotation_x, world_rotation, world_rotation);
|
|
|
|
glm_quat_mul(relative_rotation_y, world_rotation, world_rotation);
|
|
|
|
glm_quat_mul(relative_rotation_z, world_rotation, world_rotation);
|
2024-01-08 17:37:52 -07:00
|
|
|
|
2024-01-08 17:45:10 -07:00
|
|
|
vec3 movement_rot;
|
2024-01-09 10:32:22 -07:00
|
|
|
glm_quat_rotatev(world_rotation, movement_sum, movement_rot);
|
2024-01-08 17:45:10 -07:00
|
|
|
glm_vec3_add(movement_rot, world_position, world_position);
|
|
|
|
|
|
|
|
struct SceneUBO ubo = {};
|
2024-01-09 10:32:22 -07:00
|
|
|
|
2024-01-10 13:19:41 -07:00
|
|
|
glm_perspective(1.5708f, aspect_ratio, 0.01, 1000, ubo.proj);
|
2024-01-09 10:32:22 -07:00
|
|
|
glm_quat_look(world_position, world_rotation, ubo.view);
|
2024-01-08 13:10:54 -07:00
|
|
|
|
2024-01-08 12:42:59 -07:00
|
|
|
memcpy(buffers[frame_index], (void*)&ubo, sizeof(ubo));
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
VkResult draw_frame(VulkanContext* context, SceneContext* scene, uint32_t materials_count, Material* materials, uint32_t* objects_counts, Object** objects) {
|
|
|
|
update_scene_descriptor(scene->ubo_ptrs, context->current_frame, world_position, world_rotation, (float)context->swapchain_extent.width/(float)context->swapchain_extent.height, 0.01);
|
2024-01-08 12:42:59 -07:00
|
|
|
|
2024-01-07 22:27:53 -07:00
|
|
|
VkResult result;
|
2024-01-07 22:55:36 -07:00
|
|
|
result = vkWaitForFences(context->device, 1, &context->in_flight_fences[context->current_frame], VK_TRUE, UINT64_MAX);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
uint32_t image_index;
|
|
|
|
result = vkAcquireNextImageKHR(context->device, context->swapchain, UINT64_MAX, context->image_available_semaphores[context->current_frame], VK_NULL_HANDLE, &image_index);
|
2024-01-08 19:50:45 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-07 22:27:53 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-08 19:48:09 -07:00
|
|
|
result = vkResetFences(context->device, 1, &context->in_flight_fences[context->current_frame]);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
result = vkResetCommandBuffer(context->swapchain_command_buffers[context->current_frame], 0);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-10 17:18:07 -07:00
|
|
|
result = command_draw_scene(materials_count, materials, objects_counts, objects, context->current_frame, scene->descriptors, context->swapchain_command_buffers[context->current_frame], context->render_pass, context->swapchain_framebuffers[image_index], context->swapchain_extent);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPipelineStageFlags wait_stages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
2024-01-11 21:13:30 -07:00
|
|
|
VkSubmitInfo submit_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
|
|
|
.waitSemaphoreCount = 1,
|
|
|
|
.pWaitSemaphores = &context->image_available_semaphores[context->current_frame],
|
|
|
|
.pWaitDstStageMask = wait_stages,
|
|
|
|
.commandBufferCount = 1,
|
|
|
|
.pCommandBuffers = &context->swapchain_command_buffers[context->current_frame],
|
|
|
|
.signalSemaphoreCount = 1,
|
|
|
|
.pSignalSemaphores = &context->render_finished_semaphores[context->current_frame],
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
result = vkQueueSubmit(context->queues.graphics, 1, &submit_info, context->in_flight_fences[context->current_frame]);
|
2024-01-07 22:27:53 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkPresentInfoKHR present_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
|
|
|
.waitSemaphoreCount = 1,
|
|
|
|
.pWaitSemaphores = &context->render_finished_semaphores[context->current_frame],
|
|
|
|
.swapchainCount = 1,
|
|
|
|
.pSwapchains = &context->swapchain,
|
|
|
|
.pImageIndices = &image_index,
|
|
|
|
.pResults = 0,
|
|
|
|
};
|
2024-01-07 22:27:53 -07:00
|
|
|
|
|
|
|
return vkQueuePresentKHR(context->queues.present, &present_info);
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Object create_simple_mesh_object(Material* simple_mesh_material, VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, uint32_t max_frames_in_flight, VkDescriptorPool pool) {
|
2024-01-10 17:50:19 -07:00
|
|
|
Object zero = {};
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
MemoryChunk mesh_memory = {0};
|
|
|
|
VkResult result = allocate_memory_chunk(0, device, 10000, &mesh_memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryChunk transfer_memory = {0};
|
|
|
|
result = allocate_memory_chunk(2, device, 10000, &transfer_memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBuffer transfer_buffer = VK_NULL_HANDLE;
|
|
|
|
result = create_buffer(&transfer_memory, device, 10000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &transfer_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh* mesh = load_mesh_to_buffer(device, &mesh_memory, transfer_buffer, transfer_memory.memory, 4, sizeof(struct Vertex), (void*)vertices, 6, sizeof(uint16_t), (void*)indices, transfer_pool, transfer_queue);
|
2024-01-10 17:50:19 -07:00
|
|
|
if(mesh == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*max_frames_in_flight);
|
|
|
|
if(layouts == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
layouts[i] = simple_mesh_material->object_set_layout;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
VkDescriptorSetAllocateInfo allocation_info = {
|
2024-01-10 17:18:07 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
2024-01-10 17:50:19 -07:00
|
|
|
.pSetLayouts = layouts,
|
|
|
|
.descriptorSetCount = max_frames_in_flight,
|
|
|
|
.descriptorPool = pool,
|
2024-01-10 17:18:07 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
VkDescriptorSet* sets = malloc(sizeof(VkDescriptorSet)*max_frames_in_flight);
|
|
|
|
if(sets == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
result = vkAllocateDescriptorSets(device, &allocation_info, sets);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 17:50:19 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
Object object = create_renderable(mesh, simple_mesh_material, 1, sets, max_frames_in_flight);
|
|
|
|
if(object.attributes.buckets == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
Position* position = malloc(sizeof(Position));
|
|
|
|
if(position == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
2024-01-10 17:50:19 -07:00
|
|
|
glm_quat_identity(position->rotation);
|
2024-01-10 23:55:11 -07:00
|
|
|
position->scale[0] = 10.f;
|
|
|
|
position->scale[1] = 10.f;
|
|
|
|
position->scale[2] = 10.f;
|
2024-01-10 17:50:19 -07:00
|
|
|
position->position[0] = 0.0f;
|
|
|
|
position->position[1] = 0.0f;
|
2024-01-10 23:55:11 -07:00
|
|
|
position->position[2] = 1.1f;
|
2024-01-10 17:50:19 -07:00
|
|
|
bool map_result = map_add(&object.attributes, ATTRIBUTE_ID_POSITION, position);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(map_result == 0) {
|
2024-01-10 17:50:19 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer* position_buffers = allocate_buffers(memories, device, sizeof(struct ModelUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, max_frames_in_flight, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
2024-01-10 17:50:19 -07:00
|
|
|
if(position_buffers == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
MaybeValue maybe_ptrs = map_lookup(object.attributes, ATTRIBUTE_ID_DESCRIPTORS);
|
|
|
|
if(maybe_ptrs.has_value == false) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
2024-01-10 19:32:01 -07:00
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
void*** ptrs = maybe_ptrs.value;
|
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
VkResult result = vkMapMemory(device, position_buffers[i].memory, 0, sizeof(struct ModelUBO), 0, &ptrs[i][0]);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 17:50:19 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorBufferInfo buffer_info = {
|
2024-01-10 17:50:19 -07:00
|
|
|
.buffer = position_buffers[i].buffer,
|
2024-01-10 17:18:07 -07:00
|
|
|
.offset = 0,
|
|
|
|
.range = sizeof(struct ModelUBO),
|
|
|
|
};
|
|
|
|
|
|
|
|
VkWriteDescriptorSet write_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
2024-01-10 17:50:19 -07:00
|
|
|
.dstSet = sets[i],
|
2024-01-10 17:18:07 -07:00
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
2024-01-10 19:32:01 -07:00
|
|
|
.descriptorCount = 1,
|
2024-01-10 17:18:07 -07:00
|
|
|
.pBufferInfo = &buffer_info,
|
|
|
|
};
|
|
|
|
|
2024-01-10 17:50:19 -07:00
|
|
|
vkUpdateDescriptorSets(device, 1, &write_info, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Object create_texture_mesh_object(Material* texture_mesh_material, VkPhysicalDeviceMemoryProperties memories, VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkCommandPool graphics_pool, VkQueue graphics_queue, uint32_t max_frames_in_flight, VkDescriptorPool pool, uint32_t transfer_family, uint32_t graphics_family) {
|
2024-01-10 18:01:54 -07:00
|
|
|
Object zero = {};
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
MemoryChunk mesh_memory = {0};
|
|
|
|
VkResult result = allocate_memory_chunk(0, device, 10000, &mesh_memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryChunk transfer_memory = {0};
|
|
|
|
result = allocate_memory_chunk(2, device, 10000, &transfer_memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkBuffer transfer_buffer = VK_NULL_HANDLE;
|
|
|
|
result = create_buffer(&transfer_memory, device, 10000, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &transfer_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return zero;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mesh* mesh = load_mesh_to_buffer(device, &mesh_memory, transfer_buffer, transfer_memory.memory, 4, sizeof(struct TextureVertex), (void*)texture_vertices, 6, sizeof(uint16_t), (void*)indices, transfer_pool, transfer_queue);
|
2024-01-10 18:01:54 -07:00
|
|
|
if(mesh == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
VkDescriptorSetLayout* layouts = malloc(sizeof(VkDescriptorSetLayout)*max_frames_in_flight);
|
|
|
|
if(layouts == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
layouts[i] = texture_mesh_material->object_set_layout;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
VkDescriptorSetAllocateInfo allocation_info = {
|
2024-01-10 17:18:07 -07:00
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
2024-01-10 18:01:54 -07:00
|
|
|
.descriptorPool = pool,
|
|
|
|
.descriptorSetCount = max_frames_in_flight,
|
|
|
|
.pSetLayouts = layouts,
|
2024-01-10 17:18:07 -07:00
|
|
|
};
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
VkDescriptorSet* sets = malloc(sizeof(VkDescriptorSet)*max_frames_in_flight);
|
|
|
|
if(sets == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 23:28:59 -07:00
|
|
|
result = vkAllocateDescriptorSets(device, &allocation_info, sets);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 18:01:54 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
Object object = create_renderable(mesh, texture_mesh_material, 1, sets, max_frames_in_flight);
|
|
|
|
if(object.attributes.buckets == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
Position* position = malloc(sizeof(Position));
|
|
|
|
if(position == 0) {
|
2024-01-10 18:01:54 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
glm_quat_identity(position->rotation);
|
2024-01-10 19:32:01 -07:00
|
|
|
position->scale[0] = 0.5f;
|
|
|
|
position->scale[1] = 0.5f;
|
|
|
|
position->scale[2] = 0.5f;
|
2024-01-10 17:18:07 -07:00
|
|
|
position->position[0] = 0.0f;
|
|
|
|
position->position[1] = 0.0f;
|
|
|
|
position->position[2] = 1.0f;
|
2024-01-10 18:01:54 -07:00
|
|
|
bool map_result = map_add(&object.attributes, ATTRIBUTE_ID_POSITION, position);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(map_result == 0) {
|
2024-01-10 18:01:54 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
AllocatedBuffer* ubos = allocate_buffers(memories, device, sizeof(struct ModelUBO), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, max_frames_in_flight, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
2024-01-10 18:01:54 -07:00
|
|
|
if(ubos == 0) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
MaybeValue maybe_ptrs = map_lookup(object.attributes, ATTRIBUTE_ID_DESCRIPTORS);
|
|
|
|
if(maybe_ptrs.has_value == false) {
|
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
void*** ptrs = maybe_ptrs.value;
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
|
|
|
VkResult result = vkMapMemory(device, ubos[i].memory, 0, sizeof(struct ModelUBO), 0, &ptrs[i][0]);
|
2024-01-10 17:18:07 -07:00
|
|
|
if(result != VK_SUCCESS) {
|
2024-01-10 18:01:54 -07:00
|
|
|
return zero;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorBufferInfo buffer_info = {
|
2024-01-10 18:01:54 -07:00
|
|
|
.buffer = ubos[i].buffer,
|
2024-01-10 17:18:07 -07:00
|
|
|
.offset = 0,
|
|
|
|
.range = sizeof(struct ModelUBO),
|
|
|
|
};
|
|
|
|
|
|
|
|
VkWriteDescriptorSet write_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
2024-01-10 18:01:54 -07:00
|
|
|
.dstSet = sets[i],
|
2024-01-10 17:18:07 -07:00
|
|
|
.dstBinding = 1,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.pBufferInfo = &buffer_info,
|
|
|
|
};
|
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
vkUpdateDescriptorSets(device, 1, &write_info, 0, 0);
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
VkExtent2D texture_size = {
|
|
|
|
.width = 10,
|
|
|
|
.height = 10,
|
|
|
|
};
|
|
|
|
struct __attribute__((__packed__)) texel {
|
|
|
|
uint8_t r;
|
|
|
|
uint8_t g;
|
|
|
|
uint8_t b;
|
|
|
|
uint8_t a;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct texel WHT = {255, 255, 255, 255};
|
|
|
|
struct texel BLK = {0, 0, 0, 255};
|
|
|
|
struct texel RED = {255, 0, 0, 255};
|
|
|
|
struct texel GRN = {0, 255, 0, 255};
|
|
|
|
struct texel BLU = {0, 0, 255, 255};
|
|
|
|
|
|
|
|
struct texel texture_data[100] = {
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, WHT,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
RED, WHT, GRN, WHT, BLU, WHT, RED, WHT, GRN, BLK,
|
|
|
|
};
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Texture test_texture = load_texture(memories, device, transfer_pool, transfer_queue, graphics_pool, graphics_queue, texture_size, 4, VK_FORMAT_R8G8B8A8_SRGB, texture_data, transfer_family, graphics_family);
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
for(uint32_t i = 0; i < max_frames_in_flight; i++) {
|
2024-01-10 17:18:07 -07:00
|
|
|
VkDescriptorImageInfo image_info = {
|
|
|
|
.sampler = test_texture.sampler,
|
|
|
|
.imageView = test_texture.view,
|
|
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
|
|
|
};
|
|
|
|
|
2024-01-11 21:13:30 -07:00
|
|
|
VkWriteDescriptorSet descriptor_write = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstSet = sets[i],
|
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.pBufferInfo = 0,
|
|
|
|
.pImageInfo = &image_info,
|
|
|
|
.pTexelBufferView = 0,
|
|
|
|
};
|
2024-01-10 17:18:07 -07:00
|
|
|
|
2024-01-10 18:01:54 -07:00
|
|
|
vkUpdateDescriptorSets(device, 1, &descriptor_write, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
void main_loop(GLFWwindow* window, VulkanContext* context) {
|
2024-01-11 17:32:10 -07:00
|
|
|
SceneContext scene = create_scene_context(context->device, context->memories, context->max_frames_in_flight);
|
2024-01-10 18:01:54 -07:00
|
|
|
if(scene.pool == VK_NULL_HANDLE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Material simple_mesh_material = create_simple_mesh_material(context->device, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight);
|
|
|
|
if(simple_mesh_material.pipeline == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create simple mesh material\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorPoolSize simple_pool_sizes[] = {
|
|
|
|
{
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.descriptorCount = context->max_frames_in_flight,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkDescriptorPoolCreateInfo simple_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
|
|
.poolSizeCount = 1,
|
|
|
|
.pPoolSizes = simple_pool_sizes,
|
|
|
|
.maxSets = context->max_frames_in_flight,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkDescriptorPool simple_pool;
|
|
|
|
VkResult result = vkCreateDescriptorPool(context->device, &simple_pool_info, 0, &simple_pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to allocate simple_pool\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Object triangle_object = create_simple_mesh_object(&simple_mesh_material, context->memories, context->device, context->transfer_command_pool, context->queues.transfer, context->max_frames_in_flight, simple_pool);
|
2024-01-10 18:01:54 -07:00
|
|
|
if(triangle_object.attributes.buckets == 0) {
|
|
|
|
fprintf(stderr, "failed to create simple mesh object\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Material texture_mesh_material = create_texture_mesh_material(context->device, context->swapchain_extent, context->render_pass, scene.descriptor_layout, context->max_frames_in_flight);
|
|
|
|
if(texture_mesh_material.pipeline == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create texture mesh material\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorPoolSize texture_pool_sizes[] = {
|
|
|
|
{
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
|
|
.descriptorCount = context->max_frames_in_flight,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
|
|
.descriptorCount = context->max_frames_in_flight,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
VkDescriptorPoolCreateInfo texture_pool_info = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
|
|
.poolSizeCount = sizeof(texture_pool_sizes)/sizeof(VkDescriptorPoolSize),
|
|
|
|
.maxSets = context->max_frames_in_flight,
|
|
|
|
.pPoolSizes = texture_pool_sizes,
|
|
|
|
};
|
|
|
|
|
|
|
|
VkDescriptorPool texture_pool;
|
|
|
|
result = vkCreateDescriptorPool(context->device, &texture_pool_info, 0, &texture_pool);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "failed to create temporary descriptor pool\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:32:10 -07:00
|
|
|
Object triangle_object_textured = create_texture_mesh_object(&texture_mesh_material, context->memories, context->device, context->transfer_command_pool, context->queues.transfer, context->extra_graphics_pool, context->queues.graphics, context->max_frames_in_flight, texture_pool, context->queue_indices.transfer_family, context->queue_indices.graphics_family);
|
2024-01-10 18:01:54 -07:00
|
|
|
if(triangle_object_textured.attributes.buckets == 0) {
|
|
|
|
fprintf(stderr, "failed to create texture mesh object\n");
|
|
|
|
return;
|
2024-01-10 17:18:07 -07:00
|
|
|
}
|
|
|
|
|
2024-01-10 19:32:01 -07:00
|
|
|
Object* objects[] = {&triangle_object, &triangle_object_textured};
|
|
|
|
Material materials[] = {simple_mesh_material, texture_mesh_material};
|
2024-01-10 17:18:07 -07:00
|
|
|
uint32_t objects_counts[] = {1, 1};
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
context->current_frame = 0;
|
2024-01-07 03:04:12 -07:00
|
|
|
while(!glfwWindowShouldClose(window)) {
|
|
|
|
glfwPollEvents();
|
2024-01-08 17:37:52 -07:00
|
|
|
|
2024-01-10 19:32:01 -07:00
|
|
|
VkResult result = draw_frame(context, &scene, sizeof(materials)/sizeof(Material), materials, objects_counts, objects);
|
2024-01-08 19:50:45 -07:00
|
|
|
if(result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
2024-01-11 18:06:20 -07:00
|
|
|
vkDeviceWaitIdle(context->device);
|
|
|
|
recreate_swapchain(context);
|
2024-01-08 19:50:45 -07:00
|
|
|
} else if(result != VK_SUCCESS) {
|
|
|
|
fprintf(stderr, "draw_frame error %d\n", result);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
context->current_frame += 1;
|
|
|
|
if(context->current_frame >= context->max_frames_in_flight) {
|
|
|
|
context->current_frame = 0;
|
|
|
|
}
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
2024-01-07 22:55:36 -07:00
|
|
|
|
|
|
|
vkDeviceWaitIdle(context->device);
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
void cleanup(GLFWwindow* window, VulkanContext* context) {
|
|
|
|
if(context != 0) {
|
|
|
|
if(context->instance != VK_NULL_HANDLE) {
|
|
|
|
if(context->swapchain != VK_NULL_HANDLE) {
|
|
|
|
vkDestroySwapchainKHR(context->device, context->swapchain, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(context->surface != VK_NULL_HANDLE) {
|
|
|
|
vkDestroySurfaceKHR(context->instance, context->surface, 0);
|
|
|
|
}
|
2024-01-07 03:04:12 -07:00
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
if(context->device != VK_NULL_HANDLE) {
|
|
|
|
vkDestroyDevice(context->device, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(context->debug_messenger != VK_NULL_HANDLE) {
|
|
|
|
PFN_vkDestroyDebugUtilsMessengerEXT destroy_messenger = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(context->instance, "vkDestroyDebugUtilsMessengerEXT");
|
|
|
|
destroy_messenger(context->instance, context->debug_messenger, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
vkDestroyInstance(context->instance, 0);
|
|
|
|
}
|
|
|
|
free(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(window != 0) {
|
|
|
|
glfwDestroyWindow(window);
|
|
|
|
glfwTerminate();
|
|
|
|
}
|
2024-01-07 03:04:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
2024-01-11 21:45:30 -07:00
|
|
|
PlyMesh monkey = ply_load_mesh("monkey.ply", default_ply_mappings);
|
2024-01-11 16:16:10 -07:00
|
|
|
if(monkey.position == 0) {
|
2024-01-11 12:09:54 -07:00
|
|
|
fprintf(stderr, "failed to load %s\n", "monkey.ply");
|
2024-01-10 23:55:11 -07:00
|
|
|
}
|
|
|
|
|
2024-01-07 03:04:12 -07:00
|
|
|
GLFWwindow* window = init_window(800, 600);
|
|
|
|
if(window == 0) {
|
|
|
|
fprintf(stderr, "failed to initialize glfw window\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2024-01-07 22:55:36 -07:00
|
|
|
VulkanContext* context = init_vulkan(window, 2);
|
2024-01-07 16:34:09 -07:00
|
|
|
if (context == 0) {
|
|
|
|
fprintf(stderr, "failed to initialize vulkan context\n");
|
2024-01-07 03:04:12 -07:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2024-01-08 17:37:52 -07:00
|
|
|
glfwSetKeyCallback(window, key_callback);
|
2024-01-07 22:27:53 -07:00
|
|
|
main_loop(window, context);
|
2024-01-07 03:04:12 -07:00
|
|
|
|
2024-01-07 16:34:09 -07:00
|
|
|
cleanup(window, context);
|
2024-01-07 01:01:57 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|