diff --git a/CMakeLists.txt b/CMakeLists.txt
index dfafe1cd084d4b324c233d502e301c24a5ee95e1..da150fcbeafec3be555d4bbefdab37dbdedf277f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,7 +65,7 @@ add_library(vkcv STATIC ${vkcv_sources})
 
 if(MSVC)
   #enable multicore compilation on visual studio
-  target_compile_options(vkcv PRIVATE "/MP" "/openmp")
+  target_compile_options(vkcv PRIVATE "/MP" "/openmp" "/Zc:offsetof-")
 
   #set source groups to create proper filters in visual studio
   source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${vkcv_sources})
diff --git a/config/Sources.cmake b/config/Sources.cmake
index 41cd0c20f2106dc02700d9b23227f3e6c34a057a..ea95d152280fde1dcfdd93e7e48d1f8b58d3bb9e 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -1,6 +1,12 @@
 
 # adding all source files and header files of the framework:
 set(vkcv_sources
+		${vkcv_include}/vkcv/Features.hpp
+		${vkcv_source}/vkcv/Features.cpp
+		
+		${vkcv_include}/vkcv/FeatureManager.hpp
+		${vkcv_source}/vkcv/FeatureManager.cpp
+		
 		${vkcv_include}/vkcv/Context.hpp
 		${vkcv_source}/vkcv/Context.cpp
 
diff --git a/include/vkcv/Context.hpp b/include/vkcv/Context.hpp
index 824713fd1e29cbb8b7e60b22768c0019daaa9938..1160857cb2cdbbb0815390ff1f8405dda0f83796 100644
--- a/include/vkcv/Context.hpp
+++ b/include/vkcv/Context.hpp
@@ -5,6 +5,7 @@
 
 #include "QueueManager.hpp"
 #include "DrawcallRecording.hpp"
+#include "Features.hpp"
 
 namespace vkcv
 {
@@ -32,6 +33,9 @@ namespace vkcv
         [[nodiscard]]
         const vk::Device &getDevice() const;
         
+        [[nodiscard]]
+        const FeatureManager& getFeatureManager() const;
+        
         [[nodiscard]]
         const QueueManager& getQueueManager() const;
 	
@@ -41,8 +45,8 @@ namespace vkcv
         static Context create(const char *applicationName,
 							  uint32_t applicationVersion,
 							  const std::vector<vk::QueueFlagBits>& queueFlags,
-							  const std::vector<const char *>& instanceExtensions,
-							  const std::vector<const char *>& deviceExtensions);
+							  const Features& features,
+							  const std::vector<const char*>& instanceExtensions = {});
 
     private:
         /**
@@ -53,11 +57,12 @@ namespace vkcv
          * @param device Vulkan-Device
          */
         Context(vk::Instance instance, vk::PhysicalDevice physicalDevice, vk::Device device,
-				QueueManager&& queueManager, vma::Allocator&& allocator) noexcept;
+				FeatureManager&& featureManager, QueueManager&& queueManager, vma::Allocator&& allocator) noexcept;
         
         vk::Instance        m_Instance;
         vk::PhysicalDevice  m_PhysicalDevice;
         vk::Device          m_Device;
+        FeatureManager		m_FeatureManager;
 		QueueManager		m_QueueManager;
 		vma::Allocator 		m_Allocator;
 		
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 7b5c1d94a6519e626249d55c65da19b1e8f95044..2d5dcd0f5e00e0870ea3b9cb4ea8d20f2f623c3d 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -7,14 +7,14 @@
 #include <memory>
 #include <vulkan/vulkan.hpp>
 
-#include "vkcv/Context.hpp"
-#include "vkcv/Swapchain.hpp"
-#include "vkcv/Window.hpp"
-#include "vkcv/PassConfig.hpp"
-#include "vkcv/Handles.hpp"
-#include "vkcv/Buffer.hpp"
-#include "vkcv/Image.hpp"
-#include "vkcv/PipelineConfig.hpp"
+#include "Context.hpp"
+#include "Swapchain.hpp"
+#include "Window.hpp"
+#include "PassConfig.hpp"
+#include "Handles.hpp"
+#include "Buffer.hpp"
+#include "Image.hpp"
+#include "PipelineConfig.hpp"
 #include "CommandResources.hpp"
 #include "SyncResources.hpp"
 #include "Result.hpp"
@@ -139,8 +139,8 @@ namespace vkcv
                            const char *applicationName,
                            uint32_t applicationVersion,
                            const std::vector<vk::QueueFlagBits>& queueFlags    = {},
