Browse Source

Vulkan: Some work on the bindings. Add AMD_negative_viewport_height support

Panagiotis Christopoulos Charitos 8 years ago
parent
commit
a049e35392

+ 1 - 1
.appveyor.yml

@@ -34,7 +34,7 @@ before_build:
   - cmake --version
   - mkdir build
   - cd build
-  - cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DANKI_EXTRA_CHECKS=%ASSERTIONS%
+  - cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DANKI_EXTRA_CHECKS=%ASSERTIONS% -DANKI_BUILD_TESTS=ON -DANKI_BUILD_SAMPLES=ON -DANKI_BUILD_TOOLS=ON
 
 build_script:
   - mingw32-make

+ 12 - 1
CMakeLists.txt

@@ -39,6 +39,12 @@ else()
 	set(GCC FALSE)
 endif()
 
+if(${CMAKE_C_COMPILER_ID} MATCHES "Clang")
+	set(CLANG TRUE)
+else()
+	set(CLANG FALSE)
+endif()
+
 ################################################################################
 # Configuration                                                                #
 ################################################################################
@@ -143,7 +149,7 @@ endif()
 
 set(COMPILER_FLAGS "${COMPILER_FLAGS} -fno-exceptions ")
 
-if(GCC)
+if(GCC AND NOT CLANG)
 	set(CXX_FLAGS "${CXX_FLAGS} -static-libstdc++ ")
 endif()
 
@@ -365,6 +371,11 @@ elseif(WINDOWS)
 	if(GL)
 		set(_SYS ankiglew opengl32)
 	else()
+		if(NOT DEFINED ENV{VULKAN_SDK})
+			message(FATAL_ERROR "You need to have VULKAN SDK installed and the VULKAN_SDK env variable set")
+		endif()
+
+		link_directories($ENV{VULKAN_SDK}/Bin)
 		set(_SYS vulkan-1)
 	endif()
 

+ 8 - 9
src/anki/gr/gl/StateTracker.h

@@ -26,10 +26,10 @@ class StateTracker
 {
 public:
 	/// If it's false then there might be unset state.
-	Bool8 m_mayContainUnsetState = true;
+	Bool m_mayContainUnsetState = true;
 
 #if ANKI_EXTRA_CHECKS
-	Bool8 m_secondLevel = false;
+	Bool m_secondLevel = false;
 #endif
 
 	/// @name vert_state
@@ -96,14 +96,13 @@ public:
 
 	/// @name input_assembly
 	/// @{
-	Bool8 m_primitiveRestart = 2;
+	Bool m_primitiveRestart = 2;
 
 	Bool setPrimitiveRestart(Bool enable)
 	{
-		U enablei = enable ? 1 : 0;
-		if(enablei != m_primitiveRestart)
+		if(enable != m_primitiveRestart)
 		{
-			m_primitiveRestart = enablei;
+			m_primitiveRestart = enable;
 			return true;
 		}
 		return false;
@@ -169,7 +168,7 @@ public:
 
 	/// @name depth_stencil
 	/// @{
-	Bool8 m_stencilTestEnabled = 2;
+	Bool m_stencilTestEnabled = 2;
 
 	Bool maybeEnableStencilTest()
 	{
@@ -300,7 +299,7 @@ public:
 		}
 	}
 
-	Bool8 m_depthTestEnabled = 2; ///< 2 means don't know
+	Bool m_depthTestEnabled = 2; ///< 2 means don't know
 
 	Bool maybeEnableDepthTest()
 	{
@@ -316,7 +315,7 @@ public:
 		return false;
 	}
 
-	Bool8 m_depthWrite = 2;
+	Bool m_depthWrite = 2;
 
 	Bool setDepthWrite(Bool enable)
 	{

+ 3 - 3
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -58,17 +58,17 @@ void CommandBuffer::finish()
 
 void CommandBuffer::bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride)
 {
-	ANKI_ASSERT(!"TODO");
+	m_impl->bindVertexBuffer(binding, buff, offset, stride);
 }
 
 void CommandBuffer::setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
 {
-	ANKI_ASSERT(!"TODO");
+	m_impl->setVertexAttribute(location, buffBinding, fmt, relativeOffset);
 }
 
 void CommandBuffer::bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
 {
-	ANKI_ASSERT(!"TODO");
+	m_impl->bindIndexBuffer(buff, offset, type);
 }
 
 void CommandBuffer::setPrimitiveRestart(Bool enable)

+ 27 - 7
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -8,6 +8,8 @@
 #include <anki/gr/vulkan/VulkanObject.h>
 #include <anki/gr/CommandBuffer.h>
 #include <anki/gr/Texture.h>
+#include <anki/gr/Buffer.h>
+#include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
 #include <anki/gr/vulkan/Pipeline.h>
 #include <anki/util/List.h>
@@ -23,6 +25,10 @@ class CommandBufferInitInfo;
 /// @addtogroup vulkan
 /// @{
 
+#define ANKI_CMD(x_, t_)                                                                                               \
+	flushBatches(CommandBufferCommandType::t_);                                                                        \
+	x_;
+
 /// List the commands that can be batched.
 enum class CommandBufferCommandType : U8
 {
@@ -64,11 +70,28 @@ public:
 		return !!(m_flags & CommandBufferFlag::SECOND_LEVEL);
 	}
 
-	void bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride);
+	void bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride)
+	{
+		commandCommon();
+		m_state.bindVertexBuffer(binding, stride);
+		VkBuffer vkbuff = buff->m_impl->getHandle();
+		ANKI_CMD(vkCmdBindVertexBuffers(m_handle, binding, 1, &vkbuff, &offset), ANY_OTHER_COMMAND);
+		m_bufferList.pushBack(m_alloc, buff);
+	}
 
