From e55808b32f2b2eb0fc6ea42d425858ea6060f097 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 1 Jun 2022 14:41:35 +0200 Subject: [PATCH 1/9] next try, this time with vk headers and hpp --- .gitmodules | 4 + external/CMakeLists.txt | 2 + external/Vulkan-Headers | 1 + framework/sdl_service/CMakeLists.txt | 2 + framework/sdl_service/test/CMakeLists.txt | 5 +- framework/sdl_service/test/vulkan_test.cpp | 282 +++++++++++++++++++++ 6 files changed, 295 insertions(+), 1 deletion(-) create mode 160000 external/Vulkan-Headers create mode 100644 framework/sdl_service/test/vulkan_test.cpp diff --git a/.gitmodules b/.gitmodules index f476259..9957619 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,7 @@ path = external/physfs/physfs url = https://github.com/icculus/physfs.git branch = main +[submodule "external/Vulkan-Headers"] + path = external/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git + shallow = true diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index aa4c6e9..7df034a 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -38,6 +38,8 @@ if(NOT MM_HEADLESS) add_subdirectory("glad-debug") endif() + add_subdirectory("Vulkan-Headers") + # stb utilies add_subdirectory("stb") diff --git a/external/Vulkan-Headers b/external/Vulkan-Headers new file mode 160000 index 0000000..245d25c --- /dev/null +++ b/external/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit 245d25ce8c3337919dc7916d0e62e31a0d8748ab diff --git a/framework/sdl_service/CMakeLists.txt b/framework/sdl_service/CMakeLists.txt index 4ca7020..f383f5b 100644 --- a/framework/sdl_service/CMakeLists.txt +++ b/framework/sdl_service/CMakeLists.txt @@ -40,6 +40,8 @@ else() target_link_libraries(sdl_service glad) endif() +target_link_libraries(sdl_service Vulkan::Headers) + if(VCPKG_TARGET_TRIPLET) target_link_libraries(sdl_service SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static) endif() diff --git a/framework/sdl_service/test/CMakeLists.txt b/framework/sdl_service/test/CMakeLists.txt index d3f6046..a6fe4a4 100644 --- a/framework/sdl_service/test/CMakeLists.txt +++ b/framework/sdl_service/test/CMakeLists.txt @@ -1,4 +1,7 @@ -add_executable(sdl_service_test start_test.cpp) +add_executable(sdl_service_test + ./start_test.cpp + ./vulkan_test.cpp +) target_include_directories(sdl_service_test PRIVATE ".") diff --git a/framework/sdl_service/test/vulkan_test.cpp b/framework/sdl_service/test/vulkan_test.cpp new file mode 100644 index 0000000..0db9b91 --- /dev/null +++ b/framework/sdl_service/test/vulkan_test.cpp @@ -0,0 +1,282 @@ +#include + +#include +#include +#include + +#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 +#include + +#include // mf +#include + +#include + +#include + +VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE + +void setup_dispacher(void) { + // TODO: investigate why + // TODO: use SDL? + vk::DynamicLoader dl; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); + VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); +} + +void setup_instance_dispatcher(const vk::Instance& instance) { + // initialize function pointers for instance + VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); +} + +bool can_use_layer(std::string_view layer_want) { + for (const auto& layer : vk::enumerateInstanceLayerProperties()) { + if (static_cast(layer.layerName) == layer_want) { + return true; + } + } + + return false; +} + +bool can_use_validation(void) { + return can_use_layer("VK_LAYER_KHRONOS_validation"); +} + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* /*pUserData*/ +) { + spdlog::level::level_enum level{}; + switch (messageSeverity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + level = spdlog::level::level_enum::debug; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + level = spdlog::level::level_enum::info; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + level = spdlog::level::level_enum::warn; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + level = spdlog::level::level_enum::err; + break; + default: + level = spdlog::level::level_enum::critical; // what ever + } + + switch (messageType) { + case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: + spdlog::get("VulkanGeneral")->log(level, "{}", pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: + spdlog::get("VulkanValidation")->log(level, "{}", pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: + spdlog::get("VulkanPerformance")->log(level, "{}", pCallbackData->pMessage); + break; + } + + return VK_FALSE; +} + +static const vk::DebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info{ + {}, + vk::DebugUtilsMessageSeverityFlagBitsEXT::eError + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose, + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral + | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation + | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, + debug_callback +}; + +vk::Instance create_instance( + const vk::ApplicationInfo& app_info, + std::vector extensions = {}, + std::vector layers = {} +) { + // for debugging + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + // Get the required extension count + unsigned int count; + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) { + return nullptr; + } + + size_t additional_extension_count = extensions.size(); + extensions.resize(additional_extension_count + count); + + // fill sdl extensions + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) { + return nullptr; + } + + // Now we can make the Vulkan instance + vk::StructureChain c{ + vk::InstanceCreateInfo{ + {}, + &app_info, + static_cast(layers.size()), + layers.data(), + static_cast(extensions.size()), + extensions.data() + }, + debug_utils_messenger_create_info + }; + + vk::Instance instance = vk::createInstance(c.get(), nullptr); + + setup_instance_dispatcher(instance); + + return instance; +} + +void setup_device_dispatcher(const vk::Device& device) { + // function pointer specialization for device + VULKAN_HPP_DEFAULT_DISPATCHER.init(device); +} + + +TEST(sdl_service, window_vulkan) { + MM::Engine engine; + { // setup vulkan loggers +#if 0 + MM::Logger::initSectionLogger("VulkanGeneral"); + // way too noisy otherwise + spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn); +#else + // or just dont log to stdio? + MM::Logger::initSectionLogger("VulkanGeneral", false); +#endif + MM::Logger::initSectionLogger("VulkanValidation"); + MM::Logger::initSectionLogger("VulkanPerformance"); + } + + engine.addService(); + ASSERT_TRUE(engine.enableService()); + + auto* sdl_ss_ptr = engine.tryService(); + ASSERT_NE(sdl_ss_ptr, nullptr); + + setup_dispacher(); + + // create window + ASSERT_EQ(sdl_ss_ptr->win, nullptr); + ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN)); + ASSERT_NE(sdl_ss_ptr->win, nullptr); + + // create vulkan instance + + const vk::ApplicationInfo app_info { + "app_name", + VK_MAKE_VERSION(1, 0, 0), // app version + "MushMachine", + // TODO: engine version macro or something + VK_MAKE_VERSION(0, 8, 0), // engine version + VK_API_VERSION_1_1 + }; + + // TODO: make validation layer conditional + std::vector layers{}; + if (can_use_validation()) { + layers.push_back("VK_LAYER_KHRONOS_validation"); + SPDLOG_INFO("ENABLED validation layer"); + } else { + SPDLOG_INFO("validation layer NOT AVAILABLE!"); + } + + vk::Instance instance = create_instance( + app_info, + {}, + layers + ); + ASSERT_NE(static_cast(instance), nullptr); + + auto debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info); + + // the surface for the window (no device dependent?) + VkSurfaceKHR surface; + ASSERT_TRUE( + SDL_Vulkan_CreateSurface( + sdl_ss_ptr->win, + instance, + &surface + ) + ); + + // create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr + auto physicalDevices = instance.enumeratePhysicalDevices(); + ASSERT_TRUE(!physicalDevices.empty()); // make test fail on unsupported machines + + // list devices + for (const auto& ph_device : physicalDevices) { + auto props = ph_device.getProperties(); + SPDLOG_INFO( + "found device: [{}] ({}) '{}'", + props.deviceID, + (props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"), + props.deviceName + ); + } + + auto& selected_phys_dev = physicalDevices.front(); + for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) { + auto test_bit = [](const auto& flags, const auto& bit) -> bool { + return (flags & bit) == bit; + }; + SPDLOG_INFO( + "QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}", + fam_props.queueCount, + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false" + ); + } + + const float queue_prio = 1.f; // hmmmm + vk::DeviceQueueCreateInfo graphics_queue_create_info { + {}, + 0, // just pick the first one for now + 1, // count + &queue_prio + }; + + vk::PhysicalDeviceFeatures device_features { + }; + + vk::DeviceCreateInfo device_create_info { + {}, + 1, + &graphics_queue_create_info, + // layers + 0, + nullptr, + // extensions + 0, + nullptr, + &device_features + }; + vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr); + ASSERT_NE(static_cast(device), nullptr); + + setup_device_dispatcher(device); + + vk::Queue graphics_queue = device.getQueue(0, 0); + + // cleanup + device.destroy(); + + instance.destroy(surface); + instance.destroy(debug_messenger); + instance.destroy(); + + engine.disableService(); + + ASSERT_EQ(sdl_ss_ptr->win, nullptr); +} + From 808822e70b5768bf13aa3335a21ddbcb49c20e32 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 1 Jun 2022 23:56:02 +0200 Subject: [PATCH 2/9] start refactoring --- external/CMakeLists.txt | 1 + framework/sdl_service/test/vulkan_test.cpp | 385 ++++++++++++++------- 2 files changed, 258 insertions(+), 128 deletions(-) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 7df034a..6b9f60a 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -39,6 +39,7 @@ if(NOT MM_HEADLESS) endif() add_subdirectory("Vulkan-Headers") + target_compile_definitions(Vulkan-Headers INTERFACE VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1) # stb utilies add_subdirectory("stb") diff --git a/framework/sdl_service/test/vulkan_test.cpp b/framework/sdl_service/test/vulkan_test.cpp index 0db9b91..44ee063 100644 --- a/framework/sdl_service/test/vulkan_test.cpp +++ b/framework/sdl_service/test/vulkan_test.cpp @@ -4,11 +4,13 @@ #include #include -#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #include #include // mf #include +#include "spdlog/spdlog.h" +#include "vulkan/vulkan_core.h" +#include "vulkan/vulkan_handles.hpp" #include @@ -16,17 +18,19 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE +// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr void setup_dispacher(void) { - // TODO: investigate why - // TODO: use SDL? - vk::DynamicLoader dl; +#if 1 + // investigate why this stopped working + static vk::DynamicLoader dl; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); - VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); -} +#else + auto load_res = SDL_Vulkan_LoadLibrary(nullptr); + assert(load_res == 0); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); +#endif -void setup_instance_dispatcher(const vk::Instance& instance) { - // initialize function pointers for instance - VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); + VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); } bool can_use_layer(std::string_view layer_want) { @@ -131,150 +135,275 @@ vk::Instance create_instance( vk::Instance instance = vk::createInstance(c.get(), nullptr); - setup_instance_dispatcher(instance); + // initialize function pointers for instance + VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); return instance; } -void setup_device_dispatcher(const vk::Device& device) { - // function pointer specialization for device - VULKAN_HPP_DEFAULT_DISPATCHER.init(device); -} +namespace MM::Services { +class VulkanRenderer : public Service { + private: + VkInstance _instance{}; + VkDebugUtilsMessengerEXT _debug_messenger{}; -TEST(sdl_service, window_vulkan) { - MM::Engine engine; - { // setup vulkan loggers + VkSurfaceKHR _surface{}; + + VkPhysicalDevice _physical_device{}; + VkDevice _device{}; + + VkQueue _graphics_queue{}; + //VkQueue _present_queue{}; + VkSwapchainKHR _swapchain{}; + + public: + VulkanRenderer(void) { #if 0 - MM::Logger::initSectionLogger("VulkanGeneral"); - // way too noisy otherwise - spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn); + MM::Logger::initSectionLogger("VulkanGeneral"); + // way too noisy otherwise + spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn); #else - // or just dont log to stdio? - MM::Logger::initSectionLogger("VulkanGeneral", false); + // or just dont log to stdio? + MM::Logger::initSectionLogger("VulkanGeneral", false); #endif - MM::Logger::initSectionLogger("VulkanValidation"); - MM::Logger::initSectionLogger("VulkanPerformance"); - } + MM::Logger::initSectionLogger("VulkanValidation"); + MM::Logger::initSectionLogger("VulkanPerformance"); - engine.addService(); - ASSERT_TRUE(engine.enableService()); - - auto* sdl_ss_ptr = engine.tryService(); - ASSERT_NE(sdl_ss_ptr, nullptr); + SPDLOG_INFO("constructed VulkanRenderer"); + } + ~VulkanRenderer(void) {}; + + bool enable(Engine& engine, std::vector& task_array) override { + assert(!VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); + setup_dispacher(); + assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); + + // create vulkan instance + const vk::ApplicationInfo app_info { + "app_name", + VK_MAKE_VERSION(1, 0, 0), // app version + "MushMachine", + // TODO: engine version macro or something + VK_MAKE_VERSION(0, 8, 0), // engine version + VK_API_VERSION_1_1 + }; + + // TODO: make validation layer conditional + std::vector layers{}; + if (can_use_validation()) { + layers.push_back("VK_LAYER_KHRONOS_validation"); + SPDLOG_INFO("ENABLED validation layer"); + } else { + SPDLOG_INFO("validation layer NOT AVAILABLE!"); + } + + vk::Instance instance = create_instance( + app_info, + {}, + layers + ); + _instance = instance; + + _debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info); - setup_dispacher(); + return true; + } - // create window - ASSERT_EQ(sdl_ss_ptr->win, nullptr); - ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN)); - ASSERT_NE(sdl_ss_ptr->win, nullptr); + void disable(Engine&) override { + // cleanup + if (_device) { + vk::Device device{_device}; + device.destroy(_swapchain); + device.destroy(); + } + + vk::Instance instance{_instance}; + instance.destroy(_surface); + instance.destroy(_debug_messenger); + instance.destroy(); + } - // create vulkan instance + const char* name(void) override { return "VulkanRenderer"; } + + public: + bool createDevice(Engine& engine) { + // the surface for the window (not device dependent) + if (SDL_Vulkan_CreateSurface(engine.getService().win, _instance, &_surface) != SDL_TRUE) { + SPDLOG_ERROR("creating vulkan surface from window. (is the SDL_WINDOW_VULKAN flag set?)"); + return false; + } + + // convenience hpp wrapper + assert(_surface); + vk::SurfaceKHR surface{_surface}; + assert(_instance); + vk::Instance instance{_instance}; + + auto physical_devices = instance.enumeratePhysicalDevices(); + if (physical_devices.empty()) { + SPDLOG_ERROR("no physical vulkan devices found"); + return false; + } + + // list devices + for (const auto& ph_device : physical_devices) { + auto props = ph_device.getProperties(); + SPDLOG_INFO( + "found device: [{}] ({}) '{}'", + props.deviceID, + (props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"), + props.deviceName + ); + } + + auto& selected_phys_dev = physical_devices.front(); + _physical_device = selected_phys_dev; + + for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) { + auto test_bit = [](const auto& flags, const auto& bit) -> bool { + return (flags & bit) == bit; + }; + SPDLOG_INFO( + "QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}", + fam_props.queueCount, + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false" + ); + } + + uint32_t queue_fam_index = 0; + + // test for support for swapchain + if (selected_phys_dev.getSurfaceSupportKHR(queue_fam_index, surface) != VK_TRUE) { + SPDLOG_ERROR("selected device does not support the surface"); + return false; + } + + const float queue_prio = 1.f; // hmmmm + vk::DeviceQueueCreateInfo graphics_queue_create_info { + {}, + queue_fam_index, // just pick the first one for now + 1, // count + &queue_prio + }; + + vk::PhysicalDeviceFeatures device_features { + }; + + // do i need this? + std::vector device_extentions{ + VK_KHR_SWAPCHAIN_EXTENSION_NAME + }; + + vk::DeviceCreateInfo device_create_info { + {}, + 1, + &graphics_queue_create_info, + // layers + 0, + nullptr, + // extensions + static_cast(device_extentions.size()), + device_extentions.data(), + &device_features + }; + vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr); + _device = device; + + // function pointer specialization for device + VULKAN_HPP_DEFAULT_DISPATCHER.init(device); + + //_present_queue = device.getQueue(0, 0); + // we assume it also does present + _graphics_queue = device.getQueue(0, 0); - const vk::ApplicationInfo app_info { - "app_name", - VK_MAKE_VERSION(1, 0, 0), // app version - "MushMachine", - // TODO: engine version macro or something - VK_MAKE_VERSION(0, 8, 0), // engine version - VK_API_VERSION_1_1 - }; + return true; + } - // TODO: make validation layer conditional - std::vector layers{}; - if (can_use_validation()) { - layers.push_back("VK_LAYER_KHRONOS_validation"); - SPDLOG_INFO("ENABLED validation layer"); - } else { - SPDLOG_INFO("validation layer NOT AVAILABLE!"); - } + bool createSwapchain(Engine& engine) { + assert(_physical_device); + vk::PhysicalDevice physical_device {_physical_device}; + assert(_device); + vk::Device device {_device}; + + vk::SurfaceFormatKHR swap_surf_format { + vk::Format::eB8G8R8A8Srgb, + vk::ColorSpaceKHR::eSrgbNonlinear, + }; + { // select format + //for (const auto& format : selected_phys_dev.getSurfaceFormatsKHR(surface)) { + //if (format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { + //if (format.format == vk::Format::eB8G8R8A8Srgb) { + + //} + //} + //} + } + + vk::Extent2D surface_extent {}; + { + int w, h; + SDL_Vulkan_GetDrawableSize(engine.getService().win, &w, &h); + surface_extent.width = w; + surface_extent.height = h; + } + + auto phys_surf_caps = physical_device.getSurfaceCapabilitiesKHR(_surface); + + // flush all loggers + spdlog::apply_all([](const auto& logger) { logger->flush(); }); + + assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkCreateSwapchainKHR); + + // create the swapchain + _swapchain = device.createSwapchainKHR({ + {}, + _surface, + phys_surf_caps.minImageCount, + swap_surf_format.format, + swap_surf_format.colorSpace, + surface_extent, + 1, // imageArrayLayers + vk::ImageUsageFlagBits::eColorAttachment, + vk::SharingMode::eExclusive, + // TODO: fill in rest + }); + + auto images = device.getSwapchainImagesKHR(_swapchain); + SPDLOG_INFO("have {} swapchain images", images.size()); - vk::Instance instance = create_instance( - app_info, - {}, - layers - ); - ASSERT_NE(static_cast(instance), nullptr); - - auto debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info); - - // the surface for the window (no device dependent?) - VkSurfaceKHR surface; - ASSERT_TRUE( - SDL_Vulkan_CreateSurface( - sdl_ss_ptr->win, - instance, - &surface - ) - ); - - // create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr - auto physicalDevices = instance.enumeratePhysicalDevices(); - ASSERT_TRUE(!physicalDevices.empty()); // make test fail on unsupported machines - - // list devices - for (const auto& ph_device : physicalDevices) { - auto props = ph_device.getProperties(); - SPDLOG_INFO( - "found device: [{}] ({}) '{}'", - props.deviceID, - (props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"), - props.deviceName - ); - } + return true; + } +}; - auto& selected_phys_dev = physicalDevices.front(); - for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) { - auto test_bit = [](const auto& flags, const auto& bit) -> bool { - return (flags & bit) == bit; - }; - SPDLOG_INFO( - "QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}", - fam_props.queueCount, - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false", - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false", - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false" - ); - } +} // MM::Services - const float queue_prio = 1.f; // hmmmm - vk::DeviceQueueCreateInfo graphics_queue_create_info { - {}, - 0, // just pick the first one for now - 1, // count - &queue_prio - }; +TEST(sdl_service, window_vulkan) { + MM::Engine engine; - vk::PhysicalDeviceFeatures device_features { - }; + engine.addService(); + ASSERT_TRUE(engine.enableService()); - vk::DeviceCreateInfo device_create_info { - {}, - 1, - &graphics_queue_create_info, - // layers - 0, - nullptr, - // extensions - 0, - nullptr, - &device_features - }; - vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr); - ASSERT_NE(static_cast(device), nullptr); + auto* sdl_ss_ptr = engine.tryService(); + ASSERT_NE(sdl_ss_ptr, nullptr); - setup_device_dispatcher(device); + // create window + ASSERT_EQ(sdl_ss_ptr->win, nullptr); + ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN)); + ASSERT_NE(sdl_ss_ptr->win, nullptr); - vk::Queue graphics_queue = device.getQueue(0, 0); + engine.addService(); + ASSERT_TRUE(engine.enableService()); - // cleanup - device.destroy(); + auto& vk_rend = engine.getService(); + ASSERT_TRUE(vk_rend.createDevice(engine)); + ASSERT_TRUE(vk_rend.createSwapchain(engine)); - instance.destroy(surface); - instance.destroy(debug_messenger); - instance.destroy(); + engine.run(); + engine.disableService(); engine.disableService(); ASSERT_EQ(sdl_ss_ptr->win, nullptr); From 695e2e5486634931d77ecec26467d961ac301a75 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Thu, 2 Jun 2022 00:14:32 +0200 Subject: [PATCH 3/9] views --- framework/sdl_service/test/vulkan_test.cpp | 35 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/framework/sdl_service/test/vulkan_test.cpp b/framework/sdl_service/test/vulkan_test.cpp index 44ee063..4af9e78 100644 --- a/framework/sdl_service/test/vulkan_test.cpp +++ b/framework/sdl_service/test/vulkan_test.cpp @@ -155,7 +155,10 @@ class VulkanRenderer : public Service { VkQueue _graphics_queue{}; //VkQueue _present_queue{}; + VkSwapchainKHR _swapchain{}; + std::vector _swapchain_images{}; + std::vector _swapchain_image_views{}; public: VulkanRenderer(void) { @@ -214,6 +217,10 @@ class VulkanRenderer : public Service { // cleanup if (_device) { vk::Device device{_device}; + + for (const auto& img_view : _swapchain_image_views) { + device.destroy(img_view); + } device.destroy(_swapchain); device.destroy(); } @@ -371,8 +378,32 @@ class VulkanRenderer : public Service { // TODO: fill in rest }); - auto images = device.getSwapchainImagesKHR(_swapchain); - SPDLOG_INFO("have {} swapchain images", images.size()); + { + _swapchain_images.clear(); + auto images = device.getSwapchainImagesKHR(_swapchain); + for (const auto& img : images) { + _swapchain_images.push_back(img); + } + } + SPDLOG_INFO("have {} swapchain images", _swapchain_images.size()); + + _swapchain_image_views.clear(); + for (const auto& img : _swapchain_images) { + _swapchain_image_views.push_back(device.createImageView({ + {}, + img, + vk::ImageViewType::e2D, + swap_surf_format.format, + {}, // comp mapping + { // subres + vk::ImageAspectFlagBits::eColor, + 0, + 1, + 0, + 1, + }, + })); + } return true; } From cab146ac450b0cac43ca89c8d839b45b4e185a9f Mon Sep 17 00:00:00 2001 From: Green Sky Date: Thu, 2 Jun 2022 12:41:29 +0200 Subject: [PATCH 4/9] hack in framebuffers --- framework/sdl_service/test/vulkan_test.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/framework/sdl_service/test/vulkan_test.cpp b/framework/sdl_service/test/vulkan_test.cpp index 4af9e78..6eed21f 100644 --- a/framework/sdl_service/test/vulkan_test.cpp +++ b/framework/sdl_service/test/vulkan_test.cpp @@ -159,6 +159,7 @@ class VulkanRenderer : public Service { VkSwapchainKHR _swapchain{}; std::vector _swapchain_images{}; std::vector _swapchain_image_views{}; + std::vector _swapchain_framebuffers{}; public: VulkanRenderer(void) { @@ -218,6 +219,9 @@ class VulkanRenderer : public Service { if (_device) { vk::Device device{_device}; + for (const auto& fb : _swapchain_framebuffers) { + device.destroy(fb); + } for (const auto& img_view : _swapchain_image_views) { device.destroy(img_view); } @@ -405,6 +409,22 @@ class VulkanRenderer : public Service { })); } + // TODO: move + + _swapchain_framebuffers.clear(); + for (const auto& img_view : _swapchain_image_views) { + vk::ImageView tmp_img_view = img_view; + _swapchain_framebuffers.push_back(device.createFramebuffer({ + {}, + {}, // rend + 1, + &tmp_img_view, + surface_extent.width, + surface_extent.height, + 1 + })); + } + return true; } }; From 525db7fe6bb4780d945c9209209b5d0dde66379c Mon Sep 17 00:00:00 2001 From: Green Sky Date: Thu, 2 Jun 2022 20:01:23 +0200 Subject: [PATCH 5/9] refactor, move vulkan to proper location --- framework/CMakeLists.txt | 1 + framework/sdl_service/CMakeLists.txt | 3 +- framework/sdl_service/test/CMakeLists.txt | 1 - framework/sdl_service/test/vulkan_test.cpp | 462 ------------------ framework/vulkan_renderer/CMakeLists.txt | 26 + .../src/mm/services/vulkan_renderer.cpp | 406 +++++++++++++++ .../src/mm/services/vulkan_renderer.hpp | 69 +++ framework/vulkan_renderer/test/CMakeLists.txt | 13 + .../vulkan_renderer/test/vulkan_test.cpp | 37 ++ 9 files changed, 554 insertions(+), 464 deletions(-) delete mode 100644 framework/sdl_service/test/vulkan_test.cpp create mode 100644 framework/vulkan_renderer/CMakeLists.txt create mode 100644 framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp create mode 100644 framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp create mode 100644 framework/vulkan_renderer/test/CMakeLists.txt create mode 100644 framework/vulkan_renderer/test/vulkan_test.cpp diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index 822919f..0ad0dcb 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -17,6 +17,7 @@ if(NOT MM_HEADLESS) add_subdirectory(simple_sdl_renderer) add_subdirectory(opengl_primitives) add_subdirectory(opengl_renderer) + add_subdirectory(vulkan_renderer) add_subdirectory(imgui) add_subdirectory(input) add_subdirectory(sound) diff --git a/framework/sdl_service/CMakeLists.txt b/framework/sdl_service/CMakeLists.txt index f383f5b..98b4b16 100644 --- a/framework/sdl_service/CMakeLists.txt +++ b/framework/sdl_service/CMakeLists.txt @@ -40,7 +40,8 @@ else() target_link_libraries(sdl_service glad) endif() -target_link_libraries(sdl_service Vulkan::Headers) +# nope +#target_link_libraries(sdl_service Vulkan::Headers) if(VCPKG_TARGET_TRIPLET) target_link_libraries(sdl_service SDL2::SDL2 SDL2::SDL2main SDL2::SDL2-static) diff --git a/framework/sdl_service/test/CMakeLists.txt b/framework/sdl_service/test/CMakeLists.txt index a6fe4a4..d01ccc6 100644 --- a/framework/sdl_service/test/CMakeLists.txt +++ b/framework/sdl_service/test/CMakeLists.txt @@ -1,6 +1,5 @@ add_executable(sdl_service_test ./start_test.cpp - ./vulkan_test.cpp ) target_include_directories(sdl_service_test PRIVATE ".") diff --git a/framework/sdl_service/test/vulkan_test.cpp b/framework/sdl_service/test/vulkan_test.cpp deleted file mode 100644 index 6eed21f..0000000 --- a/framework/sdl_service/test/vulkan_test.cpp +++ /dev/null @@ -1,462 +0,0 @@ -#include - -#include -#include -#include - -#include - -#include // mf -#include -#include "spdlog/spdlog.h" -#include "vulkan/vulkan_core.h" -#include "vulkan/vulkan_handles.hpp" - -#include - -#include - -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE - -// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr -void setup_dispacher(void) { -#if 1 - // investigate why this stopped working - static vk::DynamicLoader dl; - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); -#else - auto load_res = SDL_Vulkan_LoadLibrary(nullptr); - assert(load_res == 0); - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); -#endif - - VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); -} - -bool can_use_layer(std::string_view layer_want) { - for (const auto& layer : vk::enumerateInstanceLayerProperties()) { - if (static_cast(layer.layerName) == layer_want) { - return true; - } - } - - return false; -} - -bool can_use_validation(void) { - return can_use_layer("VK_LAYER_KHRONOS_validation"); -} - -VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( - VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, - void* /*pUserData*/ -) { - spdlog::level::level_enum level{}; - switch (messageSeverity) { - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: - level = spdlog::level::level_enum::debug; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: - level = spdlog::level::level_enum::info; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: - level = spdlog::level::level_enum::warn; - break; - case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: - level = spdlog::level::level_enum::err; - break; - default: - level = spdlog::level::level_enum::critical; // what ever - } - - switch (messageType) { - case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: - spdlog::get("VulkanGeneral")->log(level, "{}", pCallbackData->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: - spdlog::get("VulkanValidation")->log(level, "{}", pCallbackData->pMessage); - break; - case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: - spdlog::get("VulkanPerformance")->log(level, "{}", pCallbackData->pMessage); - break; - } - - return VK_FALSE; -} - -static const vk::DebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info{ - {}, - vk::DebugUtilsMessageSeverityFlagBitsEXT::eError - | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning - | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo - | vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose, - vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral - | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation - | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, - debug_callback -}; - -vk::Instance create_instance( - const vk::ApplicationInfo& app_info, - std::vector extensions = {}, - std::vector layers = {} -) { - // for debugging - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - - // Get the required extension count - unsigned int count; - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) { - return nullptr; - } - - size_t additional_extension_count = extensions.size(); - extensions.resize(additional_extension_count + count); - - // fill sdl extensions - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) { - return nullptr; - } - - // Now we can make the Vulkan instance - vk::StructureChain c{ - vk::InstanceCreateInfo{ - {}, - &app_info, - static_cast(layers.size()), - layers.data(), - static_cast(extensions.size()), - extensions.data() - }, - debug_utils_messenger_create_info - }; - - vk::Instance instance = vk::createInstance(c.get(), nullptr); - - // initialize function pointers for instance - VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); - - return instance; -} - -namespace MM::Services { - -class VulkanRenderer : public Service { - private: - VkInstance _instance{}; - VkDebugUtilsMessengerEXT _debug_messenger{}; - - VkSurfaceKHR _surface{}; - - VkPhysicalDevice _physical_device{}; - VkDevice _device{}; - - VkQueue _graphics_queue{}; - //VkQueue _present_queue{}; - - VkSwapchainKHR _swapchain{}; - std::vector _swapchain_images{}; - std::vector _swapchain_image_views{}; - std::vector _swapchain_framebuffers{}; - - public: - VulkanRenderer(void) { -#if 0 - MM::Logger::initSectionLogger("VulkanGeneral"); - // way too noisy otherwise - spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn); -#else - // or just dont log to stdio? - MM::Logger::initSectionLogger("VulkanGeneral", false); -#endif - MM::Logger::initSectionLogger("VulkanValidation"); - MM::Logger::initSectionLogger("VulkanPerformance"); - - SPDLOG_INFO("constructed VulkanRenderer"); - } - ~VulkanRenderer(void) {}; - - bool enable(Engine& engine, std::vector& task_array) override { - assert(!VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); - setup_dispacher(); - assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); - - // create vulkan instance - const vk::ApplicationInfo app_info { - "app_name", - VK_MAKE_VERSION(1, 0, 0), // app version - "MushMachine", - // TODO: engine version macro or something - VK_MAKE_VERSION(0, 8, 0), // engine version - VK_API_VERSION_1_1 - }; - - // TODO: make validation layer conditional - std::vector layers{}; - if (can_use_validation()) { - layers.push_back("VK_LAYER_KHRONOS_validation"); - SPDLOG_INFO("ENABLED validation layer"); - } else { - SPDLOG_INFO("validation layer NOT AVAILABLE!"); - } - - vk::Instance instance = create_instance( - app_info, - {}, - layers - ); - _instance = instance; - - _debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info); - - return true; - } - - void disable(Engine&) override { - // cleanup - if (_device) { - vk::Device device{_device}; - - for (const auto& fb : _swapchain_framebuffers) { - device.destroy(fb); - } - for (const auto& img_view : _swapchain_image_views) { - device.destroy(img_view); - } - device.destroy(_swapchain); - device.destroy(); - } - - vk::Instance instance{_instance}; - instance.destroy(_surface); - instance.destroy(_debug_messenger); - instance.destroy(); - } - - const char* name(void) override { return "VulkanRenderer"; } - - public: - bool createDevice(Engine& engine) { - // the surface for the window (not device dependent) - if (SDL_Vulkan_CreateSurface(engine.getService().win, _instance, &_surface) != SDL_TRUE) { - SPDLOG_ERROR("creating vulkan surface from window. (is the SDL_WINDOW_VULKAN flag set?)"); - return false; - } - - // convenience hpp wrapper - assert(_surface); - vk::SurfaceKHR surface{_surface}; - assert(_instance); - vk::Instance instance{_instance}; - - auto physical_devices = instance.enumeratePhysicalDevices(); - if (physical_devices.empty()) { - SPDLOG_ERROR("no physical vulkan devices found"); - return false; - } - - // list devices - for (const auto& ph_device : physical_devices) { - auto props = ph_device.getProperties(); - SPDLOG_INFO( - "found device: [{}] ({}) '{}'", - props.deviceID, - (props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"), - props.deviceName - ); - } - - auto& selected_phys_dev = physical_devices.front(); - _physical_device = selected_phys_dev; - - for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) { - auto test_bit = [](const auto& flags, const auto& bit) -> bool { - return (flags & bit) == bit; - }; - SPDLOG_INFO( - "QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}", - fam_props.queueCount, - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false", - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false", - test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false" - ); - } - - uint32_t queue_fam_index = 0; - - // test for support for swapchain - if (selected_phys_dev.getSurfaceSupportKHR(queue_fam_index, surface) != VK_TRUE) { - SPDLOG_ERROR("selected device does not support the surface"); - return false; - } - - const float queue_prio = 1.f; // hmmmm - vk::DeviceQueueCreateInfo graphics_queue_create_info { - {}, - queue_fam_index, // just pick the first one for now - 1, // count - &queue_prio - }; - - vk::PhysicalDeviceFeatures device_features { - }; - - // do i need this? - std::vector device_extentions{ - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - vk::DeviceCreateInfo device_create_info { - {}, - 1, - &graphics_queue_create_info, - // layers - 0, - nullptr, - // extensions - static_cast(device_extentions.size()), - device_extentions.data(), - &device_features - }; - vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr); - _device = device; - - // function pointer specialization for device - VULKAN_HPP_DEFAULT_DISPATCHER.init(device); - - //_present_queue = device.getQueue(0, 0); - // we assume it also does present - _graphics_queue = device.getQueue(0, 0); - - return true; - } - - bool createSwapchain(Engine& engine) { - assert(_physical_device); - vk::PhysicalDevice physical_device {_physical_device}; - assert(_device); - vk::Device device {_device}; - - vk::SurfaceFormatKHR swap_surf_format { - vk::Format::eB8G8R8A8Srgb, - vk::ColorSpaceKHR::eSrgbNonlinear, - }; - { // select format - //for (const auto& format : selected_phys_dev.getSurfaceFormatsKHR(surface)) { - //if (format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { - //if (format.format == vk::Format::eB8G8R8A8Srgb) { - - //} - //} - //} - } - - vk::Extent2D surface_extent {}; - { - int w, h; - SDL_Vulkan_GetDrawableSize(engine.getService().win, &w, &h); - surface_extent.width = w; - surface_extent.height = h; - } - - auto phys_surf_caps = physical_device.getSurfaceCapabilitiesKHR(_surface); - - // flush all loggers - spdlog::apply_all([](const auto& logger) { logger->flush(); }); - - assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkCreateSwapchainKHR); - - // create the swapchain - _swapchain = device.createSwapchainKHR({ - {}, - _surface, - phys_surf_caps.minImageCount, - swap_surf_format.format, - swap_surf_format.colorSpace, - surface_extent, - 1, // imageArrayLayers - vk::ImageUsageFlagBits::eColorAttachment, - vk::SharingMode::eExclusive, - // TODO: fill in rest - }); - - { - _swapchain_images.clear(); - auto images = device.getSwapchainImagesKHR(_swapchain); - for (const auto& img : images) { - _swapchain_images.push_back(img); - } - } - SPDLOG_INFO("have {} swapchain images", _swapchain_images.size()); - - _swapchain_image_views.clear(); - for (const auto& img : _swapchain_images) { - _swapchain_image_views.push_back(device.createImageView({ - {}, - img, - vk::ImageViewType::e2D, - swap_surf_format.format, - {}, // comp mapping - { // subres - vk::ImageAspectFlagBits::eColor, - 0, - 1, - 0, - 1, - }, - })); - } - - // TODO: move - - _swapchain_framebuffers.clear(); - for (const auto& img_view : _swapchain_image_views) { - vk::ImageView tmp_img_view = img_view; - _swapchain_framebuffers.push_back(device.createFramebuffer({ - {}, - {}, // rend - 1, - &tmp_img_view, - surface_extent.width, - surface_extent.height, - 1 - })); - } - - return true; - } -}; - -} // MM::Services - -TEST(sdl_service, window_vulkan) { - MM::Engine engine; - - engine.addService(); - ASSERT_TRUE(engine.enableService()); - - auto* sdl_ss_ptr = engine.tryService(); - ASSERT_NE(sdl_ss_ptr, nullptr); - - // create window - ASSERT_EQ(sdl_ss_ptr->win, nullptr); - ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN)); - ASSERT_NE(sdl_ss_ptr->win, nullptr); - - engine.addService(); - ASSERT_TRUE(engine.enableService()); - - auto& vk_rend = engine.getService(); - ASSERT_TRUE(vk_rend.createDevice(engine)); - ASSERT_TRUE(vk_rend.createSwapchain(engine)); - - engine.run(); - - engine.disableService(); - engine.disableService(); - - ASSERT_EQ(sdl_ss_ptr->win, nullptr); -} - diff --git a/framework/vulkan_renderer/CMakeLists.txt b/framework/vulkan_renderer/CMakeLists.txt new file mode 100644 index 0000000..a101f33 --- /dev/null +++ b/framework/vulkan_renderer/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.9 FATAL_ERROR) + +project(vulkan_renderer CXX) + +add_library(vulkan_renderer + src/mm/services/vulkan_renderer.hpp + src/mm/services/vulkan_renderer.cpp +) + +target_include_directories(vulkan_renderer PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src") + +target_link_libraries(vulkan_renderer + Vulkan::Headers + + engine + logger + + sdl_service +) + +######################## + +if (BUILD_TESTING) + add_subdirectory(test) +endif() + diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp new file mode 100644 index 0000000..c4afd74 --- /dev/null +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp @@ -0,0 +1,406 @@ +#include "./vulkan_renderer.hpp" + +#include +#include + +#include + +#include + +#include + +// this needs to be defined only once +VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE + +// create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr +static void setup_dispacher(void) { +#if 1 + // investigate why this stopped working + static vk::DynamicLoader dl; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); +#else + auto load_res = SDL_Vulkan_LoadLibrary(nullptr); + assert(load_res == 0); + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = reinterpret_cast(SDL_Vulkan_GetVkGetInstanceProcAddr()); +#endif + + VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); +} + +static bool can_use_layer(std::string_view layer_want) { + for (const auto& layer : vk::enumerateInstanceLayerProperties()) { + if (static_cast(layer.layerName) == layer_want) { + return true; + } + } + + return false; +} + +static bool can_use_validation(void) { + return can_use_layer("VK_LAYER_KHRONOS_validation"); +} + +VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* /*pUserData*/ +) { + spdlog::level::level_enum level{}; + switch (messageSeverity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + level = spdlog::level::level_enum::debug; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + level = spdlog::level::level_enum::info; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + level = spdlog::level::level_enum::warn; + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + level = spdlog::level::level_enum::err; + break; + default: + level = spdlog::level::level_enum::critical; // what ever + } + + switch (messageType) { + case VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT: + spdlog::get("VulkanGeneral")->log(level, "{}", pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: + spdlog::get("VulkanValidation")->log(level, "{}", pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: + spdlog::get("VulkanPerformance")->log(level, "{}", pCallbackData->pMessage); + break; + } + + return VK_FALSE; +} + +static const vk::DebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info{ + {}, + vk::DebugUtilsMessageSeverityFlagBitsEXT::eError + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo + | vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose, + vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral + | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation + | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance, + debug_callback +}; + +static vk::Instance create_instance( + const vk::ApplicationInfo& app_info, + std::vector extensions = {}, + std::vector layers = {} +) { + // for debugging + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + // Get the required extension count + unsigned int count; + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) { + return nullptr; + } + + size_t additional_extension_count = extensions.size(); + extensions.resize(additional_extension_count + count); + + // fill sdl extensions + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) { + return nullptr; + } + + // Now we can make the Vulkan instance + vk::StructureChain c{ + vk::InstanceCreateInfo{ + {}, + &app_info, + static_cast(layers.size()), + layers.data(), + static_cast(extensions.size()), + extensions.data() + }, + debug_utils_messenger_create_info + }; + + vk::Instance instance = vk::createInstance(c.get(), nullptr); + + // initialize function pointers for instance + VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); + + return instance; +} + +namespace MM::Services { + +VulkanRenderer::VulkanRenderer(void) { +#if 0 + MM::Logger::initSectionLogger("VulkanGeneral"); + // way too noisy otherwise + spdlog::get("VulkanGeneral")->set_level(spdlog::level::level_enum::warn); +#else + // or just dont log to stdio? + MM::Logger::initSectionLogger("VulkanGeneral", false); +#endif + MM::Logger::initSectionLogger("VulkanValidation"); + MM::Logger::initSectionLogger("VulkanPerformance"); + + SPDLOG_INFO("constructed VulkanRenderer"); +} + +VulkanRenderer::~VulkanRenderer(void) { +} + +bool VulkanRenderer::enable(Engine& engine, std::vector& task_array) { + assert(!VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); + setup_dispacher(); + assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); + + // create vulkan instance + const vk::ApplicationInfo app_info { + "app_name", + VK_MAKE_VERSION(1, 0, 0), // app version + "MushMachine", + // TODO: engine version macro or something + VK_MAKE_VERSION(0, 8, 0), // engine version + VK_API_VERSION_1_1 + }; + + // TODO: make validation layer conditional + std::vector layers{}; + if (can_use_validation()) { + layers.push_back("VK_LAYER_KHRONOS_validation"); + SPDLOG_INFO("ENABLED validation layer"); + } else { + SPDLOG_INFO("validation layer NOT AVAILABLE!"); + } + + vk::Instance instance = create_instance( + app_info, + {}, + layers + ); + _instance = instance; + + _debug_messenger = instance.createDebugUtilsMessengerEXT(debug_utils_messenger_create_info); + + return true; +} + +void VulkanRenderer::disable(Engine&) { + // cleanup + if (_device) { + vk::Device device{_device}; + + for (const auto& fb : _swapchain_framebuffers) { + device.destroy(fb); + } + for (const auto& img_view : _swapchain_image_views) { + device.destroy(img_view); + } + device.destroy(_swapchain); + device.destroy(); + } + + vk::Instance instance{_instance}; + instance.destroy(_surface); + instance.destroy(_debug_messenger); + instance.destroy(); +} + +bool VulkanRenderer::createDevice(Engine& engine) { + // the surface for the window (not device dependent) + if (SDL_Vulkan_CreateSurface(engine.getService().win, _instance, &_surface) != SDL_TRUE) { + SPDLOG_ERROR("creating vulkan surface from window. (is the SDL_WINDOW_VULKAN flag set?)"); + return false; + } + + // convenience hpp wrapper + assert(_surface); + vk::SurfaceKHR surface{_surface}; + assert(_instance); + vk::Instance instance{_instance}; + + auto physical_devices = instance.enumeratePhysicalDevices(); + if (physical_devices.empty()) { + SPDLOG_ERROR("no physical vulkan devices found"); + return false; + } + + // list devices + for (const auto& ph_device : physical_devices) { + auto props = ph_device.getProperties(); + SPDLOG_INFO( + "found device: [{}] ({}) '{}'", + props.deviceID, + (props.deviceType == vk::PhysicalDeviceType::eDiscreteGpu ? "discrete" : "other"), + props.deviceName + ); + } + + auto& selected_phys_dev = physical_devices.front(); + _physical_device = selected_phys_dev; + + for (const auto& fam_props : selected_phys_dev.getQueueFamilyProperties()) { + auto test_bit = [](const auto& flags, const auto& bit) -> bool { + return (flags & bit) == bit; + }; + SPDLOG_INFO( + "QueueFamily: queueCount:{} graphics:{} compute:{} transfer:{}", + fam_props.queueCount, + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eGraphics) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eCompute) ? "true" : "false", + test_bit(fam_props.queueFlags, vk::QueueFlagBits::eTransfer) ? "true" : "false" + ); + } + + uint32_t queue_fam_index = 0; + + // test for support for swapchain + if (selected_phys_dev.getSurfaceSupportKHR(queue_fam_index, surface) != VK_TRUE) { + SPDLOG_ERROR("selected device does not support the surface"); + return false; + } + + const float queue_prio = 1.f; // hmmmm + vk::DeviceQueueCreateInfo graphics_queue_create_info { + {}, + queue_fam_index, // just pick the first one for now + 1, // count + &queue_prio + }; + + vk::PhysicalDeviceFeatures device_features { + }; + + // do i need this? + std::vector device_extentions{ + VK_KHR_SWAPCHAIN_EXTENSION_NAME + }; + + vk::DeviceCreateInfo device_create_info { + {}, + 1, + &graphics_queue_create_info, + // layers + 0, + nullptr, + // extensions + static_cast(device_extentions.size()), + device_extentions.data(), + &device_features + }; + vk::Device device = selected_phys_dev.createDevice(device_create_info, nullptr); + _device = device; + + // function pointer specialization for device + VULKAN_HPP_DEFAULT_DISPATCHER.init(device); + + //_present_queue = device.getQueue(0, 0); + // we assume it also does present + _graphics_queue = device.getQueue(0, 0); + + return true; +} + +bool VulkanRenderer::createSwapchain(Engine& engine) { + assert(_physical_device); + vk::PhysicalDevice physical_device {_physical_device}; + assert(_device); + vk::Device device {_device}; + + vk::SurfaceFormatKHR swap_surf_format { + vk::Format::eB8G8R8A8Srgb, + vk::ColorSpaceKHR::eSrgbNonlinear, + }; + { // select format + //for (const auto& format : selected_phys_dev.getSurfaceFormatsKHR(surface)) { + //if (format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) { + //if (format.format == vk::Format::eB8G8R8A8Srgb) { + + //} + //} + //} + } + + vk::Extent2D surface_extent {}; + { + int w, h; + SDL_Vulkan_GetDrawableSize(engine.getService().win, &w, &h); + surface_extent.width = w; + surface_extent.height = h; + } + + auto phys_surf_caps = physical_device.getSurfaceCapabilitiesKHR(_surface); + + // flush all loggers + spdlog::apply_all([](const auto& logger) { logger->flush(); }); + + assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkCreateSwapchainKHR); + + // create the swapchain + _swapchain = device.createSwapchainKHR({ + {}, + _surface, + phys_surf_caps.minImageCount, + swap_surf_format.format, + swap_surf_format.colorSpace, + surface_extent, + 1, // imageArrayLayers + vk::ImageUsageFlagBits::eColorAttachment, + vk::SharingMode::eExclusive, + // TODO: fill in rest + }); + + { + _swapchain_images.clear(); + auto images = device.getSwapchainImagesKHR(_swapchain); + for (const auto& img : images) { + _swapchain_images.push_back(img); + } + } + SPDLOG_INFO("have {} swapchain images", _swapchain_images.size()); + + _swapchain_image_views.clear(); + for (const auto& img : _swapchain_images) { + _swapchain_image_views.push_back(device.createImageView({ + {}, + img, + vk::ImageViewType::e2D, + swap_surf_format.format, + {}, // comp mapping + { // subres + vk::ImageAspectFlagBits::eColor, + 0, + 1, + 0, + 1, + }, + })); + } + + // TODO: move + + _swapchain_framebuffers.clear(); + for (const auto& img_view : _swapchain_image_views) { + vk::ImageView tmp_img_view = img_view; + _swapchain_framebuffers.push_back(device.createFramebuffer({ + {}, + {}, // rend + 1, + &tmp_img_view, + surface_extent.width, + surface_extent.height, + 1 + })); + } + + return true; +} + +} // MM::Services + diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp new file mode 100644 index 0000000..1282b6d --- /dev/null +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include +#include + +// fwd vk stuff + +#define MM_VK_DEFINE_HANDLE(object) typedef struct object##_T* object; +// TODO: determain what we use +//#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE + //#if (VK_USE_64_BIT_PTR_DEFINES==1) + #define MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + //#else + //#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + //#endif +//#endif + +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImage) +MM_VK_DEFINE_HANDLE(VkInstance) +MM_VK_DEFINE_HANDLE(VkPhysicalDevice) +MM_VK_DEFINE_HANDLE(VkDevice) +MM_VK_DEFINE_HANDLE(VkQueue) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) + +// extensions +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSwapchainKHR) + +namespace MM::Services { + +class VulkanRenderer : public Service { + private: + // lets use the c-api types + VkInstance _instance{}; + VkDebugUtilsMessengerEXT _debug_messenger{}; + + VkSurfaceKHR _surface{}; + + VkPhysicalDevice _physical_device{}; + VkDevice _device{}; + + VkQueue _graphics_queue{}; + //VkQueue _present_queue{}; + + VkSwapchainKHR _swapchain{}; + std::vector _swapchain_images{}; + std::vector _swapchain_image_views{}; + std::vector _swapchain_framebuffers{}; + + public: + VulkanRenderer(void); + ~VulkanRenderer(void); + + bool enable(Engine& engine, std::vector& task_array) override; + void disable(Engine&) override; + + const char* name(void) override { return "VulkanRenderer"; } + + public: + bool createDevice(Engine& engine); + + bool createSwapchain(Engine& engine); +}; + +} // MM::Services + diff --git a/framework/vulkan_renderer/test/CMakeLists.txt b/framework/vulkan_renderer/test/CMakeLists.txt new file mode 100644 index 0000000..cb88cf3 --- /dev/null +++ b/framework/vulkan_renderer/test/CMakeLists.txt @@ -0,0 +1,13 @@ +add_executable(vulkan_renderer_test + ./vulkan_test.cpp +) + +target_include_directories(vulkan_renderer_test PRIVATE ".") + +target_link_libraries(vulkan_renderer_test + vulkan_renderer + gtest_main +) + +add_test(NAME vulkan_renderer_test COMMAND vulkan_renderer_test) + diff --git a/framework/vulkan_renderer/test/vulkan_test.cpp b/framework/vulkan_renderer/test/vulkan_test.cpp new file mode 100644 index 0000000..12daa7b --- /dev/null +++ b/framework/vulkan_renderer/test/vulkan_test.cpp @@ -0,0 +1,37 @@ +#include + +#include +#include +#include + +#include + +TEST(sdl_service, window_vulkan) { + MM::Engine engine; + + engine.addService(); + ASSERT_TRUE(engine.enableService()); + + auto* sdl_ss_ptr = engine.tryService(); + ASSERT_NE(sdl_ss_ptr, nullptr); + + // create window + ASSERT_EQ(sdl_ss_ptr->win, nullptr); + ASSERT_TRUE(sdl_ss_ptr->createWindow("test vulkan window", 800, 600, SDL_WINDOW_VULKAN)); + ASSERT_NE(sdl_ss_ptr->win, nullptr); + + engine.addService(); + ASSERT_TRUE(engine.enableService()); + + auto& vk_rend = engine.getService(); + ASSERT_TRUE(vk_rend.createDevice(engine)); + ASSERT_TRUE(vk_rend.createSwapchain(engine)); + + engine.run(); + + engine.disableService(); + engine.disableService(); + + ASSERT_EQ(sdl_ss_ptr->win, nullptr); +} + From a0024b34e9c85b56649e4f6c5cf6f816fcd44089 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 3 Jun 2022 14:43:46 +0200 Subject: [PATCH 6/9] main loop and sync --- .../src/mm/services/vulkan_renderer.cpp | 74 +++++++++++++++++++ .../src/mm/services/vulkan_renderer.hpp | 22 ++++-- 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp index c4afd74..e96a9f6 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp @@ -5,6 +5,13 @@ #include +// mf ycm, FIXME: remove before merge +#include +#include +#include +#include +#include + #include #include @@ -188,6 +195,14 @@ bool VulkanRenderer::enable(Engine& engine, std::vectorrender(e); }) + ); + } + return true; } @@ -196,6 +211,8 @@ void VulkanRenderer::disable(Engine&) { if (_device) { vk::Device device{_device}; + device.waitIdle(); + for (const auto& fb : _swapchain_framebuffers) { device.destroy(fb); } @@ -203,6 +220,9 @@ void VulkanRenderer::disable(Engine&) { device.destroy(img_view); } device.destroy(_swapchain); + device.destroy(_swapchain_sem_image_available); + device.destroy(_swapchain_sem_render_finished); + device.destroy(_swapchain_fence_in_flight); device.destroy(); } @@ -212,6 +232,55 @@ void VulkanRenderer::disable(Engine&) { instance.destroy(); } +void VulkanRenderer::render(Engine&) { + vk::Device device{_device}; + vk::SwapchainKHR swapchain{_swapchain}; + + // wait for next fb/img/img_view to be free again + // in most cases there are 2 but might be 1 or more + vk::Fence in_flight{_swapchain_fence_in_flight}; + auto wait_in_flight_res = device.waitForFences(in_flight, true, UINT64_MAX); + device.resetFences(in_flight); + + uint32_t next_img_index = device.acquireNextImageKHR( + _swapchain, + UINT64_MAX, + _swapchain_sem_image_available + ).value; + + { + auto g_queue = vk::Queue{_graphics_queue}; + // do the commands n stuff + + // queue submit + vk::Semaphore tmp_sem_wait{_swapchain_sem_image_available}; + vk::PipelineStageFlags tmp_sem_wait_stages{vk::PipelineStageFlagBits::eColorAttachmentOutput}; + vk::Semaphore tmp_sem_sig{_swapchain_sem_render_finished}; + g_queue.submit({vk::SubmitInfo{ + tmp_sem_wait, + tmp_sem_wait_stages, + {}, + tmp_sem_sig + }}, _swapchain_fence_in_flight); + } + + { // queue present + auto p_queue = vk::Queue{_graphics_queue}; // TODO: present queue + + vk::Semaphore tmp_sem_wait{_swapchain_sem_render_finished}; + auto present_res = p_queue.presentKHR(vk::PresentInfoKHR{ + tmp_sem_wait, + swapchain, + // _swapchain_curr_idx + next_img_index + }); + + // TODO: do i need this?? + // next image + _swapchain_curr_idx = (_swapchain_curr_idx + 1) % _swapchain_images.size(); + } +} + bool VulkanRenderer::createDevice(Engine& engine) { // the surface for the window (not device dependent) if (SDL_Vulkan_CreateSurface(engine.getService().win, _instance, &_surface) != SDL_TRUE) { @@ -304,6 +373,10 @@ bool VulkanRenderer::createDevice(Engine& engine) { // we assume it also does present _graphics_queue = device.getQueue(0, 0); + _swapchain_sem_image_available = device.createSemaphore(vk::SemaphoreCreateInfo{}); + _swapchain_sem_render_finished = device.createSemaphore(vk::SemaphoreCreateInfo{}); + _swapchain_fence_in_flight = device.createFence({vk::FenceCreateFlagBits::eSignaled}); + return true; } @@ -383,6 +456,7 @@ bool VulkanRenderer::createSwapchain(Engine& engine) { })); } + // TODO: move _swapchain_framebuffers.clear(); diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp index 1282b6d..2b51c93 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp @@ -8,11 +8,11 @@ #define MM_VK_DEFINE_HANDLE(object) typedef struct object##_T* object; // TODO: determain what we use //#ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE - //#if (VK_USE_64_BIT_PTR_DEFINES==1) - #define MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; - //#else - //#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; - //#endif + //#if (VK_USE_64_BIT_PTR_DEFINES==1) + #define MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; + //#else + //#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; + //#endif //#endif MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkBuffer) @@ -21,6 +21,8 @@ MM_VK_DEFINE_HANDLE(VkInstance) MM_VK_DEFINE_HANDLE(VkPhysicalDevice) MM_VK_DEFINE_HANDLE(VkDevice) MM_VK_DEFINE_HANDLE(VkQueue) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) @@ -46,19 +48,27 @@ class VulkanRenderer : public Service { //VkQueue _present_queue{}; VkSwapchainKHR _swapchain{}; + uint32_t _swapchain_curr_idx{}; std::vector _swapchain_images{}; std::vector _swapchain_image_views{}; std::vector _swapchain_framebuffers{}; + VkSemaphore _swapchain_sem_image_available{}; + VkSemaphore _swapchain_sem_render_finished{}; + VkFence _swapchain_fence_in_flight{}; + public: VulkanRenderer(void); ~VulkanRenderer(void); + private: // Service interface bool enable(Engine& engine, std::vector& task_array) override; - void disable(Engine&) override; + void disable(Engine& engine) override; const char* name(void) override { return "VulkanRenderer"; } + void render(Engine& engine); + public: bool createDevice(Engine& engine); From 76161df6cd536477a591987f5f4eaea0d60310c9 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 3 Jun 2022 23:41:46 +0200 Subject: [PATCH 7/9] mult frames in flight --- .../src/mm/services/vulkan_renderer.cpp | 70 +++++++++++-------- .../src/mm/services/vulkan_renderer.hpp | 6 +- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp index e96a9f6..21c0480 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp @@ -21,8 +21,10 @@ VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE // create a dispatcher, based on additional vkDevice/vkGetDeviceProcAddr static void setup_dispacher(void) { -#if 1 - // investigate why this stopped working + // both should work + // but vk::DynamicLoader reloads the dll, so it will be open more then once + // and also might be a different one from sdl +#if 0 static vk::DynamicLoader dl; PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); #else @@ -44,10 +46,6 @@ static bool can_use_layer(std::string_view layer_want) { return false; } -static bool can_use_validation(void) { - return can_use_layer("VK_LAYER_KHRONOS_validation"); -} - VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, @@ -162,12 +160,12 @@ VulkanRenderer::VulkanRenderer(void) { VulkanRenderer::~VulkanRenderer(void) { } -bool VulkanRenderer::enable(Engine& engine, std::vector& task_array) { +bool VulkanRenderer::enable(Engine&, std::vector& task_array) { assert(!VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); setup_dispacher(); assert(VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceLayerProperties); - // create vulkan instance + // TODO: user configurable const vk::ApplicationInfo app_info { "app_name", VK_MAKE_VERSION(1, 0, 0), // app version @@ -179,7 +177,8 @@ bool VulkanRenderer::enable(Engine& engine, std::vector layers{}; - if (can_use_validation()) { + + if (can_use_layer("VK_LAYER_KHRONOS_validation")) { layers.push_back("VK_LAYER_KHRONOS_validation"); SPDLOG_INFO("ENABLED validation layer"); } else { @@ -193,8 +192,11 @@ bool VulkanRenderer::enable(Engine& engine, std::vector _swapchain_image_views{}; std::vector _swapchain_framebuffers{}; - VkSemaphore _swapchain_sem_image_available{}; - VkSemaphore _swapchain_sem_render_finished{}; - VkFence _swapchain_fence_in_flight{}; + std::vector _swapchain_sem_image_available{}; + std::vector _swapchain_sem_render_finished{}; + std::vector _swapchain_fence_in_flight{}; public: VulkanRenderer(void); From 82faf448f4469206faa4ee377d4ec2bff6d26531 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 8 Jun 2022 02:10:58 +0200 Subject: [PATCH 8/9] working on some hacky randering --- .../src/mm/services/vulkan_renderer.cpp | 72 ++++++++++ .../src/mm/services/vulkan_renderer.hpp | 14 ++ .../src/mm/vulkan/res/tut1.frag | 10 ++ .../src/mm/vulkan/res/tut1.frag.spv | Bin 0 -> 500 bytes .../src/mm/vulkan/res/tut1.frag.spv.h | 45 +++++++ .../src/mm/vulkan/res/tut1.vert | 21 +++ .../src/mm/vulkan/res/tut1.vert.spv | Bin 0 -> 1432 bytes .../src/mm/vulkan/res/tut1.vert.spv.h | 123 ++++++++++++++++++ .../vulkan_renderer/test/vulkan_test.cpp | 2 +- 9 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv.h create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert.spv create mode 100644 framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert.spv.h diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp index 21c0480..fe19066 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp @@ -14,8 +14,20 @@ #include +// HACK +namespace { // dont leak linkage +#include +#include + +// meh, we dont have the type, only the value +//static_assert(alignof(tut1_vert_spv) == alignof(uint32_t)); +//static_assert(alignof(tut1_frag_spv) == alignof(uint32_t)); +} + #include +// https://youtu.be/eaKeeRngZBo + // this needs to be defined only once VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE @@ -219,8 +231,17 @@ void VulkanRenderer::disable(Engine&) { } }; + auto device_destroy_each_kv = [&device](auto& map) { + for (const auto& it : map) { + device.destroy(it.second); + } + }; + device.waitIdle(); + // resouce cache + device_destroy_each_kv(_r_shader_module); + device_destroy_each(_swapchain_framebuffers); device_destroy_each(_swapchain_image_views); device.destroy(_swapchain); @@ -459,6 +480,57 @@ bool VulkanRenderer::createSwapchain(Engine& engine) { // TODO: move + // TODO: refactor, provide "primitive" wrapper like opengl + auto create_shader_module = [&](const uint8_t* data, const size_t size) -> vk::ShaderModule { + return device.createShaderModule(vk::ShaderModuleCreateInfo{ + {}, + size, + reinterpret_cast(data) + }); + }; + + using namespace entt::literals; + + auto vert_module = create_shader_module(tut1_vert_spv, tut1_vert_spv_len); + _r_shader_module["tut1_vert"_hs] = vert_module; + auto frag_module = create_shader_module(tut1_frag_spv, tut1_frag_spv_len); + _r_shader_module["tut1_frag"_hs] = frag_module; + + std::vector pl_shader_ci { + { + {}, + vk::ShaderStageFlagBits::eVertex, + vert_module, + "main", + }, + { + {}, + vk::ShaderStageFlagBits::eFragment, + frag_module, + "main", + } + }; + + std::vector pl_vertex_input_ci { + // hardcoded in shader, so no actual data here + {}, + {}, // do i need two? + }; + + vk::PipelineInputAssemblyStateCreateInfo pl_input_asm_ci { + {}, + vk::PrimitiveTopology::eTriangleList, + VK_FALSE + }; + + device.createGraphicsPipeline({}, { + {}, + static_cast(pl_shader_ci.size()), + pl_shader_ci.data(), + pl_vertex_input_ci.data(), + &pl_input_asm_ci, + }); + _swapchain_framebuffers.clear(); for (const auto& img_view : _swapchain_image_views) { vk::ImageView tmp_img_view = img_view; diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp index de436d7..964e08d 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.hpp @@ -1,7 +1,9 @@ #pragma once +#include "entt/core/hashed_string.hpp" #include #include +#include // fwd vk stuff @@ -25,6 +27,7 @@ MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSemaphore) MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFence) MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkImageView) MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkFramebuffer) +MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkShaderModule) // extensions MM_VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugUtilsMessengerEXT) @@ -57,6 +60,9 @@ class VulkanRenderer : public Service { std::vector _swapchain_sem_render_finished{}; std::vector _swapchain_fence_in_flight{}; + // resource cache + std::unordered_map _r_shader_module{}; + public: VulkanRenderer(void); ~VulkanRenderer(void); @@ -73,6 +79,14 @@ class VulkanRenderer : public Service { bool createDevice(Engine& engine); bool createSwapchain(Engine& engine); + + //VkShaderModule getR_shader_module(const entt::hashed_string::value_type key) { + //return _r_shader_module.at(key); + //} + + //VkShaderModule getR_shader_module(const char* key) { + //return getR_shader_module(entt::hashed_string::value(key)); + //} }; } // MM::Services diff --git a/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag new file mode 100644 index 0000000..76bdf57 --- /dev/null +++ b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag @@ -0,0 +1,10 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} + diff --git a/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..a94fd3903554fa866205c4e84b81431fe7592a5c GIT binary patch literal 500 zcmYk1y-EX75QQhZZZ;;G9|PJ+#8L<|pCBNLpf1GN`)odyjo|lPcg4G$ zotbmb%$b{Khh^lg=td{T@q0#*MT@i-?G)#WyT$ZveLp=pJyy|=JPFkdqKplqcv(KZ zda((%z!05$339%S_(@X%`(Izc*i*f)udC;3MG8}-84s)FV?)mAQn#;wW35k9k8#lB zAh|`#cgfpu6R?NgU99z=@b3_Pjr@6C>mjGUOH^;IzDMKx@3->|*=?*RMNd+#2XxcVONzS;5& F`~b~_7{>qr literal 0 HcmV?d00001 diff --git a/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv.h b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv.h new file mode 100644 index 0000000..800a5a5 --- /dev/null +++ b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.frag.spv.h @@ -0,0 +1,45 @@ +alignas(uint32_t) unsigned char tut1_frag_spv[] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x03, 0x01, 0x00, 0x0a, 0x00, 0x08, 0x00, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x43, + 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, + 0x72, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x00, 0x03, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x16, 0x00, 0x03, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, + 0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x3e, 0x00, 0x03, 0x00, 0x09, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00 +}; +unsigned int tut1_frag_spv_len = 500; diff --git a/framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert new file mode 100644 index 0000000..f8a9a20 --- /dev/null +++ b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert @@ -0,0 +1,21 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} + diff --git a/framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert.spv b/framework/vulkan_renderer/src/mm/vulkan/res/tut1.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..3f0f5fede87026dfff8db585ddc5e2c8762da125 GIT binary patch literal 1432 zcmYk5U29W85QaC2C(%}0Yi;XCt*0N>kJebVErO^>g(&o*Qt-BfHkJc1DMo^#HIY#3(Vci!2Z**&RM*BhZ$2~**6*bl{;3)N5|oDTKew+@dFo5Rsrb9Zk? z#Z0K>LN&A0xh`Sf+F8$d4co+?V>NzN{2#;#s!3e}bCujhf0&K3es4&uW(j}V@Ad}} z2|c9X^X|z}XYi#n7c`p?cQl; zoO3dB-@Dy$E@1{|a@miwp(&dA)H|~yXK~)IgZBA>y%T?gOYyGh!i_omlha3?eaYEF zDt=I7> zR>3?+yn(r_e}Fe9Z@qZ4+{C-Ly@+>8>|I+g_WM+0{w3ae^ZR@YeuK{J zQu7xk!M_FhP5HLQzK!?x2DQCC#O&)mYI}N&sh3w{fBrw@Kcn%?t&+oyx$Tm3<|C?{ y<0+=robT-0d5*I_!@N)L%)Z3xV_z?bV_(j?i`l!p8t2}_(); engine.disableService(); From e4d99ad45573815a34138234f6adde3ec26e5891 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 15 Jun 2022 23:47:05 +0200 Subject: [PATCH 9/9] lil continue --- .../src/mm/services/vulkan_renderer.cpp | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp index fe19066..b4d1483 100644 --- a/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp +++ b/framework/vulkan_renderer/src/mm/services/vulkan_renderer.cpp @@ -523,12 +523,102 @@ bool VulkanRenderer::createSwapchain(Engine& engine) { VK_FALSE }; + // rn whole screen + vk::Viewport viewport { + 0.f, // x + 0.f, // y + static_cast(surface_extent.width), + static_cast(surface_extent.height), + 0.f, // min depth + 1.f, // max depth + }; + + // whole screen + vk::Rect2D scissor { + {0, 0}, // offset + surface_extent + }; + + vk::PipelineViewportStateCreateInfo pl_viewport_state_ci { + {}, + 1, + &viewport, + 1, + &scissor, + }; + + vk::PipelineRasterizationStateCreateInfo pl_raster_state_ci { + {}, + VK_FALSE, // depth clamp + VK_FALSE, // discard + vk::PolygonMode::eFill, + //vk::CullModeFlagBits::eBack, + vk::CullModeFlagBits::eNone, // TODO: enable, just debug now + vk::FrontFace::eClockwise, // TODO: determain what the engine uses normally + VK_FALSE, + 0.f, 0.f, 0.f, + 1.f, // line width + }; + + // default for vkhpp is disabled + vk::PipelineMultisampleStateCreateInfo pl_ms_state_ci {}; + + vk::PipelineColorBlendAttachmentState pl_color_blend_attachment_state { + VK_FALSE, + + vk::BlendFactor::eOne, + vk::BlendFactor::eZero, + + vk::BlendOp::eAdd, + + vk::BlendFactor::eOne, + vk::BlendFactor::eZero, + + vk::BlendOp::eAdd, + + vk::ColorComponentFlagBits::eR + | vk::ColorComponentFlagBits::eG + | vk::ColorComponentFlagBits::eB + | vk::ColorComponentFlagBits::eA, + }; + + vk::PipelineColorBlendStateCreateInfo pl_color_blend_state_ci { + {}, + VK_FALSE, + vk::LogicOp::eCopy, + 1, + &pl_color_blend_attachment_state, + { 0.f, 0.f, 0.f, 0.f }, + }; + + //std::vector pl_dyn_states { + //vk::DynamicState::eViewport, + //vk::DynamicState::eLineWidth, + //}; + + vk::PipelineLayout pl_layout = device.createPipelineLayout({ + {}, + + 0, + {}, + 0, + {} + }); + device.createGraphicsPipeline({}, { {}, static_cast(pl_shader_ci.size()), pl_shader_ci.data(), pl_vertex_input_ci.data(), &pl_input_asm_ci, + {}, + &pl_viewport_state_ci, + &pl_raster_state_ci, + &pl_ms_state_ci, + {}, // d'n's + &pl_color_blend_state_ci, + {}, // dyn + pl_layout, }); _swapchain_framebuffers.clear();