-                           const std::vector<const char*>& instanceExtensions  = {},
-                           const std::vector<const char*>& deviceExtensions    = {});
+						   const Features& features = {},
+						   const std::vector<const char *>& instanceExtensions = {});
 
         /**
          * Creates a basic vulkan graphics pipeline using @p config from the pipeline config class and returns it using the @p handle.
@@ -249,16 +249,16 @@ namespace vkcv
 		bool beginFrame(uint32_t& width, uint32_t& height);
 
 		void recordDrawcallsToCmdStream(
-			const CommandStreamHandle       cmdStreamHandle,
-			const PassHandle                renderpassHandle, 
+			const CommandStreamHandle&      cmdStreamHandle,
+			const PassHandle&               renderpassHandle,
 			const PipelineHandle            pipelineHandle,
 			const PushConstants             &pushConstants,
 			const std::vector<DrawcallInfo> &drawcalls,
 			const std::vector<ImageHandle>  &renderTargets);
 
 		void recordMeshShaderDrawcalls(
-			const CommandStreamHandle               cmdStreamHandle,
-			const PassHandle                        renderpassHandle,
+			const CommandStreamHandle&              cmdStreamHandle,
+			const PassHandle&                       renderpassHandle,
 			const PipelineHandle                    pipelineHandle,
 			const PushConstants&                    pushConstantData,
             const std::vector<MeshShaderDrawcall>&  drawcalls,
diff --git a/include/vkcv/FeatureManager.hpp b/include/vkcv/FeatureManager.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf945d7498fec83f0b128294caa3ba267b69a6b3
--- /dev/null
+++ b/include/vkcv/FeatureManager.hpp
@@ -0,0 +1,150 @@
+#pragma once
+
+#include "Logger.hpp"
+
+#include <functional>
+#include <unordered_set>
+#include <vector>
+#include <vulkan/vulkan.hpp>
+
+namespace vkcv {
+
+	class FeatureManager {
+	private:
+		vk::PhysicalDevice& m_physicalDevice;
+		
+		std::vector<const char*> m_supportedExtensions;
+		std::vector<const char*> m_activeExtensions;
+		
+		vk::PhysicalDeviceFeatures2 m_featuresBase;
+		std::vector<vk::BaseOutStructure*> m_featuresExtensions;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceFeatures& features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDevice16BitStorageFeatures& features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDevice8BitStorageFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceBufferDeviceAddressFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceDescriptorIndexingFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceHostQueryResetFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceImagelessFramebufferFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceMultiviewFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceProtectedMemoryFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceSamplerYcbcrConversionFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceScalarBlockLayoutFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceShaderAtomicInt64Features &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceShaderFloat16Int8Features& features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceTimelineSemaphoreFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceUniformBufferStandardLayoutFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceVariablePointersFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceVulkanMemoryModelFeatures &features, bool required) const;
+		
+		[[nodiscard]]
+		bool checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV& features, bool required) const;
+		
+		vk::BaseOutStructure* findFeatureStructure(vk::StructureType type) const;
+	
+	public:
+		explicit FeatureManager(vk::PhysicalDevice& physicalDevice);
+		
+		FeatureManager(const FeatureManager& other) = delete;
+		FeatureManager(FeatureManager&& other) noexcept;
+		
+		~FeatureManager();
+		
+		FeatureManager& operator=(const FeatureManager& other) = delete;
+		FeatureManager& operator=(FeatureManager&& other) noexcept;
+		
+		[[nodiscard]]
+		bool isExtensionSupported(const std::string& extension) const;
+		
+		bool useExtension(const std::string& extension, bool required = true);
+		
+		[[nodiscard]]
+		bool isExtensionActive(const std::string& extension) const;
+		
+		[[nodiscard]]
+		const std::vector<const char*>& getActiveExtensions() const;
+		
+		bool useFeatures(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction, bool required = true);
+		
+		template<typename T>
+		bool useFeatures(const std::function<void(T&)>& featureFunction, bool required = true) {
+			T features;
+			T* features_ptr = reinterpret_cast<T*>(findFeatureStructure(features.sType));
+			
+			if (features_ptr) {
+				features = *features_ptr;
+			}
+			
+			featureFunction(features);
+			
+			if (!checkSupport(features, required)) {
+				return false;
+			}
+			
+			if (features_ptr) {
+				*features_ptr = features;
+				return true;
+			}
+			
+			features_ptr = new T(features);
+			
+			if (m_featuresExtensions.empty()) {
+				m_featuresBase.setPNext(features_ptr);
+			} else {
+				m_featuresExtensions.back()->setPNext(
+						reinterpret_cast<vk::BaseOutStructure*>(features_ptr)
+				);
+			}
+			
+			m_featuresExtensions.push_back(
+					reinterpret_cast<vk::BaseOutStructure*>(features_ptr)
+			);
+			
+			return true;
+		}
+		
+		[[nodiscard]]
+		const vk::PhysicalDeviceFeatures2& getFeatures() const;
+		
+	};
+	
+}
diff --git a/include/vkcv/Features.hpp b/include/vkcv/Features.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..6ef3fa28be912627b4495c66427336dfaa51beff
--- /dev/null
+++ b/include/vkcv/Features.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include <functional>
+#include <vector>
+#include <initializer_list>
+
+#include "FeatureManager.hpp"
+
+namespace vkcv {
+	
+	typedef std::function<bool(FeatureManager&)> Feature;
+	
+	class Features {
+	private:
+		std::vector<Feature> m_features;
+		
+	public:
+		Features() = default;
+		
+		Features(const std::initializer_list<std::string>& list);
+		
+		Features(const Features& other) = default;
+		Features(Features&& other) = default;
+		
+		~Features() = default;
+		
+		Features& operator=(const Features& other) = default;
+		Features& operator=(Features&& other) = default;
+		
+		void requireExtension(const std::string& extension);
+		
+		void requireExtensionFeature(const std::string& extension,
+									 const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void requireExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) {
+				if (featureManager.useExtension(extension, true)) {
+					return featureManager.template useFeatures<T>(featureFunction, true);
+				} else {
+					return false;
+				}
+			});
+		}
+		
+		void requireFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void requireFeature(const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([featureFunction](FeatureManager& featureManager) {
+				return featureManager.template useFeatures<T>(featureFunction, true);
+			});
+		}
+		
+		void tryExtension(const std::string& extension);
+		
+		void tryExtensionFeature(const std::string& extension,
+								 const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void tryExtensionFeature(const std::string& extension, const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) {
+				if (featureManager.useExtension(extension, false)) {
+					return featureManager.template useFeatures<T>(featureFunction, false);
+				} else {
+					return false;
+				}
+			});
+		}
+		
+		void tryFeature(const std::function<void(vk::PhysicalDeviceFeatures&)>& featureFunction);
+		
+		template<typename T>
+		void tryFeature(const std::function<void(T&)>& featureFunction) {
+			m_features.emplace_back([featureFunction](FeatureManager& featureManager) {
+				return featureManager.template useFeatures<T>(featureFunction, false);
+			});
+		}
+		
+		[[nodiscard]]
+		const std::vector<Feature>& getList() const;
+		
+	};
+	
+}
diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
index 460a6d0b459fe7d1d2a917a62138fea2e5a40908..85908a76d51082b09cf5e6b09ac01fbbd4ef9266 100644
--- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
@@ -177,7 +177,7 @@ namespace vkcv::upscaling {
 		vkcv::shader::GLSLCompiler easuCompiler;
 		vkcv::shader::GLSLCompiler rcasCompiler;
 		
-		const auto& features = m_core.getContext().getPhysicalDevice().getFeatures2();
+		const auto& features = m_core.getContext().getFeatureManager().getFeatures();
 		const bool float16Support = (
 				checkFeatures<vk::PhysicalDeviceFloat16Int8FeaturesKHR>(
 						reinterpret_cast<const vk::BaseInStructure*>(&features),
@@ -189,7 +189,7 @@ namespace vkcv::upscaling {
 						vk::StructureType::ePhysicalDevice16BitStorageFeaturesKHR,
 						check16Storage
 				)
-		) || (true); // check doesn't work because chain is empty
+		);
 		
 		if (!float16Support) {
 			easuCompiler.setDefine("SAMPLE_SLOW_FALLBACK", "1");
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index fc682ae1f8b3d1a174ff230c274b89093bc3325c..2ad76e8f78c5870f6b582a1970caac306026166f 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -18,14 +18,13 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		true
 	);
-
+	
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
-		{},
-		{ "VK_KHR_swapchain" }
+		{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }
 	);
 
 	vkcv::asset::Scene mesh;
diff --git a/projects/first_scene/src/main.cpp b/projects/first_scene/src/main.cpp
index 527eba8c3a1e020e14d92f5d305e2ddced936333..21f8deacdb3f81fcd29c5f14cbe74485f36d13cd 100644
--- a/projects/first_scene/src/main.cpp
+++ b/projects/first_scene/src/main.cpp
@@ -28,14 +28,13 @@ int main(int argc, const char** argv) {
 	cameraManager.getCamera(camIndex0).setNearFar(0.1f, 30.0f);
 	
 	cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f);
-
+	
 	vkcv::Core core = vkcv::Core::create(
 		window,
 		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
-		{},
-		{ "VK_KHR_swapchain" }
+		{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }
 	);
 	
 	vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path(
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index 3598da5f579b608d2c29f1f6fea0b0e25a560336..76e860dea27126c943fa6b6a7d5a01f174203920 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -16,14 +16,13 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		false
 	);
-
+	
 	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" }
+		{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }
 	);
 
 	auto triangleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3, vkcv::BufferMemoryType::DEVICE_LOCAL);
diff --git a/projects/indirect_dispatch/src/App.cpp b/projects/indirect_dispatch/src/App.cpp
index 92d548acde9c5a27e69c6daf4d92ca1da9d50a2c..5927970333d63d7e0c3bbbda4b7ccbf321c48a48 100644
--- a/projects/indirect_dispatch/src/App.cpp
+++ b/projects/indirect_dispatch/src/App.cpp
@@ -18,8 +18,7 @@ App::App() :
 		m_applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
 		{ vk::QueueFlagBits::eGraphics ,vk::QueueFlagBits::eCompute , vk::QueueFlagBits::eTransfer },
-		{},
-		{ "VK_KHR_swapchain" })),
+		{ VK_KHR_SWAPCHAIN_EXTENSION_NAME })),
 	m_cameraManager(m_window){}
 
 bool App::initialize() {
diff --git a/projects/mesh_shader/.gitignore b/projects/mesh_shader/.gitignore
index 54601c357bf3fb97b914a6e657c042a5c6a985d7..fd009a6281f4b2b6716e193d23829907f4bb5f33 100644
--- a/projects/mesh_shader/.gitignore
+++ b/projects/mesh_shader/.gitignore
@@ -1 +1 @@
-mesh_shader
+mesh_shader
\ No newline at end of file
diff --git a/projects/mesh_shader/src/main.cpp b/projects/mesh_shader/src/main.cpp
index 611a324f875f5726ebd674e3ee51d27ad2d8e849..15aaf527619b4fb06d89bccc78cffe843cc723b7 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -86,14 +86,21 @@ int main(int argc, const char** argv) {
 		windowHeight,
 		false
 	);
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	features.requireExtensionFeature<vk::PhysicalDeviceMeshShaderFeaturesNV>(
+			VK_NV_MESH_SHADER_EXTENSION_NAME, [](vk::PhysicalDeviceMeshShaderFeaturesNV& features) {
+		features.setTaskShader(true);
+		features.setMeshShader(true);
+	});
 
 	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", VK_NV_MESH_SHADER_EXTENSION_NAME }
+		features
 	);
 
     vkcv::gui::GUI gui (core, window);
diff --git a/projects/particle_simulation/src/main.cpp b/projects/particle_simulation/src/main.cpp
index 07ba6b194ce72dbad15a921ca13a4814c6d4f5df..4de016aefd345a4231ea2dae0818b0839b163729 100644
--- a/projects/particle_simulation/src/main.cpp
+++ b/projects/particle_simulation/src/main.cpp
@@ -23,14 +23,13 @@ int main(int argc, const char **argv) {
     );
 
     vkcv::camera::CameraManager cameraManager(window);
-
+	
     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"}
+			{ VK_KHR_SWAPCHAIN_EXTENSION_NAME }
     );
 
     auto particleIndexBuffer = core.createBuffer<uint16_t>(vkcv::BufferType::INDEX, 3,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index e7f9caa493714d30f13f64c292f1b6e51e5170b1..3c23c7eabbbdc5d83d37bde79b43a2730b1f28b2 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -80,14 +80,18 @@ int main(int argc, const char** argv) {
 	cameraManager.getCamera(camIndex).setFov(glm::radians(37.8));	// fov of a 35mm lens
 	
 	cameraManager.getCamera(camIndex2).setNearFar(0.1f, 30.0f);
-
+	
+	vkcv::Features features;
+	features.requireExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
+	features.requireExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME);
+	features.requireExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME);
+	
 	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", "VK_KHR_shader_float16_int8", "VK_KHR_16bit_storage" }
+		features
 	);
 
 	vkcv::asset::Scene mesh;
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
index 2e30fb961d0b0931e4ff8796dd92b2cbd0b5f734..f48fad1a9022cbf99f6452c319d629060befbd98 100644
--- a/src/vkcv/Context.cpp
+++ b/src/vkcv/Context.cpp
@@ -9,8 +9,9 @@ namespace vkcv
             m_Instance(other.m_Instance),
             m_PhysicalDevice(other.m_PhysicalDevice),
             m_Device(other.m_Device),
-            m_QueueManager(other.m_QueueManager),
-            m_Allocator(other.m_Allocator)
+			m_FeatureManager(std::move(other.m_FeatureManager)),
+			m_QueueManager(std::move(other.m_QueueManager)),
+			m_Allocator(other.m_Allocator)
     {
         other.m_Instance        = nullptr;
         other.m_PhysicalDevice  = nullptr;
@@ -23,7 +24,8 @@ namespace vkcv
         m_Instance          = other.m_Instance;
         m_PhysicalDevice    = other.m_PhysicalDevice;
         m_Device            = other.m_Device;
-        m_QueueManager		= other.m_QueueManager;
+        m_FeatureManager	= std::move(other.m_FeatureManager);
+        m_QueueManager		= std::move(other.m_QueueManager);
         m_Allocator			= other.m_Allocator;
 
         other.m_Instance        = nullptr;
@@ -37,12 +39,14 @@ namespace vkcv
     Context::Context(vk::Instance instance,
                      vk::PhysicalDevice physicalDevice,
                      vk::Device device,
+                     FeatureManager&& featureManager,
 					 QueueManager&& queueManager,
 					 vma::Allocator&& allocator) noexcept :
     m_Instance(instance),
     m_PhysicalDevice(physicalDevice),
     m_Device(device),
-    m_QueueManager(queueManager),
+    m_FeatureManager(std::move(featureManager)),
+    m_QueueManager(std::move(queueManager)),
     m_Allocator(allocator)
     {}
 
@@ -68,6 +72,10 @@ namespace vkcv
         return m_Device;
     }
     
+    const FeatureManager& Context::getFeatureManager() const {
+    	return m_FeatureManager;
+    }
+    
     const QueueManager& Context::getQueueManager() const {
     	return m_QueueManager;
     }
@@ -167,7 +175,6 @@ namespace vkcv
 		return true;
 	}
 	
-	
 	std::vector<const char*> getRequiredExtensions() {
 		uint32_t glfwExtensionCount = 0;
 		const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
@@ -180,20 +187,11 @@ namespace vkcv
 		return extensions;
 	}
 	
-	bool isPresentInCharPtrVector(const std::vector<const char*>& v, const char* term){
-		for (const auto& entry : v) {
-			if (strcmp(entry, term) != 0) {
-				return true;
-			}
-		}
-		return false;
-	}
-	
 	Context Context::create(const char *applicationName,
 							uint32_t applicationVersion,
 							const std::vector<vk::QueueFlagBits>& queueFlags,
-							const std::vector<const char *>& instanceExtensions,
-							const std::vector<const char *>& deviceExtensions) {
+							const Features& features,
+							const std::vector<const char*>& instanceExtensions) {
 		// check for layer support
 		
 		const std::vector<vk::LayerProperties>& layerProperties = vk::enumerateInstanceLayerProperties();
@@ -226,14 +224,14 @@ namespace vkcv
 			supportedExtensions.push_back(elem.extensionName);
 		}
 		
-		if (!checkSupport(supportedExtensions, instanceExtensions)) {
-			throw std::runtime_error("The requested instance extensions are not supported!");
-		}
-		
 		// for GLFW: get all required extensions
 		std::vector<const char*> requiredExtensions = getRequiredExtensions();
 		requiredExtensions.insert(requiredExtensions.end(), instanceExtensions.begin(), instanceExtensions.end());
 		
+		if (!checkSupport(supportedExtensions, requiredExtensions)) {
+			throw std::runtime_error("The requested instance extensions are not supported!");
+		}
+		
 		const vk::ApplicationInfo applicationInfo(
 				applicationName,
 				applicationVersion,
@@ -261,16 +259,35 @@ namespace vkcv
 		std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
 		vk::PhysicalDevice physicalDevice = pickPhysicalDevice(instance);
 		
-		// check for physical device extension support
-		std::vector<vk::ExtensionProperties> deviceExtensionProperties = physicalDevice.enumerateDeviceExtensionProperties();
-		supportedExtensions.clear();
-		for (auto& elem : deviceExtensionProperties) {
-			supportedExtensions.push_back(elem.extensionName);
+		FeatureManager featureManager (physicalDevice);
+		
+		if (featureManager.useExtension(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, false)) {
+			featureManager.useFeatures<vk::PhysicalDeviceShaderFloat16Int8Features>(
+					[](vk::PhysicalDeviceShaderFloat16Int8Features& features) {
+				features.setShaderFloat16(true);
+			}, false);
 		}
-		if (!checkSupport(supportedExtensions, deviceExtensions)) {
-			throw std::runtime_error("The requested device extensions are not supported by the physical device!");
+		
+		if (featureManager.useExtension(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, false)) {
+			featureManager.useFeatures<vk::PhysicalDevice16BitStorageFeatures>(
+					[](vk::PhysicalDevice16BitStorageFeatures& features) {
+				features.setStorageBuffer16BitAccess(true);
+			}, false);
 		}
 		
+		featureManager.useFeatures([](vk::PhysicalDeviceFeatures& features) {
+			features.setFragmentStoresAndAtomics(true);
+			features.setGeometryShader(true);
+			features.setDepthClamp(true);
+			features.setShaderInt16(true);
+		});
+		
+		for (const auto& feature : features.getList()) {
+			feature(featureManager);
+		}
+		
+		const auto& extensions = featureManager.getActiveExtensions();
+		
 		std::vector<vk::DeviceQueueCreateInfo> qCreateInfos;
 		
 		// create required queues
@@ -286,58 +303,21 @@ namespace vkcv
 				qCreateInfos.data(),
 				0,
 				nullptr,
-				deviceExtensions.size(),
-				deviceExtensions.data(),
-				nullptr		// Should our device use some features??? If yes: TODO
+				extensions.size(),
+				extensions.data(),
+				nullptr
 		);
 
 #ifndef NDEBUG
 		deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
 		deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 #endif
-		const bool shaderFloat16 = checkSupport(deviceExtensions, { "VK_KHR_shader_float16_int8" });
-		const bool storage16bit  = checkSupport(deviceExtensions, { "VK_KHR_16bit_storage" });
-		
-		// FIXME: check if device feature is supported
-		vk::PhysicalDeviceShaderFloat16Int8Features deviceShaderFloat16Int8Features;
-		deviceShaderFloat16Int8Features.shaderFloat16 = shaderFloat16;
-		
-		vk::PhysicalDevice16BitStorageFeatures device16BitStorageFeatures;
-		device16BitStorageFeatures.storageBuffer16BitAccess = storage16bit;
-		
-		vk::PhysicalDeviceFeatures2 deviceFeatures2;
-		deviceFeatures2.features.fragmentStoresAndAtomics = true;
-		deviceFeatures2.features.geometryShader = true;
-		deviceFeatures2.features.depthClamp = true;
-		deviceFeatures2.features.shaderInt16 = true;
-		
-		const bool usingMeshShaders = isPresentInCharPtrVector(deviceExtensions, VK_NV_MESH_SHADER_EXTENSION_NAME);
-		vk::PhysicalDeviceMeshShaderFeaturesNV meshShadingFeatures;
-		if (usingMeshShaders) {
-			meshShadingFeatures.taskShader = true;
-			meshShadingFeatures.meshShader = true;
-            deviceFeatures2.setPNext(&meshShadingFeatures);
-		}
-		
-		if (shaderFloat16) {
-			deviceFeatures2.setPNext(&deviceShaderFloat16Int8Features);
-		}
 		
-		if (storage16bit) {
-			deviceShaderFloat16Int8Features.setPNext(&device16BitStorageFeatures);
-		}
-		
-		deviceCreateInfo.setPNext(&deviceFeatures2);
-
-		// Ablauf
-		// qCreateInfos erstellen --> braucht das Device
-		// device erstellen
-		// jetzt koennen wir mit dem device die queues erstellen
+		deviceCreateInfo.setPNext(&(featureManager.getFeatures()));
 		
 		vk::Device device = physicalDevice.createDevice(deviceCreateInfo);
 
-		if (usingMeshShaders)
-		{
+		if (featureManager.isExtensionActive(VK_NV_MESH_SHADER_EXTENSION_NAME)) {
 			InitMeshShaderDrawFunctions(device);
 		}
 		
@@ -376,6 +356,7 @@ namespace vkcv
 				instance,
 				physicalDevice,
 				device,
+				std::move(featureManager),
 				std::move(queueManager),
 				std::move(allocator)
 		);
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index 92e2df4f18f59355868e9dcce7a78c4e1a9c5cb7..851f08a4c0894b6f6753270ba068e9b2dd544574 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -54,14 +54,14 @@ namespace vkcv
                       const char *applicationName,
                       uint32_t applicationVersion,
                       const std::vector<vk::QueueFlagBits>& queueFlags,
-                      const std::vector<const char *>& instanceExtensions,
-                      const std::vector<const char *>& deviceExtensions)
+					  const Features& features,
+                      const std::vector<const char *>& instanceExtensions)
     {
         Context context = Context::create(
         		applicationName, applicationVersion,
         		queueFlags,
-        		instanceExtensions,
-        		deviceExtensions
+				features,
+        		instanceExtensions
 		);
 
         Swapchain swapChain = Swapchain::create(window, context);
@@ -331,8 +331,8 @@ namespace vkcv
 	}
 
 	void Core::recordDrawcallsToCmdStream(
-		const CommandStreamHandle       cmdStreamHandle,
-		const PassHandle                renderpassHandle, 
+		const CommandStreamHandle&      cmdStreamHandle,
+		const PassHandle&               renderpassHandle,
 		const PipelineHandle            pipelineHandle, 
         const PushConstants             &pushConstantData,
         const std::vector<DrawcallInfo> &drawcalls,
@@ -368,7 +368,6 @@ namespace vkcv
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-
 			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
 
 			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
@@ -377,16 +376,14 @@ namespace vkcv
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
 
 			const PipelineConfig &pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle);
-			if(pipeConfig.m_UseDynamicViewport)
-			{
+			if (pipeConfig.m_UseDynamicViewport) {
 				recordDynamicViewport(cmdBuffer, width, height);
 			}
 
-			for (int i = 0; i < drawcalls.size(); i++) {
+			for (size_t i = 0; i < drawcalls.size(); i++) {
 				recordDrawcall(drawcalls[i], cmdBuffer, pipelineLayout, pushConstantData, i);
 			}
 
-        vk::Rect2D dynamicScissor({0, 0}, {width, height});
 			cmdBuffer.endRenderPass();
 		};
 
@@ -399,8 +396,8 @@ namespace vkcv
 	}
 
 	void Core::recordMeshShaderDrawcalls(
-		const CommandStreamHandle                           cmdStreamHandle,
-		const PassHandle                                    renderpassHandle,
+		const CommandStreamHandle&                          cmdStreamHandle,
+		const PassHandle&                                   renderpassHandle,
 		const PipelineHandle                                pipelineHandle,
 		const PushConstants&                                pushConstantData,
 		const std::vector<MeshShaderDrawcall>&              drawcalls,
@@ -436,7 +433,6 @@ namespace vkcv
 		submitInfo.signalSemaphores = { m_SyncResources.renderFinished };
 
 		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
-
 			const std::vector<vk::ClearValue> clearValues = createAttachmentClearValues(passConfig.attachments);
 
 			const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data());
@@ -445,12 +441,11 @@ namespace vkcv
 			cmdBuffer.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline, {});
 
 			const PipelineConfig& pipeConfig = m_PipelineManager->getPipelineConfig(pipelineHandle);
-			if (pipeConfig.m_UseDynamicViewport)
-			{
+			if (pipeConfig.m_UseDynamicViewport) {
 				recordDynamicViewport(cmdBuffer, width, height);
 			}
 
-			for (int i = 0; i < drawcalls.size(); i++) {
+			for (size_t i = 0; i < drawcalls.size(); i++) {
                 const uint32_t pushConstantOffset = i * pushConstantData.getSizePerDrawcall();
                 recordMeshShaderDrawcall(
                     cmdBuffer,
@@ -458,14 +453,14 @@ namespace vkcv
                     pushConstantData,
                     pushConstantOffset,
                     drawcalls[i],
-                    0);
+                    0
+				);
 			}
 
 			cmdBuffer.endRenderPass();
 		};
 
-		auto finishFunction = [framebuffer, this]()
-		{
+		auto finishFunction = [framebuffer, this]() {
 			m_Context.m_Device.destroy(framebuffer);
 		};
 
diff --git a/src/vkcv/FeatureManager.cpp b/src/vkcv/FeatureManager.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18307999bb28ed60791a801b952619eeeba51a53
--- /dev/null
+++ b/src/vkcv/FeatureManager.cpp
@@ -0,0 +1,437 @@
+
+#include "vkcv/FeatureManager.hpp"
+
+#include <stddef.h>
+#include <string.h>
+#include <type_traits>
+
+namespace vkcv {
+	
+#ifdef _MSVC_LANG
+#define typeof(var) std::decay<decltype((var))>::type
+#endif
+	
+#define vkcv_check_init_features2(type)\
+type supported;                        \
+vk::PhysicalDeviceFeatures2 query;     \
+query.setPNext(&supported);            \
+m_physicalDevice.getFeatures2(&query)
+
+#define vkcv_check_feature(attribute) {                                                                    \
+  const char *f = reinterpret_cast<const char*>(&(features));                                              \
+  const char *s = reinterpret_cast<const char*>(&(supported));                                             \
+  const vk::Bool32* fb = reinterpret_cast<const vk::Bool32*>(f + offsetof(typeof((features)), attribute)); \
+  const vk::Bool32* sb = reinterpret_cast<const vk::Bool32*>(s + offsetof(typeof((features)), attribute)); \
+  if ((*fb) && (!*sb)) {                                                                                   \
+    vkcv_log(((required)? LogLevel::ERROR : LogLevel::WARNING),                                            \
+    "Feature '" #attribute "' is not supported");                                                          \
+    return false;                                                                                          \
+  }                                                                                                        \
+}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceFeatures &features, bool required) const {
+		const auto& supported = m_physicalDevice.getFeatures();
+		
+		vkcv_check_feature(alphaToOne);
+		vkcv_check_feature(depthBiasClamp);
+		vkcv_check_feature(depthBounds);
+		vkcv_check_feature(depthClamp);
+		vkcv_check_feature(drawIndirectFirstInstance);
+		vkcv_check_feature(dualSrcBlend);
+		vkcv_check_feature(fillModeNonSolid);
+		vkcv_check_feature(fragmentStoresAndAtomics);
+		vkcv_check_feature(fullDrawIndexUint32);
+		vkcv_check_feature(geometryShader);
+		vkcv_check_feature(imageCubeArray);
+		vkcv_check_feature(independentBlend);
+		vkcv_check_feature(inheritedQueries);
+		vkcv_check_feature(largePoints);
+		vkcv_check_feature(logicOp);
+		vkcv_check_feature(multiDrawIndirect);
+		vkcv_check_feature(multiViewport);
+		vkcv_check_feature(occlusionQueryPrecise);
+		vkcv_check_feature(pipelineStatisticsQuery);
+		vkcv_check_feature(robustBufferAccess);
+		vkcv_check_feature(sampleRateShading);
+		vkcv_check_feature(samplerAnisotropy);
+		vkcv_check_feature(shaderClipDistance);
+		vkcv_check_feature(shaderCullDistance);
+		vkcv_check_feature(shaderFloat64);
+		vkcv_check_feature(shaderImageGatherExtended);
+		vkcv_check_feature(shaderInt16);
+		vkcv_check_feature(shaderInt64);
+		vkcv_check_feature(shaderResourceMinLod);
+		vkcv_check_feature(shaderResourceResidency);
+		vkcv_check_feature(shaderSampledImageArrayDynamicIndexing);
+		vkcv_check_feature(shaderStorageBufferArrayDynamicIndexing);
+		vkcv_check_feature(shaderStorageImageArrayDynamicIndexing);
+		vkcv_check_feature(shaderStorageImageExtendedFormats);
+		vkcv_check_feature(shaderStorageImageMultisample);
+		vkcv_check_feature(shaderStorageImageReadWithoutFormat);
+		vkcv_check_feature(shaderStorageImageWriteWithoutFormat);
+		vkcv_check_feature(shaderTessellationAndGeometryPointSize);
+		vkcv_check_feature(shaderUniformBufferArrayDynamicIndexing);
+		vkcv_check_feature(sparseBinding);
+		vkcv_check_feature(sparseResidency2Samples);
+		vkcv_check_feature(sparseResidency4Samples);
+		vkcv_check_feature(sparseResidency8Samples);
+		vkcv_check_feature(sparseResidency16Samples);
+		vkcv_check_feature(sparseResidencyAliased);
+		vkcv_check_feature(sparseResidencyBuffer);
+		vkcv_check_feature(sparseResidencyImage2D);
+		vkcv_check_feature(sparseResidencyImage3D);
+		vkcv_check_feature(tessellationShader);
+		vkcv_check_feature(textureCompressionASTC_LDR);
+		vkcv_check_feature(textureCompressionBC);
+		vkcv_check_feature(textureCompressionETC2);
+		vkcv_check_feature(variableMultisampleRate);
+		vkcv_check_feature(vertexPipelineStoresAndAtomics);
+		vkcv_check_feature(wideLines);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDevice16BitStorageFeatures &features, bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDevice16BitStorageFeatures);
+		
+		vkcv_check_feature(storageBuffer16BitAccess);
+		vkcv_check_feature(storageInputOutput16);
+		vkcv_check_feature(storagePushConstant16);
+		vkcv_check_feature(uniformAndStorageBuffer16BitAccess);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDevice8BitStorageFeatures &features, bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDevice8BitStorageFeatures);
+		
+		vkcv_check_feature(storageBuffer8BitAccess);
+		vkcv_check_feature(storagePushConstant8);
+		vkcv_check_feature(uniformAndStorageBuffer8BitAccess);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceBufferDeviceAddressFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceBufferDeviceAddressFeatures);
+		
+		vkcv_check_feature(bufferDeviceAddress);
+		vkcv_check_feature(bufferDeviceAddressCaptureReplay);
+		vkcv_check_feature(bufferDeviceAddressMultiDevice);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceDescriptorIndexingFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceDescriptorIndexingFeatures);
+		
+		vkcv_check_feature(shaderInputAttachmentArrayDynamicIndexing);
+		vkcv_check_feature(shaderInputAttachmentArrayNonUniformIndexing);
+		vkcv_check_feature(shaderSampledImageArrayNonUniformIndexing);
+		vkcv_check_feature(shaderStorageBufferArrayNonUniformIndexing);
+		vkcv_check_feature(shaderStorageImageArrayNonUniformIndexing);
+		vkcv_check_feature(shaderStorageTexelBufferArrayDynamicIndexing);
+		vkcv_check_feature(shaderStorageTexelBufferArrayNonUniformIndexing);
+		vkcv_check_feature(shaderUniformBufferArrayNonUniformIndexing);
+		vkcv_check_feature(shaderUniformTexelBufferArrayDynamicIndexing);
+		vkcv_check_feature(shaderUniformTexelBufferArrayNonUniformIndexing);
+		vkcv_check_feature(descriptorBindingPartiallyBound);
+		vkcv_check_feature(descriptorBindingSampledImageUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingStorageBufferUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingStorageImageUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingStorageTexelBufferUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingUniformBufferUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingUniformTexelBufferUpdateAfterBind);
+		vkcv_check_feature(descriptorBindingUpdateUnusedWhilePending);
+		vkcv_check_feature(descriptorBindingVariableDescriptorCount);
+		vkcv_check_feature(runtimeDescriptorArray);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceHostQueryResetFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceHostQueryResetFeatures);
+		
+		vkcv_check_feature(hostQueryReset);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceImagelessFramebufferFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceImagelessFramebufferFeatures);
+		
+		vkcv_check_feature(imagelessFramebuffer);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceMultiviewFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceMultiviewFeatures);
+		
+		vkcv_check_feature(multiview);
+		vkcv_check_feature(multiviewGeometryShader);
+		vkcv_check_feature(multiviewTessellationShader);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceProtectedMemoryFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceProtectedMemoryFeatures);
+		
+		vkcv_check_feature(protectedMemory);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceSamplerYcbcrConversionFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceSamplerYcbcrConversionFeatures);
+
+		vkcv_check_feature(samplerYcbcrConversion);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceScalarBlockLayoutFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceScalarBlockLayoutFeatures);
+		
+		vkcv_check_feature(scalarBlockLayout);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceSeparateDepthStencilLayoutsFeatures);
+		
+		vkcv_check_feature(separateDepthStencilLayouts);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderAtomicInt64Features &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceShaderAtomicInt64Features);
+		
+		vkcv_check_feature(shaderBufferInt64Atomics);
+		vkcv_check_feature(shaderSharedInt64Atomics);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderFloat16Int8Features &features, bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceShaderFloat16Int8Features);
+		
+		vkcv_check_feature(shaderFloat16);
+		vkcv_check_feature(shaderInt8);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceShaderSubgroupExtendedTypesFeatures);
+		
+		vkcv_check_feature(shaderSubgroupExtendedTypes);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceTimelineSemaphoreFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceTimelineSemaphoreFeatures);
+		
+		vkcv_check_feature(timelineSemaphore);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceUniformBufferStandardLayoutFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceUniformBufferStandardLayoutFeatures);
+		
+		vkcv_check_feature(uniformBufferStandardLayout);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceVariablePointersFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceVariablePointersFeatures);
+		
+		vkcv_check_feature(variablePointers);
+		vkcv_check_feature(variablePointersStorageBuffer);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceVulkanMemoryModelFeatures &features,
+									  bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceVulkanMemoryModelFeatures);
+		
+		vkcv_check_feature(vulkanMemoryModel);
+		vkcv_check_feature(vulkanMemoryModelDeviceScope);
+		vkcv_check_feature(vulkanMemoryModelAvailabilityVisibilityChains);
+		
+		return true;
+	}
+	
+	bool FeatureManager::checkSupport(const vk::PhysicalDeviceMeshShaderFeaturesNV &features, bool required) const {
+		vkcv_check_init_features2(vk::PhysicalDeviceMeshShaderFeaturesNV);
+		
+		vkcv_check_feature(taskShader);
+		vkcv_check_feature(meshShader);
+		
+		return true;
+	}
+	
+	vk::BaseOutStructure* FeatureManager::findFeatureStructure(vk::StructureType type) const {
+		for (auto& base : m_featuresExtensions) {
+			if (base->sType == type) {
+				return base;
+			}
+		}
+		
+		return nullptr;
+	}
+	
+	const char* strclone(const char* str) {
+		if (!str) {
+			return nullptr;
+		}
+		
+		const size_t length = strlen(str) + 1;
+		
+		if (length <= 1) {
+			return nullptr;
+		}
+		
+		char* clone = new char[length];
+		strcpy(clone, str);
+		return clone;
+	}
+	
+	FeatureManager::FeatureManager(vk::PhysicalDevice &physicalDevice) :
+	m_physicalDevice(physicalDevice),
+	m_supportedExtensions(),
+	m_activeExtensions(),
+	m_featuresBase(),
+	m_featuresExtensions() {
+		for (const auto& extension : m_physicalDevice.enumerateDeviceExtensionProperties()) {
+			const char* clone = strclone(extension.extensionName);
+			
+			if (clone) {
+				m_supportedExtensions.push_back(clone);
+			}
+		}
+	}
+	
+	FeatureManager::FeatureManager(FeatureManager &&other) noexcept :
+	m_physicalDevice(other.m_physicalDevice),
+	m_supportedExtensions(std::move(other.m_supportedExtensions)),
+	m_activeExtensions(std::move(other.m_activeExtensions)),
+    m_featuresBase(other.m_featuresBase),
+    m_featuresExtensions(std::move(other.m_featuresExtensions)) {
+		other.m_featuresExtensions.clear();
+		other.m_activeExtensions.clear();
+		other.m_supportedExtensions.clear();
+	}
+	
+	FeatureManager::~FeatureManager() {
+		for (auto& features : m_featuresExtensions) {
+			delete features;
+		}
+		
+		for (auto& extension : m_activeExtensions) {
+			delete[] extension;
+		}
+		
+		for (auto& extension : m_supportedExtensions) {
+			delete[] extension;
+		}
+	}
+	
+	FeatureManager &FeatureManager::operator=(FeatureManager &&other) noexcept {
+		m_physicalDevice = other.m_physicalDevice;
+		m_supportedExtensions = std::move(other.m_supportedExtensions);
+		m_activeExtensions = std::move(other.m_activeExtensions);
+		m_featuresBase = other.m_featuresBase;
+		m_featuresExtensions = std::move(other.m_featuresExtensions);
+		
+		other.m_featuresExtensions.clear();
+		other.m_activeExtensions.clear();
+		other.m_supportedExtensions.clear();
+		
+		return *this;
+	}
+	
+	bool FeatureManager::isExtensionSupported(const std::string& extension) const {
+		for (const auto& supported : m_supportedExtensions) {
+			if (0 == strcmp(supported, extension.c_str())) {
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	bool FeatureManager::useExtension(const std::string& extension, bool required) {
+		const char* clone = strclone(extension.c_str());
+		
+		if (!clone) {
+			vkcv_log(LogLevel::WARNING, "Extension '%s' is not valid", extension.c_str());
+			return false;
+		}
+		
+		if (!isExtensionSupported(extension)) {
+			vkcv_log((required? LogLevel::ERROR : LogLevel::WARNING), "Extension '%s' is not supported",
+					 extension.c_str());
+			
+			delete[] clone;
+			return false;
+		}
+		
+		m_activeExtensions.push_back(clone);
+		return true;
+	}
+	
+	bool FeatureManager::isExtensionActive(const std::string& extension) const {
+		for (const auto& supported : m_activeExtensions) {
+			if (0 == strcmp(supported, extension.c_str())) {
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	const std::vector<const char*>& FeatureManager::getActiveExtensions() const {
+		return m_activeExtensions;
+	}
+	
+	bool FeatureManager::useFeatures(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction,
+									 bool required) {
+		vk::PhysicalDeviceFeatures features = m_featuresBase.features;
+		
+		featureFunction(features);
+		
+		if (!checkSupport(features, required)) {
+			return false;
+		}
+		
+		m_featuresBase.features = features;
+		return true;
+	}
+	
+	const vk::PhysicalDeviceFeatures2& FeatureManager::getFeatures() const {
+		return m_featuresBase;
+	}
+	
+}
diff --git a/src/vkcv/Features.cpp b/src/vkcv/Features.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..60616685f67084b6875ce14bf09f524a9127688f
--- /dev/null
+++ b/src/vkcv/Features.cpp
@@ -0,0 +1,62 @@
+
+#include "vkcv/Features.hpp"
+
+namespace vkcv {
+	
+	Features::Features(const std::initializer_list<std::string>& list) : m_features() {
+		for (const auto& extension : list) {
+			requireExtension(extension);
+		}
+	}
+	
+	void Features::requireExtension(const std::string& extension) {
+		m_features.emplace_back([extension](FeatureManager& featureManager) {
+			return featureManager.useExtension(extension, true);
+		});
+	}
+	
+	void Features::requireExtensionFeature(const std::string &extension,
+										   const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) {
+			if (featureManager.useExtension(extension, true)) {
+				return featureManager.useFeatures(featureFunction, true);
+			} else {
+				return false;
+			}
+		});
+	}
+	
+	void Features::requireFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([featureFunction](FeatureManager& featureManager) {
+			return featureManager.useFeatures(featureFunction, true);
+		});
+	}
+	
+	void Features::tryExtension(const std::string& extension) {
+		m_features.emplace_back([extension](FeatureManager& featureManager) {
+			return featureManager.useExtension(extension, false);
+		});
+	}
+	
+	void Features::tryExtensionFeature(const std::string &extension,
+									   const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([extension, featureFunction](FeatureManager& featureManager) {
+			if (featureManager.useExtension(extension, false)) {
+				return featureManager.useFeatures(featureFunction, false);
+			} else {
+				return false;
+			}
+		});
+	}
+	
+	void Features::tryFeature(const std::function<void(vk::PhysicalDeviceFeatures &)> &featureFunction) {
+		m_features.emplace_back([featureFunction](FeatureManager& featureManager) {
+			return featureManager.useFeatures(featureFunction, false);
+		});
+	}
+	
+	const std::vector<Feature>& Features::getList() const {
+		return m_features;
+	}
+
+}