-	void setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset);
+	void setVertexAttribute(U32 location, U32 buffBinding, const PixelFormat& fmt, PtrSize relativeOffset)
+	{
+		commandCommon();
+		m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
+	}
 
-	void bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type);
+	void bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
+	{
+		commandCommon();
+		ANKI_CMD(vkCmdBindIndexBuffer(m_handle, buff->m_impl->getHandle(), offset, convertIndexType(type)),
+			ANY_OTHER_COMMAND);
+		m_bufferList.pushBack(m_alloc, buff);
+	}
 
 	void setPrimitiveRestart(Bool enable);
 
@@ -159,6 +182,7 @@ public:
 		commandCommon();
 		U realBinding = MAX_TEXTURE_BINDINGS + binding;
 		m_dsetState[set].bindUniformBuffer(realBinding, buff.get(), offset, range);
+		m_bufferList.pushBack(m_alloc, buff);
 	}
 
 private:
@@ -332,10 +356,6 @@ private:
 		VkImage img,
 		const VkImageSubresourceRange& range);
 };
-
-#define ANKI_CMD(x_, t_)                                                                                               \
-	flushBatches(CommandBufferCommandType::t_);                                                                        \
-	x_;
 /// @}
 
 } // end namespace anki

+ 8 - 6
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -6,8 +6,6 @@
 #include <anki/gr/vulkan/CommandBufferImpl.h>
 #include <anki/gr/vulkan/GrManagerImpl.h>
 #include <anki/gr/vulkan/TextureImpl.h>
-#include <anki/gr/Buffer.h>
-#include <anki/gr/vulkan/BufferImpl.h>
 #include <anki/gr/OcclusionQuery.h>
 #include <anki/gr/vulkan/OcclusionQueryImpl.h>
 #include <anki/core/Trace.h>
@@ -463,8 +461,11 @@ inline void CommandBufferImpl::drawcallCommon()
 			Bool dirty;
 			Array<U32, MAX_UNIFORM_BUFFER_BINDINGS + MAX_STORAGE_BUFFER_BINDINGS> dynamicOffsets;
 			U dynamicOffsetCount;
