2
0
Эх сурвалжийг харах

Add some assertions to enum overloads to avoid various bugs

Panagiotis Christopoulos Charitos 5 жил өмнө
parent
commit
1262f15f52

+ 1 - 1
docs/code_style.md

@@ -73,7 +73,7 @@ C++ rules
 **Always use strongly typed enums**. If you need to relax the rules use the `ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS` macro.
 
 	enum class MyEnum : uint {...};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MyEnum, inline);
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MyEnum);
 
 **Never use `typedef`** to define types. Use `using` instead.
 

+ 1 - 0
src/anki/Config.h.cmake

@@ -186,6 +186,7 @@
 #if ANKI_COMPILER_MSVC
 #	include <intrin.h>
 #	define __builtin_popcount __popcnt
+#	define __builtin_popcountl __popcnt64
 #	define __builtin_clzll(x) ((int)__lzcnt64(x))
 #endif
 

+ 3 - 3
src/anki/collision/Common.h

@@ -28,7 +28,7 @@ enum class FrustumPlaneType : U8
 	COUNT,
 	FIRST = 0
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumPlaneType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumPlaneType)
 
 /// Collision shape type.
 enum class CollisionShapeType : U8
@@ -45,7 +45,7 @@ enum class CollisionShapeType : U8
 	COUNT,
 	FIRST = 0
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CollisionShapeType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CollisionShapeType)
 
 /// Frustum type
 enum class FrustumType : U8
@@ -56,7 +56,7 @@ enum class FrustumType : U8
 	COUNT,
 	FIRST = 0
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumType)
 /// @}
 
 } // end namespace anki

+ 2 - 2
src/anki/core/StagingGpuMemoryManager.h

@@ -18,7 +18,7 @@ class ConfigSet;
 /// @addtogroup core
 /// @{
 
-enum class StagingGpuMemoryType
+enum class StagingGpuMemoryType : U8
 {
 	UNIFORM,
 	STORAGE,
@@ -26,7 +26,7 @@ enum class StagingGpuMemoryType
 	TEXTURE,
 	COUNT
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(StagingGpuMemoryType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(StagingGpuMemoryType)
 
 /// Token that gets returned when requesting for memory to write to a resource.
 class StagingGpuMemoryToken

+ 1 - 1
src/anki/gr/CommandBuffer.h

@@ -102,7 +102,7 @@ enum class CommandBufferFlag : U8
 	/// Will contain compute work.
 	COMPUTE_WORK = 1 << 6,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CommandBufferFlag, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(CommandBufferFlag)
 
 /// Command buffer init info.
 class CommandBufferInitInfo : public GrBaseInitInfo

+ 13 - 19
src/anki/gr/Enums.h

@@ -23,7 +23,7 @@ enum class ColorBit : U8
 	ALPHA = 1 << 3,
 	ALL = RED | GREEN | BLUE | ALPHA
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ColorBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ColorBit)
 
 enum class PrimitiveTopology : U8
 {
@@ -50,7 +50,7 @@ enum class FaceSelectionBit : U8
 	BACK = 1 << 1,
 	FRONT_AND_BACK = FRONT | BACK
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FaceSelectionBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FaceSelectionBit)
 
 enum class CompareOperation : U8
 {
@@ -128,7 +128,7 @@ enum class DepthStencilAspectBit : U8
 	STENCIL = 1 << 1,
 	DEPTH_STENCIL = DEPTH | STENCIL
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DepthStencilAspectBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DepthStencilAspectBit)
 
 /// Pixel or vertex format.
 /// WARNING: Keep it the same as vulkan (one conversion less).
@@ -328,7 +328,7 @@ enum class Format : U32
 	PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
 	PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Format, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Format)
 
 inline Bool formatIsDepthStencil(const Format fmt)
 {
@@ -422,7 +422,7 @@ enum class TextureUsageBit : U32
 	ALL_WRITE = IMAGE_GEOMETRY_WRITE | IMAGE_FRAGMENT_WRITE | IMAGE_COMPUTE_WRITE | IMAGE_RAY_GEN_WRITE
 				| FRAMEBUFFER_ATTACHMENT_WRITE | TRANSFER_DESTINATION | GENERATE_MIPMAPS
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureUsageBit)
 
 enum class SamplingFilter : U8
 {
@@ -443,7 +443,7 @@ enum class SamplingAddressing : U8
 	LAST = COUNT - 1,
 };
 
