|
|
@ -18,11 +18,15 @@ typedef struct QueueIndicesStruct {
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t present_family;
|
|
|
|
uint32_t present_family;
|
|
|
|
uint32_t present_index;
|
|
|
|
uint32_t present_index;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t transfer_family;
|
|
|
|
|
|
|
|
uint32_t transfer_index;
|
|
|
|
} QueueIndices;
|
|
|
|
} QueueIndices;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct QueuesStruct {
|
|
|
|
typedef struct QueuesStruct {
|
|
|
|
VkQueue graphics;
|
|
|
|
VkQueue graphics;
|
|
|
|
VkQueue present;
|
|
|
|
VkQueue present;
|
|
|
|
|
|
|
|
VkQueue transfer;
|
|
|
|
} Queues;
|
|
|
|
} Queues;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct SwapchainDetailsStruct {
|
|
|
|
typedef struct SwapchainDetailsStruct {
|
|
|
@ -79,10 +83,12 @@ typedef struct VulkanContextStruct {
|
|
|
|
VkRenderPass render_pass;
|
|
|
|
VkRenderPass render_pass;
|
|
|
|
|
|
|
|
|
|
|
|
VkCommandPool graphics_command_pool;
|
|
|
|
VkCommandPool graphics_command_pool;
|
|
|
|
|
|
|
|
VkCommandPool transfer_command_pool;
|
|
|
|
|
|
|
|
|
|
|
|
VkPipelineLayout triangle_pipeline_layout;
|
|
|
|
VkPipelineLayout triangle_pipeline_layout;
|
|
|
|
VkPipeline triangle_pipeline;
|
|
|
|
VkPipeline triangle_pipeline;
|
|
|
|
AllocatedBuffer triangle_buffer;
|
|
|
|
AllocatedBuffer triangle_vertex_buffer;
|
|
|
|
|
|
|
|
AllocatedBuffer triangle_index_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t current_frame;
|
|
|
|
uint32_t current_frame;
|
|
|
|
} VulkanContext;
|
|
|
|
} VulkanContext;
|
|
|
@ -93,13 +99,22 @@ struct Vertex{
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const struct Vertex vertices[] = {
|
|
|
|
const struct Vertex vertices[] = {
|
|
|
|
{.pos = { 0.0f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
|
|
|
{.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}},
|
|
|
|
{.pos = { 0.5f, 0.5f}, .color = {0.0f, 1.0f, 0.0f}},
|
|
|
|
{.pos = { 0.5f, -0.5f}, .color = {0.0f, 1.0f, 0.0f}},
|
|
|
|
{.pos = {-0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}},
|
|
|
|
{.pos = { 0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}},
|
|
|
|
|
|
|
|
{.pos = {-0.5f, 0.5f}, .color = {1.0f, 1.0f, 1.0f}},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const uint16_t indices[] = {
|
|
|
|
|
|
|
|
0, 1, 2, 2, 3, 0,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const char * validation_layers[] = {
|
|
|
|
const char * validation_layers[] = {
|
|
|
|
"VK_LAYER_KHRONOS_validation",
|
|
|
|
"VK_LAYER_KHRONOS_validation",
|
|
|
|
|
|
|
|
//"VK_LAYER_LUNARG_api_dump",
|
|
|
|
|
|
|
|
//"VK_LAYER_KHRONOS_profiles",
|
|
|
|
|
|
|
|
//"VK_LAYER_KHRONOS_synchronization2",
|
|
|
|
|
|
|
|
"VK_LAYER_KHRONOS_shader_object",
|
|
|
|
};
|
|
|
|
};
|
|
|
|
uint32_t validation_layer_count = sizeof(validation_layers) / sizeof(const char *);
|
|
|
|
uint32_t validation_layer_count = sizeof(validation_layers) / sizeof(const char *);
|
|
|
|
|
|
|
|
|
|
|
@ -266,17 +281,20 @@ VkPhysicalDevice get_best_physical_device(VkInstance instance) {
|
|
|
|
return device;
|
|
|
|
return device;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeQueueIndices {
|
|
|
|
bool check_queue_indices(QueueIndices indices) {
|
|
|
|
bool valid;
|
|
|
|
return ((indices.graphics_family != 0xFFFFFFFF)
|
|
|
|
QueueIndices indices;
|
|
|
|
&& (indices.present_family != 0xFFFFFFFF)
|
|
|
|
};
|
|
|
|
&& (indices.transfer_family != 0xFFFFFFFF));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeQueueIndices get_queue_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
|
|
|
QueueIndices get_queue_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface) {
|
|
|
|
struct MaybeQueueIndices ret = {};
|
|
|
|
QueueIndices indices = {};
|
|
|
|
ret.indices.graphics_family = 0xFFFFFFFF;
|
|
|
|
indices.graphics_family = 0xFFFFFFFF;
|
|
|
|
ret.indices.graphics_index = 0xFFFFFFFF;
|
|
|
|
indices.graphics_index = 0xFFFFFFFF;
|
|
|
|
ret.indices.present_family = 0xFFFFFFFF;
|
|
|
|
indices.present_family = 0xFFFFFFFF;
|
|
|
|
ret.indices.present_index = 0xFFFFFFFF;
|
|
|
|
indices.present_index = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
indices.transfer_family = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
indices.transfer_index = 0xFFFFFFFF;
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t queue_family_count;
|
|
|
|
uint32_t queue_family_count;
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, 0);
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, 0);
|
|
|
@ -285,31 +303,43 @@ struct MaybeQueueIndices get_queue_indices(VkPhysicalDevice physical_device, VkS
|
|
|
|
|
|
|
|
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_families);
|
|
|
|
|
|
|
|
|
|
|
|
for(uint32_t i = 0;
|
|
|
|
for(uint32_t family_idx = 0; family_idx < queue_family_count; family_idx++) {
|
|
|
|
(i < queue_family_count)
|
|
|
|
VkBool32 present_support;
|
|
|
|
&& ((ret.indices.graphics_family == 0xFFFFFFFF) || (ret.indices.present_family == 0xFFFFFFFF));
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, family_idx, surface, &present_support);
|
|
|
|
i++) {
|
|
|
|
for(uint32_t queue_idx = 0; queue_idx < queue_families[family_idx].queueCount; queue_idx++) {
|
|
|
|
if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
|
|
if(((indices.graphics_family == 0xFFFFFFFF)
|
|
|
|
ret.indices.graphics_family = i;
|
|
|
|
|| (indices.present_family == 0xFFFFFFFF)
|
|
|
|
ret.indices.graphics_index = 0;
|
|
|
|
|| (indices.present_family != indices.graphics_family))
|
|
|
|
}
|
|
|
|
&& (queue_families[family_idx].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
|
|
|
|
|
|
&& (present_support == VK_TRUE)) {
|
|
|
|
VkBool32 present_support = false;
|
|
|
|
fprintf(stderr, "Selected %d:%d for graphics and present queues\n", family_idx, queue_idx);
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support);
|
|
|
|
indices.graphics_family = family_idx;
|
|
|
|
|
|
|
|
indices.graphics_index = queue_idx;
|
|
|
|
if(present_support == VK_TRUE) {
|
|
|
|
|
|
|
|
ret.indices.present_family = i;
|
|
|
|
indices.present_family = family_idx;
|
|
|
|
ret.indices.present_index = 0;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if((ret.indices.graphics_family != 0xFFFFFFFF) && (ret.indices.present_family != 0xFFFFFFFF)) {
|
|
|
|
|
|
|
|
ret.valid = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
free(queue_families);
|
|
|
|
free(queue_families);
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
return indices;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
|
|
|
|
VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
|
|
|
@ -318,7 +348,7 @@ VkDebugUtilsMessengerEXT create_debug_messenger(VkInstance instance) {
|
|
|
|
VkDebugUtilsMessengerCreateInfoEXT messenger_info = {};
|
|
|
|
VkDebugUtilsMessengerCreateInfoEXT messenger_info = {};
|
|
|
|
messenger_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
|
|
messenger_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
|
|
messenger_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
|
|
|
messenger_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
|
|
|
|
messenger_info.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;
|
|
|
|
messenger_info.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;
|
|
|
|
messenger_info.pfnUserCallback = debug_callback;
|
|
|
|
messenger_info.pfnUserCallback = debug_callback;
|
|
|
|
messenger_info.pUserData = 0;
|
|
|
|
messenger_info.pUserData = 0;
|
|
|
|
|
|
|
|
|
|
|
@ -390,35 +420,50 @@ VkInstance create_instance() {
|
|
|
|
VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices queue_indices) {
|
|
|
|
VkDevice create_logical_device(VkPhysicalDevice physical_device, QueueIndices queue_indices) {
|
|
|
|
VkDevice device;
|
|
|
|
VkDevice device;
|
|
|
|
|
|
|
|
|
|
|
|
VkDeviceQueueCreateInfo queue_create_info[2] = {};
|
|
|
|
uint32_t unique_families[3] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
|
|
|
|
uint32_t queue_create_count;
|
|
|
|
uint32_t unique_family_queues[3] = {0, 0, 0};
|
|
|
|
float default_queue_priority = 1.0f;
|
|
|
|
uint32_t unique_family_count = 0;
|
|
|
|
if(queue_indices.graphics_family == queue_indices.present_family) {
|
|
|
|
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
uint32_t queue_family[] = {queue_indices.transfer_family, queue_indices.graphics_family, queue_indices.present_family};
|
|
|
|
queue_create_info[0].queueFamilyIndex = queue_indices.graphics_family;
|
|
|
|
uint32_t unique_queue_count = 3;
|
|
|
|
queue_create_info[0].queueCount = 1;
|
|
|
|
if((queue_indices.graphics_family == queue_indices.present_family)
|
|
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
|
|
&& (queue_indices.graphics_index == queue_indices.present_index)) {
|
|
|
|
queue_create_count = 1;
|
|
|
|
unique_queue_count = 2;
|
|
|
|
} else {
|
|
|
|
}
|
|
|
|
queue_create_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
|
|
|
|
queue_create_info[0].queueFamilyIndex = queue_indices.graphics_family;
|
|
|
|
|
|
|
|
queue_create_info[0].queueCount = 1;
|
|
|
|
|
|
|
|
queue_create_info[0].pQueuePriorities = &default_queue_priority;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
for(uint32_t queue_idx = 0; queue_idx < unique_queue_count; queue_idx++) {
|
|
|
|
queue_create_info[1].queueFamilyIndex = queue_indices.present_family;
|
|
|
|
uint32_t idx = 0xFFFFFFFF;
|
|
|
|
queue_create_info[1].queueCount = 1;
|
|
|
|
for(uint32_t check_idx = 0; check_idx < unique_family_count; check_idx++) {
|
|
|
|
queue_create_info[1].pQueuePriorities = &default_queue_priority;
|
|
|
|
if(queue_family[queue_idx] == unique_families[check_idx]) {
|
|
|
|
queue_create_count = 2;
|
|
|
|
idx = check_idx;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkPhysicalDeviceFeatures device_features = {};
|
|
|
|
VkPhysicalDeviceFeatures device_features = {};
|
|
|
|
|
|
|
|
|
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
|
|
device_create_info.pQueueCreateInfos = queue_create_info;
|
|
|
|
device_create_info.pQueueCreateInfos = queue_create_info;
|
|
|
|
device_create_info.queueCreateInfoCount = queue_create_count;
|
|
|
|
device_create_info.queueCreateInfoCount = unique_family_count;
|
|
|
|
device_create_info.pEnabledFeatures = &device_features;
|
|
|
|
device_create_info.pEnabledFeatures = &device_features;
|
|
|
|
|
|
|
|
|
|
|
|
device_create_info.enabledExtensionCount = device_extension_count;
|
|
|
|
device_create_info.enabledExtensionCount = device_extension_count;
|
|
|
@ -753,51 +798,150 @@ uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t type_filter
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
return 0xFFFFFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer create_vertex_buffer(VkPhysicalDevice physical_device, VkDevice device, void* data, uint32_t size) {
|
|
|
|
AllocatedBuffer allocate_buffer(VkPhysicalDevice physical_device, VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties) {
|
|
|
|
AllocatedBuffer allocated_buffer = {};
|
|
|
|
AllocatedBuffer ret = {};
|
|
|
|
allocated_buffer.buffer = VK_NULL_HANDLE;
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
allocated_buffer.memory = VK_NULL_HANDLE;
|
|
|
|
ret.buffer = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkBufferCreateInfo buffer_info = {};
|
|
|
|
VkBufferCreateInfo buffer_info = {};
|
|
|
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
|
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
|
|
buffer_info.size = size;
|
|
|
|
buffer_info.size = size;
|
|
|
|
buffer_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
|
|
|
buffer_info.usage = usage;
|
|
|
|
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
|
|
|
|
|
|
|
|
VkResult result = vkCreateBuffer(device, &buffer_info, 0, &allocated_buffer.buffer);
|
|
|
|
VkResult result = vkCreateBuffer(device, &buffer_info, 0, &ret.buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return allocated_buffer;
|
|
|
|
ret.buffer = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
ret.memory = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetBufferMemoryRequirements(device, allocated_buffer.buffer, &memory_requirements);
|
|
|
|
vkGetBufferMemoryRequirements(device, ret.buffer, &memory_requirements);
|
|
|
|
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo alloc_info = {};
|
|
|
|
VkMemoryAllocateInfo alloc_info = {};
|
|
|
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
|
|
alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
|
|
alloc_info.allocationSize = memory_requirements.size;
|
|
|
|
alloc_info.allocationSize = memory_requirements.size;
|
|
|
|
alloc_info.memoryTypeIndex = find_memory_type(physical_device, memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
|
|
alloc_info.memoryTypeIndex = find_memory_type(physical_device, memory_requirements.memoryTypeBits, properties);
|
|
|
|
|
|
|
|
|
|
|
|
result = vkAllocateMemory(device, &alloc_info, 0, &allocated_buffer.memory);
|
|
|
|
result = vkAllocateMemory(device, &alloc_info, 0, &ret.memory);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return allocated_buffer;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = vkBindBufferMemory(device, allocated_buffer.buffer, allocated_buffer.memory, 0);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void deallocate_buffer(VkDevice device, AllocatedBuffer buffer) {
|
|
|
|
|
|
|
|
vkDestroyBuffer(device, buffer.buffer, 0);
|
|
|
|
|
|
|
|
vkFreeMemory(device, buffer.memory, 0);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkResult command_copy_buffers(VkDevice device, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBuffer source, VkBuffer dest, VkDeviceSize size) {
|
|
|
|
|
|
|
|
VkCommandBufferAllocateInfo command_info = {};
|
|
|
|
|
|
|
|
command_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
|
|
|
|
|
|
command_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
|
|
|
|
|
|
command_info.commandPool = transfer_pool;
|
|
|
|
|
|
|
|
command_info.commandBufferCount = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkCommandBuffer command_buffer;
|
|
|
|
|
|
|
|
VkResult result = vkAllocateCommandBuffers(device, &command_info, &command_buffer);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return allocated_buffer;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
|
|
|
|
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
|
|
|
|
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = vkBeginCommandBuffer(command_buffer, &begin_info);
|
|
|
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkBufferCopy copy_region = {};
|
|
|
|
|
|
|
|
copy_region.srcOffset = 0;
|
|
|
|
|
|
|
|
copy_region.dstOffset = 0;
|
|
|
|
|
|
|
|
copy_region.size = size;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vkCmdCopyBuffer(command_buffer, source, dest, 1, ©_region);
|
|
|
|
|
|
|
|
result = vkEndCommandBuffer(command_buffer);
|
|
|
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkSubmitInfo submit_info = {};
|
|
|
|
|
|
|
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
|
|
|
|
submit_info.commandBufferCount = 1;
|
|
|
|
|
|
|
|
submit_info.pCommandBuffers = &command_buffer;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = vkQueueSubmit(transfer_queue, 1, &submit_info, 0);
|
|
|
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = vkQueueWaitIdle(transfer_queue);
|
|
|
|
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vkFreeCommandBuffers(device, transfer_pool, 1, &command_buffer);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return VK_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer create_populated_buffer(VkPhysicalDevice physical_device, VkDevice device, void* data, VkDeviceSize size, VkCommandPool transfer_pool, VkQueue transfer_queue, VkBufferUsageFlags usage) {
|
|
|
|
|
|
|
|
AllocatedBuffer staging_buffer = {};
|
|
|
|
|
|
|
|
AllocatedBuffer vertex_buffer = {};
|
|
|
|
|
|
|
|
staging_buffer = allocate_buffer(physical_device, device, size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
|
|
|
|
|
|
if(staging_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
|
|
|
|
return vertex_buffer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void* buffer_data;
|
|
|
|
void* buffer_data;
|
|
|
|
result = vkMapMemory(device, allocated_buffer.memory, 0, buffer_info.size, 0, &buffer_data);
|
|
|
|
VkResult result = vkMapMemory(device, staging_buffer.memory, 0, size, 0, &buffer_data);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return allocated_buffer;
|
|
|
|
deallocate_buffer(device, staging_buffer);
|
|
|
|
|
|
|
|
return vertex_buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(buffer_data, data, size);
|
|
|
|
memcpy(buffer_data, data, size);
|
|
|
|
|
|
|
|
|
|
|
|
vkUnmapMemory(device, allocated_buffer.memory);
|
|
|
|
vkUnmapMemory(device, staging_buffer.memory);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
vertex_buffer = allocate_buffer(physical_device, device, size, VK_BUFFER_USAGE_TRANSFER_DST_BIT | usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return allocated_buffer;
|
|
|
|
return vertex_buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass) {
|
|
|
|
VkPipeline create_graphics_pipeline(VkDevice device, VkExtent2D extent, VkPipelineLayout layout, VkRenderPass render_pass) {
|
|
|
@ -943,7 +1087,7 @@ VkCommandPool create_command_pool(VkDevice device, uint32_t queue_family) {
|
|
|
|
return command_pool;
|
|
|
|
return command_pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline, VkBuffer vertex_buffer, uint32_t num_vertices) {
|
|
|
|
VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t image_index, VkRenderPass render_pass, VkFramebuffer* framebuffers, VkExtent2D extent, VkPipeline graphics_pipeline, VkBuffer vertex_buffer, VkBuffer index_buffer, uint32_t num_vertices) {
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
|
|
VkCommandBufferBeginInfo begin_info = {};
|
|
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
begin_info.flags = 0;
|
|
|
|
begin_info.flags = 0;
|
|
|
@ -971,6 +1115,7 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t
|
|
|
|
VkBuffer vertex_buffers[] = {vertex_buffer};
|
|
|
|
VkBuffer vertex_buffers[] = {vertex_buffer};
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
|
|
|
|
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offsets);
|
|
|
|
|
|
|
|
vkCmdBindIndexBuffer(command_buffer, index_buffer, 0, VK_INDEX_TYPE_UINT16);
|
|
|
|
|
|
|
|
|
|
|
|
VkViewport viewport = {};
|
|
|
|
VkViewport viewport = {};
|
|
|
|
viewport.x = 0.0f;
|
|
|
|
viewport.x = 0.0f;
|
|
|
@ -987,7 +1132,7 @@ VkResult record_command_buffer_triangle(VkCommandBuffer command_buffer, uint32_t
|
|
|
|
scissor.extent = extent;
|
|
|
|
scissor.extent = extent;
|
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
|
|
|
|
|
|
|
|
|
|
|
vkCmdDraw(command_buffer, num_vertices, 1, 0, 0);
|
|
|
|
vkCmdDrawIndexed(command_buffer, num_vertices, 1, 0, 0, 0);
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
vkCmdEndRenderPass(command_buffer);
|
|
|
|
|
|
|
|
|
|
|
|
return vkEndCommandBuffer(command_buffer);
|
|
|
|
return vkEndCommandBuffer(command_buffer);
|
|
|
@ -1088,12 +1233,12 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
context->surface = surface;
|
|
|
|
context->surface = surface;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeQueueIndices maybe_indices = get_queue_indices(context->physical_device, context->surface);
|
|
|
|
QueueIndices queue_indices = get_queue_indices(context->physical_device, context->surface);
|
|
|
|
if(maybe_indices.valid == false) {
|
|
|
|
if(check_queue_indices(queue_indices) == false) {
|
|
|
|
fprintf(stderr, "failed to get vulkan queue indices\n");
|
|
|
|
fprintf(stderr, "failed to get vulkan queue indices\n");
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
context->queue_indices = maybe_indices.indices;
|
|
|
|
context->queue_indices = queue_indices;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkDevice device = create_logical_device(context->physical_device, context->queue_indices);
|
|
|
|
VkDevice device = create_logical_device(context->physical_device, context->queue_indices);
|
|
|
@ -1105,6 +1250,7 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.graphics_family, context->queue_indices.graphics_index, &context->queues.graphics);
|
|
|
|
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);
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.present_family, context->queue_indices.present_index, &context->queues.present);
|
|
|
|
|
|
|
|
vkGetDeviceQueue(device, context->queue_indices.transfer_family, context->queue_indices.transfer_index, &context->queues.transfer);
|
|
|
|
|
|
|
|
|
|
|
|
struct MaybeSwapchainDetails maybe_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
struct MaybeSwapchainDetails maybe_details = get_swapchain_details(context->physical_device, context->surface);
|
|
|
|
if(maybe_details.valid == false) {
|
|
|
|
if(maybe_details.valid == false) {
|
|
|
@ -1159,12 +1305,20 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
context->swapchain_framebuffers = framebuffers;
|
|
|
|
context->swapchain_framebuffers = framebuffers;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkCommandPool command_pool = create_command_pool(context->device, context->queue_indices.graphics_family);
|
|
|
|
VkCommandPool graphics_command_pool = create_command_pool(context->device, context->queue_indices.graphics_family);
|
|
|
|
if(command_pool == VK_NULL_HANDLE) {
|
|
|
|
if(graphics_command_pool == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to create vulkan graphics command pool");
|
|
|
|
fprintf(stderr, "failed to create vulkan graphics command pool");
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
context->graphics_command_pool = command_pool;
|
|
|
|
context->graphics_command_pool = graphics_command_pool;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkCommandPool transfer_command_pool = create_command_pool(context->device, context->queue_indices.transfer_family);
|
|
|
|
|
|
|
|
if(transfer_command_pool == VK_NULL_HANDLE) {
|
|
|
|
|
|
|
|
fprintf(stderr, "failed to create vulkan transfer command pool");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->transfer_command_pool = transfer_command_pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
context->max_frames_in_flight = max_frames_in_flight;
|
|
|
|
context->max_frames_in_flight = max_frames_in_flight;
|
|
|
@ -1217,11 +1371,18 @@ VulkanContext* init_vulkan(GLFWwindow* window, uint32_t max_frames_in_flight) {
|
|
|
|
context->triangle_pipeline = triangle_pipeline;
|
|
|
|
context->triangle_pipeline = triangle_pipeline;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer triangle_buffer = create_vertex_buffer(context->physical_device, context->device, (void*)vertices, sizeof(vertices));
|
|
|
|
AllocatedBuffer triangle_vertex_buffer = create_populated_buffer(context->physical_device, context->device, (void*)vertices, sizeof(vertices), context->transfer_command_pool, context->queues.transfer, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
|
|
|
|
if(triangle_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
if(triangle_vertex_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
|
|
|
|
fprintf(stderr, "failed to allocate vulkan buffer for triangle buffer\n");
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
context->triangle_vertex_buffer = triangle_vertex_buffer;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AllocatedBuffer triangle_index_buffer = create_populated_buffer(context->physical_device, context->device, (void*)indices, sizeof(indices), context->transfer_command_pool, context->queues.transfer, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
|
|
|
|
|
|
|
|
if(triangle_index_buffer.memory == VK_NULL_HANDLE) {
|
|
|
|
fprintf(stderr, "failed to allocate vulkan buffer for triangle buffer\n");
|
|
|
|
fprintf(stderr, "failed to allocate vulkan buffer for triangle buffer\n");
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
context->triangle_buffer = triangle_buffer;
|
|
|
|
context->triangle_index_buffer = triangle_index_buffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return context;
|
|
|
|
return context;
|
|
|
@ -1250,7 +1411,7 @@ VkResult draw_frame(VulkanContext* context) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline, context->triangle_buffer.buffer, 3);
|
|
|
|
result = record_command_buffer_triangle(context->swapchain_command_buffers[context->current_frame], image_index, context->render_pass, context->swapchain_framebuffers, context->swapchain_extent, context->triangle_pipeline, context->triangle_vertex_buffer.buffer, context->triangle_index_buffer.buffer, 6);
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
if(result != VK_SUCCESS) {
|
|
|
|
return result;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|