/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN #include "vulkan/vulkan.h" #include "vulkan/vk_enum_string_helper.h" #define GET_EXTENSION_FUNCTION(_id) ((PFN_##_id)(vkGetInstanceProcAddr(instance, #_id))) #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND #include #include #include #include "../lib/xdg-shell-client-protocol.h" #include "../lib/wayland-xdg-decoration-unstable-v1-client-protocol.h" #include "../lib/fractional-scale-v1.h" #include "../lib/viewporter.h" #include #include #include #include #include #include #endif module Crafter.Graphics:Device_impl; import :Device; import :Window; import :MouseElement; import :Types; import std; using namespace Crafter; #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN const char* const instanceExtensionNames[] = { "VK_EXT_debug_utils", "VK_KHR_surface", #ifdef CRAFTER_GRAPHICS_WINDOW_WIN32 "VK_KHR_win32_surface" #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND "VK_KHR_wayland_surface" #endif }; const char* const deviceExtensionNames[] = { "VK_KHR_swapchain", "VK_KHR_spirv_1_4", "VK_KHR_shader_float_controls", "VK_KHR_acceleration_structure", "VK_KHR_ray_tracing_pipeline", "VK_EXT_descriptor_heap", "VK_KHR_deferred_host_operations", "VK_KHR_maintenance5", "VK_KHR_shader_untyped_pointers", "VK_EXT_device_fault" }; const char* const layerNames[] = { "VK_LAYER_KHRONOS_validation" }; void Device::CheckVkResult(VkResult result) { if (result != VK_SUCCESS) { if(result == VK_ERROR_DEVICE_LOST) { VkDeviceFaultCountsEXT faultCounts = { .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT, .pNext = NULL, }; Device::vkGetDeviceFaultInfoEXT(device, &faultCounts, NULL); std::vector addressInfos(faultCounts.addressInfoCount); std::vector vendorInfos(faultCounts.vendorInfoCount); std::vector vendorBinaryData(faultCounts.vendorBinarySize); VkDeviceFaultInfoEXT faultInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT, .pNext = NULL, .pAddressInfos = addressInfos.data(), .pVendorInfos = vendorInfos.data(), .pVendorBinaryData = vendorBinaryData.data(), }; Device::vkGetDeviceFaultInfoEXT(device, &faultCounts, &faultInfo); std::println("{}", faultInfo.description); std::println("{} AddressInfos:", addressInfos.size()); for(const VkDeviceFaultAddressInfoEXT& info : addressInfos) { std::println("\t{} {}", static_cast(info.addressType), info.reportedAddress); } std::println("{} vendorInfos:", vendorInfos.size()); for(const VkDeviceFaultVendorInfoEXT& info : vendorInfos) { std::println("\t{} {} {}", info.description, info.vendorFaultCode, info.vendorFaultData); } if(!vendorBinaryData.empty()) { std::string ext = ".bin"; if(vendorBinaryData.size() >= sizeof(VkDeviceFaultVendorBinaryHeaderVersionOneEXT)) { VkDeviceFaultVendorBinaryHeaderVersionOneEXT header; std::memcpy(&header, vendorBinaryData.data(), sizeof(header)); if(header.vendorID == 0x10DE) { // NVIDIA ext = ".nv-gpudmp"; } } const auto now = std::chrono::system_clock::now(); const std::string dumpPath = std::format("gpu_crash_dump-{:%Y%m%d-%H%M%S}{}", now, ext); std::ofstream file(dumpPath, std::ios::binary); if(file.write(vendorBinaryData.data(), vendorBinaryData.size())) { std::println("Vendor binary saved to: {}", std::filesystem::canonical(dumpPath).string()); } else { std::println(stderr, "Failed to write vendor binary to: {}", dumpPath); } } } throw std::runtime_error(string_VkResult(result)); } } VkBool32 onError(VkDebugUtilsMessageSeverityFlagBitsEXT severity, VkDebugUtilsMessageTypeFlagsEXT type, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData) { printf("Vulkan "); switch (type) { case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT : printf("general "); break; case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT : printf("validation "); break; case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT : printf("performance "); break; } switch (severity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT : printf("(verbose): "); break; default : case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT : printf("(info): "); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT : printf("(warning): "); break; case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT : printf("(error): "); break; } printf("%s\n", callbackData->pMessage); return 0; } #endif #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND constexpr CrafterKeys keysym_to_crafter_key(xkb_keysym_t sym) { switch (sym) { // Alphabet case XKB_KEY_a: return CrafterKeys::A; case XKB_KEY_b: return CrafterKeys::B; case XKB_KEY_c: return CrafterKeys::C; case XKB_KEY_d: return CrafterKeys::D; case XKB_KEY_e: return CrafterKeys::E; case XKB_KEY_f: return CrafterKeys::F; case XKB_KEY_g: return CrafterKeys::G; case XKB_KEY_h: return CrafterKeys::H; case XKB_KEY_i: return CrafterKeys::I; case XKB_KEY_j: return CrafterKeys::J; case XKB_KEY_k: return CrafterKeys::K; case XKB_KEY_l: return CrafterKeys::L; case XKB_KEY_m: return CrafterKeys::M; case XKB_KEY_n: return CrafterKeys::N; case XKB_KEY_o: return CrafterKeys::O; case XKB_KEY_p: return CrafterKeys::P; case XKB_KEY_q: return CrafterKeys::Q; case XKB_KEY_r: return CrafterKeys::R; case XKB_KEY_s: return CrafterKeys::S; case XKB_KEY_t: return CrafterKeys::T; case XKB_KEY_u: return CrafterKeys::U; case XKB_KEY_v: return CrafterKeys::V; case XKB_KEY_w: return CrafterKeys::W; case XKB_KEY_x: return CrafterKeys::X; case XKB_KEY_y: return CrafterKeys::Y; case XKB_KEY_z: return CrafterKeys::Z; // Numbers case XKB_KEY_0: return CrafterKeys::_0; case XKB_KEY_1: return CrafterKeys::_1; case XKB_KEY_2: return CrafterKeys::_2; case XKB_KEY_3: return CrafterKeys::_3; case XKB_KEY_4: return CrafterKeys::_4; case XKB_KEY_5: return CrafterKeys::_5; case XKB_KEY_6: return CrafterKeys::_6; case XKB_KEY_7: return CrafterKeys::_7; case XKB_KEY_8: return CrafterKeys::_8; case XKB_KEY_9: return CrafterKeys::_9; // Function keys case XKB_KEY_F1: return CrafterKeys::F1; case XKB_KEY_F2: return CrafterKeys::F2; case XKB_KEY_F3: return CrafterKeys::F3; case XKB_KEY_F4: return CrafterKeys::F4; case XKB_KEY_F5: return CrafterKeys::F5; case XKB_KEY_F6: return CrafterKeys::F6; case XKB_KEY_F7: return CrafterKeys::F7; case XKB_KEY_F8: return CrafterKeys::F8; case XKB_KEY_F9: return CrafterKeys::F9; case XKB_KEY_F10: return CrafterKeys::F10; case XKB_KEY_F11: return CrafterKeys::F11; case XKB_KEY_F12: return CrafterKeys::F12; // Control keys case XKB_KEY_Escape: return CrafterKeys::Escape; case XKB_KEY_Tab: return CrafterKeys::Tab; case XKB_KEY_Return: return CrafterKeys::Enter; case XKB_KEY_space: return CrafterKeys::Space; case XKB_KEY_BackSpace: return CrafterKeys::Backspace; case XKB_KEY_Delete: return CrafterKeys::Delete; case XKB_KEY_Insert: return CrafterKeys::Insert; case XKB_KEY_Home: return CrafterKeys::Home; case XKB_KEY_End: return CrafterKeys::End; case XKB_KEY_Page_Up: return CrafterKeys::PageUp; case XKB_KEY_Page_Down: return CrafterKeys::PageDown; case XKB_KEY_Caps_Lock: return CrafterKeys::CapsLock; case XKB_KEY_Num_Lock: return CrafterKeys::NumLock; case XKB_KEY_Scroll_Lock:return CrafterKeys::ScrollLock; // Modifiers case XKB_KEY_Shift_L: return CrafterKeys::LeftShift; case XKB_KEY_Shift_R: return CrafterKeys::RightShift; case XKB_KEY_Control_L: return CrafterKeys::LeftCtrl; case XKB_KEY_Control_R: return CrafterKeys::RightCtrl; case XKB_KEY_Alt_L: return CrafterKeys::LeftAlt; case XKB_KEY_Alt_R: return CrafterKeys::RightAlt; case XKB_KEY_Super_L: return CrafterKeys::LeftSuper; case XKB_KEY_Super_R: return CrafterKeys::RightSuper; // Arrows case XKB_KEY_Up: return CrafterKeys::Up; case XKB_KEY_Down: return CrafterKeys::Down; case XKB_KEY_Left: return CrafterKeys::Left; case XKB_KEY_Right: return CrafterKeys::Right; // Keypad case XKB_KEY_KP_0: return CrafterKeys::keypad_0; case XKB_KEY_KP_1: return CrafterKeys::keypad_1; case XKB_KEY_KP_2: return CrafterKeys::keypad_2; case XKB_KEY_KP_3: return CrafterKeys::keypad_3; case XKB_KEY_KP_4: return CrafterKeys::keypad_4; case XKB_KEY_KP_5: return CrafterKeys::keypad_5; case XKB_KEY_KP_6: return CrafterKeys::keypad_6; case XKB_KEY_KP_7: return CrafterKeys::keypad_7; case XKB_KEY_KP_8: return CrafterKeys::keypad_8; case XKB_KEY_KP_9: return CrafterKeys::keypad_9; case XKB_KEY_KP_Enter: return CrafterKeys::keypad_enter; case XKB_KEY_KP_Add: return CrafterKeys::keypad_plus; case XKB_KEY_KP_Subtract: return CrafterKeys::keypad_minus; case XKB_KEY_KP_Multiply: return CrafterKeys::keypad_multiply; case XKB_KEY_KP_Divide: return CrafterKeys::keypad_divide; case XKB_KEY_KP_Decimal: return CrafterKeys::keypad_decimal; // Punctuation case XKB_KEY_grave: return CrafterKeys::grave; case XKB_KEY_minus: return CrafterKeys::minus; case XKB_KEY_equal: return CrafterKeys::equal; case XKB_KEY_bracketleft: return CrafterKeys::bracket_left; case XKB_KEY_bracketright:return CrafterKeys::bracket_right; case XKB_KEY_backslash: return CrafterKeys::backslash; case XKB_KEY_semicolon: return CrafterKeys::semicolon; case XKB_KEY_apostrophe: return CrafterKeys::quote; case XKB_KEY_comma: return CrafterKeys::comma; case XKB_KEY_period: return CrafterKeys::period; case XKB_KEY_slash: return CrafterKeys::slash; default: throw std::runtime_error(std::format("Unkown XKB_KEY: {}", sym)); } } void Device::xdg_wm_base_handle_ping(void* data, xdg_wm_base* xdg_wm_base, std::uint32_t serial) { xdg_wm_base_pong(xdg_wm_base, serial); } void Device::handle_global(void *data, wl_registry *registry, std::uint32_t name, const char *interface, std::uint32_t version) { if (strcmp(interface, wl_shm_interface.name) == 0) { shm = reinterpret_cast(wl_registry_bind(registry, name, &wl_shm_interface, 1)); } else if (strcmp(interface, wl_seat_interface.name) == 0) { wl_seat* seat = reinterpret_cast(wl_registry_bind(registry, name, &wl_seat_interface, 1)); wl_seat_add_listener(seat, &seat_listener, nullptr); } else if (compositor == nullptr && strcmp(interface, wl_compositor_interface.name) == 0) { compositor = reinterpret_cast(wl_registry_bind(registry, name, &wl_compositor_interface, 3)); } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { xdgWmBase = reinterpret_cast(wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)); xdg_wm_base_add_listener(xdgWmBase, &xdgWmBaseListener, nullptr); } else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0) { manager = reinterpret_cast(wl_registry_bind(registry, name, &zxdg_decoration_manager_v1_interface, 1)); } else if (strcmp(interface, wp_viewporter_interface.name) == 0) { wpViewporter = reinterpret_cast(wl_registry_bind(registry, name, &wp_viewporter_interface, 1)); } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == 0) { fractionalScaleManager = reinterpret_cast(wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1)); } } void Device::handle_global_remove(void* data, wl_registry* registry, uint32_t name) { } void Device::pointer_handle_button(void* data, wl_pointer* pointer, std::uint32_t serial, std::uint32_t time, std::uint32_t button, std::uint32_t state) { if (button == BTN_LEFT) { if(state == WL_POINTER_BUTTON_STATE_PRESSED) { Device::focusedWindow->mouseLeftHeld = true; Device::focusedWindow->onMouseLeftClick.Invoke(); for(MouseElement* element : Device::focusedWindow->mouseElements) { if(element) { if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) { element->onMouseLeftClick.Invoke(); } } } } else { Device::focusedWindow->mouseLeftHeld = false; Device::focusedWindow->onMouseLeftRelease.Invoke(); for(MouseElement* element : Device::focusedWindow->mouseElements) { if(element) { if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) { element->onMouseLeftRelease.Invoke(); } } } } } else if(button == BTN_RIGHT){ if(state == WL_POINTER_BUTTON_STATE_PRESSED) { Device::focusedWindow->mouseRightHeld = true; Device::focusedWindow->onMouseRightClick.Invoke(); for(MouseElement* element : Device::focusedWindow->mouseElements) { if(element) { if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) { element->onMouseRightClick.Invoke(); } } } } else { Device::focusedWindow->mouseRightHeld = false; Device::focusedWindow->onMouseRightRelease.Invoke(); for(MouseElement* element : Device::focusedWindow->mouseElements) { if(element) { if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) { element->onMouseRightRelease.Invoke(); } } } } } Device::focusedWindow->mouseElements.erase(std::remove(Device::focusedWindow->mouseElements.begin(), Device::focusedWindow->mouseElements.end(), static_cast(nullptr)), Device::focusedWindow->mouseElements.end()); Device::focusedWindow->mouseElements.insert(Device::focusedWindow->mouseElements.end(), Device::focusedWindow->pendingMouseElements.begin(), Device::focusedWindow->pendingMouseElements.end()); Device::focusedWindow->pendingMouseElements.clear(); } void Device::PointerListenerHandleMotion(void* data, wl_pointer* wl_pointer, std::uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) { Vector pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y)); //Device::focusedWindow->lastMousePos = Device::focusedWindow->currentMousePos; Device::focusedWindow->currentMousePos = pos * Device::focusedWindow->scale; //Device::focusedWindow->mouseDelta = {Device::focusedWindow->currentMousePos.x-Device::focusedWindow->lastMousePos.x, Device::focusedWindow->currentMousePos.y-Device::focusedWindow->lastMousePos.y}; Device::focusedWindow->onMouseMove.Invoke(); for(MouseElement* element : Device::focusedWindow->mouseElements) { if(element) { if(Device::focusedWindow->currentMousePos.x >= element->scaled.position.x && Device::focusedWindow->currentMousePos.x <= element->scaled.position.x+element->scaled.size.x && Device::focusedWindow->currentMousePos.y > element->scaled.position.y && Device::focusedWindow->currentMousePos.y < element->scaled.position.y+element->scaled.size.y) { element->onMouseMove.Invoke(); if(!element->mouseHover) { element->mouseHover = true; element->onMouseEnter.Invoke(); } } else if(element->mouseHover) { element->mouseHover = false; element->onMouseLeave.Invoke(); } } } Device::focusedWindow->mouseElements.erase(std::remove(Device::focusedWindow->mouseElements.begin(), Device::focusedWindow->mouseElements.end(), static_cast(nullptr)), Device::focusedWindow->mouseElements.end()); } void Device::PointerListenerHandleEnter(void* data, wl_pointer* wl_pointer, std::uint32_t serial, wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { Device::wlPointer = wl_pointer; for(Window* window : windows) { if(window->surface == surface) { if(window->cursorSurface != nullptr) { wl_pointer_set_cursor(wl_pointer, serial, window->cursorSurface, 0, 0); } focusedWindow = window; window->onMouseEnter.Invoke(); return; } } } void Device::PointerListenerHandleLeave(void* data, wl_pointer*, std::uint32_t, wl_surface*) { Device::focusedWindow->onMouseLeave.Invoke(); focusedWindow = nullptr; } void Device::PointerListenerHandleAxis(void*, wl_pointer*, std::uint32_t, std::uint32_t, wl_fixed_t value) { } void Device::keyboard_keymap(void *data, wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size) { if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); fprintf(stderr, "Unsupported keymap format\n"); return; } void *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) { close(fd); perror("mmap"); return; } xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); xkb_keymap = xkb_keymap_new_from_string(xkb_context, (const char *)map, XKB_KEYMAP_FORMAT_TEXT_V1,XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map, size); close(fd); xkb_state = xkb_state_new(xkb_keymap); } void Device::keyboard_enter(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface, wl_array *keys) { } void Device::keyboard_leave(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface) { } void Device::keyboard_key(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { xkb_keycode_t keycode = key + 8; xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkb_state, keycode); CrafterKeys crafterKey = keysym_to_crafter_key(keysym); if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { if(Device::focusedWindow->heldkeys[static_cast(crafterKey)]) { Device::focusedWindow->onKeyHold[static_cast(crafterKey)].Invoke(); Device::focusedWindow->onAnyKeyHold.Invoke(crafterKey); } else{ Device::focusedWindow->heldkeys[static_cast(crafterKey)] = true; Device::focusedWindow->onKeyDown[static_cast(crafterKey)].Invoke(); Device::focusedWindow->onAnyKeyDown.Invoke(crafterKey); } } else{ Device::focusedWindow->heldkeys[static_cast(crafterKey)] = false; Device::focusedWindow->onKeyUp[static_cast(crafterKey)].Invoke(); Device::focusedWindow->onAnyKeyUp.Invoke(crafterKey); } } void Device::keyboard_modifiers(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { } void Device::keyboard_repeat_info(void *data, wl_keyboard *keyboard, int32_t rate, int32_t delay) { } void Device::seat_handle_capabilities(void* data, wl_seat* seat, uint32_t capabilities) { seat = seat; if (capabilities & WL_SEAT_CAPABILITY_POINTER) { wl_pointer* pointer = wl_seat_get_pointer(seat); wl_pointer_add_listener(pointer, &pointer_listener, nullptr); } if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { wl_keyboard* keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr); } } #endif void Device::Initialize() { #ifdef CRAFTER_GRAPHICS_WINDOW_WAYLAND display = wl_display_connect(NULL); if (display == nullptr) { throw std::runtime_error("Could not connect to wayland display"); } wl_registry* registry = wl_display_get_registry(display); wl_registry_add_listener(registry, ®istry_listener, nullptr); if (wl_display_roundtrip(display) == -1) { exit(EXIT_FAILURE); } if (shm == NULL || compositor == NULL || xdgWmBase == NULL) { throw std::runtime_error("No wl_shm, wl_compositor or xdg_wm_base support"); } #endif #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN VkApplicationInfo app{VK_STRUCTURE_TYPE_APPLICATION_INFO}; app.pApplicationName = ""; app.pEngineName = "Crafter.Graphics"; app.apiVersion = VK_MAKE_VERSION(1, 4, 0); VkValidationFeatureEnableEXT enables[] = { VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT }; VkValidationFeaturesEXT validationFeatures = { .sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT, .enabledValidationFeatureCount = 1, .pEnabledValidationFeatures = enables }; VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pNext = &validationFeatures; instanceCreateInfo.pApplicationInfo = &app; instanceCreateInfo.enabledExtensionCount = sizeof(instanceExtensionNames) / sizeof(const char*); instanceCreateInfo.ppEnabledExtensionNames = instanceExtensionNames; size_t foundInstanceLayers = 0; std::uint32_t instanceLayerCount; CheckVkResult(vkEnumerateInstanceLayerProperties(&instanceLayerCount, NULL)); std::vector instanceLayerProperties(instanceLayerCount); CheckVkResult(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProperties.data())); for (uint32_t i = 0; i < instanceLayerCount; i++) { for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) { if (std::strcmp(instanceLayerProperties[i].layerName, layerNames[j]) == 0) { foundInstanceLayers++; } } } if (foundInstanceLayers >= sizeof(layerNames) / sizeof(const char*)) { instanceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); instanceCreateInfo.ppEnabledLayerNames = layerNames; } CheckVkResult(vkCreateInstance(&instanceCreateInfo, NULL, &instance)); VkDebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfo = {}; debugUtilsMessengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; debugUtilsMessengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; debugUtilsMessengerCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; debugUtilsMessengerCreateInfo.pfnUserCallback = onError; CheckVkResult(GET_EXTENSION_FUNCTION(vkCreateDebugUtilsMessengerEXT)(instance, &debugUtilsMessengerCreateInfo, NULL, &debugMessenger)); uint32_t physDeviceCount; vkEnumeratePhysicalDevices(instance, &physDeviceCount, NULL); std::vector physDevices(physDeviceCount); vkEnumeratePhysicalDevices(instance, &physDeviceCount, physDevices.data()); uint32_t bestScore = 0; for (uint32_t i = 0; i < physDeviceCount; i++) { VkPhysicalDevice device = physDevices[i]; uint32_t score; VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); switch (properties.deviceType) { default : continue; case VK_PHYSICAL_DEVICE_TYPE_OTHER : score = 1; break; case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : score = 4; break; case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU : score = 5; break; case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU : score = 3; break; case VK_PHYSICAL_DEVICE_TYPE_CPU : score = 2; break; } if (score > bestScore) { physDevice = device; bestScore = score; } } VkPhysicalDeviceProperties2 properties2 { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, .pNext = &rayTracingProperties }; vkGetPhysicalDeviceProperties2(physDevice, &properties2); uint32_t queueFamilyCount; vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, NULL); std::vector queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(physDevice, &queueFamilyCount, queueFamilies.data()); for (uint32_t i = 0; i < queueFamilyCount; i++) { if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queueFamilyIndex = i; break; } } float priority = 1; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &priority; VkPhysicalDeviceFaultFeaturesEXT faultFeatures2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT, }; VkPhysicalDeviceFeatures2 features22 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .pNext = &faultFeatures2, }; vkGetPhysicalDeviceFeatures2(physDevice, &features22); VkPhysicalDeviceFaultFeaturesEXT faultFeatures = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT, .deviceFault = VK_TRUE, .deviceFaultVendorBinary = faultFeatures2.deviceFaultVendorBinary, }; VkPhysicalDeviceShaderUntypedPointersFeaturesKHR untypedPointersFeatures { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_UNTYPED_POINTERS_FEATURES_KHR, .pNext = &faultFeatures, .shaderUntypedPointers = VK_TRUE, }; VkPhysicalDeviceDescriptorHeapFeaturesEXT desciptorHeapFeatures { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_FEATURES_EXT, .pNext = &untypedPointersFeatures, .descriptorHeap = VK_TRUE, }; VkPhysicalDevice16BitStorageFeatures bit16 { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, .pNext = &desciptorHeapFeatures, .storageBuffer16BitAccess = VK_TRUE, }; VkPhysicalDeviceVulkan12Features features12 { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .pNext = &bit16, .shaderFloat16 = VK_TRUE, .runtimeDescriptorArray = VK_TRUE, .bufferDeviceAddress = VK_TRUE }; VkPhysicalDeviceRayTracingPipelineFeaturesKHR physicalDeviceRayTracingPipelineFeatures{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR, .pNext = &features12, .rayTracingPipeline = VK_TRUE }; VkPhysicalDeviceAccelerationStructureFeaturesKHR deviceAccelerationStructureFeature = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR, .pNext = &physicalDeviceRayTracingPipelineFeatures, .accelerationStructure = VK_TRUE }; VkPhysicalDeviceFeatures2 physical_features2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .pNext = &deviceAccelerationStructureFeature, .features = { .samplerAnisotropy = VK_TRUE, .shaderInt16 = VK_TRUE } }; VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = 1; deviceCreateInfo.pQueueCreateInfos = &queueCreateInfo; deviceCreateInfo.enabledExtensionCount = sizeof(deviceExtensionNames) / sizeof(const char*); deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; deviceCreateInfo.pNext = &physical_features2; uint32_t deviceLayerCount; CheckVkResult(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, NULL)); std::vector deviceLayerProperties(deviceLayerCount); CheckVkResult(vkEnumerateDeviceLayerProperties(physDevice, &deviceLayerCount, deviceLayerProperties.data())); size_t foundDeviceLayers = 0; for (uint32_t i = 0; i < deviceLayerCount; i++) { for (size_t j = 0; j < sizeof(layerNames) / sizeof(const char*); j++) { if (std::strcmp(deviceLayerProperties[i].layerName, layerNames[j]) == 0) { foundDeviceLayers++; } } } if (foundDeviceLayers >= sizeof(layerNames) / sizeof(const char*)) { deviceCreateInfo.enabledLayerCount = sizeof(layerNames) / sizeof(const char*); deviceCreateInfo.ppEnabledLayerNames = layerNames; } CheckVkResult(vkCreateDevice(physDevice, &deviceCreateInfo, NULL, &device)); vkGetDeviceQueue(device, queueFamilyIndex, 0, &queue); VkCommandPoolCreateInfo commandPoolcreateInfo = {}; commandPoolcreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; commandPoolcreateInfo.queueFamilyIndex = queueFamilyIndex; commandPoolcreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; CheckVkResult(vkCreateCommandPool(device, &commandPoolcreateInfo, NULL, &commandPool)); vkGetPhysicalDeviceMemoryProperties(physDevice, &memoryProperties); vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetAccelerationStructureBuildSizesKHR")); vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateAccelerationStructureKHR")); vkCmdBuildAccelerationStructuresKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructuresKHR")); vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetAccelerationStructureDeviceAddressKHR")); vkCreateRayTracingPipelinesKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateRayTracingPipelinesKHR")); vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetRayTracingShaderGroupHandlesKHR")); vkCmdTraceRaysKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdTraceRaysKHR")); vkCmdBindResourceHeapEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBindResourceHeapEXT")); vkCmdBindSamplerHeapEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBindSamplerHeapEXT")); vkWriteResourceDescriptorsEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkWriteResourceDescriptorsEXT")); vkGetPhysicalDeviceDescriptorSizeEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceDescriptorSizeEXT")); vkGetDeviceFaultInfoEXT = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetDeviceFaultInfoEXT")); #endif } #ifdef CRAFTER_GRAPHICS_RENDERER_VULKAN std::uint32_t Device::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties) { for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { if ((typeBits & 1) == 1) { if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties) { return i; } } typeBits >>= 1; } throw std::runtime_error("Could not find a matching memory type"); } #endif