-enum class ShaderType : U8
+enum class ShaderType : U16
 {
 	VERTEX,
 	TESSELLATION_CONTROL,
@@ -466,7 +466,7 @@ enum class ShaderType : U8
 	FIRST_RAY_TRACING = RAY_GEN,
 	LAST_RAY_TRACING = CALLABLE,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderType)
 
 enum class ShaderTypeBit : U16
 {
@@ -488,13 +488,7 @@ enum class ShaderTypeBit : U16
 	ALL_RAY_TRACING = RAY_GEN | ANY_HIT | CLOSEST_HIT | MISS | INTERSECTION | CALLABLE,
 	ALL = ALL_GRAPHICS | COMPUTE | ALL_RAY_TRACING,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderTypeBit, inline)
-
-inline ShaderTypeBit shaderTypeToBit(ShaderType type)
-{
-	ANKI_ASSERT(type < ShaderType::COUNT);
-	return ShaderTypeBit(1 << U32(type));
-}
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderTypeBit)
 
 enum class ShaderVariableDataType : U8
 {
@@ -529,7 +523,7 @@ enum class ShaderVariableDataType : U8
 	IMAGE_FIRST = IMAGE_1D,
 	IMAGE_LAST = IMAGE_CUBE_ARRAY,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderVariableDataType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ShaderVariableDataType)
 
 /// Occlusion query result bit.
 enum class OcclusionQueryResultBit : U8
@@ -538,7 +532,7 @@ enum class OcclusionQueryResultBit : U8
 	VISIBLE = 1 << 1,
 	NOT_VISIBLE = 1 << 2
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(OcclusionQueryResultBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(OcclusionQueryResultBit)
 
 /// Occlusion query result.
 enum class OcclusionQueryResult : U8
@@ -643,7 +637,7 @@ enum class BufferUsageBit : U64
 				| TEXTURE_GEOMETRY_WRITE | TEXTURE_FRAGMENT_WRITE | TEXTURE_COMPUTE_WRITE | TEXTURE_TRACE_RAYS_WRITE
 				| TRANSFER_DESTINATION,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferUsageBit)
 
 /// Buffer access when mapped.
 enum class BufferMapAccessBit : U8
@@ -652,7 +646,7 @@ enum class BufferMapAccessBit : U8
 	READ = 1 << 0,
 	WRITE = 1 << 1
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferMapAccessBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BufferMapAccessBit)
 
 /// Index buffer's index type.
 enum class IndexType : U8
@@ -693,7 +687,7 @@ enum class AccelerationStructureUsageBit : U8
 	ALL_READ = ATTACH | GEOMETRY_READ | FRAGMENT_READ | COMPUTE_READ | RAY_GEN_READ,
 	ALL_WRITE = BUILD
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(AccelerationStructureUsageBit)
 /// @}
 
 } // end namespace anki

+ 70 - 0
src/anki/gr/vulkan/Common.cpp

@@ -452,6 +452,76 @@ VkStencilOp convertStencilOp(StencilOperation ak)
 	return out;
 }
 
