diff --git a/.gitignore b/.gitignore index d2bf98a016f588760241f9dc7f90f6197c458404..7ee4ff1903e902c4715c6e2b0c3e784ed5755aaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,3 @@ -<<<<<<< HEAD -======= - ->>>>>>> develop # IDE specific files .project .cproject @@ -19,3 +15,6 @@ cmake-build-release/ *.exe *.ilk *.pdb + +# GUI configuration files +imgui.ini diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 318f3e931e557421a5e9275735174cdee7947453..33b70018e368ecc3ad019ea33e57485814eb233a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ build_ubuntu_gcc: - $RUN =~ /\bubuntu.*/i || $RUN =~ /\ball.*/i stage: build tags: - - ubuntu-gcc + - ubuntu-gcc-cached variables: GIT_SUBMODULE_STRATEGY: recursive timeout: 10m @@ -37,11 +37,11 @@ build_win10_msvc: - $RUN =~ /\bwin.*/i || $RUN =~ /\ball.*/i stage: build tags: - - win10-msvc + - win10-msvc-cached variables: GIT_SUBMODULE_STRATEGY: recursive timeout: 10m - retry: 1 + retry: 0 script: - cd 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\' - .\Launch-VsDevShell.ps1 diff --git a/.gitmodules b/.gitmodules index 62938a4b1ff2c6787b619cc2c18ef91cb0f0f679..e0aaf2d17c340f98ae875f7e0f1238bfe04f7e5d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "modules/shader_compiler/lib/glslang"] path = modules/shader_compiler/lib/glslang url = https://github.com/KhronosGroup/glslang.git +[submodule "modules/gui/lib/imgui"] + path = modules/gui/lib/imgui + url = https://github.com/ocornut/imgui.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a7f978f81313ecc3a657dd670d2a16db3cd4e8d..bff486150f082c2e96e543436d977cf3112403ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,15 +41,15 @@ if (vkcv_build_debug) endif() endif() +# configure everything to use the required dependencies +include(${vkcv_config}/Libraries.cmake) + # add modules as targets add_subdirectory(modules) # add source files for compilation include(${vkcv_config}/Sources.cmake) -# configure everything to use the required dependencies -include(${vkcv_config}/Libraries.cmake) - message("-- Libraries: [ ${vkcv_libraries} ]") message("-- Flags: [ ${vkcv_flags} ]") diff --git a/config/Sources.cmake b/config/Sources.cmake index 62cec249367995db0217c71455cfcee982c65af3..4397e4978eb022d267571d185a1f122d053a5ea1 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -32,8 +32,8 @@ set(vkcv_sources ${vkcv_include}/vkcv/Logger.hpp - ${vkcv_include}/vkcv/SwapChain.hpp - ${vkcv_source}/vkcv/SwapChain.cpp + ${vkcv_include}/vkcv/Swapchain.hpp + ${vkcv_source}/vkcv/Swapchain.cpp ${vkcv_include}/vkcv/ShaderStage.hpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 3d21e4bbfffef180c62a10b61add2ac015e52aa9..dab18892b892aff9564a6d86b9252789ea3c2b03 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -8,7 +8,7 @@ #include <vulkan/vulkan.hpp> #include "vkcv/Context.hpp" -#include "vkcv/SwapChain.hpp" +#include "vkcv/Swapchain.hpp" #include "vkcv/Window.hpp" #include "vkcv/PassConfig.hpp" #include "vkcv/Handles.hpp" @@ -41,6 +41,7 @@ namespace vkcv QueueType queueType; std::vector<vk::Semaphore> waitSemaphores; std::vector<vk::Semaphore> signalSemaphores; + vk::Fence fence; }; class Core final @@ -52,7 +53,7 @@ namespace vkcv * * @param context encapsulates various Vulkan objects */ - Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> imageViews, + Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> imageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept; // explicit destruction of default constructor Core() = delete; @@ -61,8 +62,8 @@ namespace vkcv Context m_Context; - SwapChain m_swapchain; - const Window& m_window; + Swapchain m_swapchain; + Window& m_window; std::unique_ptr<PassManager> m_PassManager; std::unique_ptr<PipelineManager> m_PipelineManager; @@ -76,9 +77,9 @@ namespace vkcv SyncResources m_SyncResources; uint32_t m_currentSwapchainImageIndex; - std::function<void(int, int)> e_resizeHandle; + event_handle<int,int> e_resizeHandle; - static std::vector<vk::ImageView> createSwapchainImageViews( Context &context, SwapChain& swapChain); + static std::vector<vk::ImageView> createSwapchainImageViews( Context &context, Swapchain& swapChain); public: /** @@ -118,6 +119,9 @@ namespace vkcv [[nodiscard]] const Context &getContext() const; + + [[nodiscard]] + const Swapchain& getSwapchain() const; /** * Creates a #Core with given @p applicationName and @p applicationVersion for your application. @@ -248,8 +252,6 @@ namespace vkcv */ void endFrame(); - vk::Format getSwapchainImageFormat(); - /** * Submit a command buffer to any queue of selected type. The recording can be customized by a * custom record-command-function. If the command submission has finished, an optional finish-function @@ -277,5 +279,8 @@ namespace vkcv void prepareImageForStorage(const CommandStreamHandle cmdStream, const ImageHandle image); void recordImageMemoryBarrier(const CommandStreamHandle cmdStream, const ImageHandle image); void recordBufferMemoryBarrier(const CommandStreamHandle cmdStream, const BufferHandle buffer); - }; + + const vk::ImageView& getSwapchainImageView() const; + + }; } diff --git a/include/vkcv/Event.hpp b/include/vkcv/Event.hpp index 0836e836e84ff7dfc4931a7cedd65497bf9a89cf..e324917674cd2e1773ee23a9411ab28f6eb0d684 100644 --- a/include/vkcv/Event.hpp +++ b/include/vkcv/Event.hpp @@ -3,10 +3,18 @@ #include <functional> namespace vkcv { + + template<typename... T> + struct event_handle { + uint32_t id; + }; template<typename... T> struct event_function { typedef std::function<void(T...)> type; + + event_handle<T...> handle; + type callback; }; /** @@ -16,7 +24,8 @@ namespace vkcv { template<typename... T> struct event { private: - std::vector<typename event_function<T...>::type> m_handles; + std::vector< event_function<T...> > m_functions; + uint32_t m_id_counter; public: @@ -25,28 +34,34 @@ namespace vkcv { * @param arguments of the given function */ void operator()(T... arguments) { - for (auto &handle : this->m_handles) { - handle(arguments...); + for (auto &function : this->m_functions) { + function.callback(arguments...); } } /** * adds a function handle to the event to be called - * @param handle of the function + * @param callback of the function + * @return handle of the function */ - typename event_function<T...>::type add(typename event_function<T...>::type handle) { - this->m_handles.push_back(handle); - return handle; + event_handle<T...> add(typename event_function<T...>::type callback) { + event_function<T...> function; + function.handle = { m_id_counter++ }; + function.callback = callback; + this->m_functions.push_back(function); + return function.handle; } /** * removes a function handle of the event * @param handle of the function */ - void remove(typename event_function<T...>::type handle) { - this->m_handles.erase( - remove(this->m_handles.begin(), this->m_handles.end(), handle), - this->m_handles.end() + void remove(event_handle<T...> handle) { + this->m_functions.erase( + std::remove_if(this->m_functions.begin(), this->m_functions.end(), [&handle](auto function){ + return (handle.id == function.handle.id); + }), + this->m_functions.end() ); } diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp index e1eb78ee02ea9142dcbaaa51ab06e3f3bbfa78e1..1795b63e844a002564932f5d7ef839746e32fae5 100644 --- a/include/vkcv/Image.hpp +++ b/include/vkcv/Image.hpp @@ -29,9 +29,6 @@ namespace vkcv { [[nodiscard]] uint32_t getDepth() const; - - [[nodiscard]] - vk::ImageLayout getLayout() const; [[nodiscard]] vkcv::ImageHandle getHandle() const; diff --git a/include/vkcv/SwapChain.hpp b/include/vkcv/Swapchain.hpp similarity index 83% rename from include/vkcv/SwapChain.hpp rename to include/vkcv/Swapchain.hpp index 089205d1633551b4ad9f11d0bdd5540b2bb61bbb..b75fc5a87156ea56061e41b4b0974928c83ffa28 100644 --- a/include/vkcv/SwapChain.hpp +++ b/include/vkcv/Swapchain.hpp @@ -7,8 +7,9 @@ namespace vkcv { - class SwapChain final { + class Swapchain final { private: + friend class Core; struct Surface { @@ -21,10 +22,10 @@ namespace vkcv Surface m_Surface; vk::SwapchainKHR m_Swapchain; - vk::Format m_SwapchainFormat; - vk::ColorSpaceKHR m_SwapchainColorSpace; - vk::PresentModeKHR m_SwapchainPresentMode; - uint32_t m_SwapchainImageCount; + vk::Format m_Format; + vk::ColorSpaceKHR m_ColorSpace; + vk::PresentModeKHR m_PresentMode; + uint32_t m_ImageCount; vk::Extent2D m_Extent; @@ -39,16 +40,36 @@ namespace vkcv * @param format */ // TODO: - SwapChain(const Surface &surface, + Swapchain(const Surface &surface, vk::SwapchainKHR swapchain, vk::Format format, vk::ColorSpaceKHR colorSpace, vk::PresentModeKHR presentMode, uint32_t imageCount, vk::Extent2D extent) noexcept; + + /** + * TODO + * + * @return + */ + bool shouldUpdateSwapchain() const; + + /** + * TODO + * + * context + * window + */ + void updateSwapchain(const Context &context, const Window &window); + + /** + * + */ + void signalSwapchainRecreation(); public: - SwapChain(const SwapChain& other); + Swapchain(const Swapchain& other); /** * @return The swapchain linked with the #SwapChain class @@ -69,7 +90,7 @@ namespace vkcv * @return gets the chosen swapchain format */ [[nodiscard]] - vk::Format getSwapchainFormat() const; + vk::Format getFormat() const; /** * creates a swap chain object out of the given window and the given context @@ -77,37 +98,17 @@ namespace vkcv * @param context of the application * @return returns an object of swapChain */ - static SwapChain create(const Window &window, const Context &context); + static Swapchain create(const Window &window, const Context &context); /** * Destructor of SwapChain */ - virtual ~SwapChain(); + virtual ~Swapchain(); /** * @return number of images in swapchain */ - uint32_t getImageCount(); - - /** - * TODO - * - * @return - */ - bool shouldUpdateSwapchain() const; - - /** - * TODO - * - * context - * window - */ - void updateSwapchain(const Context &context, const Window &window); - - /** - * - */ - void signalSwapchainRecreation(); + uint32_t getImageCount() const; /** * TODO diff --git a/include/vkcv/Window.hpp b/include/vkcv/Window.hpp index f71671c935a0a5e17bb517c726d75ffff2973532..51d6e2245a8b588334b38254c05276ee0eb10150 100644 --- a/include/vkcv/Window.hpp +++ b/include/vkcv/Window.hpp @@ -13,16 +13,19 @@ struct GLFWwindow; namespace vkcv { - class Window final { - private: - GLFWwindow *m_window; - - /** + class Window { + protected: + GLFWwindow *m_window; + + /** * * @param GLFWwindow of the class */ - explicit Window(GLFWwindow *window); - + explicit Window(GLFWwindow *window); + + static GLFWwindow* createGLFWWindow(const char *windowTitle, int width, int height, bool resizable); + + private: /** * mouse callback for moving the mouse on the screen * @param[in] window The window that received the event. @@ -58,6 +61,13 @@ namespace vkcv { * @param[in] mods Bit field describing which [modifier keys](@ref mods) were held down. */ static void onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods); + + /** + * char callback for any typed character + * @param[in] window The window that received the event + * @param[in] c The character that got typed + */ + static void onCharEvent(GLFWwindow *callbackWindow, unsigned int c); public: /** @@ -95,6 +105,7 @@ namespace vkcv { event< double, double > e_mouseScroll; event< int, int > e_resize; event< int, int, int, int > e_key; + event< unsigned int > e_char; /** * returns the current window diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index e8efea4981da3ffb338d508431ed4f92805ed5cd..5edb802b3adf16878c2dec4050d8444278739026 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -2,5 +2,6 @@ # Add new modules here: add_subdirectory(asset_loader) add_subdirectory(camera) +add_subdirectory(gui) add_subdirectory(shader_compiler) add_subdirectory(testing) diff --git a/modules/camera/include/vkcv/camera/CameraManager.hpp b/modules/camera/include/vkcv/camera/CameraManager.hpp index 0c5041795ece9cd84e740a04c0d64e4964d0f4c8..5755d6cdc20f0321197b7755e459725eb363fc90 100644 --- a/modules/camera/include/vkcv/camera/CameraManager.hpp +++ b/modules/camera/include/vkcv/camera/CameraManager.hpp @@ -25,11 +25,11 @@ namespace vkcv::camera { */ class CameraManager{ private: - std::function<void(int, int, int, int)> m_keyHandle; - std::function<void(double, double)> m_mouseMoveHandle; - std::function<void(double, double)> m_mouseScrollHandle; - std::function<void(int, int, int)> m_mouseButtonHandle; - std::function<void(int, int)> m_resizeHandle; + event_handle<int, int, int, int> m_keyHandle; + event_handle<double, double> m_mouseMoveHandle; + event_handle<double, double> m_mouseScrollHandle; + event_handle<int, int, int> m_mouseButtonHandle; + event_handle<int, int> m_resizeHandle; Window& m_window; std::vector<Camera> m_cameras; diff --git a/modules/camera/src/vkcv/camera/CameraManager.cpp b/modules/camera/src/vkcv/camera/CameraManager.cpp index 561596c25a66334b56b3253b998c8c63428ef121..84a0d7ca3049846c4fbb234bab02b5f4d3c7ffd5 100644 --- a/modules/camera/src/vkcv/camera/CameraManager.cpp +++ b/modules/camera/src/vkcv/camera/CameraManager.cpp @@ -14,7 +14,13 @@ namespace vkcv::camera { m_lastY = static_cast<float>(window.getHeight()) / 2.0f; } - CameraManager::~CameraManager() {} + CameraManager::~CameraManager() { + m_window.e_key.remove(m_keyHandle); + m_window.e_mouseMove.remove(m_mouseMoveHandle); + m_window.e_mouseScroll.remove(m_mouseScrollHandle); + m_window.e_mouseButton.remove(m_mouseButtonHandle); + m_window.e_resize.remove(m_resizeHandle); + } void CameraManager::bindCameraToEvents() { m_keyHandle = m_window.e_key.add( [&](int key, int scancode, int action, int mods) { this->keyCallback(key, scancode, action, mods); }); diff --git a/modules/gui/CMakeLists.txt b/modules/gui/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ce03f16e1f8d421f5b8e6c2fe913c0da04d34598 --- /dev/null +++ b/modules/gui/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.16) +project(vkcv_gui) + +# setting c++ standard for the module +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(vkcv_gui_source ${PROJECT_SOURCE_DIR}/src) +set(vkcv_gui_include ${PROJECT_SOURCE_DIR}/include) + +# Add source and header files to the module +set(vkcv_gui_sources + ${vkcv_gui_include}/vkcv/gui/GUI.hpp + ${vkcv_gui_source}/vkcv/gui/GUI.cpp + ) + +# Setup some path variables to load libraries +set(vkcv_gui_lib lib) +set(vkcv_gui_lib_path ${PROJECT_SOURCE_DIR}/${vkcv_gui_lib}) + +# Check and load IMGUI +include(config/ImGui.cmake) + +# adding source files to the module +add_library(vkcv_gui STATIC ${vkcv_gui_sources} ${vkcv_imgui_sources}) + +# link the required libraries to the module +target_link_libraries(vkcv_gui ${vkcv_gui_libraries} vkcv ${vkcv_libraries}) + +# including headers of dependencies and the VkCV framework +target_include_directories(vkcv_gui SYSTEM BEFORE PRIVATE ${vkcv_gui_includes} ${vkcv_include} ${vkcv_includes}) + +# add the own include directory for public headers +target_include_directories(vkcv_gui BEFORE PUBLIC ${vkcv_gui_include} ${vkcv_imgui_includes}) diff --git a/modules/gui/config/ImGui.cmake b/modules/gui/config/ImGui.cmake new file mode 100644 index 0000000000000000000000000000000000000000..3f55ad05c34783ba0e82c41d2cbc4e5b204d60e7 --- /dev/null +++ b/modules/gui/config/ImGui.cmake @@ -0,0 +1,17 @@ + +if (EXISTS "${vkcv_gui_lib_path}/imgui") + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/backends/imgui_impl_glfw.cpp) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/backends/imgui_impl_vulkan.cpp ) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui.cpp) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_draw.cpp) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_demo.cpp) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_tables.cpp) + list(APPEND vkcv_imgui_sources ${vkcv_gui_lib_path}/imgui/imgui_widgets.cpp) + + list(APPEND vkcv_imgui_includes ${vkcv_gui_lib}/imgui) + list(APPEND vkcv_imgui_includes ${vkcv_gui_lib}/imgui/backend) + + list(APPEND vkcv_gui_include ${vkcv_gui_lib}) +else() + message(WARNING "IMGUI is required..! Update the submodules!") +endif () diff --git a/modules/gui/include/vkcv/gui/GUI.hpp b/modules/gui/include/vkcv/gui/GUI.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d1a9986c5f69bfd9d4392bd5ae50f0b1f8b60642 --- /dev/null +++ b/modules/gui/include/vkcv/gui/GUI.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "imgui/imgui.h" +#include "imgui/backends/imgui_impl_glfw.h" +#include "imgui/backends/imgui_impl_vulkan.h" + +#include <vkcv/Core.hpp> +#include <vkcv/Window.hpp> + +namespace vkcv::gui { + + class GUI final { + private: + Window& m_window; + Core& m_core; + + const Context& m_context; + + ImGuiContext* m_gui_context; + + vk::DescriptorPool m_descriptor_pool; + vk::RenderPass m_render_pass; + + event_handle<int,int,int> f_mouseButton; + event_handle<double,double> f_mouseScroll; + event_handle<int,int,int,int> f_key; + event_handle<unsigned int> f_char; + + public: + /** + * Constructor of a new instance of ImGui management + * + * @param core Valid #Core instance of the framework + * @param window Valid #Window instance of the framework + */ + GUI(Core& core, Window& window); + + GUI(const GUI& other) = delete; + GUI(GUI&& other) = delete; + + GUI& operator=(const GUI& other) = delete; + GUI& operator=(GUI&& other) = delete; + + /** + * Destructor of a #GUI instance + */ + virtual ~GUI(); + + /** + * Sets up a new frame for ImGui to draw + */ + void beginGUI(); + + /** + * Ends a frame for ImGui, renders it and draws it onto + * the currently active swapchain image of the core (ready to present). + */ + void endGUI(); + + }; + +} diff --git a/modules/gui/lib/imgui b/modules/gui/lib/imgui new file mode 160000 index 0000000000000000000000000000000000000000..d5828cd988db525f27128edeadb1a689cd2d7461 --- /dev/null +++ b/modules/gui/lib/imgui @@ -0,0 +1 @@ +Subproject commit d5828cd988db525f27128edeadb1a689cd2d7461 diff --git a/modules/gui/src/vkcv/gui/GUI.cpp b/modules/gui/src/vkcv/gui/GUI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a08cb4f02551cae2fd5d1e3ea4e6ff0bd2b2e04 --- /dev/null +++ b/modules/gui/src/vkcv/gui/GUI.cpp @@ -0,0 +1,241 @@ + +#include "vkcv/gui/GUI.hpp" + +#include <GLFW/glfw3.h> +#include <vkcv/Logger.hpp> + +namespace vkcv::gui { + + static void checkVulkanResult(VkResult resultCode) { + if (resultCode == 0) + return; + + const auto result = vk::Result(resultCode); + + vkcv_log(LogLevel::ERROR, "ImGui has a problem with Vulkan! (%s)", vk::to_string(result).c_str()); + } + + GUI::GUI(Core& core, Window& window) : + m_window(window), + m_core(core), + m_context(m_core.getContext()), + m_gui_context(nullptr) { + IMGUI_CHECKVERSION(); + + m_gui_context = ImGui::CreateContext(); + + ImGui_ImplGlfw_InitForVulkan(m_window.getWindow(), false); + + f_mouseButton = m_window.e_mouseButton.add([&](int button, int action, int mods) { + ImGui_ImplGlfw_MouseButtonCallback(m_window.getWindow(), button, action, mods); + }); + + f_mouseScroll = m_window.e_mouseScroll.add([&](double xoffset, double yoffset) { + ImGui_ImplGlfw_ScrollCallback(m_window.getWindow(), xoffset, yoffset); + }); + + f_key = m_window.e_key.add([&](int key, int scancode, int action, int mods) { + ImGui_ImplGlfw_KeyCallback(m_window.getWindow(), key, scancode, action, mods); + }); + + f_char = m_window.e_char.add([&](unsigned int c) { + ImGui_ImplGlfw_CharCallback(m_window.getWindow(), c); + }); + + vk::DescriptorPoolSize pool_sizes[] = { + vk::DescriptorPoolSize(vk::DescriptorType::eSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eCombinedImageSampler, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eSampledImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageImage, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformTexelBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageTexelBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eUniformBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eStorageBufferDynamic, 1000), + vk::DescriptorPoolSize(vk::DescriptorType::eInputAttachment, 1000) + }; + + const vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo ( + vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, + static_cast<uint32_t>(1000 * IM_ARRAYSIZE(pool_sizes)), + static_cast<uint32_t>(IM_ARRAYSIZE(pool_sizes)), + pool_sizes + ); + + m_descriptor_pool = m_context.getDevice().createDescriptorPool(descriptorPoolCreateInfo); + + const vk::PhysicalDevice& physicalDevice = m_context.getPhysicalDevice(); + const Swapchain& swapchain = m_core.getSwapchain(); + + const uint32_t graphicsQueueFamilyIndex = ( + m_context.getQueueManager().getGraphicsQueues()[0].familyIndex + ); + + ImGui_ImplVulkan_InitInfo init_info = {}; + init_info.Instance = m_context.getInstance(); + init_info.PhysicalDevice = m_context.getPhysicalDevice(); + init_info.Device = m_context.getDevice(); + init_info.QueueFamily = graphicsQueueFamilyIndex; + init_info.Queue = m_context.getQueueManager().getGraphicsQueues()[0].handle; + init_info.PipelineCache = nullptr; + init_info.DescriptorPool = m_descriptor_pool; + init_info.Allocator = nullptr; + init_info.MinImageCount = swapchain.getImageCount(); + init_info.ImageCount = swapchain.getImageCount(); + init_info.CheckVkResultFn = checkVulkanResult; + + const vk::AttachmentDescription attachment ( + vk::AttachmentDescriptionFlags(), + swapchain.getFormat(), + vk::SampleCountFlagBits::e1, + vk::AttachmentLoadOp::eLoad, + vk::AttachmentStoreOp::eStore, + vk::AttachmentLoadOp::eDontCare, + vk::AttachmentStoreOp::eDontCare, + vk::ImageLayout::eUndefined, + vk::ImageLayout::ePresentSrcKHR + ); + + const vk::AttachmentReference attachmentReference ( + 0, + vk::ImageLayout::eColorAttachmentOptimal + ); + + const vk::SubpassDescription subpass ( + vk::SubpassDescriptionFlags(), + vk::PipelineBindPoint::eGraphics, + 0, + nullptr, + 1, + &attachmentReference, + nullptr, + nullptr, + 0, + nullptr + ); + + const vk::SubpassDependency dependency ( + VK_SUBPASS_EXTERNAL, + 0, + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::PipelineStageFlagBits::eColorAttachmentOutput, + vk::AccessFlags(), + vk::AccessFlagBits::eColorAttachmentWrite, + vk::DependencyFlags() + ); + + const vk::RenderPassCreateInfo passCreateInfo ( + vk::RenderPassCreateFlags(), + 1, + &attachment, + 1, + &subpass, + 1, + &dependency + ); + + m_render_pass = m_context.getDevice().createRenderPass(passCreateInfo); + + ImGui_ImplVulkan_Init(&init_info, m_render_pass); + + const SubmitInfo submitInfo { QueueType::Graphics, {}, {} }; + + m_core.recordAndSubmitCommands(submitInfo, [](const vk::CommandBuffer& commandBuffer) { + ImGui_ImplVulkan_CreateFontsTexture(commandBuffer); + }, []() { + ImGui_ImplVulkan_DestroyFontUploadObjects(); + }); + + m_context.getDevice().waitIdle(); + } + + GUI::~GUI() { + m_context.getDevice().waitIdle(); + + ImGui_ImplVulkan_Shutdown(); + + m_context.getDevice().destroyRenderPass(m_render_pass); + m_context.getDevice().destroyDescriptorPool(m_descriptor_pool); + + ImGui_ImplGlfw_Shutdown(); + + m_window.e_mouseButton.remove(f_mouseButton); + m_window.e_mouseScroll.remove(f_mouseScroll); + m_window.e_key.remove(f_key); + m_window.e_char.remove(f_char); + + if (m_gui_context) { + ImGui::DestroyContext(m_gui_context); + } + } + + void GUI::beginGUI() { + const Swapchain& swapchain = m_core.getSwapchain(); + const auto extent = swapchain.getExtent(); + + if ((extent.width > 0) && (extent.height > 0)) { + ImGui_ImplVulkan_SetMinImageCount(swapchain.getImageCount()); + } + + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + } + + void GUI::endGUI() { + ImGui::Render(); + + ImDrawData* drawData = ImGui::GetDrawData(); + + if ((!drawData) || + (drawData->DisplaySize.x <= 0.0f) || + (drawData->DisplaySize.y <= 0.0f)) { + return; + } + + const Swapchain& swapchain = m_core.getSwapchain(); + const auto extent = swapchain.getExtent(); + + const vk::ImageView swapchainImageView = m_core.getSwapchainImageView(); + + const vk::FramebufferCreateInfo framebufferCreateInfo ( + vk::FramebufferCreateFlags(), + m_render_pass, + 1, + &swapchainImageView, + extent.width, + extent.height, + 1 + ); + + const vk::Framebuffer framebuffer = m_context.getDevice().createFramebuffer(framebufferCreateInfo); + + SubmitInfo submitInfo; + submitInfo.queueType = QueueType::Graphics; + + m_core.recordAndSubmitCommands(submitInfo, [&](const vk::CommandBuffer& commandBuffer) { + const vk::Rect2D renderArea ( + vk::Offset2D(0, 0), + extent + ); + + const vk::RenderPassBeginInfo beginInfo ( + m_render_pass, + framebuffer, + renderArea, + 0, + nullptr + ); + + commandBuffer.beginRenderPass(beginInfo, vk::SubpassContents::eInline); + + ImGui_ImplVulkan_RenderDrawData(drawData, commandBuffer); + + commandBuffer.endRenderPass(); + }, [&]() { + m_context.getDevice().destroyFramebuffer(framebuffer); + }); + } + +} diff --git a/projects/cmd_sync_test/src/main.cpp b/projects/cmd_sync_test/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ec54582aac6b16a484b74183036539e91cfe731 --- /dev/null +++ b/projects/cmd_sync_test/src/main.cpp @@ -0,0 +1,317 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "First Mesh"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Window window = vkcv::Window::create( + applicationName, + windowWidth, + windowHeight, + true + ); + + vkcv::camera::CameraManager cameraManager(window); + uint32_t camIndex = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex2 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex).setPosition(glm::vec3(0.f, 0.f, 3.f)); + cameraManager.getCamera(camIndex).setNearFar(0.1f, 30.0f); + cameraManager.getCamera(camIndex).setYaw(180.0f); + + cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f); + + window.initEvents(); + + vkcv::Core core = vkcv::Core::create( + window, + applicationName, + VK_MAKE_VERSION(0, 0, 1), + { vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute }, + {}, + { "VK_KHR_swapchain" } + ); + + vkcv::asset::Scene mesh; + + const char* path = argc > 1 ? argv[1] : "resources/cube/cube.gltf"; + int result = vkcv::asset::loadScene(path, mesh); + + if (result == 1) { + std::cout << "Mesh loading successful!" << std::endl; + } + else { + std::cout << "Mesh loading failed: " << result << std::endl; + return 1; + } + + assert(mesh.vertexGroups.size() > 0); + auto vertexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::VERTEX, + mesh.vertexGroups[0].vertexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + + vertexBuffer.fill(mesh.vertexGroups[0].vertexBuffer.data); + + auto indexBuffer = core.createBuffer<uint8_t>( + vkcv::BufferType::INDEX, + mesh.vertexGroups[0].indexBuffer.data.size(), + vkcv::BufferMemoryType::DEVICE_LOCAL + ); + + indexBuffer.fill(mesh.vertexGroups[0].indexBuffer.data); + + auto& attributes = mesh.vertexGroups[0].vertexBuffer.attributes; + + std::sort(attributes.begin(), attributes.end(), [](const vkcv::asset::VertexAttribute& x, const vkcv::asset::VertexAttribute& y) { + return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type); + }); + + const std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = { + vkcv::VertexBufferBinding(attributes[0].offset, vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(attributes[1].offset, vertexBuffer.getVulkanHandle()), + vkcv::VertexBufferBinding(attributes[2].offset, vertexBuffer.getVulkanHandle()) }; + + const vkcv::Mesh loadedMesh(vertexBufferBindings, indexBuffer.getVulkanHandle(), mesh.vertexGroups[0].numIndices); + + // an example attachment for passes that output to the window + const vkcv::AttachmentDescription present_color_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain().getFormat() + ); + + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig firstMeshPassDefinition({ present_color_attachment, depth_attachment }); + vkcv::PassHandle firstMeshPass = core.createPass(firstMeshPassDefinition); + + if (!firstMeshPass) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram firstMeshProgram{}; + firstMeshProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("resources/shaders/vert.spv")); + firstMeshProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("resources/shaders/frag.spv")); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = firstMeshProgram.getVertexAttachments(); + + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const vkcv::VertexLayout firstMeshLayout (bindings); + + std::vector<vkcv::DescriptorBinding> descriptorBindings = { firstMeshProgram.getReflectedDescriptors()[0] }; + vkcv::DescriptorSetHandle descriptorSet = core.createDescriptorSet(descriptorBindings); + + const vkcv::PipelineConfig firstMeshPipelineConfig { + firstMeshProgram, + windowWidth, + windowHeight, + firstMeshPass, + firstMeshLayout, + { core.getDescriptorSet(descriptorSet).layout }, + true + }; + + vkcv::PipelineHandle firstMeshPipeline = core.createGraphicsPipeline(firstMeshPipelineConfig); + + if (!firstMeshPipeline) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + //vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h); + //texture.fill(mesh.texture_hack.img); + vkcv::asset::Texture &tex = mesh.textures[0]; + vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, tex.w, tex.h); + texture.fill(tex.data.data()); + + vkcv::SamplerHandle sampler = core.createSampler( + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerFilterType::LINEAR, + vkcv::SamplerMipmapMode::LINEAR, + vkcv::SamplerAddressMode::REPEAT + ); + + vkcv::SamplerHandle shadowSampler = core.createSampler( + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerFilterType::NEAREST, + vkcv::SamplerMipmapMode::NEAREST, + vkcv::SamplerAddressMode::CLAMP_TO_EDGE + ); + + vkcv::ImageHandle depthBuffer = core.createImage(vk::Format::eD32Sfloat, windowWidth, windowHeight).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + const vkcv::DescriptorSetUsage descriptorUsage(0, core.getDescriptorSet(descriptorSet).vulkanHandle); + + const std::vector<glm::vec3> instancePositions = { + glm::vec3( 0.f, -2.f, 0.f), + glm::vec3( 3.f, 0.f, 0.f), + glm::vec3(-3.f, 0.f, 0.f), + glm::vec3( 0.f, 2.f, 0.f), + glm::vec3( 0.f, -5.f, 0.f) + }; + + std::vector<glm::mat4> modelMatrices; + std::vector<vkcv::DrawcallInfo> drawcalls; + std::vector<vkcv::DrawcallInfo> shadowDrawcalls; + for (const auto& position : instancePositions) { + modelMatrices.push_back(glm::translate(glm::mat4(1.f), position)); + drawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, { descriptorUsage })); + shadowDrawcalls.push_back(vkcv::DrawcallInfo(loadedMesh, {})); + } + + modelMatrices.back() *= glm::scale(glm::mat4(1.f), glm::vec3(10.f, 1.f, 10.f)); + + std::vector<std::array<glm::mat4, 2>> mainPassMatrices; + std::vector<glm::mat4> mvpLight; + + vkcv::ShaderProgram shadowShader; + shadowShader.addShader(vkcv::ShaderStage::VERTEX, "resources/shaders/shadow_vert.spv"); + shadowShader.addShader(vkcv::ShaderStage::FRAGMENT, "resources/shaders/shadow_frag.spv"); + + const vk::Format shadowMapFormat = vk::Format::eD16Unorm; + const std::vector<vkcv::AttachmentDescription> shadowAttachments = { + vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat) + }; + const vkcv::PassConfig shadowPassConfig(shadowAttachments); + const vkcv::PassHandle shadowPass = core.createPass(shadowPassConfig); + + const uint32_t shadowMapResolution = 1024; + const vkcv::Image shadowMap = core.createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1); + const vkcv::PipelineConfig shadowPipeConfig { + shadowShader, + shadowMapResolution, + shadowMapResolution, + shadowPass, + firstMeshLayout, + {}, + false + }; + + const vkcv::PipelineHandle shadowPipe = core.createGraphicsPipeline(shadowPipeConfig); + + struct LightInfo { + glm::vec3 direction; + float padding; + glm::mat4 lightMatrix; + }; + LightInfo lightInfo; + vkcv::Buffer lightBuffer = core.createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3)); + + vkcv::DescriptorWrites setWrites; + setWrites.sampledImageWrites = { + vkcv::SampledImageDescriptorWrite(0, texture.getHandle()), + vkcv::SampledImageDescriptorWrite(3, shadowMap.getHandle()) }; + setWrites.samplerWrites = { + vkcv::SamplerDescriptorWrite(1, sampler), + vkcv::SamplerDescriptorWrite(4, shadowSampler) }; + setWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(2, lightBuffer.getHandle()) }; + core.writeDescriptorSet(descriptorSet, setWrites); + + auto start = std::chrono::system_clock::now(); + const auto appStartTime = start; + while (window.isWindowOpen()) { + vkcv::Window::pollEvents(); + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight)) { + continue; + } + + if ((swapchainWidth != windowWidth) || ((swapchainHeight != windowHeight))) { + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + windowWidth = swapchainWidth; + windowHeight = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - appStartTime); + + const float sunTheta = 0.001f * static_cast<float>(duration.count()); + lightInfo.direction = glm::normalize(glm::vec3(std::cos(sunTheta), 1, std::sin(sunTheta))); + + const float shadowProjectionSize = 5.f; + glm::mat4 projectionLight = glm::ortho( + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize, + -shadowProjectionSize, + shadowProjectionSize); + + glm::mat4 vulkanCorrectionMatrix(1.f); + vulkanCorrectionMatrix[2][2] = 0.5; + vulkanCorrectionMatrix[3][2] = 0.5; + projectionLight = vulkanCorrectionMatrix * projectionLight; + + const glm::mat4 viewLight = glm::lookAt(glm::vec3(0), -lightInfo.direction, glm::vec3(0, -1, 0)); + + lightInfo.lightMatrix = projectionLight * viewLight; + lightBuffer.fill({ lightInfo }); + + const glm::mat4 viewProjectionCamera = cameraManager.getActiveCamera().getMVP(); + + mainPassMatrices.clear(); + mvpLight.clear(); + for (const auto& m : modelMatrices) { + mainPassMatrices.push_back({ viewProjectionCamera * m, m }); + mvpLight.push_back(lightInfo.lightMatrix* m); + } + + vkcv::PushConstantData pushConstantData((void*)mainPassMatrices.data(), 2 * sizeof(glm::mat4)); + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + + vkcv::PushConstantData shadowPushConstantData((void*)mvpLight.data(), sizeof(glm::mat4)); + + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + core.recordDrawcallsToCmdStream( + cmdStream, + shadowPass, + shadowPipe, + shadowPushConstantData, + shadowDrawcalls, + { shadowMap.getHandle() }); + + core.prepareImageForSampling(cmdStream, shadowMap.getHandle()); + + core.recordDrawcallsToCmdStream( + cmdStream, + firstMeshPass, + firstMeshPipeline, + pushConstantData, + drawcalls, + renderTargets); + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + core.endFrame(); + } + + return 0; +} diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index ed67af878dcd594154361aaec11e85ab6ab3d79d..d9650f3577cf5633ac915f435b59367a9f993d62 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -63,7 +63,7 @@ int main(int argc, const char** argv) { const vkcv::AttachmentDescription present_color_attachment( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, - core.getSwapchainImageFormat() + core.getSwapchain().getFormat() ); const vkcv::AttachmentDescription depth_attachment( diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp index 5a59edf7549dfd50877e78e3ca5071bba72098b3..00a862cfd77b522e9d83b51e703ea48ce45e5d5c 100644 --- a/projects/first_scene/src/main.cpp +++ b/projects/first_scene/src/main.cpp @@ -112,7 +112,7 @@ int main(int argc, const char** argv) { const vkcv::AttachmentDescription present_color_attachment( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, - core.getSwapchainImageFormat() + core.getSwapchain().getFormat() ); const vkcv::AttachmentDescription depth_attachment( diff --git a/projects/first_triangle/CMakeLists.txt b/projects/first_triangle/CMakeLists.txt index 7e606b2348ea82486c2a57ee1062ef34150e46a0..ba8c83c06fc804082e6a0a14c3c0414899ef3057 100644 --- a/projects/first_triangle/CMakeLists.txt +++ b/projects/first_triangle/CMakeLists.txt @@ -22,7 +22,7 @@ if(MSVC) endif() # including headers of dependencies and the VkCV framework -target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include}) +target_include_directories(first_triangle SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_testing_include} ${vkcv_camera_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) # linking with libraries from all dependencies and the VkCV framework -target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler) +target_link_libraries(first_triangle vkcv vkcv_testing vkcv_camera vkcv_shader_compiler vkcv_gui) diff --git a/projects/first_triangle/shaders/shader.frag b/projects/first_triangle/shaders/shader.frag index d26446a73020111695aa2c86166205796dfa5e44..080678beb011afe4b03aed3bf7ae7148b77932dc 100644 --- a/projects/first_triangle/shaders/shader.frag +++ b/projects/first_triangle/shaders/shader.frag @@ -4,6 +4,6 @@ layout(location = 0) in vec3 fragColor; layout(location = 0) out vec4 outColor; -void main() { +void main() { outColor = vec4(fragColor, 1.0); } \ No newline at end of file diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 1c6f96041874a262b481727caf41e0b1142f5570..5a962b8983f6735530b38de5be679096fa997bd5 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -5,6 +5,7 @@ #include <chrono> #include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/gui/GUI.hpp> int main(int argc, const char** argv) { const char* applicationName = "First Triangle"; @@ -28,6 +29,8 @@ int main(int argc, const char** argv) { {}, { "VK_KHR_swapchain" } ); + + vkcv::gui::GUI gui (core, window); const auto& context = core.getContext(); const vk::Instance& instance = context.getInstance(); @@ -81,7 +84,7 @@ int main(int argc, const char** argv) { const vkcv::AttachmentDescription present_color_attachment( vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, - core.getSwapchainImageFormat()); + core.getSwapchain().getFormat()); vkcv::PassConfig trianglePassDefinition({ present_color_attachment }); vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); @@ -215,6 +218,14 @@ int main(int argc, const char** argv) { core.prepareSwapchainImageForPresent(cmdStream); core.submitCommandStream(cmdStream); + + gui.beginGUI(); + + ImGui::Begin("Hello world"); + ImGui::Text("This is a test!"); + ImGui::End(); + + gui.endGUI(); core.endFrame(); } diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp index b2d1303053f02366912e25bf8bd8871ea9e0d096..554a6ee05c4327f169ceca87b639de8a95e0613b 100644 --- a/projects/voxelization/src/main.cpp +++ b/projects/voxelization/src/main.cpp @@ -7,6 +7,7 @@ #include <vkcv/shader/GLSLCompiler.hpp> #include <vkcv/Logger.hpp> #include "Voxelization.hpp" +#include <glm/glm.hpp> int main(int argc, const char** argv) { const char* applicationName = "Voxelization"; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 86d8b518bb5ddb4056d03e4ccecdffc6a710acb0..fd2c595b4305740e801e8d3d50af74521fc3418c 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -35,7 +35,7 @@ namespace vkcv deviceExtensions ); - SwapChain swapChain = SwapChain::create(window, context); + Swapchain swapChain = Swapchain::create(window, context); std::vector<vk::ImageView> swapchainImageViews = createSwapchainImageViews( context, swapChain); @@ -53,8 +53,12 @@ namespace vkcv { return m_Context; } + + const Swapchain& Core::getSwapchain() const { + return m_swapchain; + } - Core::Core(Context &&context, Window &window, const SwapChain& swapChain, std::vector<vk::ImageView> swapchainImageViews, + Core::Core(Context &&context, Window &window, const Swapchain& swapChain, std::vector<vk::ImageView> swapchainImageViews, const CommandResources& commandResources, const SyncResources& syncResources) noexcept : m_Context(std::move(context)), m_window(window), @@ -74,8 +78,8 @@ namespace vkcv m_CommandStreamManager->init(this); m_ImageManager->m_core = this; - - e_resizeHandle = window.e_resize.add( [&](int width, int height) { + + e_resizeHandle = m_window.e_resize.add( [&](int width, int height) { m_swapchain.signalSwapchainRecreation(); }); @@ -85,10 +89,12 @@ namespace vkcv swapchainImageViews, swapChain.getExtent().width, swapChain.getExtent().height, - swapChain.getSwapchainFormat()); + swapChain.getFormat()); } Core::~Core() noexcept { + m_window.e_resize.remove(e_resizeHandle); + m_Context.getDevice().waitIdle(); destroyCommandResources(m_Context.getDevice(), m_CommandResources); @@ -150,7 +156,7 @@ namespace vkcv const auto swapchainViews = createSwapchainImageViews(m_Context, m_swapchain); const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); - m_ImageManager->setSwapchainImages(swapchainImages, swapchainViews, width, height, m_swapchain.getSwapchainFormat()); + m_ImageManager->setSwapchainImages(swapchainImages, swapchainViews, width, height, m_swapchain.getFormat()); } if (acquireSwapchainImage() != Result::SUCCESS) { @@ -223,7 +229,6 @@ namespace vkcv attachmentsViews.push_back(targetHandle); } - vk::Framebuffer framebuffer = nullptr; const vk::FramebufferCreateInfo createInfo( {}, renderpass, @@ -231,16 +236,21 @@ namespace vkcv attachmentsViews.data(), width, height, - 1); - if(m_Context.m_Device.createFramebuffer(&createInfo, nullptr, &framebuffer) != vk::Result::eSuccess) - { + 1 + ); + + vk::Framebuffer framebuffer = m_Context.m_Device.createFramebuffer(createInfo); + + if (!framebuffer) { vkcv_log(LogLevel::ERROR, "Failed to create temporary framebuffer"); return; } - vk::Viewport dynamicViewport(0.0f, 0.0f, - static_cast<float>(width), static_cast<float>(height), - 0.0f, 1.0f); + vk::Viewport dynamicViewport( + 0.0f, 0.0f, + static_cast<float>(width), static_cast<float>(height), + 0.0f, 1.0f + ); vk::Rect2D dynamicScissor({0, 0}, {width, height}); @@ -340,15 +350,17 @@ namespace vkcv const auto swapchainImages = m_Context.getDevice().getSwapchainImagesKHR(m_swapchain.getSwapchain()); const auto& queueManager = m_Context.getQueueManager(); - std::array<vk::Semaphore, 2> waitSemaphores{ - m_SyncResources.renderFinished, - m_SyncResources.swapchainImageAcquired }; + std::array<vk::Semaphore, 2> waitSemaphores{ + m_SyncResources.renderFinished, + m_SyncResources.swapchainImageAcquired + }; const vk::SwapchainKHR& swapchain = m_swapchain.getSwapchain(); const vk::PresentInfoKHR presentInfo( waitSemaphores, swapchain, - m_currentSwapchainImageIndex); + m_currentSwapchainImageIndex + ); vk::Result result; @@ -362,10 +374,6 @@ namespace vkcv vkcv_log(LogLevel::ERROR, "Swapchain present failed (%s)", vk::to_string(result).c_str()); } } - - vk::Format Core::getSwapchainImageFormat() { - return m_swapchain.getSwapchainFormat(); - } void Core::recordAndSubmitCommands( const SubmitInfo &submitInfo, @@ -381,11 +389,19 @@ namespace vkcv beginCommandBuffer(cmdBuffer, vk::CommandBufferUsageFlagBits::eOneTimeSubmit); record(cmdBuffer); cmdBuffer.end(); - - const vk::Fence waitFence = createFence(device); + + vk::Fence waitFence; + + if (!submitInfo.fence) { + waitFence = createFence(device); + } + submitCommandBufferToQueue(queue.handle, cmdBuffer, waitFence, submitInfo.waitSemaphores, submitInfo.signalSemaphores); waitForFence(device, waitFence); - device.destroyFence(waitFence); + + if (!submitInfo.fence) { + device.destroyFence(waitFence); + } device.freeCommandBuffers(cmdPool, cmdBuffer); @@ -449,7 +465,7 @@ namespace vkcv return m_DescriptorManager->getDescriptorSet(handle); } - std::vector<vk::ImageView> Core::createSwapchainImageViews( Context &context, SwapChain& swapChain){ + std::vector<vk::ImageView> Core::createSwapchainImageViews( Context &context, Swapchain& swapChain){ std::vector<vk::ImageView> imageViews; std::vector<vk::Image> swapChainImages = context.getDevice().getSwapchainImagesKHR(swapChain.getSwapchain()); imageViews.reserve( swapChainImages.size() ); @@ -468,7 +484,7 @@ namespace vkcv vk::ImageViewCreateFlags(), image, vk::ImageViewType::e2D, - swapChain.getSwapchainFormat(), + swapChain.getFormat(), componentMapping, subResourceRange); @@ -507,4 +523,9 @@ namespace vkcv m_BufferManager->recordBufferMemoryBarrier(buffer, cmdBuffer); }, nullptr); } + + const vk::ImageView& Core::getSwapchainImageView() const { + return m_ImageManager->getVulkanImageView(vkcv::ImageHandle::createSwapchainImageHandle()); + } + } diff --git a/src/vkcv/SwapChain.cpp b/src/vkcv/Swapchain.cpp similarity index 88% rename from src/vkcv/SwapChain.cpp rename to src/vkcv/Swapchain.cpp index a6e1f2a141be71f7f296ad66a5a64341f370b379..33714adac7cec7c1b5e0013387424c4f865454ab 100644 --- a/src/vkcv/SwapChain.cpp +++ b/src/vkcv/Swapchain.cpp @@ -1,4 +1,4 @@ -#include <vkcv/SwapChain.hpp> +#include <vkcv/Swapchain.hpp> #include <utility> #define GLFW_INCLUDE_VULKAN @@ -27,44 +27,44 @@ namespace vkcv return vk::SurfaceKHR(surface); } - SwapChain::SwapChain(const Surface &surface, + Swapchain::Swapchain(const Surface &surface, vk::SwapchainKHR swapchain, vk::Format format, vk::ColorSpaceKHR colorSpace, vk::PresentModeKHR presentMode, uint32_t imageCount, vk::Extent2D extent) noexcept : - m_Surface(surface), - m_Swapchain(swapchain), - m_SwapchainFormat(format), - m_SwapchainColorSpace(colorSpace), - m_SwapchainPresentMode(presentMode), - m_SwapchainImageCount(imageCount), - m_Extent(extent), - m_RecreationRequired(false) + m_Surface(surface), + m_Swapchain(swapchain), + m_Format(format), + m_ColorSpace(colorSpace), + m_PresentMode(presentMode), + m_ImageCount(imageCount), + m_Extent(extent), + m_RecreationRequired(false) {} - SwapChain::SwapChain(const SwapChain &other) : + Swapchain::Swapchain(const Swapchain &other) : m_Surface(other.m_Surface), m_Swapchain(other.m_Swapchain), - m_SwapchainFormat(other.m_SwapchainFormat), - m_SwapchainColorSpace(other.m_SwapchainColorSpace), - m_SwapchainPresentMode(other.m_SwapchainPresentMode), - m_SwapchainImageCount(other.m_SwapchainImageCount), + m_Format(other.m_Format), + m_ColorSpace(other.m_ColorSpace), + m_PresentMode(other.m_PresentMode), + m_ImageCount(other.m_ImageCount), m_Extent(other.m_Extent), m_RecreationRequired(other.m_RecreationRequired.load()) {} - const vk::SwapchainKHR& SwapChain::getSwapchain() const { + const vk::SwapchainKHR& Swapchain::getSwapchain() const { return m_Swapchain; } - vk::SurfaceKHR SwapChain::getSurface() const { + vk::SurfaceKHR Swapchain::getSurface() const { return m_Surface.handle; } - vk::Format SwapChain::getSwapchainFormat() const{ - return m_SwapchainFormat; + vk::Format Swapchain::getFormat() const{ + return m_Format; } /** @@ -162,7 +162,7 @@ namespace vkcv * @param context that keeps instance, physicalDevice and a device. * @return swapchain */ - SwapChain SwapChain::create(const Window &window, const Context &context) { + Swapchain Swapchain::create(const Window &window, const Context &context) { const vk::Instance& instance = context.getInstance(); const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice(); const vk::Device& device = context.getDevice(); @@ -199,7 +199,7 @@ namespace vkcv vk::SwapchainKHR swapchain = device.createSwapchainKHR(swapchainCreateInfo); - return SwapChain(surface, + return Swapchain(surface, swapchain, chosenSurfaceFormat.format, chosenSurfaceFormat.colorSpace, @@ -208,11 +208,11 @@ namespace vkcv chosenExtent); } - bool SwapChain::shouldUpdateSwapchain() const { + bool Swapchain::shouldUpdateSwapchain() const { return m_RecreationRequired; } - void SwapChain::updateSwapchain(const Context &context, const Window &window) { + void Swapchain::updateSwapchain(const Context &context, const Window &window) { if (!m_RecreationRequired.exchange(false)) return; @@ -222,9 +222,9 @@ namespace vkcv vk::SwapchainCreateInfoKHR swapchainCreateInfo( vk::SwapchainCreateFlagsKHR(), m_Surface.handle, - m_SwapchainImageCount, - m_SwapchainFormat, - m_SwapchainColorSpace, + m_ImageCount, + m_Format, + m_ColorSpace, extent2D, 1, vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage, @@ -233,7 +233,7 @@ namespace vkcv nullptr, vk::SurfaceTransformFlagBitsKHR::eIdentity, vk::CompositeAlphaFlagBitsKHR::eOpaque, - m_SwapchainPresentMode, + m_PresentMode, true, oldSwapchain ); @@ -244,19 +244,19 @@ namespace vkcv m_Extent = extent2D; } - void SwapChain::signalSwapchainRecreation() { + void Swapchain::signalSwapchainRecreation() { m_RecreationRequired = true; } - const vk::Extent2D& SwapChain::getExtent() const { + const vk::Extent2D& Swapchain::getExtent() const { return m_Extent; } - SwapChain::~SwapChain() { + Swapchain::~Swapchain() { // needs to be destroyed by creator } - uint32_t SwapChain::getImageCount() { - return m_SwapchainImageCount; + uint32_t Swapchain::getImageCount() const { + return m_ImageCount; } } diff --git a/src/vkcv/Window.cpp b/src/vkcv/Window.cpp index c21271b78f7501721d5c0496d0344dd68e2e7e52..2436619300c24f035cba727481dfce8e1b397c9b 100644 --- a/src/vkcv/Window.cpp +++ b/src/vkcv/Window.cpp @@ -24,22 +24,25 @@ namespace vkcv { glfwTerminate(); } } + + GLFWwindow* Window::createGLFWWindow(const char *windowTitle, int width, int height, bool resizable) { + if(s_WindowCount == 0) { + glfwInit(); + } + + s_WindowCount++; + + width = std::max(width, 1); + height = std::max(height, 1); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); + + return glfwCreateWindow(width, height, windowTitle, nullptr, nullptr); + } Window Window::create( const char *windowTitle, int width, int height, bool resizable) { - if(s_WindowCount == 0) { - glfwInit(); - } - s_WindowCount++; - - width = std::max(width, 1); - height = std::max(height, 1); - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - glfwWindowHint(GLFW_RESIZABLE, resizable ? GLFW_TRUE : GLFW_FALSE); - GLFWwindow *window; - window = glfwCreateWindow(width, height, windowTitle, nullptr, nullptr); - - return Window(window); + return Window(createGLFWWindow(windowTitle, width, height, resizable)); } void Window::initEvents() { @@ -55,6 +58,8 @@ namespace vkcv { glfwSetKeyCallback(m_window, Window::onKeyEvent); glfwSetScrollCallback(m_window, Window::onMouseScrollEvent); + + glfwSetCharCallback(m_window, Window::onCharEvent); } void Window::pollEvents() { @@ -62,7 +67,6 @@ namespace vkcv { } void Window::onMouseButtonEvent(GLFWwindow *callbackWindow, int button, int action, int mods) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -71,7 +75,6 @@ namespace vkcv { } void Window::onMouseMoveEvent(GLFWwindow *callbackWindow, double x, double y) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -88,7 +91,6 @@ namespace vkcv { } void Window::onResize(GLFWwindow *callbackWindow, int width, int height) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { @@ -97,13 +99,20 @@ namespace vkcv { } void Window::onKeyEvent(GLFWwindow *callbackWindow, int key, int scancode, int action, int mods) { - auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); if (window != nullptr) { window->e_key(key, scancode, action, mods); } } + + void Window::onCharEvent(GLFWwindow *callbackWindow, unsigned int c) { + auto window = static_cast<Window *>(glfwGetWindowUserPointer(callbackWindow)); + + if (window != nullptr) { + window->e_char(c); + } + } bool Window::isWindowOpen() const { return !glfwWindowShouldClose(m_window);