diff --git a/CMakeLists.txt b/CMakeLists.txt
index f8e28a3d23e7b0ada5040a5ee01fb8d13d855962..15f953b3b3b46e7e6f86526d90a53a5d4d40d3bc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,6 +8,7 @@ option(BUILD_CLANG_FORMAT "Enables formatting the source code" OFF)
 option(BUILD_DOXYGEN_DOCS "Enables building the VkCV doxygen documentation" OFF)
 option(BUILD_SHARED "Enables building VkCV as shared libraries" OFF)
 option(BUILD_VMA_VULKAN_VERSION "Enforce a specific Vulkan version for VMA" OFF)
+option(BUILD_VALIDATION_FORCED "Enforce validation layers being built-in" OFF)
 
 # uncomment the following line if cmake will refuse to build projects
 #set(BUILD_PROJECTS ON)
@@ -79,6 +80,10 @@ if (vkcv_build_debug)
 	else()
 		set(vkcv_flags ${vkcv_flags} " -W4")
 	endif()
+	
+	list(APPEND vkcv_definitions VULKAN_VALIDATION_LAYERS)
+elseif (BUILD_VALIDATION_FORCED)
+	list(APPEND vkcv_definitions VULKAN_VALIDATION_LAYERS)
 endif()
 
 if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "11.0.0"))
diff --git a/modules/camera/include/vkcv/camera/Camera.hpp b/modules/camera/include/vkcv/camera/Camera.hpp
index b333fbbd696a4583bd4aa9f9591a75d4de532d1d..9851cb7348d139a3bd95828d50fcca37382f0228 100644
--- a/modules/camera/include/vkcv/camera/Camera.hpp
+++ b/modules/camera/include/vkcv/camera/Camera.hpp
@@ -72,6 +72,7 @@ namespace vkcv::camera {
          * @brief Gets the view matrix of the camera
          * @return The view matrix of the camera
          */
+		[[nodiscard]]
         const glm::mat4& getView() const;
 
         /**
@@ -86,12 +87,14 @@ namespace vkcv::camera {
          * @brief Gets the current projection of the camera
          * @return The current projection matrix
          */
+		[[nodiscard]]
         const glm::mat4& getProjection() const;
 
         /**
          * @brief Gets the model-view-projection matrix of the camera with y-axis-correction applied
          * @return The model-view-projection matrix
          */
+		[[nodiscard]]
         glm::mat4 getMVP() const;
 
         /**
@@ -105,6 +108,7 @@ namespace vkcv::camera {
          * @brief Gets the current field of view of the camera in radians
          * @return[in] The current field of view in radians
          */
+		[[nodiscard]]
         float getFov() const;
 
         /**
@@ -117,6 +121,7 @@ namespace vkcv::camera {
          * @brief Gets the current aspect ratio of the camera
          * @return The current aspect ratio of the camera
          */
+		[[nodiscard]]
         float getRatio() const;
 
         /**
@@ -136,6 +141,7 @@ namespace vkcv::camera {
          * @brief Gets the current front vector of the camera in world space
          * @return The current front vector of the camera
          */
+		[[nodiscard]]
         glm::vec3 getFront() const;
         
         /**
@@ -148,6 +154,7 @@ namespace vkcv::camera {
          * @brief Gets the current position of the camera in world space
          * @return The current position of the camera in world space
          */
+		[[nodiscard]]
         const glm::vec3& getPosition() const;
 
         /**
@@ -160,6 +167,7 @@ namespace vkcv::camera {
          * @brief Gets the center point.
          * @return The center point.
          */
+		[[nodiscard]]
         const glm::vec3& getCenter() const;
 
         /**
@@ -186,6 +194,7 @@ namespace vkcv::camera {
          * @brief Gets the pitch value of the camera in degrees.
          * @return The pitch value in degrees.
          */
+		[[nodiscard]]
         float getPitch() const;
 
         /**
@@ -198,6 +207,7 @@ namespace vkcv::camera {
          * @brief Gets the yaw value of the camera in degrees.
          * @return The yaw value in degrees.
          */
+		[[nodiscard]]
         float getYaw() const;
 
         /**
@@ -210,6 +220,7 @@ namespace vkcv::camera {
          * @brief Gets the up vector.
          * @return The up vector.
          */
+		[[nodiscard]]
         const glm::vec3& getUp() const;
 
         /**
@@ -217,6 +228,7 @@ namespace vkcv::camera {
          * @param[in] up The new up vector.
          */
         void setUp(const glm::vec3 &up);
+		
     };
 
     /** @} */
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index da07fdca624b29f9d4d509c12d6757d34e92eed1..2705c61cdb8755136d7c660aeb4a5e494b35a55e 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -87,7 +87,7 @@ int main(int argc, const char** argv) {
 	}
 
 	vkcv::SamplerHandle sampler = vkcv::samplerLinear(core);