-			getGrManagerImpl().getDescriptorSetFactory().newDescriptorSet(
-				m_tid, m_dsetState[i], dset, dirty, dynamicOffsets, dynamicOffsetCount);
+			if(getGrManagerImpl().getDescriptorSetFactory().newDescriptorSet(
+				   m_tid, m_dsetState[i], dset, dirty, dynamicOffsets, dynamicOffsetCount))
+			{
+				ANKI_VK_LOGF("Cannot recover");
+			}
 
 			if(dirty)
 			{
@@ -487,6 +488,7 @@ inline void CommandBufferImpl::drawcallCommon()
 	if(ANKI_UNLIKELY(m_viewportDirty))
 	{
 		// Do some hacks to flip the viewport
+		const Bool khrMaintenance1 = !!(getGrManagerImpl().getExtensions() & VulkanExtensions::KHR_MAINENANCE1);
 
 		const I minx = m_viewport[0];
 		const I miny = m_viewport[1];
@@ -498,9 +500,9 @@ inline void CommandBufferImpl::drawcallCommon()
 
 		VkViewport s;
 		s.x = minx;
-		s.y = fbHeight - miny; // Move to the bottom
+		s.y = (khrMaintenance1) ? (fbHeight - miny) : (fbHeight - maxy); // Move to the bottom
 		s.width = maxx - minx;
-		s.height = -(maxy - miny); // Negative to flip
+		s.height = -(maxy - miny); // Negate to flip
 		s.minDepth = 0.0;
 		s.maxDepth = 1.0;
 		ANKI_CMD(vkCmdSetViewport(m_handle, 0, 1, &s), ANY_OTHER_COMMAND);

+ 28 - 1
src/anki/gr/vulkan/Common.h

@@ -29,7 +29,7 @@ namespace anki
 // Forward
 class GrManagerImpl;
 
-/// @addtogroup vulkan
+/// @addtogrou/cygdrive/c/VulkanSDK/1.0.39.1/Include/vulkan/vulkan.h
 /// @{
 
 #define ANKI_VK_LOGI(...) ANKI_LOG("VK  ", NORMAL, __VA_ARGS__)
@@ -37,6 +37,14 @@ class GrManagerImpl;
 #define ANKI_VK_LOGW(...) ANKI_LOG("VK  ", WARNING, __VA_ARGS__)
 #define ANKI_VK_LOGF(...) ANKI_LOG("VK  ", FATAL, __VA_ARGS__)
 
+enum class VulkanExtensions : U8
+{
+	NONE = 0,
+	KHR_MAINENANCE1 = 1 << 0,
+	AMD_NEGATIVE_VIEWPORT_HEIGHT = 1 << 1,
+};
+ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(VulkanExtensions, inline)
+
 /// @name Constants
 /// @{
 const U DESCRIPTOR_POOL_INITIAL_SIZE = 64;
@@ -168,6 +176,25 @@ ANKI_USE_RESULT inline VkDescriptorType convertDescriptorType(DescriptorType ak)
 
 	return out;
 }
+
+ANKI_USE_RESULT inline VkIndexType convertIndexType(IndexType ak)
+{
+	VkIndexType out;
+	switch(ak)
+	{
+	case IndexType::U16:
+		out = VK_INDEX_TYPE_UINT16;
+		break;
+	case IndexType::U32:
+		out = VK_INDEX_TYPE_UINT32;
+		break;
+	default:
+		ANKI_ASSERT(0);
+		out = VK_INDEX_TYPE_MAX_ENUM;
+	}
+
+	return out;
+}
 /// @}
 
 } // end namespace anki

+ 2 - 1
src/anki/gr/vulkan/GpuMemoryManager.cpp