+VkShaderStageFlags convertShaderTypeBit(ShaderTypeBit bit)
+{
+	ANKI_ASSERT(bit != ShaderTypeBit::NONE);
+
+	VkShaderStageFlags out = 0;
+	if(!!(bit & ShaderTypeBit::VERTEX))
+	{
+		out |= VK_SHADER_STAGE_VERTEX_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::TESSELLATION_CONTROL))
+	{
+		out |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::TESSELLATION_EVALUATION))
+	{
+		out |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::GEOMETRY))
+	{
+		out |= VK_SHADER_STAGE_GEOMETRY_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::FRAGMENT))
+	{
+		out |= VK_SHADER_STAGE_FRAGMENT_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::COMPUTE))
+	{
+		out |= VK_SHADER_STAGE_COMPUTE_BIT;
+	}
+
+	if(!!(bit & ShaderTypeBit::RAY_GEN))
+	{
+		out |= VK_SHADER_STAGE_RAYGEN_BIT_KHR;
+	}
+
+	if(!!(bit & ShaderTypeBit::ANY_HIT))
+	{
+		out |= VK_SHADER_STAGE_ANY_HIT_BIT_KHR;
+	}
+
+	if(!!(bit & ShaderTypeBit::CLOSEST_HIT))
+	{
+		out |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
+	}
+
+	if(!!(bit & ShaderTypeBit::MISS))
+	{
+		out |= VK_SHADER_STAGE_MISS_BIT_KHR;
+	}
+
+	if(!!(bit & ShaderTypeBit::INTERSECTION))
+	{
+		out |= VK_SHADER_STAGE_INTERSECTION_BIT_KHR;
+	}
+
+	if(!!(bit & ShaderTypeBit::CALLABLE))
+	{
+		out |= VK_SHADER_STAGE_CALLABLE_BIT_KHR;
+	}
+
+	ANKI_ASSERT(out != 0);
+	ANKI_ASSERT(__builtin_popcount(U32(bit)) == __builtin_popcount(out));
+	return out;
+}
+
 const char* vkResultToString(VkResult res)
 {
 	const char* out;

+ 2 - 6
src/anki/gr/vulkan/Common.h

@@ -70,7 +70,7 @@ enum class VulkanExtensions : U16
 	AMD_RASTERIZATION_ORDER = 1 << 11,
 	KHR_RAY_TRACING = 1 << 12
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions)
 
 /// @name Constants
 /// @{
