summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.c122
1 files changed, 114 insertions, 8 deletions
diff --git a/src/main.c b/src/main.c
index 4ca37ec..118d9e8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -18,7 +18,12 @@
struct vulkan_renderer {
VkInstance instance;
+ VkPhysicalDevice physical_device;
+ VkDevice device;
+ VkQueue graphics_queue;
VkDebugUtilsMessengerEXT debug_messenger;
+ VkSurfaceKHR surface;
+ VkQueue present_queue;
bool enable_validation_layers;
};
@@ -199,16 +204,19 @@ bool vulkan_renderer_create_debug_messenger(struct vulkan_renderer *renderer) {
struct queue_family_indices {
uint32_t graphics_family;
+ uint32_t present_family;
bool has_graphics_family;
+ bool has_present_family;
};
bool queue_family_indices_is_complete(
const struct queue_family_indices *indices) {
- return indices->has_graphics_family;
+ return indices->has_graphics_family && indices->has_present_family;
}
#define MAX_QUEUE_FAMILY_COUNT 64
-struct queue_family_indices find_queue_families(VkPhysicalDevice device) {
+struct queue_family_indices find_queue_families(VkPhysicalDevice device,
+ VkSurfaceKHR surface) {
struct queue_family_indices indices = {0};
uint32_t queue_family_count = 0;
@@ -222,11 +230,21 @@ struct queue_family_indices find_queue_families(VkPhysicalDevice device) {
for (uint32_t queue_family_index = 0; queue_family_index < queue_family_count;
queue_family_index++) {
VkQueueFamilyProperties *queue_family = &queue_families[queue_family_index];
+
+ VkBool32 present_support;
+ vkGetPhysicalDeviceSurfaceSupportKHR(device, queue_family_index, surface,
+ &present_support);
+
if (queue_family->queueFlags & VK_QUEUE_GRAPHICS_BIT) {
indices.graphics_family = queue_family_index;
indices.has_graphics_family = true;
}
+ if (present_support) {
+ indices.present_family = queue_family_index;
+ indices.has_present_family = true;
+ }
+
if (queue_family_indices_is_complete(&indices)) {
break;
}
@@ -235,9 +253,9 @@ struct queue_family_indices find_queue_families(VkPhysicalDevice device) {
return indices;
}
-bool is_device_suitable(VkPhysicalDevice device) {
+bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface) {
struct queue_family_indices queue_family_indices =
- find_queue_families(device);
+ find_queue_families(device, surface);
return queue_family_indices_is_complete(&queue_family_indices);
}
@@ -256,7 +274,7 @@ bool vulkan_renderer_pick_physical_device(struct vulkan_renderer *renderer) {
vkEnumeratePhysicalDevices(renderer->instance, &device_count, devices);
for (uint32_t device_index = 0; device_index < device_count; device_index++) {
- if (is_device_suitable(devices[device_index])) {
+ if (is_device_suitable(devices[device_index], renderer->surface)) {
physical_device = devices[device_index];
break;
}
@@ -267,13 +285,86 @@ bool vulkan_renderer_pick_physical_device(struct vulkan_renderer *renderer) {
goto err;
}
+ renderer->physical_device = physical_device;
+
return true;
err:
return false;
}
-bool vulkan_renderer_init(struct vulkan_renderer *renderer) {
+bool is_in_array(uint32_t *array, int length, uint32_t value) {
+ for (int i = 0; i < length; i++) {
+ if (array[i] == value) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool vulkan_renderer_create_logical_device(struct vulkan_renderer *renderer) {
+ struct queue_family_indices indices =
+ find_queue_families(renderer->physical_device, renderer->surface);
+
+ VkDeviceQueueCreateInfo queue_create_infos[MAX_QUEUE_FAMILY_COUNT] = {0};
+ int queue_create_info_count = 0;
+
+ uint32_t unique_queue_families[MAX_QUEUE_FAMILY_COUNT] = {0};
+ int unique_queue_family_count = 0;
+
+ if (!is_in_array(unique_queue_families, unique_queue_family_count,
+ indices.graphics_family)) {
+ unique_queue_families[unique_queue_family_count++] =
+ indices.graphics_family;
+ }
+ if (!is_in_array(unique_queue_families, unique_queue_family_count,
+ indices.present_family)) {
+ unique_queue_families[unique_queue_family_count++] = indices.present_family;
+ }
+
+ float queue_priority = 1.0f;
+ for (int unique_queue_family_index = 0;
+ unique_queue_family_index < unique_queue_family_count;
+ unique_queue_family_index++) {
+ queue_create_infos[queue_create_info_count++] = (VkDeviceQueueCreateInfo){
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .queueFamilyIndex = unique_queue_families[unique_queue_family_index],
+ .queueCount = 1,
+ .pQueuePriorities = &queue_priority};
+ }
+
+ VkPhysicalDeviceFeatures device_features = {0};
+
+ if (vkCreateDevice(renderer->physical_device,
+ &(const VkDeviceCreateInfo){
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pQueueCreateInfos = queue_create_infos,
+ .queueCreateInfoCount = queue_create_info_count,
+ .pEnabledFeatures = &device_features,
+ .enabledExtensionCount = 0,
+ // TODO maybe add the validation layers
+ // Not required according to vulkan-tutorial, but might
+ // be good for compatibility
+ },
+ NULL, &renderer->device) != VK_SUCCESS) {
+ LOG("Couldn't create logical vulkan device");
+ return false;
+ }
+
+ vkGetDeviceQueue(renderer->device, indices.graphics_family, 0,
+ &renderer->graphics_queue);
+ vkGetDeviceQueue(renderer->device, indices.present_family, 0,
+ &renderer->present_queue);
+ LOG("graphics_queue: %p", (void *)renderer->graphics_queue);
+ LOG("present_queue: %p", (void *)renderer->present_queue);
+
+ return true;
+}
+
+bool vulkan_renderer_init(struct vulkan_renderer *renderer,
+ SDL_Window *window) {
assert(renderer);
+ assert(window);
#ifdef NDEBUG
renderer->enable_validation_layers = false;
#else
@@ -290,13 +381,26 @@ bool vulkan_renderer_init(struct vulkan_renderer *renderer) {
}
}
+ if (!SDL_Vulkan_CreateSurface(window, renderer->instance, NULL,
+ &renderer->surface)) {
+ LOG("Couldn't create Vulkan rendering surface: %s", SDL_GetError());
+ goto destroy_instance;
+ }
+
if (!vulkan_renderer_pick_physical_device(renderer)) {
LOG("Couldn't pick the appropriate physical device.");
- goto destroy_instance;
+ goto destroy_surface;
+ }
+
+ if (!vulkan_renderer_create_logical_device(renderer)) {
+ LOG("Couldn't create the logical device");
+ goto destroy_surface;
}
return true;
+destroy_surface:
+ vkDestroySurfaceKHR(renderer->instance, renderer->surface, NULL);
destroy_instance:
if (renderer->enable_validation_layers) {
vkDestroyDebugUtilsMessengerEXT(renderer->instance,
@@ -308,6 +412,8 @@ err:
}
void vulkan_renderer_deinit(struct vulkan_renderer *renderer) {
+ vkDestroyDevice(renderer->device, NULL);
+ vkDestroySurfaceKHR(renderer->instance, renderer->surface, NULL);
if (renderer->enable_validation_layers) {
vkDestroyDebugUtilsMessengerEXT(renderer->instance,
renderer->debug_messenger, NULL);
@@ -329,7 +435,7 @@ int main(void) {
}
struct vulkan_renderer renderer;
- if (!vulkan_renderer_init(&renderer)) {
+ if (!vulkan_renderer_init(&renderer, window)) {
LOG("Couldn't init vulkan renderer");
goto destroy_window;
}
Go back to lisible.xyz