@@ -193,9 +193,10 @@ void GpuMemoryManager::init(VkPhysicalDevice pdev, VkDevice dev, GrAllocator<U8>
 	ANKI_ASSERT(dev);
 
 	// Print some info
+	ANKI_VK_LOGI("Initializing memory manager");
 	for(const ClassInf& c : CLASSES)
 	{
-		ANKI_VK_LOGI("GPU mem class. Chunk size: %u, slotSize: %u, allocsPerChunk %u",
+		ANKI_VK_LOGI("\tGPU mem class. Chunk size: %u, slotSize: %u, allocsPerChunk %u",
 			c.m_chunkSize,
 			c.m_slotSize,
 			c.m_chunkSize / c.m_slotSize);

+ 29 - 2
src/anki/gr/vulkan/GrManagerImpl.cpp

@@ -223,9 +223,8 @@ Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
 {
 	// Create the instance
 	//
-	static Array<const char*, 8> LAYERS = {{"VK_LAYER_LUNARG_core_validation",
+	static Array<const char*, 7> LAYERS = {{"VK_LAYER_LUNARG_core_validation",
 		"VK_LAYER_LUNARG_swapchain",
-		"VK_LAYER_LUNARG_image",
 		"VK_LAYER_GOOGLE_threading",
 		"VK_LAYER_LUNARG_parameter_validation",
 		"VK_LAYER_GOOGLE_unique_objects",
@@ -312,6 +311,25 @@ Error GrManagerImpl::initInstance(const GrManagerInitInfo& init)
 
 	vkGetPhysicalDeviceFeatures(m_physicalDevice, &m_devFeatures);
 
+	// Get extensions
+	vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &count, nullptr);
+	DynamicArrayAuto<VkExtensionProperties> extensions(getAllocator());
+	extensions.create(count);
+	vkEnumerateDeviceExtensionProperties(m_physicalDevice, nullptr, &count, &extensions[0]);
+
+	m_extensions = VulkanExtensions::NONE;
+	while(count-- != 0)
+	{
+		if(strcmp(&extensions[count].extensionName[0], VK_KHR_MAINTENANCE1_EXTENSION_NAME) == 0)
+		{
+			m_extensions |= VulkanExtensions::KHR_MAINENANCE1;
+		}
+		else if(strcmp(&extensions[count].extensionName[0], VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME) == 0)
+		{
+			m_extensions |= VulkanExtensions::AMD_NEGATIVE_VIEWPORT_HEIGHT;
+		}
+	}
+
 	return ErrorCode::NONE;
 }
 
@@ -361,6 +379,15 @@ Error GrManagerImpl::initDevice(const GrManagerInitInfo& init)
 	static Array<const char*, 2> DEV_EXTENSIONS = {
 		{VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_MAINTENANCE1_EXTENSION_NAME}};
 
+	if(!!(m_extensions & VulkanExtensions::KHR_MAINENANCE1))
+	{
+		// Do nothing
+	}
+	else if(!!(m_extensions & VulkanExtensions::AMD_NEGATIVE_VIEWPORT_HEIGHT))
+	{
+		DEV_EXTENSIONS[1] = VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME;
+	}
+
 	ANKI_VK_LOGI("Will enable the following device extensions:");
 	for(const char* ext : DEV_EXTENSIONS)
 	{

+ 6 - 0
src/anki/gr/vulkan/GrManagerImpl.h

@@ -189,6 +189,11 @@ public:
 		return m_pplineLayoutFactory;
 	}
 
+	VulkanExtensions getExtensions() const
+	{
+		return m_extensions;
+	}
+
 private:
 	GrManager* m_manager = nullptr;
 
@@ -200,6 +205,7 @@ private:
 
 	VkInstance m_instance = VK_NULL_HANDLE;
 	VkPhysicalDevice m_physicalDevice = VK_NULL_HANDLE;
+	VulkanExtensions m_extensions;
 	GpuVendor m_vendor = GpuVendor::UNKNOWN;
 	VkDevice m_device = VK_NULL_HANDLE;
 	U32 m_queueIdx = MAX_U32;

+ 2 - 0
src/anki/gr/vulkan/Pipeline.cpp

@@ -193,6 +193,8 @@ const VkGraphicsPipelineCreateInfo& PipelineStateTracker::updatePipelineCreateIn
 	VkPipelineVertexInputStateCreateInfo& vertCi = m_ci.m_vert;
 	vertCi = {};
 	vertCi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
+	vertCi.pVertexAttributeDescriptions = &m_ci.m_attribs[0];
+	vertCi.pVertexBindingDescriptions = &m_ci.m_vertBindings[0];
 
 	for(U i = 0; i < MAX_VERTEX_ATTRIBUTES; ++i)
 	{

+ 2 - 1
src/anki/gr/vulkan/ShaderProgramImpl.cpp

@@ -92,7 +92,8 @@ Error ShaderProgramImpl::init(const Array<ShaderPtr, U(ShaderType::COUNT)>& shad
 		DescriptorSetLayoutInitInfo inf;
 		inf.m_bindings = WeakArray<DescriptorBinding>((counts[set]) ? &bindings[set][0] : nullptr, counts[set]);
 
-		getGrManagerImpl().getDescriptorSetFactory().newDescriptorSetLayout(inf, m_descriptorSetLayouts[set]);
+		ANKI_CHECK(
+			getGrManagerImpl().getDescriptorSetFactory().newDescriptorSetLayout(inf, m_descriptorSetLayouts[set]));
 	}
 
 	// Create the ppline layout

+ 12 - 22
src/anki/math/Functions.h

@@ -89,31 +89,21 @@ inline T mod(const T x, const T y)
 template<typename T>
 T absolute(const T f);
 
-#define ANKI_SPECIALIZE_ABS_INT(type_)                                                                                 \
+#define ANKI_SPECIALIZE_ABS(type_)                                                                                     \
 	template<>                                                                                                         \
 	inline type_ absolute(const type_ f)                                                                               \
 	{                                                                                                                  \
-		return std::abs(f);                                                                                            \
+		return (f < type_(0)) ? -f : f;                                                                                \
 	}
 
-ANKI_SPECIALIZE_ABS_INT(I8)
-ANKI_SPECIALIZE_ABS_INT(I16)
-ANKI_SPECIALIZE_ABS_INT(I32)
-ANKI_SPECIALIZE_ABS_INT(I64)
+ANKI_SPECIALIZE_ABS(I8)
+ANKI_SPECIALIZE_ABS(I16)
+ANKI_SPECIALIZE_ABS(I32)
+ANKI_SPECIALIZE_ABS(I64)
+ANKI_SPECIALIZE_ABS(F32)
+ANKI_SPECIALIZE_ABS(F64)
 
-#undef ANKI_SPECIALIZE_ABS_INT
-
-template<>
-inline F32 absolute(const F32 f)
-{
-	return std::fabs(f);
-}
-
-template<>
-inline F64 absolute(const F64 f)
-{
-	return std::fabs(f);
-}
+#undef ANKI_SPECIALIZE_ABS
 
 template<typename T>
 inline Bool isZero(const T f)
@@ -158,7 +148,7 @@ inline T toDegrees(const T rad)
 template<typename Type>
 static Type linearInterpolate(const Type& from, const Type& to, F32 u)
 {
-	return from * (1.0 - u) + to * u;
+	return from * (1.0f - u) + to * u;
 }
 
 /// Cosine interpolation
@@ -168,8 +158,8 @@ static Type linearInterpolate(const Type& from, const Type& to, F32 u)
 template<typename Type>
 static Type cosInterpolate(const Type& from, const Type& to, F32 u)
 {
-	F32 u2 = (1.0 - cos<F32>(u * PI)) / 2.0;
-	return from * (1.0 - u2) + to * u2;
+	F32 u2 = (1.0f - cos<Type>(u * PI)) / 2.0f;
+	return from * (1.0f - u2) + to * u2;
 }
 
 /// Cubic interpolation

+ 25 - 76
src/anki/util/Atomic.h

@@ -7,7 +7,7 @@
 
 #include <anki/util/StdTypes.h>
 #include <anki/util/NonCopyable.h>
-#include <type_traits>
+#include <atomic>
 
 namespace anki
 {
@@ -17,16 +17,12 @@ namespace anki
 
 enum class AtomicMemoryOrder
 {
-#if defined(__GNUC__)
-	RELAXED = __ATOMIC_RELAXED,
-	CONSUME = __ATOMIC_CONSUME,
-	ACQUIRE = __ATOMIC_ACQUIRE,
-	RELEASE = __ATOMIC_RELEASE,
-	ACQ_REL = __ATOMIC_ACQ_REL,
-	SEQ_CST = __ATOMIC_SEQ_CST
-#else
-#error "TODO"
-#endif
+	RELAXED = std::memory_order_relaxed,
+	CONSUME = std::memory_order_consume,
+	ACQUIRE = std::memory_order_acquire,
+	RELEASE = std::memory_order_release,
+	ACQ_REL = std::memory_order_acq_rel,
+	SEQ_CST = std::memory_order_seq_cst
 };
 
 /// Atomic template. At the moment it doesn't work well with pointers.
@@ -40,7 +36,6 @@ public:
 	/// It will not set itself to zero.
 	Atomic()
 	{
-		static_assert(std::is_pointer<T>::value || std::is_arithmetic<T>::value, "Check the type");
 	}
 
 	Atomic(const Value& a)
@@ -63,69 +58,27 @@ public:
 	/// Get the value of the atomic.
 	Value load(AtomicMemoryOrder memOrd = MEMORY_ORDER) const
 	{
-#if defined(__GNUC__)
-		return __atomic_load_n(&m_val, static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
+		return m_att.load(static_cast<std::memory_order>(memOrd));
 	}
 
 	/// Store
 	void store(const Value& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
-#if defined(__GNUC__)
-		__atomic_store_n(&m_val, a, static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
+		m_att.store(a, static_cast<std::memory_order>(memOrd));
 	}
 
-	/// Fetch and add. Pointer specialization
-	template<typename Y, typename Q = T>
-	typename std::enable_if<std::is_pointer<Q>::value, Q>::type fetchAdd(
-		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	/// Fetch and add.
+	template<typename Y>
+	Value fetchAdd(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
-#if defined(__GNUC__)
-		return __atomic_fetch_add(&m_val, a * sizeof(typename std::remove_pointer<Q>::type), static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
+		return m_att.fetch_add(a, static_cast<std::memory_order>(memOrd));
 	}
 
-	/// Fetch and add. Arithmetic specialization.
-	template<typename Y, typename Q = T>
-	typename std::enable_if<!std::is_pointer<Q>::value, Q>::type fetchAdd(
-		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
+	/// Fetch and subtract.
+	template<typename Y>
+	Value fetchSub(const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
-#if defined(__GNUC__)
-		return __atomic_fetch_add(&m_val, a, static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
-	}
-
-	/// Fetch and subtract. Pointer specialization.
-	template<typename Y, typename Q = T>
-	typename std::enable_if<std::is_pointer<Q>::value, Q>::type fetchSub(
-		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
-	{
-#if defined(__GNUC__)
-		return __atomic_fetch_sub(&m_val, a * sizeof(typename std::remove_pointer<Q>::type), static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
-	}
-
-	/// Fetch and subtract. Arithmetic specialization.
-	template<typename Y, typename Q = T>
-	typename std::enable_if<!std::is_pointer<Q>::value, Q>::type fetchSub(
-		const Y& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
-	{
-#if defined(__GNUC__)
-		return __atomic_fetch_sub(&m_val, a, static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
+		return m_att.fetch_sub(a, static_cast<std::memory_order>(memOrd));
 	}
 
 	/// @code
@@ -139,22 +92,14 @@ public:
 	/// @endcode
 	Bool compareExchange(Value& expected, const Value& desired, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
-#if defined(__GNUC__)
-		return __atomic_compare_exchange_n(
-			&m_val, &expected, desired, false, static_cast<int>(memOrd), __ATOMIC_RELAXED);
-#else
-#error "TODO"
-#endif
+		return m_att.compare_exchange_weak(
+			expected, desired, static_cast<std::memory_order>(memOrd), static_cast<std::memory_order>(memOrd));
 	}
 
 	/// Set @a a to the atomic and return the previous value.
 	Value exchange(const Value& a, AtomicMemoryOrder memOrd = MEMORY_ORDER)
 	{
-#if defined(__GNUC__)
-		return __atomic_exchange_n(&m_val, a, static_cast<int>(memOrd));
-#else
-#error "TODO"
-#endif
+		return m_att.exchange(a, static_cast<std::memory_order>(memOrd));
 	}
 
 	/// Store the minimum using compare-and-swap.
@@ -176,7 +121,11 @@ public:
 	}
 
 private:
-	Value m_val;
+	union
+	{
+		Value m_val;
+		std::atomic<Value> m_att;
+	};
 };
 /// @}
 

+ 0 - 10
src/anki/util/Functions.h

@@ -175,16 +175,6 @@ To staticCastPtr(From from)
 #endif
 }
 
-/// Count bits
-inline U32 countBits(U32 number)
-{
-#if defined(__GNUC__)
-	return __builtin_popcount(number);
-#else
-#error "Unimplemented"
-#endif
-}
-
 /// Check if types are the same.
 template<class T, class Y>
 struct TypesAreTheSame

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

@@ -156,7 +156,7 @@ public:
 private:
 #if ANKI_MEM_USE_SIGNATURES
 	AllocationSignature m_signature = 0;
-	static const U32 MAX_ALIGNMENT = 16;
+	static const U32 MAX_ALIGNMENT = 64;
 	U32 m_headerSize = 0;
 #endif
 };

+ 3 - 3
src/anki/util/StdTypes.h

@@ -68,9 +68,9 @@ using F64 = double; ///< Floating point 64bit
 const F64 MAX_F64 = std::numeric_limits<F64>::max();
 const F64 MIN_F64 = -std::numeric_limits<F64>::max();
 
-using Bool = bool; ///< Fast boolean type
-using Bool8 = U8; ///< Small 8bit boolean type
-using Bool32 = U32; ///< A 32bit boolean
+using Bool = int; ///< Fast boolean type
+using Bool8 = I8; ///< Small 8bit boolean type
+using Bool32 = I32; ///< A 32bit boolean
 
 /// Error codes
 enum class ErrorCode : I32

+ 3 - 3
src/anki/util/String.h

@@ -192,10 +192,10 @@ public:
 	}
 
 	/// Get the string length.
-	U getLength() const
+	U32 getLength() const
 	{
 		checkInit();
-		return std::strlen(m_ptr);
+		return U32(std::strlen(m_ptr));
 	}
 
 	PtrSize find(const CString& cstr, PtrSize position = 0) const
@@ -203,7 +203,7 @@ public:
 		checkInit();
 		ANKI_ASSERT(position < getLength());
 		const Char* out = std::strstr(m_ptr, &cstr[0]);
-		return (out == nullptr) ? NPOS : (out - m_ptr);
+		return (out == nullptr) ? NPOS : PtrSize(out - m_ptr);
 	}
 
 	/// Convert to F64.

+ 10 - 4
tests/gr/Gr.cpp

@@ -443,12 +443,17 @@ ANKI_TEST(Gr, SimpleDrawcall)
 {
 	COMMON_BEGIN()
 
-	ANKI_TEST_LOGI("Expect to see a grey triangle");
+	ANKI_TEST_LOGI("Expect to see a grey triangle appearing in the 4 corners");
 	ShaderProgramPtr prog = createProgram(VERT_SRC, FRAG_SRC, *gr);
 	FramebufferPtr fb = createDefaultFb(*gr);
 
-	U iterations = 100;
-	while(iterations--)
+	static const Array2d<U, 4, 4> VIEWPORTS = {{{{0, 0, WIDTH / 2, HEIGHT / 2}},
+		{{WIDTH / 2, 0, WIDTH, HEIGHT / 2}},
+		{{WIDTH / 2, HEIGHT / 2, WIDTH, HEIGHT}},
+		{{0, HEIGHT / 2, WIDTH / 2, HEIGHT}}}};
+
+	const U ITERATIONS = 200;
+	for(U i = 0; i < ITERATIONS; ++i)
 	{
 		HighRezTimer timer;
 		timer.start();
@@ -459,7 +464,8 @@ ANKI_TEST(Gr, SimpleDrawcall)
 		cinit.m_flags = CommandBufferFlag::GRAPHICS_WORK;
 		CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
-		cmdb->setViewport(0, 0, WIDTH, HEIGHT);
+		auto vp = VIEWPORTS[(i / 30) % 4];
+		cmdb->setViewport(vp[0], vp[1], vp[2], vp[3]);
 		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
 		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);