diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c1ab78b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/build/ +vulkan_config_log.txt \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..9c8351e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "thirdparty/Vulkan-Headers"] + path = thirdparty/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "thirdparty/SDL"] + path = thirdparty/SDL + url = https://github.com/libsdl-org/SDL.git diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/dictionaries b/.idea/dictionaries new file mode 100644 index 0000000..03e131b --- /dev/null +++ b/.idea/dictionaries @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modern_cpp_vulkan_project.iml b/.idea/modern_cpp_vulkan_project.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/modern_cpp_vulkan_project.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..9351e82 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..8eb4701 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.25) +project(modern_cpp_vulkan_project) + +add_subdirectory(source) +add_subdirectory(thirdparty) +target_link_libraries(source PRIVATE thirdparty) \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt new file mode 100644 index 0000000..9c2541c --- /dev/null +++ b/source/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(source main.cpp) +target_compile_features(source PRIVATE cxx_std_23) +set_target_properties(source PROPERTIES CXX_EXTENSIONS off CXX_STANDARD_REQUIRED on) + +if (MSVC) + target_compile_options(source PRIVATE /W3 /sdl /external:anglebrackets /external:W2 /fsanitize=address /wd4068) +else () + target_compile_options(source PRIVATE -Wall -Wextra -Wpedantic -isystem) +endif () \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..960f1ba --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,152 @@ +#include +#include +#include + +#define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 0 + +#include + +class Noncopyable { +public: + Noncopyable() = default; + + Noncopyable(const Noncopyable &) = delete; + + const Noncopyable &operator=(const Noncopyable &) = delete; +}; + +class SDLException : private std::runtime_error, Noncopyable { + const int code; +public: + explicit SDLException(const char *message, const int code = 0) : runtime_error(message), code{code} {} + + [[nodiscard]] auto get_code() const noexcept { + return code; + } +}; + +class SDL : Noncopyable { +public: + explicit SDL(SDL_InitFlags init_flags) { + if (const auto error_code = SDL_Init(init_flags)) + throw SDLException{SDL_GetError(), error_code}; + } + + ~SDL() { + SDL_Quit(); + } +}; + +class VulkanLibrary : Noncopyable { +public: + explicit VulkanLibrary(const char *path = nullptr) { + if (const auto error_code = SDL_Vulkan_LoadLibrary(path)) + throw SDLException{SDL_GetError(), error_code}; + + } + + ~VulkanLibrary() { + SDL_Vulkan_UnloadLibrary(); + } + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "readability-convert-member-functions-to-static" + + [[nodiscard]] auto get_instance_proc_addr() const { + if (const auto get_instance_proc_addr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr())) + return get_instance_proc_addr; + else + throw SDLException{"Couldn't load vkGetInstanceProcAddr function from the vulkan dynamic library"}; + } + + [[nodiscard]] auto get_instance_extensions() const { + uint32_t count; + if (!SDL_Vulkan_GetInstanceExtensions(&count, nullptr)) + throw SDLException{"Couldn't get vulkan instance extensions count"}; + std::vector extensions(count); + if (!SDL_Vulkan_GetInstanceExtensions(&count, extensions.data())) + throw SDLException{"Couldn't get vulkan instance extensions"}; + return extensions; + } + +#pragma clang diagnostic pop +}; + +class Window : Noncopyable { + SDL_Window *handle; +public: + Window(const char *title, const int width, const int height, + const SDL_WindowFlags flags = static_cast(0)) : handle{ + SDL_CreateWindow(title, width, height, flags)} { + if (!handle) + throw SDLException{SDL_GetError()}; + } + + ~Window() { + SDL_DestroyWindow(handle); + } + + [[nodiscard]] auto create_surface(const vk::raii::Instance &instance) const { + vk::SurfaceKHR::NativeType surface_handle; + if (!SDL_Vulkan_CreateSurface(handle, *instance, &surface_handle)) + throw SDLException{SDL_GetError()}; + return vk::raii::SurfaceKHR{instance, surface_handle}; + } + + [[nodiscard]] auto get_handle() const noexcept { + return handle; + } +}; + +using QueueFamily = std::pair; + +auto main(int argc, char **argv) -> int { + const SDL sdl{SDL_InitFlags::SDL_INIT_VIDEO}; + const VulkanLibrary vulkan_library{}; + + vk::raii::Context context{vulkan_library.get_instance_proc_addr()}; + + vk::ApplicationInfo application_info{}; + application_info.apiVersion = VK_API_VERSION_1_3; + + vk::InstanceCreateInfo create_info{}; + auto extensions = vulkan_library.get_instance_extensions(); + if (SDL_GetPlatform() == std::string_view{"macOS"}) { + create_info.flags |= vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR; + extensions.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); + } + create_info.setPEnabledExtensionNames(extensions); + create_info.pApplicationInfo = &application_info; + const vk::raii::Instance instance{context, create_info}; + + const Window window{"Salam", 800, 600, SDL_WindowFlags::SDL_WINDOW_VULKAN}; + const auto surface = window.create_surface(instance); + + std::optional queue_family{}; + for (const auto &physical_device: instance.enumeratePhysicalDevices()) { + const auto queue_families_properties = physical_device.getQueueFamilyProperties(); + for (std::size_t queue_family_index = 0; + queue_family_index != queue_families_properties.size(); ++queue_family_index) { + const auto queue_family_properties = queue_families_properties[queue_family_index]; + + if (queue_family_properties.queueFlags & vk::QueueFlagBits::eGraphics) + queue_family = {physical_device, queue_family_index}; + } + } + if (queue_family.has_value()) { + const auto &[physical_device, queue_family_index] = *queue_family; + SDL_Log("Found queue family: %s %d", physical_device.getProperties().deviceName.data(), queue_family_index); + } + + bool should_close{}; + while (!should_close) { + for (SDL_Event event; SDL_PollEvent(&event);) { + switch (event.type) { + case SDL_EventType::SDL_EVENT_QUIT: + should_close = true; + } + } + } + + return 0; +}; \ No newline at end of file diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt new file mode 100644 index 0000000..8f7ba4b --- /dev/null +++ b/thirdparty/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(thirdparty INTERFACE) + +add_subdirectory(Vulkan-Headers) +add_subdirectory(SDL) + +target_link_libraries(thirdparty INTERFACE Vulkan::Headers SDL3::SDL3) \ No newline at end of file diff --git a/thirdparty/SDL b/thirdparty/SDL new file mode 160000 index 0000000..5782007 --- /dev/null +++ b/thirdparty/SDL @@ -0,0 +1 @@ +Subproject commit 57820071a497d57e362f6a7c71ab10c4a6fb5228 diff --git a/thirdparty/Vulkan-Headers b/thirdparty/Vulkan-Headers new file mode 160000 index 0000000..bc14fda --- /dev/null +++ b/thirdparty/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit bc14fdad60c51235e23ee569834a5baecae9231a