diff --git a/src/Magnum/Vk/Context.cpp b/src/Magnum/Vk/Context.cpp new file mode 100644 index 000000000..387535d5b --- /dev/null +++ b/src/Magnum/Vk/Context.cpp @@ -0,0 +1,164 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 + Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Context.h" + +#include +#include +#include +#include "vulkan.h" + +PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback; +PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback; +PFN_vkDebugReportMessageEXT dbgBreakCallback; + +VkDebugReportCallbackEXT msgCallback; + +namespace Magnum { namespace Vk { + +const char *validationLayerNames[] = +{ + // This is a meta layer that enables all of the standard + // validation layers in the correct order : + // threading, parameter_validation, device_limits, object_tracker, image, core_validation, swapchain, and unique_objects + "VK_LAYER_LUNARG_standard_validation" +}; + +Context* Context::_current = nullptr; + +bool Context::hasCurrent() { return _current; } + +Context& Context::current() { + CORRADE_ASSERT(_current, "Context::current(): no current context", *_current); + return *_current; +} + +Context::Context(NoCreateT, Int argc, char** argv, void functionLoader()): _functionLoader{functionLoader}, _version{Version::None} { + Utility::Arguments args{"magnum"}; + args.parse(argc, argv); +} + +Context::Context(Flags flags): _functionLoader{nullptr}, _version{Version::None}, _flags(flags) { + create(); +} + +Context::Context(Context&& other): _version{std::move(other._version)}, + _flags{std::move(other._flags)} +{ + if(_current == &other) _current = this; +} + +Context::~Context() { + if(_current == this) _current = nullptr; + + if(_instance == nullptr) { + Error() << "No VkInstance to destroy"; + return; + } + + if (_flags >= Flag::EnableValidation) { + DestroyDebugReportCallback(_instance, msgCallback, nullptr); + } + vkDestroyInstance(_instance, nullptr); +} + +void Context::create() { + /* Hard exit if the context cannot be created */ + if(!tryCreate()) std::exit(1); +} + +VkBool32 messageCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, + uint64_t srcObject, size_t location, int32_t msgCode, const char* pLayerPrefix, const char* pMsg, void* pUserData) { + + if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) { + Error() << "[" << pLayerPrefix << "] Code" << msgCode << ":" << pMsg; + } else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT) { + Warning() << "[" << pLayerPrefix << "] Code" << msgCode << ":" << pMsg; + } + + return false; +} + +bool Context::tryCreate() { + VkApplicationInfo appInfo = {}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "Vulkan Example"; + appInfo.pEngineName = "Magnum"; + appInfo.apiVersion = UnsignedInt(Version::Vulkan_1_0); + + std::vector enabledExtensions = { VK_KHR_SURFACE_EXTENSION_NAME }; + + // Enable surface extensions depending on os + //enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + + VkInstanceCreateInfo instanceCreateInfo = {}; + instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceCreateInfo.pNext = nullptr; + instanceCreateInfo.pApplicationInfo = &appInfo; + if (_flags >= Flag::EnableValidation) { + enabledExtensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + + instanceCreateInfo.enabledLayerCount = 1; + instanceCreateInfo.ppEnabledLayerNames = validationLayerNames; + } + if (enabledExtensions.size() > 0) { + instanceCreateInfo.enabledExtensionCount = enabledExtensions.size(); + instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data(); + } + + VkResult ret = vkCreateInstance(&instanceCreateInfo, nullptr, &_instance); + if(ret != VK_SUCCESS) { + Error() << "Vulkan Instance creation failed with error" << ret; + return false; + } + + _current = this; + + /* setup debugging */ + if (_flags >= Flag::EnableValidation) { + CreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(_instance, "vkCreateDebugReportCallbackEXT"); + DestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(_instance, "vkDestroyDebugReportCallbackEXT"); + dbgBreakCallback = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(_instance, "vkDebugReportMessageEXT"); + + VkDebugReportCallbackCreateInfoEXT dbgCreateInfo = {}; + dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback; + dbgCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; + + VkResult err = CreateDebugReportCallback( + _instance, + &dbgCreateInfo, + nullptr, + &msgCallback); + assert(!err); + } + return true; +} + +bool Context::isVersionSupported(Version) const { + return true; +} + +}} diff --git a/src/Magnum/Vk/Context.h b/src/Magnum/Vk/Context.h new file mode 100644 index 000000000..6efc62be4 --- /dev/null +++ b/src/Magnum/Vk/Context.h @@ -0,0 +1,161 @@ +#ifndef Magnum_Vk_Context_h +#define Magnum_Vk_Context_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016 + Vladimír Vondruš + Copyright © 2016 Jonathan Hale + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class @ref Magnum::Vk::Context + */ + +#include "vulkan.h" + +#include +#include +#include +#include +#include + +#include "Magnum/Tags.h" +#include "Magnum/Magnum.h" +#include "Magnum/Vk/visibility.h" +#include "MagnumExternal/Optional/optional.hpp" + +namespace Magnum { namespace Vk { + +enum class Version: UnsignedInt { + None = 0, /**< No version */ + Vulkan_1_0 = VK_VERSION_1_0, /**< Vulkan 1.0 */ +}; + +/** +@brief Magnum context + +Provides access to version and extension information. Instance available +through @ref Context::current() is automatically created during construction of +`*Application` classes in @ref Platform namespace. You can safely assume that +the instance is available during whole lifetime of `*Application` object. It's +also possible to create the context without using any `*Application` class +using @ref Platform::Context subclass, see @ref platform documentation for more +information. + +## Command-line options + +The context is configurable through command-line options, that are passed +either from the `Platform::*Application` classes or from the @ref Platform::Context +class. Usage: + + [--magnum-help] ... + +Arguments: + +- `...` -- main application arguments (see `-h` or `--help` for details) +- `--magnum-help` -- display this help message and exit +*/ +class MAGNUM_VK_EXPORT Context { + public: + /** + * @brief Context flag + * + * @see @ref Flags, @ref flags(), + * @ref Platform::Sdl2Application::Configuration::setFlags() "Platform::*Application::Configuration::setFlags()" + */ + enum class Flag: Int { + EnableValidation = 1, /**< Enable validation layer */ + }; + + /** + * @brief Context flags + * + * @see @ref flags() + */ + typedef Containers::EnumSet Flags; + + /** + * @brief Whether there is any current context + * + * @see @ref current() + */ + static bool hasCurrent(); + + /** + * @brief Current context + * + * Expect that there is current context. + * @see @ref hasCurrent() + */ + static Context& current(); + + Context(Flags flags); + + /** @brief Copying is not allowed */ + Context(const Context&) = delete; + + /** @brief Move constructor */ + Context(Context&& other); + + ~Context(); + + /** @brief Copying is not allowed */ + Context& operator=(const Context&) = delete; + + /** @brief Move assignment is not allowed */ + Context& operator=(Context&&) = delete; + + /** @brief Vulkan version */ + Version version() const { return _version; } + + /** @brief Context flags */ + Flags flags() const { return _flags; } + + /** + * @brief Whether given Vulkan version is supported + * + * @see @ref MAGNUM_ASSERT_VERSION_SUPPORTED() + */ + bool isVersionSupported(Version version) const; + + VkInstance vkInstance() { + return _instance; + } + + private: + MAGNUM_VK_LOCAL static Context* _current; + + explicit Context(NoCreateT, Int argc, char** argv, void functionLoader()); + + bool tryCreate(); + void create(); + + void(*_functionLoader)(); + Version _version; + Flags _flags; + + VkInstance _instance; +}; + +}} + +#endif