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 66068e64cb3bd15cdaeab0c3c35515888223ca5f..3c2e903a2047b689fe7f328244cb280d47ce7011 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 33bcc97c8bd6fd98c1d75a300a85731bd1545232..f9d52110bae8b87f2e16b46755372b7877cb48d8 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"
@@ -146,8 +146,8 @@ namespace vkcv
         static Core 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 = {});
 
         /**
          * Creates a basic vulkan graphics pipeline using @p config from the pipeline config class and returns it using the @p handle.
@@ -275,16 +275,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,
@@ -296,6 +296,12 @@ namespace vkcv
 			const uint32_t dispatchCount[3],
 			const std::vector<DescriptorSetUsage> &descriptorSetUsages,
 			const PushConstants& pushConstants);
+		
+		void recordBeginDebugLabel(const CommandStreamHandle &cmdStream,
+								   const std::string& label,
+								   const std::array<float, 4>& color);
+		
+		void recordEndDebugLabel(const CommandStreamHandle &cmdStream);
 
 		void recordComputeIndirectDispatchToCmdStream(
 			const CommandStreamHandle               cmdStream,
@@ -346,6 +352,14 @@ namespace vkcv
 		
 		void recordBlitImage(const CommandStreamHandle& cmdStream, const ImageHandle& src, const ImageHandle& dst,
 							 SamplerFilterType filterType);
+	
+		void setDebugLabel(const BufferHandle &handle, const std::string &label);
+		void setDebugLabel(const PassHandle &handle, const std::string &label);
+		void setDebugLabel(const PipelineHandle &handle, const std::string &label);
+		void setDebugLabel(const DescriptorSetHandle &handle, const std::string &label);
+		void setDebugLabel(const SamplerHandle &handle, const std::string &label);
+		void setDebugLabel(const ImageHandle &handle, const std::string &label);
+		void setDebugLabel(const CommandStreamHandle &handle, const std::string &label);
 		
     };
 }
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/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
index 571d965a400de7197b6fb46f163c4099a5b353f1..2ca35bdab791ea18a67f33e53ab17fc485cbad02 100644
--- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
+++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp
@@ -107,7 +107,7 @@ namespace vkcv::asset {
 									const std::vector<fx::gltf::BufferView> &bufferViews,
 									std::vector<VertexAttribute> &dst) {
 		for (const auto &attrib : src) {
-			VertexAttribute att;
+			VertexAttribute att {};
 			
 			if (attrib.first == "POSITION") {
 				att.type = PrimitiveType::POSITION;
@@ -282,7 +282,7 @@ namespace vkcv::asset {
 	 * modes, default is repeat, the other modes aren't available.
 	 */
 	static vkcv::asset::Sampler loadSampler(const fx::gltf::Sampler &src) {
-		Sampler dst;
+		Sampler dst {};
 		
 		dst.minLOD = 0;
 		dst.maxLOD = VK_LOD_CLAMP_NONE;
@@ -414,13 +414,13 @@ namespace vkcv::asset {
 			}
 	
 			if (posAccessor.bufferView >= sceneObjects.bufferViews.size()) {
-				vkcv_log(LogLevel::ERROR, "Access to bufferView out of bounds: %lu",
+				vkcv_log(LogLevel::ERROR, "Access to bufferView out of bounds: %d",
 						posAccessor.bufferView);
 				return ASSET_ERROR;
 			}
 			const fx::gltf::BufferView& vertexBufferView = sceneObjects.bufferViews[posAccessor.bufferView];
 			if (vertexBufferView.buffer >= sceneObjects.buffers.size()) {
-				vkcv_log(LogLevel::ERROR, "Access to buffer out of bounds: %lu",
+				vkcv_log(LogLevel::ERROR, "Access to buffer out of bounds: %d",
 						vertexBufferView.buffer);
 				return ASSET_ERROR;
 			}
@@ -571,7 +571,7 @@ namespace vkcv::asset {
 					texture.sampler = -1;
 				} else
 				if (static_cast<size_t>(textureObject.sampler) >= scene.samplers.size()) {
-					vkcv_log(LogLevel::ERROR, "Sampler of texture '%s' missing (%s) %d",
+					vkcv_log(LogLevel::ERROR, "Sampler of texture '%s' missing (%s)",
 							 textureObject.name.c_str(), path.c_str());
 					return ASSET_ERROR;
 				} else {
diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp
index d6fa2a40a494ef57386e52a306e962a460c66dd6..c0065af5928d9ad2e2c9afd1a1ea44c35d94d799 100644
--- a/modules/scene/src/vkcv/scene/Scene.cpp
+++ b/modules/scene/src/vkcv/scene/Scene.cpp
@@ -116,6 +116,10 @@ namespace vkcv::scene {
 								size_t							 pushConstantsSizePerDrawcall,
 								const RecordMeshDrawcallFunction &record,
 								const std::vector<ImageHandle>   &renderTargets) {
+		m_core->recordBeginDebugLabel(cmdStream, "vkcv::scene::Scene", {
+			0.0f, 1.0f, 0.0f, 1.0f
+		});
+		
 		PushConstants pushConstants (pushConstantsSizePerDrawcall);
 		std::vector<DrawcallInfo> drawcalls;
 		size_t count = 0;
@@ -137,6 +141,8 @@ namespace vkcv::scene {
 				drawcalls,
 				renderTargets
 		);
+		
+		m_core->recordEndDebugLabel(cmdStream);
 	}
 	
 	Scene Scene::create(Core& core) {
diff --git a/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp
index 9c36acf5d050e3f4f19223020357b6c32534a2de..54df1829006964b30cc1831dc7115e9d5d222a51 100644
--- a/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/BilinearUpscaling.cpp
@@ -7,7 +7,13 @@ namespace vkcv::upscaling {
 	
 	void BilinearUpscaling::recordUpscaling(const CommandStreamHandle &cmdStream, const ImageHandle &input,
 											const ImageHandle &output) {
+		m_core.recordBeginDebugLabel(cmdStream, "vkcv::upscaling::BilinearUpscaling", {
+			0.0f, 0.0f, 1.0f, 1.0f
+		});
+		
 		m_core.recordBlitImage(cmdStream, input, output, SamplerFilterType::LINEAR);
+		
+		m_core.recordEndDebugLabel(cmdStream);
 	}
 
 }
diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
index 460a6d0b459fe7d1d2a917a62138fea2e5a40908..b11051273ba6f9e56d3a537931f9d33fff657e43 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");
@@ -245,6 +245,10 @@ namespace vkcv::upscaling {
 	void FSRUpscaling::recordUpscaling(const CommandStreamHandle& cmdStream,
 									   const ImageHandle& input,
 									   const ImageHandle& output) {
+		m_core.recordBeginDebugLabel(cmdStream, "vkcv::upscaling::FSRUpscaling", {
+			1.0f, 0.0f, 0.0f, 1.0f
+		});
+		
 		const uint32_t inputWidth = m_core.getImageWidth(input);
 		const uint32_t inputHeight = m_core.getImageHeight(input);
 		
@@ -361,6 +365,8 @@ namespace vkcv::upscaling {
 					PushConstants(0)
 			);
 		}
+		
+		m_core.recordEndDebugLabel(cmdStream);
 	}
 	
 	bool FSRUpscaling::isHdrEnabled() const {
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index 130b6e6138a03bcc380273438c173d2bf9ca915a..feb2153f5b5274a168fb49bd7087a8b4092dcc47 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -15,8 +15,7 @@ int main(int argc, const char** argv) {
 		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 4a485cdeb1293fe394278a7338be129b4e126447..6741a26c9f484d94241aa8ffd368101390d9c5f6 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 713c844a2f7c904a05f49332d88c4fd01d9dc7e2..79bdd67b085338072094b7a8948b0e8a523b33cd 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -15,20 +15,21 @@ int main(int argc, const char** argv) {
 		windowWidth,
 		windowHeight
 	);
-
+	
 	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);
 	uint16_t indices[3] = { 0, 1, 2 };
 	triangleIndexBuffer.fill(&indices[0], sizeof(indices));
 
+	core.setDebugLabel(triangleIndexBuffer.getHandle(), "Triangle Index Buffer");
+	
 	// an example attachment for passes that output to the window
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentOperation::STORE,
@@ -43,6 +44,8 @@ int main(int argc, const char** argv) {
 		std::cout << "Error. Could not create renderpass. Exiting." << std::endl;
 		return EXIT_FAILURE;
 	}
+	
+	core.setDebugLabel(trianglePass, "Triangle Pass");
 
 	vkcv::ShaderProgram triangleShaderProgram;
 	vkcv::shader::GLSLCompiler compiler;
@@ -75,12 +78,15 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 	
+	core.setDebugLabel(trianglePipeline, "Triangle Pipeline");
+	
 	auto start = std::chrono::system_clock::now();
 
 	const vkcv::Mesh renderMesh({}, triangleIndexBuffer.getVulkanHandle(), 3);
 	vkcv::DrawcallInfo drawcall(renderMesh, {},1);
 
 	const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle();
+	core.setDebugLabel(swapchainInput, "Swapchain Image");
 
     vkcv::camera::CameraManager cameraManager(window);
     uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT);
@@ -110,6 +116,7 @@ int main(int argc, const char** argv) {
 		pushConstants.appendDrawcall(mvp);
 		
 		auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics);
+		core.setDebugLabel(cmdStream, "Render Commands");
 
 		core.recordDrawcallsToCmdStream(
 			cmdStream,
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 242be45f897fd7a765b748b0f91168a3c3996fea..0f602b8d7a9580480f5b59fba71b3677cf740ea2 100644
--- a/projects/mesh_shader/src/main.cpp
+++ b/projects/mesh_shader/src/main.cpp
@@ -85,14 +85,21 @@ int main(int argc, const char** argv) {
 		windowWidth,
 		windowHeight
 	);
+	
+	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 05befa54a03ee7d1357771d15c51d166b1474229..9550cdd7b33ec31a5a4d9ea13ae0dd97f5bdb93d 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 af0ca5fa9a2aeb37cb6e201bb197b3ad776ea607..ad1cc4556d82d23a29c06adfd74e05a0b7cdbc69 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 ecf4de6934e2115be73992babf8a61cfd7ec1223..886a20b1dbbb7dd88b303d97ec6281ec81b2e375 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -24,14 +24,14 @@ namespace vkcv
     Core Core::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)
     {
         Context context = Context::create(
         		applicationName, applicationVersion,
         		queueFlags,
-        		instanceExtensions,
-        		deviceExtensions
+				features,
+        		instanceExtensions
 		);
 
         const auto& queueManager = context.getQueueManager();
@@ -205,9 +205,8 @@ namespace vkcv
 		vk::Device                      device) {
 
 		std::vector<vk::ImageView> attachmentsViews;
-		for (const ImageHandle handle : renderTargets) {
-			vk::ImageView targetHandle = imageManager.getVulkanImageView(handle);
-			attachmentsViews.push_back(targetHandle);
+		for (const ImageHandle& handle : renderTargets) {
+			attachmentsViews.push_back(imageManager.getVulkanImageView(handle));
 		}
 
 		const std::array<uint32_t, 2> widthHeight = getWidthHeightFromRenderTargets(renderTargets, swapchain, imageManager);
@@ -229,8 +228,7 @@ namespace vkcv
 		ImageManager&                   imageManager,
 		const vk::CommandBuffer         cmdBuffer) {
 
-		for (const ImageHandle handle : renderTargets) {
-			vk::ImageView targetHandle = imageManager.getVulkanImageView(handle);
+		for (const ImageHandle& handle : renderTargets) {
 			const bool isDepthImage = isDepthFormat(imageManager.getImageFormat(handle));
 			const vk::ImageLayout targetLayout =
 				isDepthImage ? vk::ImageLayout::eDepthStencilAttachmentOptimal : vk::ImageLayout::eColorAttachmentOptimal;
@@ -273,8 +271,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,
@@ -310,7 +308,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());
@@ -319,16 +316,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();
 		};
 
@@ -341,8 +336,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,
@@ -378,7 +373,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());
@@ -387,12 +381,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,
@@ -400,14 +393,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);
 		};
 
@@ -448,7 +441,50 @@ namespace vkcv
 
 		recordCommandsToStream(cmdStreamHandle, submitFunction, nullptr);
 	}
+	
+	void Core::recordBeginDebugLabel(const CommandStreamHandle &cmdStream,
+									 const std::string& label,
+									 const std::array<float, 4>& color) {
+#ifndef NDEBUG
+		static PFN_vkCmdBeginDebugUtilsLabelEXT beginDebugLabel = reinterpret_cast<PFN_vkCmdBeginDebugUtilsLabelEXT>(
+				m_Context.getDevice().getProcAddr("vkCmdBeginDebugUtilsLabelEXT")
+		);
+		
+		if (!beginDebugLabel) {
+			return;
+		}
+		
+		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
+			const vk::DebugUtilsLabelEXT debug (
+					label.c_str(),
+					color
+			);
+			
+			beginDebugLabel(cmdBuffer, &(static_cast<const VkDebugUtilsLabelEXT&>(debug)));
+		};
+
+		recordCommandsToStream(cmdStream, submitFunction, nullptr);
+#endif
+	}
+	
+	void Core::recordEndDebugLabel(const CommandStreamHandle &cmdStream) {
+#ifndef NDEBUG
+		static PFN_vkCmdEndDebugUtilsLabelEXT endDebugLabel = reinterpret_cast<PFN_vkCmdEndDebugUtilsLabelEXT>(
+				m_Context.getDevice().getProcAddr("vkCmdEndDebugUtilsLabelEXT")
+		);
+		
+		if (!endDebugLabel) {
+			return;
+		}
+		
+		auto submitFunction = [&](const vk::CommandBuffer& cmdBuffer) {
+			endDebugLabel(cmdBuffer);
+		};
 
+		recordCommandsToStream(cmdStream, submitFunction, nullptr);
+#endif
+	}
+	
 	void Core::recordComputeIndirectDispatchToCmdStream(
 		const CommandStreamHandle               cmdStream,
 		const PipelineHandle                    computePipeline,
@@ -801,4 +837,142 @@ namespace vkcv
 				swapchain.getFormat()
 		);
 	}
+	
+	static void setDebugObjectLabel(const vk::Device& device, const vk::ObjectType& type,
+									uint64_t handle, const std::string& label) {
+#ifndef NDEBUG
+		static PFN_vkSetDebugUtilsObjectNameEXT setDebugLabel = reinterpret_cast<PFN_vkSetDebugUtilsObjectNameEXT>(
+				device.getProcAddr("vkSetDebugUtilsObjectNameEXT")
+		);
+		
+		if (!setDebugLabel) {
+			return;
+		}
+		
+		const vk::DebugUtilsObjectNameInfoEXT debug (
+				type,
+				handle,
+				label.c_str()
+		);
+		
+		setDebugLabel(device, &(static_cast<const VkDebugUtilsObjectNameInfoEXT&>(debug)));
+#endif
+	}
+	
+	void Core::setDebugLabel(const BufferHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eBuffer,
+				reinterpret_cast<uint64_t>(static_cast<VkBuffer>(
+						m_BufferManager->getBuffer(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const PassHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eRenderPass,
+				reinterpret_cast<uint64_t>(static_cast<VkRenderPass>(
+						m_PassManager->getVkPass(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const PipelineHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::ePipeline,
+				reinterpret_cast<uint64_t>(static_cast<VkPipeline>(
+						m_PipelineManager->getVkPipeline(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const DescriptorSetHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eDescriptorSet,
+				reinterpret_cast<uint64_t>(static_cast<VkDescriptorSet>(
+						m_DescriptorManager->getDescriptorSet(handle).vulkanHandle
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const SamplerHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eSampler,
+				reinterpret_cast<uint64_t>(static_cast<VkSampler>(
+						m_SamplerManager->getVulkanSampler(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const ImageHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		} else
+		if (handle.isSwapchainImage()) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to swapchain image");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eImage,
+				reinterpret_cast<uint64_t>(static_cast<VkImage>(
+						m_ImageManager->getVulkanImage(handle)
+				)),
+				label
+		);
+	}
+	
+	void Core::setDebugLabel(const CommandStreamHandle &handle, const std::string &label) {
+		if (!handle) {
+			vkcv_log(LogLevel::WARNING, "Can't set debug label to invalid handle");
+			return;
+		}
+		
+		setDebugObjectLabel(
+				m_Context.getDevice(),
+				vk::ObjectType::eCommandBuffer,
+				reinterpret_cast<uint64_t>(static_cast<VkCommandBuffer>(
+						m_CommandStreamManager->getStreamCommandBuffer(handle)
+				)),
+				label
+		);
+	}
+	
 }
diff --git a/src/vkcv/DrawcallRecording.cpp b/src/vkcv/DrawcallRecording.cpp
index d89ace3859717f753534402507a713a78bfb6876..ca8b248a06d06c7aed6f8d0e9760645b727a5993 100644
--- a/src/vkcv/DrawcallRecording.cpp
+++ b/src/vkcv/DrawcallRecording.cpp
@@ -52,8 +52,6 @@ namespace vkcv {
         }
     }
 
-
-
     struct MeshShaderFunctions
     {
         PFN_vkCmdDrawMeshTasksNV cmdDrawMeshTasks                           = nullptr;
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;
+	}
+
+}
diff --git a/src/vkcv/QueueManager.cpp b/src/vkcv/QueueManager.cpp
index 15e958b0de929e53170324ade27a9b3663a15d6a..79e15c9b00e4c67fb956bdcd0e8b1ff05261b2f1 100644
--- a/src/vkcv/QueueManager.cpp
+++ b/src/vkcv/QueueManager.cpp
@@ -44,7 +44,7 @@ namespace vkcv {
         std::vector<int> prios;
         for(auto flag: queueFlags) {
             int prioCount = 0;
-            for (int i = 0; i < qFamilyProperties.size(); i++) {
+            for (size_t i = 0; i < qFamilyProperties.size(); i++) {
                 prioCount += (static_cast<uint32_t>(flag & qFamilyProperties[i].queueFlags) != 0) * qFamilyProperties[i].queueCount;
             }
             prios.push_back(prioCount);
@@ -65,10 +65,14 @@ namespace vkcv {
         std::vector<std::vector<int>> queueFamilyStatus, initialQueueFamilyStatus;
 
         for (auto qFamily : qFamilyProperties) {
-            int graphicsCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0) * qFamily.queueCount;
-            int computeCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0) * qFamily.queueCount;
-            int transferCount = int(static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0) * qFamily.queueCount;
-            queueFamilyStatus.push_back({graphicsCount, computeCount, transferCount});
+            auto graphicsCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eGraphics) != 0? qFamily.queueCount : 0;
+			auto computeCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eCompute) != 0? qFamily.queueCount : 0;
+			auto transferCount = static_cast<uint32_t>(qFamily.queueFlags & vk::QueueFlagBits::eTransfer) != 0? qFamily.queueCount : 0;
+            queueFamilyStatus.push_back({
+				static_cast<int>(graphicsCount),
+				static_cast<int>(computeCount),
+				static_cast<int>(transferCount)
+			});
         }
 
         initialQueueFamilyStatus = queueFamilyStatus;