diff --git a/CMakeLists.txt b/CMakeLists.txt index 1180d53..f7ea71b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,10 +98,20 @@ if (MINGW) target_link_libraries(${PROJECT_NAME} PUBLIC mingw32) endif() -# Vulkan -find_package(Vulkan REQUIRED) -target_include_directories(${PROJECT_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS}) -target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) +# GLAD: +set(GLAD_PROFILE "core" CACHE INTERNAL "" FORCE) +set(GLAD_API "gl=3.3" CACHE INTERNAL "" FORCE) +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(GLAD_GENERATOR "c-debug" CACHE INTERNAL "" FORCE) +else() + set(GLAD_GENERATOR "c" CACHE INTERNAL "" FORCE) +endif() +set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE) +set(BUILD_SHARED_LIBS OFF) +add_subdirectory(dependencies/glad) +set_property(TARGET glad PROPERTY POSITION_INDEPENDENT_CODE ON) +target_link_libraries(${PROJECT_NAME} PUBLIC glad) +target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include) # SDL2: find_package(SDL2) @@ -124,21 +134,6 @@ set(BUILD_SHARED_LIBS OFF) add_subdirectory(dependencies/glm) target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glm) -# GLAD: -set(GLAD_PROFILE "core" CACHE INTERNAL "" FORCE) -set(GLAD_API "gl=3.3" CACHE INTERNAL "" FORCE) -if (CMAKE_BUILD_TYPE STREQUAL "Debug") - set(GLAD_GENERATOR "c-debug" CACHE INTERNAL "" FORCE) -else() - set(GLAD_GENERATOR "c" CACHE INTERNAL "" FORCE) -endif() -set(GLAD_SPEC "gl" CACHE INTERNAL "" FORCE) -set(BUILD_SHARED_LIBS OFF) -add_subdirectory(dependencies/glad) -set_property(TARGET glad PROPERTY POSITION_INDEPENDENT_CODE ON) -target_link_libraries(${PROJECT_NAME} PUBLIC glad) -target_include_directories(${PROJECT_NAME} PUBLIC dependencies/glad/include) - # spdlog set(SPDLOG_BUILD_SHARED ON CACHE INTERNAL "" FORCE) set(BUILD_SHARED_LIBS ON) diff --git a/include/gfx_device.hpp b/include/gfx_device.hpp index 3a454e5..b5288d1 100644 --- a/include/gfx_device.hpp +++ b/include/gfx_device.hpp @@ -15,7 +15,7 @@ namespace engine::gfx { private: class Impl; - std::unique_ptr pimpl{}; + std::unique_ptr pimpl; }; diff --git a/include/window.hpp b/include/window.hpp index 1079d83..2633ad6 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -28,25 +28,10 @@ public: // Return the title name std::string getTitle() const; - // Make this window the current OpenGL context. - // This is already done in window initialisation. - void makeContextCurrent(); - - // Tell the GPU to render the back buffer to the screen. - // Run this on every frame. - void swapBuffers(); // Update the window state to capture any events that have occurred. // Run this on every frame. void getInputAndEvents(); - // if 'true', swapBuffers() will wait in order to synchronise with the - // monitor's refresh rate. - void setVSync(bool enable); - // Returns true if VSync is enabled. - bool getVSync() const; - - glm::ivec2 getViewportSize(); - void setTitle(std::string title); // Hides the window (it will appear closed to the user). @@ -146,7 +131,6 @@ public: private: SDL_Window* m_handle; - SDL_GLContext m_glContext; bool m_shouldClose = false; @@ -158,8 +142,6 @@ public: // size in screen coordinates glm::ivec2 m_winSize = glm::vec2(640, 480); - // actual framebuffer size - glm::ivec2 m_fbSize; // performance counter frequency uint64_t m_counterFreq; diff --git a/src/components/camera.cpp b/src/components/camera.cpp index edc035b..3c83fdc 100644 --- a/src/components/camera.cpp +++ b/src/components/camera.cpp @@ -54,7 +54,7 @@ void Camera::updateCam(glm::mat4 transform) auto shader = dynamic_cast(lockedPtr.get()); shader->setUniform_m4(VIEW_MAT_UNIFORM, viewMatrix); shader->setUniform_m4(PROJ_MAT_UNIFORM, m_projMatrix); - shader->setUniform_v2(WINDOW_SIZE_UNIFORM, win.getViewportSize()); +// shader->setUniform_v2(WINDOW_SIZE_UNIFORM, win.getViewportSize()); shader->setUniform_v3("lightPos", m_lightPos); } diff --git a/src/gfx_device_vulkan.cpp b/src/gfx_device_vulkan.cpp index 67448e3..7db4f4e 100644 --- a/src/gfx_device_vulkan.cpp +++ b/src/gfx_device_vulkan.cpp @@ -6,10 +6,14 @@ #include "window.hpp" +#include "log.hpp" + #include #include + #include +#include namespace engine::gfx { @@ -17,48 +21,192 @@ namespace engine::gfx { friend Device; VkInstance m_instance; +#ifndef NDEBUG + VkDebugUtilsMessengerEXT m_debugMessenger; +#endif + + static constexpr const char * VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation"; + static constexpr VkDebugUtilsMessageSeverityFlagBitsEXT MESSAGE_LEVEL = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + + std::vector m_layersAvailable{}; + std::optional::iterator> m_validationLayer; + + + + void findAvailableLayers() + { + VkResult res; + + uint32_t layerCount; + res = vkEnumerateInstanceLayerProperties(&layerCount, nullptr); + assert(res == VK_SUCCESS); + m_layersAvailable.resize(layerCount); + res = vkEnumerateInstanceLayerProperties(&layerCount, m_layersAvailable.data()); + assert(res == VK_SUCCESS); + +#ifndef NDEBUG + for (auto it = m_layersAvailable.begin(); it != m_layersAvailable.end(); it++) { + TRACE("Found Vulkan layer: {}, {}", it->layerName, it->description); + if (strncmp(it->layerName, VALIDATION_LAYER_NAME, 256) == 0) { + m_validationLayer = it; + } + } + if (m_validationLayer.has_value() == false) { + WARN("The validation layer was not found. Continuing."); + } +#endif + } + + void createInstance(AppInfo appInfo, const std::vector& windowExtensions) + { + VkResult res; + + int appVersionMajor, appVersionMinor, appVersionPatch; + assert(versionFromCharArray(appInfo.version, &appVersionMajor, &appVersionMinor, &appVersionPatch)); + int engineVersionMajor, engineVersionMinor, engineVersionPatch; + assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch)); + + VkApplicationInfo applicationInfo { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = appInfo.name, + .applicationVersion = VK_MAKE_VERSION(appVersionMajor, appVersionMinor, appVersionPatch), + .pEngineName = "engine", + .engineVersion = VK_MAKE_VERSION(engineVersionMajor, engineVersionMinor, engineVersionPatch), + .apiVersion = VK_API_VERSION_1_0, + }; + + // make a list of all extensions to use + std::vector extensions{}; + extensions.insert(extensions.end(), windowExtensions.begin(), windowExtensions.end()); +#ifndef NDEBUG + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); +#endif + + std::vector layers{}; + +#ifndef NDEBUG + if (m_validationLayer.has_value()) + layers.push_back(m_validationLayer.value()->layerName); +#endif + + VkInstanceCreateInfo instanceInfo { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .pApplicationInfo = &applicationInfo, + .enabledLayerCount = (uint32_t)layers.size(), + .ppEnabledLayerNames = layers.data(), + .enabledExtensionCount = (uint32_t)extensions.size(), + .ppEnabledExtensionNames = extensions.data(), + }; + + res = vkCreateInstance(&instanceInfo, nullptr, &m_instance); + if (res == VK_ERROR_INCOMPATIBLE_DRIVER) { + CRITICAL("The graphics driver is incompatible with vulkan"); + throw std::runtime_error("Graphics driver is incompatible with Vulkan"); + } + assert(res == VK_SUCCESS); + } + +#ifndef NDEBUG + static VkBool32 debugMessenger( + VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageTypes, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) + { + + std::string msgType{}; + + if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) + msgType += " (GENERAL)"; + if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT) + msgType += " (PERF.)"; + if (messageTypes & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT) + msgType += " (VALID.)"; + + switch (messageSeverity) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + TRACE("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + INFO("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + WARN("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); + break; + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + ERROR("VULKAN MESSAGE{}: ID: {} MSG: {}", msgType, pCallbackData->pMessageIdName, pCallbackData->pMessage); + break; + default: + break; + } + return VK_FALSE; + } +#endif + + void createDebugMessenger() + { +#ifndef NDEBUG + VkResult res; + + if (m_validationLayer.has_value() == false) return; + + VkDebugUtilsMessengerCreateInfoEXT createInfo { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = 0, + .messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, + .pfnUserCallback = debugMessenger, + .pUserData = nullptr, + }; + + switch (MESSAGE_LEVEL) { + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: + createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT; + // fall-through + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: + createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT; + // fall-through + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: + createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; + // fall-through + case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: + createInfo.messageSeverity |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + // fall-through + default: + break; + } + + res = vkCreateDebugUtilsMessengerEXT(m_instance, &createInfo, nullptr, &m_debugMessenger); + assert(res == VK_SUCCESS); +#endif + } + + }; - Device::Device(AppInfo appInfo, const Window& window) + + + Device::Device(AppInfo appInfo, const Window& window) : pimpl(std::make_unique()) { - VkResult res; - - int appVersionMajor, appVersionMinor, appVersionPatch; - assert(versionFromCharArray(appInfo.version, &appVersionMajor, &appVersionMinor, &appVersionPatch)); - int engineVersionMajor, engineVersionMinor, engineVersionPatch; - assert(versionFromCharArray(ENGINE_VERSION, &engineVersionMajor, &engineVersionMinor, &engineVersionPatch)); - - VkApplicationInfo applicationInfo{ - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .pApplicationName = appInfo.name, - .applicationVersion = VK_MAKE_VERSION(appVersionMajor, appVersionMinor, appVersionPatch), - .pEngineName = "engine", - .engineVersion = VK_MAKE_VERSION(engineVersionMajor, engineVersionMinor, engineVersionPatch), - .apiVersion = VK_VERSION_1_0, - }; - - VkInstanceCreateInfo instanceInfo{ - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .pApplicationInfo = nullptr, - .enabledLayerCount = 0, - .ppEnabledLayerNames = nullptr, - .enabledExtensionCount = 0, - .ppEnabledExtensionNames = nullptr, - }; - - res = vkCreateInstance(&instanceInfo, nullptr, &pimpl->m_instance); - std::cout << "ERROR CODE: " << res << std::endl; - assert(res == VK_SUCCESS); - + pimpl->findAvailableLayers(); + pimpl->createInstance(appInfo, window.getRequiredVulkanExtensions()); + pimpl->createDebugMessenger(); } Device::~Device() { vkDestroyInstance(pimpl->m_instance, nullptr); +#ifndef NDEBUG + vkDestroyDebugUtilsMessengerEXT(pimpl->m_instance, pimpl->m_debugMessenger, nullptr); +#endif } } diff --git a/src/window.cpp b/src/window.cpp index 87a6669..e8e6829 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1,7 +1,5 @@ #include "window.hpp" -#include - #include #include @@ -28,17 +26,13 @@ Window::Window(const std::string& title) : m_title(title) m_lastFrameStamp = m_startTime - 1; m_avgFpsStart = m_startTime; - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - // create the window m_handle = SDL_CreateWindow( m_title.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, static_cast(m_winSize.x), static_cast(m_winSize.y), - SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI); + 0); if (m_handle == NULL) { SDL_Quit(); throw std::runtime_error("Unable to create window: " + std::string(SDL_GetError())); @@ -54,6 +48,7 @@ Window::Window(const std::string& title) : m_title(title) const int WINDOWED_MIN_HEIGHT = 480; SDL_SetWindowMinimumSize(m_handle, WINDOWED_MIN_WIDTH, WINDOWED_MIN_HEIGHT); + /* m_glContext = SDL_GL_CreateContext(m_handle); if (m_glContext == NULL) { SDL_DestroyWindow(m_handle); @@ -66,14 +61,14 @@ Window::Window(const std::string& title) : m_title(title) SDL_Quit(); throw std::runtime_error("Unable to initialise GLAD"); } + */ - onResize(m_winSize.x, m_winSize.y); +// onResize(m_winSize.x, m_winSize.y); } Window::~Window() { - SDL_GL_DeleteContext(m_glContext); SDL_DestroyWindow(m_handle); SDL_Quit(); } @@ -86,13 +81,6 @@ void Window::onResize(Sint32 width, Sint32 height) m_winSize.x = static_cast(width); m_winSize.y = static_cast(height); - // get framebuffer size - int fbWidth, fbHeight; - SDL_GL_GetDrawableSize(m_handle, &fbWidth, &fbHeight); - m_fbSize.x = static_cast(fbWidth); - m_fbSize.y = static_cast(fbHeight); - glViewport(0, 0, fbWidth, fbHeight); - m_justResized = true; } @@ -195,26 +183,13 @@ std::string Window::getTitle() const return m_title; } -void Window::makeContextCurrent() +void Window::getInputAndEvents() { - if (SDL_GL_MakeCurrent(m_handle, m_glContext) != 0) { - throw std::runtime_error("Failed to make GL context current"); - } -} -void Window::swapBuffers() -{ -#ifndef SDLTEST_NOGFX - SDL_GL_SwapWindow(m_handle); -#endif m_frames++; uint64_t currentFrameStamp = getNanos(); m_lastFrameTime = currentFrameStamp - m_lastFrameStamp; m_lastFrameStamp = currentFrameStamp; -} - -void Window::getInputAndEvents() -{ resetInputDeltas(); @@ -254,23 +229,6 @@ void Window::getInputAndEvents() } -void Window::setVSync(bool enable) -{ - if (SDL_GL_SetSwapInterval(enable ? 1 : 0) != 0) { - throw std::runtime_error("Failed to set swap interval"); - } -} - -bool Window::getVSync() const -{ - return SDL_GL_GetSwapInterval() == 0 ? false : true; -} - -glm::ivec2 Window::getViewportSize() -{ - return m_fbSize; -} - void Window::setTitle(std::string title) { SDL_SetWindowTitle(m_handle, title.c_str());