-
+	
 	vkcv::DescriptorWrites setWrites;
 	setWrites.writeSampledImage(0, texture.getHandle());
 	setWrites.writeSampler(1, sampler);
@@ -144,5 +144,7 @@ int main(int argc, const char** argv) {
 		core.submitCommandStream(cmdStream);
 	});
 	
+	core.getContext().getDevice().waitIdle();
+	
 	return 0;
 }
diff --git a/src/vkcv/BufferManager.cpp b/src/vkcv/BufferManager.cpp
index 567041bb602493196512b554014cf39277926bdc..4ee9592592e73f71617dddebe04f37771b497ded 100644
--- a/src/vkcv/BufferManager.cpp
+++ b/src/vkcv/BufferManager.cpp
@@ -7,6 +7,8 @@
 #include "vkcv/Core.hpp"
 #include <vkcv/Logger.hpp>
 
+#include <limits>
+
 namespace vkcv {
 
 	bool BufferManager::init(Core &core) {
@@ -287,7 +289,7 @@ namespace vkcv {
 		auto &buffer = (*this) [handle];
 
 		if (size == 0) {
-			size = SIZE_MAX;
+			size = std::numeric_limits<size_t>::max();
 		}
 
 		const vma::Allocator &allocator = getCore().getContext().getAllocator();
@@ -326,7 +328,7 @@ namespace vkcv {
 		auto &buffer = (*this) [handle];
 
 		if (size == 0) {
-			size = SIZE_MAX;
+			size = std::numeric_limits<size_t>::max();
 		}
 
 		const vma::Allocator &allocator = getCore().getContext().getAllocator();
@@ -364,7 +366,7 @@ namespace vkcv {
 		auto &buffer = (*this) [handle];
 
 		if (size == 0) {
-			size = SIZE_MAX;
+			size = std::numeric_limits<size_t>::max();
 		}
 
 		const vma::Allocator &allocator = getCore().getContext().getAllocator();
diff --git a/src/vkcv/CommandStreamManager.cpp b/src/vkcv/CommandStreamManager.cpp
index a776042ffa1d0d5429b93dc02ae1d72a0a2e23ac..b93cf0a812933ef3f1ea3f62689a5c03062e6e80 100644
--- a/src/vkcv/CommandStreamManager.cpp
+++ b/src/vkcv/CommandStreamManager.cpp
@@ -3,6 +3,8 @@
 
 #include "vkcv/Logger.hpp"
 
+#include <limits>
+
 namespace vkcv {
 
 	uint64_t CommandStreamManager::getIdFrom(const CommandStreamHandle &handle) const {
@@ -86,7 +88,12 @@ namespace vkcv {
 											 signalSemaphores);
 
 		stream.queue.submit(queueSubmitInfo, waitFence);
-		assert(device.waitForFences(waitFence, true, UINT64_MAX) == vk::Result::eSuccess);
+		
+		const auto result = device.waitForFences(waitFence, true, std::numeric_limits<uint64_t>::max());
+		
+		if (result == vk::Result::eTimeout) {
+			device.waitIdle();
+		}
 
 		device.destroyFence(waitFence);
 		stream.queue = nullptr;
diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp
index c9d48456550f786ce6f6ee25d755ad258bc11d1f..c26bf632e3278364f61e77a66745f75c1ccc3684 100644
--- a/src/vkcv/Context.cpp
+++ b/src/vkcv/Context.cpp
@@ -4,6 +4,7 @@
 #include "vkcv/Window.hpp"
 
 namespace vkcv {
+	
 	Context::Context(Context &&other) noexcept :
 		m_Instance(other.m_Instance), m_PhysicalDevice(other.m_PhysicalDevice),
 		m_Device(other.m_Device), m_FeatureManager(std::move(other.m_FeatureManager)),
@@ -147,7 +148,7 @@ namespace vkcv {
 	std::vector<std::string> getRequiredExtensions() {
 		std::vector<std::string> extensions = Window::getExtensions();
 
-#ifndef NDEBUG
+#ifdef VULKAN_DEBUG_LABELS
 		extensions.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 #endif
 
@@ -346,7 +347,7 @@ namespace vkcv {
 		}
 
 // if in debug mode, check if validation layers are supported. Enable them if supported
-#ifndef NDEBUG
+#ifdef VULKAN_VALIDATION_LAYERS
 		std::vector<const char*> validationLayers = { "VK_LAYER_KHRONOS_validation" };
 
 		if (!checkSupport(supportedLayers, validationLayers)) {
@@ -388,7 +389,7 @@ namespace vkcv {
 			vk::InstanceCreateFlags(), &applicationInfo, 0, nullptr,
 			static_cast<uint32_t>(requiredExtensions.size()), requiredExtensions.data());
 
-#ifndef NDEBUG
+#ifdef VULKAN_VALIDATION_LAYERS
 		instanceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
 		instanceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 #endif
@@ -478,7 +479,7 @@ namespace vkcv {
 			vk::DeviceCreateFlags(), qCreateInfos.size(), qCreateInfos.data(), 0, nullptr,
 			extensions.size(), extensions.data(), nullptr, &(featureManager.getFeatures()));
 
-#ifndef NDEBUG
+#ifdef VULKAN_VALIDATION_LAYERS
 		deviceCreateInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
 		deviceCreateInfo.ppEnabledLayerNames = validationLayers.data();
 #endif
diff --git a/src/vkcv/Handles.cpp b/src/vkcv/Handles.cpp
index abf5b9d7ec44699f6c581236b29fa921459c7ab4..ef90ffd9a928fa348847bdc07acf25b58d4b6ac0 100644
--- a/src/vkcv/Handles.cpp
+++ b/src/vkcv/Handles.cpp
@@ -1,10 +1,11 @@
 #include "vkcv/Handles.hpp"
 
 #include <iostream>
+#include <limits>
 
 namespace vkcv {
 
-	Handle::Handle() : m_id(UINT64_MAX), m_rc(nullptr), m_destroy(nullptr) {}
+	Handle::Handle() : m_id(std::numeric_limits<uint64_t>::max()), m_rc(nullptr), m_destroy(nullptr) {}
 
 	Handle::Handle(uint64_t id, const HandleDestroyFunction &destroy) :
 		m_id(id), m_rc(new uint64_t(1)), m_destroy(destroy) {}
@@ -66,11 +67,11 @@ namespace vkcv {
 	}
 
 	Handle::operator bool() const {
-		return (m_id < UINT64_MAX);
+		return (m_id < std::numeric_limits<uint64_t>::max());
 	}
 
 	bool Handle::operator!() const {
-		return (m_id == UINT64_MAX);
+		return (m_id == std::numeric_limits<uint64_t>::max());
 	}
 
 	std::ostream &operator<<(std::ostream &out, const Handle &handle) {
@@ -83,11 +84,11 @@ namespace vkcv {
 	}
 
 	bool ImageHandle::isSwapchainImage() const {
-		return (getId() == UINT64_MAX - 1);
+		return (getId() == std::numeric_limits<uint64_t>::max() - 1);
 	}
 
 	ImageHandle ImageHandle::createSwapchainImageHandle(const HandleDestroyFunction &destroy) {
-		return ImageHandle(uint64_t(UINT64_MAX - 1), destroy);
+		return ImageHandle(uint64_t(std::numeric_limits<uint64_t>::max() - 1), destroy);
 	}
 
 } // namespace vkcv