diff options
| author | Clement Sibille <clements@lisible.xyz> | 2024-12-10 21:30:59 +0100 | 
|---|---|---|
| committer | Clement Sibille <clements@lisible.xyz> | 2024-12-10 21:30:59 +0100 | 
| commit | a89077cefe1a2b690062d477b9575908f0959997 (patch) | |
| tree | ef916c90bb8f6330d0a1a06f87e469cf8da01b1e | |
| parent | 6439acef6b5a07c59141632404c60ad668258e3e (diff) | |
Add graphics and present queue creation
| -rw-r--r-- | src/main.c | 122 | 
1 files changed, 114 insertions, 8 deletions
@@ -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;    }  | 
