diff options
Diffstat (limited to 'hk21/game/gpu.cpp')
-rw-r--r-- | hk21/game/gpu.cpp | 146 |
1 files changed, 138 insertions, 8 deletions
diff --git a/hk21/game/gpu.cpp b/hk21/game/gpu.cpp index c18093f..9122f83 100644 --- a/hk21/game/gpu.cpp +++ b/hk21/game/gpu.cpp @@ -74,13 +74,24 @@ class GpuImpl : public Gpu {
bool m_destroyed{};
- VkInstance m_instance;
- VkSurfaceKHR m_surface;
+ VkInstance m_instance;
+ VkSurfaceKHR m_surface;
+ uint32_t m_queue_family_index;
+ VkDevice m_device;
+ VkQueue m_queue;
public:
- GpuImpl(VkInstance instance, VkSurfaceKHR surface)
+ GpuImpl(
+ VkInstance instance,
+ VkSurfaceKHR surface,
+ uint32_t queue_family_index,
+ VkDevice device,
+ VkQueue queue)
: m_instance{instance}
, m_surface{surface}
+ , m_queue_family_index{queue_family_index}
+ , m_device{device}
+ , m_queue{queue}
{}
ASL_DELETE_COPY_MOVE(GpuImpl);
@@ -94,11 +105,16 @@ public: {
ASL_ASSERT(!m_destroyed);
m_destroyed = true;
+ vkDestroyDevice(m_device, VK_ALLOCATOR);
vkDestroySurfaceKHR(m_instance, m_surface, VK_ALLOCATOR);
vkDestroyInstance(m_instance, VK_ALLOCATOR);
}
};
+static uint32_t kTargetVersionMajor = 1;
+static uint32_t kTargetVersionMinor = 3;
+static uint32_t kTargetVersion = VK_MAKE_API_VERSION(0, kTargetVersionMajor, kTargetVersionMinor, 0); // NOLINT
+
static asl::status_or<VkInstance> create_instance()
{
asl::buffer<const char*> instance_extensions;
@@ -127,7 +143,7 @@ static asl::status_or<VkInstance> create_instance() uint32_t vk_major = VK_API_VERSION_MAJOR(version); // NOLINT
uint32_t vk_minor = VK_API_VERSION_MINOR(version); // NOLINT
- if (vk_major != 1 || vk_minor < 3)
+ if (vk_major != kTargetVersionMajor || vk_minor < kTargetVersionMinor)
{
return asl::runtime_error("Incompatible Vulkan version: {}.{}", vk_major, vk_minor);
}
@@ -139,7 +155,7 @@ static asl::status_or<VkInstance> create_instance() .applicationVersion = 0,
.pEngineName = "Custom",
.engineVersion = 0,
- .apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), // NOLINT
+ .apiVersion = kTargetVersion,
};
VkInstanceCreateInfo instance_create_info{
@@ -163,6 +179,8 @@ static asl::status_or<VkInstance> create_instance() status = vulkan_loader::load_instance(vkGetInstanceProcAddr, instance);
ASL_TRY(status);
+ ASL_LOG_INFO("Vulkan instance created");
+
return instance;
}
@@ -177,6 +195,105 @@ static asl::status_or<VkSurfaceKHR> create_surface(SDL_Window* window, VkInstanc return surface;
}
+struct PhysicalDeviceInfo
+{
+ VkPhysicalDevice physical_device;
+ uint32_t queue_family_index;
+};
+
+static asl::status_or<PhysicalDeviceInfo> find_physical_device(VkInstance instance)
+{
+ uint32_t count{};
+ asl::buffer<VkPhysicalDevice> physical_devices;
+ asl::buffer<VkQueueFamilyProperties> queue_family_prps;
+
+ vkEnumeratePhysicalDevices(instance, &count, nullptr);
+ physical_devices.resize_zero(count);
+ VkResult res = vkEnumeratePhysicalDevices(instance, &count, physical_devices.data());
+ if (res != VK_SUCCESS)
+ {
+ return asl::runtime_error("Couldn't enumerate Vulkan physical devices: {}", res);
+ }
+
+ for (auto* physical_device: physical_devices)
+ {
+ VkPhysicalDeviceProperties prps;
+ vkGetPhysicalDeviceProperties(physical_device, &prps);
+
+ asl::string_view name{prps.deviceName, asl::strlen(prps.deviceName)};
+
+ if (prps.apiVersion < kTargetVersion)
+ {
+ ASL_LOG_INFO("Device {}: invalid supported Vulkan API version", name);
+ continue;
+ }
+
+ uint32_t queue_family_count{};
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, nullptr);
+ queue_family_prps.resize_zero(queue_family_count);
+ vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count, queue_family_prps.data());
+
+ static constexpr VkQueueFlags kWantedQueueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
+
+ for (uint32_t queue_family_index = 0; queue_family_index < queue_family_count; ++queue_family_index)
+ {
+ if ((queue_family_prps[queue_family_index].queueFlags & kWantedQueueFlags) != kWantedQueueFlags) { continue; }
+ if (!SDL_Vulkan_GetPresentationSupport(instance, physical_device, queue_family_index)) { continue; }
+
+ ASL_LOG_INFO("Chosing device \"{}\" with queue family {}", name, queue_family_index);
+ return PhysicalDeviceInfo{ physical_device, queue_family_index };
+ }
+
+ ASL_LOG_INFO("Device {}: no valid queue found", name);
+ }
+
+ return asl::runtime_error("Couldn't find a valid Vulkan physical device");
+}
+
+static asl::status_or<VkDevice> create_device(VkPhysicalDevice physical_device, uint32_t queue_family_index)
+{
+ asl::buffer<const char*> device_extensions;
+ device_extensions.push(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+
+ const float queue_priority = 1.0F;
+
+ VkDeviceQueueCreateInfo queue_create_info{
+ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .queueFamilyIndex = queue_family_index,
+ .queueCount = 1,
+ .pQueuePriorities = &queue_priority,
+ };
+
+ VkDeviceCreateInfo create_info{
+ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
+ .pNext = nullptr,
+ .flags = 0,
+ .queueCreateInfoCount = 1,
+ .pQueueCreateInfos = &queue_create_info,
+ .enabledLayerCount = 0,
+ .ppEnabledLayerNames = nullptr,
+ .enabledExtensionCount = static_cast<uint32_t>(device_extensions.size()),
+ .ppEnabledExtensionNames = device_extensions.data(),
+ .pEnabledFeatures = nullptr,
+ };
+
+ VkDevice device{};
+ VkResult res = vkCreateDevice(physical_device, &create_info, VK_ALLOCATOR, &device);
+ if (res != VK_SUCCESS)
+ {
+ return asl::runtime_error("Couldn't create Vulkan device: {}", res);
+ }
+
+ ASL_LOG_INFO("Vulkan device created");
+
+ auto status = vulkan_loader::load_device(device);
+ ASL_TRY(status);
+
+ return device;
+}
+
asl::status_or<asl::box<Gpu>> init(SDL_Window* window)
{
auto instance = create_instance();
@@ -185,10 +302,23 @@ asl::status_or<asl::box<Gpu>> init(SDL_Window* window) auto surface = create_surface(window, instance.value());
ASL_TRY(surface);
- // asl::buffer<const char*> device_extensions;
- // device_extensions.push(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+ auto physical_device_info = find_physical_device(instance.value());
+ ASL_TRY(physical_device_info);
+
+ auto device = create_device(
+ physical_device_info.value().physical_device,
+ physical_device_info.value().queue_family_index);
+ ASL_TRY(device);
+
+ VkQueue queue{};
+ vkGetDeviceQueue(device.value(), physical_device_info.value().queue_family_index, 0, &queue);
- return asl::make_box<GpuImpl>(instance.value(), surface.value());
+ return asl::make_box<GpuImpl>(
+ instance.value(),
+ surface.value(),
+ physical_device_info.value().queue_family_index,
+ device.value(),
+ queue);
};
} // namespace gpu
|