@@ -197,11 +197,7 @@ ANKI_USE_RESULT VkImageUsageFlags convertTextureUsage(const TextureUsageBit ak,
 
 ANKI_USE_RESULT VkStencilOp convertStencilOp(StencilOperation ak);
 
-ANKI_USE_RESULT inline VkShaderStageFlagBits convertShaderTypeBit(ShaderTypeBit bit)
-{
-	ANKI_ASSERT(bit != ShaderTypeBit::NONE);
-	return static_cast<VkShaderStageFlagBits>(bit);
-}
+ANKI_USE_RESULT VkShaderStageFlags convertShaderTypeBit(ShaderTypeBit bit);
 
 ANKI_USE_RESULT inline VkVertexInputRate convertVertexStepRate(VertexStepRate ak)
 {

+ 1 - 1
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -1046,7 +1046,7 @@ Error GrManagerImpl::printPipelineShaderInfoInternal(VkPipeline ppline, CString
 			}
 
 			size_t size = sizeof(stats);
-			ANKI_VK_CHECK(m_pfnGetShaderInfoAMD(m_device, ppline, convertShaderTypeBit(stage),
+			ANKI_VK_CHECK(m_pfnGetShaderInfoAMD(m_device, ppline, VkShaderStageFlagBits(convertShaderTypeBit(stage)),
 												VK_SHADER_INFO_TYPE_STATISTICS_AMD, &size, &stats));
 
 			str.append(StringAuto(getAllocator())

+ 1 - 1
src/anki/gr/vulkan/Pipeline.h

@@ -457,7 +457,7 @@ private:
 		NONE = 0,
 		ALL = PROG | IA | RASTER | STENCIL | DEPTH | COLOR
 	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(DirtyBit, friend)
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(DirtyBit)
 
 	class DirtyBits
 	{

+ 1 - 1
src/anki/gr/vulkan/ShaderImpl.cpp

@@ -165,7 +165,7 @@ void ShaderImpl::doReflection(ConstWeakArray<U8> spirv, SpecConstsVector& specCo
 				DescriptorBinding& descriptor = descriptors[set][counts[set]++];
 				descriptor.m_binding = U8(binding);
 				descriptor.m_type = type;
-				descriptor.m_stageMask = static_cast<ShaderTypeBit>(1 << m_shaderType);
+				descriptor.m_stageMask = ShaderTypeBit(1 << m_shaderType);
 				descriptor.m_arraySizeMinusOne = U8(arraySize - 1);
 			}
 			else

+ 7 - 8
src/anki/gr/vulkan/ShaderProgramImpl.cpp

@@ -205,7 +205,7 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 			VkPipelineShaderStageCreateInfo& inf = m_graphics.m_shaderCreateInfos[m_graphics.m_shaderCreateInfoCount++];
 			inf = {};
 			inf.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-			inf.stage = convertShaderTypeBit(ShaderTypeBit(1 << shader->getShaderType()));
+			inf.stage = VkShaderStageFlagBits(convertShaderTypeBit(ShaderTypeBit(1 << shader->getShaderType())));
 			inf.pName = "main";
 			inf.module = shaderImpl.m_handle;
 			inf.pSpecializationInfo = shaderImpl.getSpecConstInfo();
@@ -256,7 +256,7 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 			VkPipelineShaderStageCreateInfo& stage = stages[i];
 			stage = {};
 			stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
-			stage.stage = convertShaderTypeBit(ShaderTypeBit(1 << impl.getShaderType()));
+			stage.stage = VkShaderStageFlagBits(convertShaderTypeBit(ShaderTypeBit(1 << impl.getShaderType())));
 			stage.pName = "main";
 			stage.module = impl.m_handle;
 			stage.pSpecializationInfo = impl.getSpecConstInfo();
@@ -270,21 +270,20 @@ Error ShaderProgramImpl::init(const ShaderProgramInitInfo& inf)
 		defaultGroup.anyHitShader = VK_SHADER_UNUSED_KHR;
 		defaultGroup.intersectionShader = VK_SHADER_UNUSED_KHR;
 
-		DynamicArrayAuto<VkRayTracingShaderGroupCreateInfoKHR> groups(
-			getAllocator(),
-			1 + inf.m_rayTracingShaders.m_missShaders.getSize() + inf.m_rayTracingShaders.m_hitGroups.getSize(),
-			defaultGroup);
+		U32 groupCount =
+			1 + inf.m_rayTracingShaders.m_missShaders.getSize() + inf.m_rayTracingShaders.m_hitGroups.getSize();
+		DynamicArrayAuto<VkRayTracingShaderGroupCreateInfoKHR> groups(getAllocator(), groupCount, defaultGroup);
 
 		// 1st group is the ray gen
 		groups[0].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
 		groups[0].generalShader = 0;
 
 		// Miss
-		U32 groupCount = 1;
+		groupCount = 1;
 		for(U32 i = 0; i < inf.m_rayTracingShaders.m_missShaders.getSize(); ++i)
 		{
 			groups[groupCount].type = VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR;
-			groups[groupCount].generalShader = 0;
+			groups[groupCount].generalShader = groupCount;
 			++groupCount;
 		}
 

+ 1 - 1
src/anki/gr/vulkan/TextureImpl.h

@@ -28,7 +28,7 @@ enum class TextureImplWorkaround : U8
 	S8_TO_D24S8 = 1 << 1,
 	D24S8_TO_D32S8 = 1 << 2,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureImplWorkaround, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(TextureImplWorkaround)
 
 /// A Vulkan image view with some extra data.
 class MicroImageView

+ 2 - 2
src/anki/input/KeyCode.h

@@ -266,7 +266,7 @@ enum class KeyCode
 	COUNT,
 	FIRST = 0,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(KeyCode, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(KeyCode)
 
 enum class MouseButton
 {
@@ -278,6 +278,6 @@ enum class MouseButton
 
 	COUNT
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MouseButton, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MouseButton)
 
 } // end namespace anki

+ 1 - 1
src/anki/physics/Common.h

@@ -89,7 +89,7 @@ enum class PhysicsMaterialBit : U64
 
 	ALL = MAX_U64
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsMaterialBit, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsMaterialBit)
 
 ANKI_USE_RESULT inline Vec3 toAnki(const btVector3& v)
 {

+ 1 - 1
src/anki/physics/PhysicsObject.h

@@ -29,7 +29,7 @@ enum class PhysicsObjectType : U8
 	FIRST_FILTERED = BODY,
 	LAST_FILTERED = TRIGGER,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsObjectType, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsObjectType)
 
 /// Base of all physics objects.
 class PhysicsObject : public IntrusiveListEnabled<PhysicsObject>

+ 1 - 1
src/anki/resource/Common.h

@@ -52,7 +52,7 @@ enum class VertexAttributeLocation : U8
 	COUNT,
 	FIRST = POSITION,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VertexAttributeLocation, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VertexAttributeLocation)
 /// @}
 
 /// Deleter for ResourcePtr.

+ 1 - 1
src/anki/resource/ImageLoader.h

@@ -40,7 +40,7 @@ enum class ImageLoaderDataCompression : U32
 	S3TC = 1 << 1,
 	ETC = 1 << 2
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ImageLoaderDataCompression, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(ImageLoaderDataCompression)
 
 /// An image surface
 /// @memberof ImageLoader

+ 2 - 2
src/anki/resource/MaterialResource.h

@@ -41,7 +41,7 @@ enum class BuiltinMaterialVariableId : U8
 	COUNT,
 	FIRST = 0,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMaterialVariableId, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMaterialVariableId)
 
 /// The ID of builtin mutators.
 enum class BuiltinMutatorId : U8
@@ -56,7 +56,7 @@ enum class BuiltinMutatorId : U8
 	COUNT,
 	FIRST = 0
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMutatorId, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(BuiltinMutatorId)
 
 /// Holds the shader variables. It's a container for shader program variables that share the same name.
 class MaterialVariable : public NonCopyable

+ 1 - 1
src/anki/resource/MeshLoader.h

@@ -31,7 +31,7 @@ public:
 
 		ALL = QUAD | CONVEX,
 	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Flag, friend)
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(Flag)
 
 	struct VertexBuffer
 	{

+ 1 - 1
src/anki/resource/ShaderProgramResource.cpp

@@ -360,7 +360,7 @@ void ShaderProgramResource::initVariant(const ShaderProgramResourceVariantInitIn
 	ShaderProgramInitInfo progInf(cprogName);
 	for(ShaderType shaderType : EnumIterable<ShaderType>())
 	{
-		if(!(shaderTypeToBit(shaderType) & m_shaderStages))
+		if(!(ShaderTypeBit(1 << shaderType) & m_shaderStages))
 		{
 			continue;
 		}

+ 1 - 1
src/anki/scene/Octree.h

@@ -188,7 +188,7 @@ private:
 		FRONT = PX_PY_PZ | PX_NY_PZ | NX_PY_PZ | NX_NY_PZ,
 		BACK = PX_PY_NZ | PX_NY_NZ | NX_PY_NZ | NX_NY_NZ,
 	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(LeafMask, friend)
+	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(LeafMask)
 
 	SceneAllocator<U8> m_alloc;
 	U32 m_maxDepth = 0;

+ 1 - 1
src/anki/scene/components/FrustumComponent.h

@@ -50,7 +50,7 @@ enum class FrustumComponentVisibilityTestFlag : U16
 	ALL_SHADOWS_ENABLED =
 		POINT_LIGHT_SHADOWS_ENABLED | SPOT_LIGHT_SHADOWS_ENABLED | DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumComponentVisibilityTestFlag, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumComponentVisibilityTestFlag)
 
 /// Frustum component. Useful for nodes that take part in visibility tests like cameras and lights.
 class FrustumComponent : public SceneComponent

+ 1 - 1
src/anki/scene/components/MoveComponent.h

@@ -30,7 +30,7 @@ enum class MoveComponentFlag : U8
 	/// If dirty then is marked for update
 	MARKED_FOR_UPDATE = 1 << 3,
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MoveComponentFlag, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(MoveComponentFlag)
 
 /// Interface for movable scene nodes
 class MoveComponent : public SceneComponent

+ 1 - 1
src/anki/scene/components/RenderComponent.h

@@ -24,7 +24,7 @@ enum class RenderComponentFlag : U8
 	FORWARD_SHADING = 1 << 1,
 	SORT_LAST = 1 << 2, ///< Push it last when sorting the visibles.
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(RenderComponentFlag, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(RenderComponentFlag)
 
 /// Render component interface. Implemented by renderable scene nodes
 class RenderComponent : public SceneComponent

+ 1 - 1
src/anki/shader_compiler/ShaderProgramCompiler.cpp

@@ -178,7 +178,7 @@ static Error compileSpirv(ConstWeakArray<MutatorValue> mutation, const ShaderPro
 	// Compile stages
 	for(ShaderType shaderType : EnumIterable<ShaderType>())
 	{
-		if(!(shaderTypeToBit(shaderType) & parser.getShaderTypes()))
+		if(!(ShaderTypeBit(1 << shaderType) & parser.getShaderTypes()))
 		{
 			continue;
 		}

+ 1 - 1
src/anki/shader_compiler/ShaderProgramParser.cpp

@@ -262,7 +262,7 @@ Error ShaderProgramParser::parsePragmaStart(const StringAuto* begin, const Strin
 	}
 
 	// Set the mask
-	ShaderTypeBit mask = ShaderTypeBit(1 << U(shaderType));
+	const ShaderTypeBit mask = ShaderTypeBit(1 << shaderType);
 	if(!!(mask & m_shaderTypes))
 	{
 		ANKI_PP_ERROR_MALFORMED_MSG("Can't have #pragma start <shader> appearing more than once");

+ 80 - 75
src/anki/util/Enum.h

@@ -5,138 +5,141 @@
 
 #pragma once
 
-#include <anki/Config.h>
+#include <anki/util/Assert.h>
+
+namespace anki
+{
 
 /// @privatesection
 /// @{
 
-// Re-implement std::underlying_type to avoid including the whole typetraits header
-template<typename TEnum>
-struct EnumUnderlyingType
+/// This is a template where the Type will be I64 if the T is any unsigned integer and U64 otherwise
+template<typename T, bool = std::is_unsigned<T>::value>
+class EnumSafeIntegerType
 {
-	using Type = __underlying_type(TEnum);
+public:
+	using Type = I64;
 };
 
-/// Convert an enum to it's integer type.
-template<typename TEnum>
-constexpr inline typename EnumUnderlyingType<TEnum>::Type enumToType(TEnum e)
+template<typename T>
+class EnumSafeIntegerType<T, true>
 {
-	return static_cast<typename EnumUnderlyingType<TEnum>::Type>(e);
-}
+public:
+	using Type = U64;
+};
 
-#define _ANKI_ENUM_OPERATOR(enum_, qualifier_, operator_, assignOperator_) \
-	constexpr qualifier_ enum_ operator operator_(const enum_ a, const enum_ b) \
+/// This macro will do an operation between 2 values. It will be used in constexpr functions. There is also an assertion
+/// which makes sure that the result will fit in an enum. Despite the fact that the assertion contains non-constexpr
+/// elements it will work on constexpr expressions. The compiler will compile-time ignore the non-constexpr part if the
+/// assert if the assertion expression is true.
+#define _ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b) \
+	using EnumInt = std::underlying_type<enumType>::type; \
+	using SafeInt = EnumSafeIntegerType<EnumInt>::Type; \
+	const SafeInt c = SafeInt(a) regularOperator SafeInt(b); \
+	ANKI_ASSERT(c <= SafeInt(std::numeric_limits<EnumInt>::max())); \
+	return enumType(c)
+
+#define _ANKI_ENUM_OPERATOR(enumType, qualifier, regularOperator, assignmentOperator) \
+	constexpr qualifier enumType operator regularOperator(const enumType a, const enumType b) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		return static_cast<enum_>(static_cast<Int>(a) operator_ static_cast<Int>(b)); \
+		_ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
 	} \
-	constexpr qualifier_ enum_ operator operator_(const enum_ a, const EnumUnderlyingType<enum_>::Type b) \
+	constexpr qualifier enumType operator regularOperator(const enumType a, \
+														  const std::underlying_type<enumType>::type b) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		return static_cast<enum_>(static_cast<Int>(a) operator_ b); \
+		_ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
 	} \
-	constexpr qualifier_ enum_ operator operator_(const EnumUnderlyingType<enum_>::Type a, const enum_ b) \
+	constexpr qualifier enumType operator regularOperator(const std::underlying_type<enumType>::type a, \
+														  const enumType b) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		return static_cast<enum_>(a operator_ static_cast<Int>(b)); \
+		_ANKI_ENUM_OPERATION_BODY(enumType, regularOperator, a, b); \
 	} \
-	qualifier_ enum_& operator assignOperator_(enum_& a, const enum_ b) \
+	qualifier enumType& operator assignmentOperator(enumType& a, const enumType b) \
 	{ \
-		a = a operator_ b; \
+		a = a regularOperator b; \
 		return a; \
 	} \
-	qualifier_ enum_& operator assignOperator_(enum_& a, const EnumUnderlyingType<enum_>::Type b) \
+	qualifier enumType& operator assignmentOperator(enumType& a, const std::underlying_type<enumType>::type b) \
 	{ \
-		a = a operator_ b; \
+		a = a regularOperator b; \
 		return a; \
 	} \
-	qualifier_ EnumUnderlyingType<enum_>::Type& operator assignOperator_(EnumUnderlyingType<enum_>::Type& a, \
-																		 const enum_ b) \
+	qualifier std::underlying_type<enumType>::type& operator assignmentOperator( \
+		std::underlying_type<enumType>::type& a, const enumType b) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		a = static_cast<Int>(a operator_ static_cast<Int>(b)); \
+		using EnumInt = std::underlying_type<enumType>::type; \
+		a = EnumInt(a regularOperator b); \
 		return a; \
 	}
 
-#define _ANKI_ENUM_UNARAY_OPERATOR(enum_, qualifier_, operator_) \
-	constexpr qualifier_ enum_ operator operator_(const enum_ a) \
+#define _ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, regularOperator) \
+	constexpr qualifier enumType operator regularOperator(const enumType a) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		return static_cast<enum_>(operator_ static_cast<Int>(a)); \
+		using EnumInt = std::underlying_type<enumType>::type; \
+		return enumType(regularOperator EnumInt(a)); \
 	}
 
-#define _ANKI_ENUM_INCREMENT_DECREMENT(enum_, qualifier_) \
-	qualifier_ enum_& operator++(enum_& a) \
+#define _ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
+	qualifier enumType& operator++(enumType& a) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		a = static_cast<enum_>(static_cast<Int>(a) + 1); \
+		a = a + 1; \
 		return a; \
 	} \
-	qualifier_ enum_& operator--(enum_& a) \
+	qualifier enumType& operator--(enumType& a) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		a = static_cast<enum_>(static_cast<Int>(a) - 1); \
+		a = a - 1; \
 		return a; \
 	} \
-	qualifier_ enum_ operator++(enum_& a, int) \
+	qualifier enumType operator++(enumType& a, int) \
 	{ \
-		enum_ old = a; \
+		const enumType old = a; \
 		++a; \
 		return old; \
 	} \
-	qualifier_ enum_ operator--(enum_& a, int) \
+	qualifier enumType operator--(enumType& a, int) \
 	{ \
-		enum_ old = a; \
+		const enumType old = a; \
 		--a; \
 		return old; \
 	}
 
-#define _ANKI_ENUM_NEGATIVE_OPERATOR(enum_, qualifier_) \
-	qualifier_ Bool operator!(const enum_& a) \
+#define _ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier) \
+	qualifier Bool operator!(const enumType a) \
 	{ \
-		using Int = EnumUnderlyingType<enum_>::Type; \
-		return static_cast<Int>(a) == 0; \
-	} \
+		using EnumInt = std::underlying_type<enumType>::type; \
+		return EnumInt(a) == 0; \
+	}
+
+#define _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, qualifier) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, |, |=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, &, &=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, ^, ^=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, +, +=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, -, -=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, *, *=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, /, /=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, <<, <<=) \
+	_ANKI_ENUM_OPERATOR(enumType, qualifier, >>, >>=) \
+	_ANKI_ENUM_UNARAY_OPERATOR(enumType, qualifier, ~) \
+	_ANKI_ENUM_INCREMENT_DECREMENT(enumType, qualifier) \
+	_ANKI_ENUM_NEGATIVE_OPERATOR(enumType, qualifier)
 /// @}
 
 /// @addtogroup util_other
 /// @{
 
 /// Implement all those functions that will make a stronly typed enum behave like the old type of enums.
