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