From a73b2724e1dcdd25e80af15753346fb07d3cedbb Mon Sep 17 00:00:00 2001 From: Squareys Date: Thu, 21 Apr 2016 09:15:37 +0200 Subject: [PATCH] Vk: Add Context Signed-off-by: Squareys --- src/Magnum/Vk/Context.cpp | 207 ++++++++++++++++++++++++++++++++++++++ src/Magnum/Vk/Context.h | 191 +++++++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 src/Magnum/Vk/Context.cpp create mode 100644 src/Magnum/Vk/Context.h diff --git a/src/Magnum/Vk/Context.cpp b/src/Magnum/Vk/Context.cpp new file mode 100644 index 000000000..6a63e3b6e --- /dev/null +++ b/src/Magnum/Vk/Context.cpp @@ -0,0 +1,207 @@ +/* + 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.empty()) { + 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; +} + +Debug& operator<<(Debug& debug, Result value) { + switch(value) { + #define _c(value) case Result::value: return debug << "Vk::Result::" #value; + _c(Success) + _c(NotReady) + _c(Timeout) + _c(EventSet) + _c(EventReset) + _c(Incomplete) + _c(ErrorOutOfHostMemory) + _c(ErrorOutOfDevieMemory) + _c(ErrorInitializationFailed) + _c(ErrorDeviceLost) + _c(ErrorMemoryMapFailed) + _c(ErrorLayerNotPresent) + _c(ErrorExtensionNotPresent) + _c(ErrorFeatureNotPresent) + _c(ErrorIncompatibleDriver) + _c(ErrorTooManyObjects) + _c(ErrorFormatNotSupported) + _c(ErrorSurfaceLost) + _c(ErrorNativeWindowInUse) + _c(Suboptimal) + _c(ErrorOutOfDate) + _c(ErrorIncompatibleDisplay) + _c(ErrorValidationFailed) + _c(ErrorInvalidShader) + #undef _c + } + + return debug << "Vk::Result::(invalid)"; +} + +Debug& operator<<(Debug& debug, Context::Flag value) { + switch(value) { + #define _c(value) case Context::Flag::value: return debug << "Context::Flag::" #value; + _c(EnableValidation) + #undef _c + } + + return debug << "Context::Flag::(invalid)"; +} + +}} diff --git a/src/Magnum/Vk/Context.h b/src/Magnum/Vk/Context.h new file mode 100644 index 000000000..429054371 --- /dev/null +++ b/src/Magnum/Vk/Context.h @@ -0,0 +1,191 @@ +#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, /**< No version */ + Vulkan_1_0 = VK_API_VERSION_1_0, /**< Vulkan 1.0 */ +}; + +enum class Result: Int { + Success = VK_SUCCESS, /**< Success */ + NotReady = VK_NOT_READY, /**< Not ready */ + Timeout = VK_TIMEOUT, /**< Timeout */ + EventSet = VK_EVENT_SET, /**< Event set */ + EventReset = VK_EVENT_RESET, /**< Event reset */ + Incomplete = VK_INCOMPLETE, /**< Incomplete */ + ErrorOutOfHostMemory = VK_ERROR_OUT_OF_HOST_MEMORY, /**< Out of host memory */ + ErrorOutOfDevieMemory = VK_ERROR_OUT_OF_DEVICE_MEMORY, /**< Out of device memory */ + ErrorInitializationFailed = VK_ERROR_INITIALIZATION_FAILED, /**< Initialization failed */ + ErrorDeviceLost = VK_ERROR_DEVICE_LOST, /**< Device lost */ + ErrorMemoryMapFailed = VK_ERROR_MEMORY_MAP_FAILED, /**< Memory map failed */ + ErrorLayerNotPresent = VK_ERROR_LAYER_NOT_PRESENT, /**< Layer not present */ + ErrorExtensionNotPresent = VK_ERROR_EXTENSION_NOT_PRESENT, /**< Extension not present */ + ErrorFeatureNotPresent = VK_ERROR_FEATURE_NOT_PRESENT, /**< Feature not present */ + ErrorIncompatibleDriver = VK_ERROR_INCOMPATIBLE_DRIVER, /**< Incompatible driver */ + ErrorTooManyObjects = VK_ERROR_TOO_MANY_OBJECTS, /**< Too many objects */ + ErrorFormatNotSupported = VK_ERROR_FORMAT_NOT_SUPPORTED, /**< Format not supported */ + ErrorSurfaceLost = VK_ERROR_SURFACE_LOST_KHR, /**< Surface lost */ + ErrorNativeWindowInUse = VK_ERROR_NATIVE_WINDOW_IN_USE_KHR, /**< Native window in use */ + Suboptimal = VK_SUBOPTIMAL_KHR, /**< Suboptimal */ + ErrorOutOfDate = VK_ERROR_OUT_OF_DATE_KHR, /**< Out of date */ + ErrorIncompatibleDisplay = VK_ERROR_INCOMPATIBLE_DISPLAY_KHR, /**< Incompatible display */ + ErrorValidationFailed = VK_ERROR_VALIDATION_FAILED_EXT, /**< Validation failed */ + ErrorInvalidShader = VK_ERROR_INVALID_SHADER_NV /**< Invalid shader */ +}; + +/** +@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, /**< 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; +}; + +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, Result value); +MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, Context::Flag value); + +}} + +#endif