-#define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enum_, qualifier_) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, |, |=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, &, &=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, ^, ^=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, +, +=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, -, -=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, *, *=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, /, /=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, <<, <<=) \
-	_ANKI_ENUM_OPERATOR(enum_, qualifier_, >>, >>=) \
-	_ANKI_ENUM_UNARAY_OPERATOR(enum_, qualifier_, ~) \
-	_ANKI_ENUM_INCREMENT_DECREMENT(enum_, qualifier_) \
-	_ANKI_ENUM_NEGATIVE_OPERATOR(enum_, qualifier_)
-
-/// Convert enum to the underlying type.
-template<typename TEnum>
-inline typename EnumUnderlyingType<TEnum>::Type enumToValue(TEnum e)
-{
-	return static_cast<typename EnumUnderlyingType<TEnum>::Type>(e);
-}
+#define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, inline)
 
-/// Convert enum to the underlying type.
-template<typename TEnum>
-inline TEnum valueToEnum(typename EnumUnderlyingType<TEnum>::Type v)
-{
-	return static_cast<TEnum>(v);
-}
+/// Same as ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS but for enums that are defined in a class.
+#define ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS_FRIEND(enumType) _ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(enumType, friend)
 
 /// @memberof EnumIterable
 template<typename TEnum>
 class EnumIterableIterator
 {
 public:
-	using Type = typename EnumUnderlyingType<TEnum>::Type;
+	using Type = typename std::underlying_type<TEnum>::type;
 
 	EnumIterableIterator(TEnum val)
 		: m_val(static_cast<Type>(val))
@@ -186,3 +189,5 @@ public:
 	}
 };
 /// @}
+
+} // end namespace anki

+ 1 - 1
src/anki/util/File.h

@@ -28,7 +28,7 @@ enum class FileOpenFlag : U8
 	ENDIAN_LITTLE = 1 << 5, ///< The default
 	ENDIAN_BIG = 1 << 6
 };
-ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FileOpenFlag, inline)
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FileOpenFlag)
 
 /// Passed to seek function
 /// @memberof File