I am currently going through this Vulkan tutorial.
An extra excercise was writing a function which checks if the hardware you are running on supports the extensions other libraries require (GLFW in this case).
All the code is here:
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <vector>
#include <unordered_set>
#include <functional>
const uint32_t WIDTH = 800;
const uint32_t HEIGHT = 600;
enum Verbosity : bool {
VERBOSE = true,
TERSE = false,
};
//todo: enumerate the available extensions, print them
// and check if the ones required by glfw are in that list
class HelloTriangleApplication {
public:
void run() {
initWindow();
initVulkan();
mainLoop();
cleanup();
}
private:
GLFWwindow* window;
VkInstance instance;
void initWindow() {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "vulkan",
nullptr, nullptr);
}
void initVulkan() {
createInstance();
}
void createInstance() {
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
uint32_t glfwExtensionCount = 0;
const char ** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
try {
checkRequiredExtensions(std::vector<std::string>(glfwExtensions, glfwExtensions + glfwExtensionCount),
VERBOSE);
} catch (std::exception &e) {
throw;
}
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.enabledLayerCount = 0;
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
}
void checkRequiredExtensions(std::vector<std::string> requiredExtensions, const Verbosity &&verbose) {
if (verbose) {
std::cerr << "Required extensions: ";
for (auto &extension: requiredExtensions)
std::cerr << extension << ", ";
std::cerr << '\n';
}
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(
nullptr, &extensionCount, nullptr);
std::vector<VkExtensionProperties> supportedExtensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr,
&extensionCount, supportedExtensions.data());
std::unordered_set<std::string> supportedExtensionNames;
std::transform(supportedExtensions.begin(), supportedExtensions.end(),
std::inserter(supportedExtensionNames, supportedExtensionNames.begin()),
[](const auto& extension) {
return extension.extensionName;
});
if (verbose) {
std::cerr << "Available extensions: ";
for (auto &extension: supportedExtensionNames) {
std::cerr << extension << ", ";
}
std::cerr << '\n';
}
if(std::any_of(requiredExtensions.begin(), requiredExtensions.end(),
[&](const auto& extension) {
return !supportedExtensionNames.contains(extension);
})) {
throw std::runtime_error("Hardware does not support the required Vulkan extensions");
}
if (verbose) {
std::cerr << "Hardware supports required extensions\n";
}
}
void mainLoop() {
while(!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
}
void cleanup() {
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}
};
int main() {
HelloTriangleApplication app;
try {
app.run();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
I'm specifically interested in the code I wrote in void checkRequiredExtensions(std::vector<std::string> requiredExtensions, const Verbosity &&verbose)
.
Am I handling exceptions correctly? Have I chosen a good way of selecting the verbosity mode of the function?
I find graphics programs super hard to debug so like logging everything and want the best way to do this.
I'm also worried about runtime overhead (as those if conditions need to be evaluated multiple times). Is there a way to avoid this? Am I making any dumb mistakes?