Browse Source

Introduce a globals uniform buffer in material shaders

Panagiotis Christopoulos Charitos 3 years ago
parent
commit
d1d3076014

+ 3 - 3
AnKi/Gr/Utils/FrameGpuAllocator.cpp

@@ -50,9 +50,9 @@ Error FrameGpuAllocator::allocate(PtrSize originalSize, PtrSize& outOffset)
 	PtrSize size = getAlignedRoundUp(m_alignment, originalSize);
 	ANKI_ASSERT(size <= m_maxAllocationSize && "Too high!");
 
-	PtrSize offset = m_offset.fetchAdd(size);
-	PtrSize perFrameSize = m_size / MAX_FRAMES_IN_FLIGHT;
-	PtrSize crntFrameStartOffset = perFrameSize * (m_frame % MAX_FRAMES_IN_FLIGHT);
+	const PtrSize offset = m_offset.fetchAdd(size);
+	const PtrSize perFrameSize = m_size / MAX_FRAMES_IN_FLIGHT;
+	const PtrSize crntFrameStartOffset = perFrameSize * (m_frame % MAX_FRAMES_IN_FLIGHT);
 
 	if(offset - crntFrameStartOffset + size <= perFrameSize)
 	{

+ 9 - 12
AnKi/Gr/Utils/Functions.cpp

@@ -18,10 +18,6 @@ static void writeShaderBlockMemorySanityChecks(const ShaderVariableBlockInfo& va
 	ANKI_ASSERT(buffEnd != nullptr);
 	ANKI_ASSERT(buffBegin < buffEnd);
 
-	ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(elements)) && "Breaking strict aliasing rules");
-	ANKI_ASSERT(isAligned(alignof(T), ptrToNumber(static_cast<U8*>(buffBegin) + varBlkInfo.m_offset))
-				&& "Breaking strict aliasing rules");
-
 	// Check varBlkInfo
 	ANKI_ASSERT(varBlkInfo.m_offset != -1);
 	ANKI_ASSERT(varBlkInfo.m_arraySize > 0);
@@ -41,16 +37,16 @@ static void writeShaderBlockMemorySimple(const ShaderVariableBlockInfo& varBlkIn
 {
 	writeShaderBlockMemorySanityChecks<T>(varBlkInfo, elements, elementsCount, buffBegin, buffEnd);
 
-	U8* buff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
+	U8* outBuff = static_cast<U8*>(buffBegin) + varBlkInfo.m_offset;
+	const U8* inBuff = static_cast<const U8*>(elements);
 	for(U i = 0; i < elementsCount; i++)
 	{
-		ANKI_ASSERT(buff + sizeof(T) <= static_cast<const U8*>(buffEnd));
+		ANKI_ASSERT(outBuff + sizeof(T) <= static_cast<const U8*>(buffEnd));
 
-		T* out = reinterpret_cast<T*>(buff);
-		const T* in = reinterpret_cast<const T*>(elements) + i;
-		*out = *in;
+		// Memcpy because Vec might have SIMD alignment but not the output buffer
+		memcpy(outBuff, inBuff + i * sizeof(T), sizeof(T));
 
-		buff += varBlkInfo.m_arrayStride;
+		outBuff += varBlkInfo.m_arrayStride;
 	}
 }
 
@@ -71,10 +67,11 @@ static void writeShaderBlockMemoryMatrix(const ShaderVariableBlockInfo& varBlkIn
 		{
 			ANKI_ASSERT((subbuff + sizeof(Vec)) <= static_cast<const U8*>(buffEnd));
 
-			Vec* out = reinterpret_cast<Vec*>(subbuff);
-			*out = matrix.getRow(j);
+			const Vec in = matrix.getRow(j);
+			memcpy(subbuff, &in, sizeof(Vec)); // Memcpy because Vec might have SIMD alignment but not the output buffer
 			subbuff += varBlkInfo.m_matrixStride;
 		}
+
 		buff += varBlkInfo.m_arrayStride;
 	}
 }

+ 17 - 0
AnKi/Renderer/Drawer.cpp

@@ -9,6 +9,7 @@
 #include <AnKi/Renderer/Renderer.h>
 #include <AnKi/Util/Tracer.h>
 #include <AnKi/Util/Logger.h>
+#include <AnKi/Shaders/Include/MaterialTypes.h>
 
 namespace anki {
 
@@ -44,6 +45,19 @@ void RenderableDrawer::drawRange(Pass pass, const Mat4& viewMat, const Mat4& vie
 {
 	ANKI_ASSERT(begin && end && begin < end);
 
+	// Allocate and set global uniforms
+	StagingGpuMemoryToken globalUniformsToken;
+	MaterialGlobalUniforms* globalIniforms =
+		static_cast<MaterialGlobalUniforms*>(m_r->getStagingGpuMemory().allocateFrame(
+			sizeof(MaterialGlobalUniforms), StagingGpuMemoryType::UNIFORM, globalUniformsToken));
+	memcpy(&globalIniforms->m_viewProjectionMatrix[0], &viewProjMat, sizeof(viewProjMat));
+	const Mat3x4 viewMat3x4(viewMat);
+	memcpy(&globalIniforms->m_viewMatrix[0], &viewMat3x4, sizeof(viewMat3x4));
+	globalIniforms->m_viewRotationMatrix = viewMat.getRotationPart();
+	const Mat3 camRotationMatrix = viewMat.getInverse().getRotationPart();
+	globalIniforms->m_cameraRotationMatrix = camRotationMatrix;
+
+	// Set a few things
 	DrawContext ctx;
 	ctx.m_queueCtx.m_viewMatrix = viewMat;
 	ctx.m_queueCtx.m_viewProjectionMatrix = viewProjMat;
@@ -55,6 +69,9 @@ void RenderableDrawer::drawRange(Pass pass, const Mat4& viewMat, const Mat4& vie
 	ctx.m_queueCtx.m_sampler = sampler;
 	ctx.m_queueCtx.m_key = RenderingKey(pass, 0, 1, false, false);
 	ctx.m_queueCtx.m_debugDraw = false;
+	ctx.m_queueCtx.m_globalUniforms.m_buffer = globalUniformsToken.m_buffer;
+	ctx.m_queueCtx.m_globalUniforms.m_offset = globalUniformsToken.m_offset;
+	ctx.m_queueCtx.m_globalUniforms.m_range = globalUniformsToken.m_range;
 
 	ANKI_ASSERT(minLod < MAX_LOD_COUNT && maxLod < MAX_LOD_COUNT);
 	ctx.m_minLod = U8(minLod);

+ 10 - 1
AnKi/Renderer/RenderQueue.h

@@ -45,6 +45,14 @@ public:
 	StackAllocator<U8> m_frameAllocator;
 	Bool m_debugDraw; ///< If true the drawcall should be drawing some kind of debug mesh.
 	BitSet<U(RenderQueueDebugDrawFlag::COUNT), U32> m_debugDrawFlags = {false};
+
+	class
+	{
+	public:
+		BufferPtr m_buffer;
+		PtrSize m_offset;
+		PtrSize m_range;
+	} m_globalUniforms; ///< Points to a MaterialGlobalUniforms structure.
 };
 
 /// Draw callback for drawing.
@@ -416,7 +424,7 @@ public:
 	/// bugs.
 	RenderQueue* m_rayTracingQueue = nullptr;
 
-	SkyboxQueueElement m_skybox = {};
+	SkyboxQueueElement m_skybox;
 
 	/// Applies only if the RenderQueue holds shadow casters. It's the max timesamp of all shadow casters
 	Timestamp m_shadowRenderablesLastUpdateTimestamp = 0;
@@ -433,6 +441,7 @@ public:
 	RenderQueue()
 	{
 		zeroMemory(m_directionalLight);
+		zeroMemory(m_skybox);
 	}
 
 	PtrSize countAllRenderables() const;

+ 25 - 11
AnKi/Resource/MaterialResource.cpp

@@ -23,17 +23,9 @@ public:
 
 static const Array<BuiltinVarInfo, U(BuiltinMaterialVariableId::COUNT)> BUILTIN_INFOS = {
 	{{"NONE", ShaderVariableDataType::NONE, false},
-	 {"m_ankiMvp", ShaderVariableDataType::MAT4, true},
-	 {"m_ankiPreviousMvp", ShaderVariableDataType::MAT4, true},
-	 {"m_ankiModelMatrix", ShaderVariableDataType::MAT4, true},
-	 {"m_ankiViewMatrix", ShaderVariableDataType::MAT4, false},
-	 {"m_ankiProjectionMatrix", ShaderVariableDataType::MAT4, false},
-	 {"m_ankiModelViewMatrix", ShaderVariableDataType::MAT4, true},
-	 {"m_ankiViewProjectionMatrix", ShaderVariableDataType::MAT4, false},
-	 {"m_ankiNormalMatrix", ShaderVariableDataType::MAT3, true},
-	 {"m_ankiRotationMatrix", ShaderVariableDataType::MAT3, true},
-	 {"m_ankiCameraRotationMatrix", ShaderVariableDataType::MAT3, false},
-	 {"m_ankiCameraPosition", ShaderVariableDataType::VEC3, false},
+	 {"m_ankiTransform", ShaderVariableDataType::MAT3X4, true},
+	 {"m_ankiPreviousTransform", ShaderVariableDataType::MAT3X4, true},
+	 {"m_ankiRotation", ShaderVariableDataType::MAT3, true},
 	 {"u_ankiGlobalSampler", ShaderVariableDataType::SAMPLER, false}}};
 
 static ANKI_USE_RESULT Error checkBuiltin(CString name, ShaderVariableDataType dataType, Bool instanced,
@@ -250,6 +242,8 @@ Error MaterialResource::load(const ResourceFilename& filename, Bool async)
 		ANKI_CHECK(parseRtMaterial(rtMaterialEl));
 	}
 
+	ANKI_CHECK(findGlobalUniformsUbo());
+
 	return Error::NONE;
 }
 
@@ -1292,4 +1286,24 @@ Error MaterialResource::parseRtMaterial(XmlElement rtMaterialEl)
 	return Error::NONE;
 }
 
+Error MaterialResource::findGlobalUniformsUbo()
+{
+	const ShaderProgramBinary& binary = m_prog->getBinary();
+	for(const ShaderProgramBinaryBlock& block : binary.m_uniformBlocks)
+	{
+		if(block.m_name.getBegin() == CString("b_ankiGlobalUniforms"))
+		{
+			m_globalUniformsUboBinding = block.m_binding;
+		}
+	}
+
+	if(m_globalUniformsUboBinding == MAX_U32)
+	{
+		ANKI_RESOURCE_LOGE("Couldn't find a UBO named b_ankiGlobalUniforms");
+		return Error::USER_DATA;
+	}
+
+	return Error::NONE;
+}
+
 } // end namespace anki

+ 13 - 12
AnKi/Resource/MaterialResource.h

@@ -25,17 +25,9 @@ class XmlElement;
 enum class BuiltinMaterialVariableId : U8
 {
 	NONE = 0,
-	MODEL_VIEW_PROJECTION_MATRIX,
-	PREVIOUS_MODEL_VIEW_PROJECTION_MATRIX,
-	MODEL_MATRIX,
-	VIEW_MATRIX,
-	PROJECTION_MATRIX,
-	MODEL_VIEW_MATRIX,
-	VIEW_PROJECTION_MATRIX,
-	NORMAL_MATRIX,
-	ROTATION_MATRIX,
-	CAMERA_ROTATION_MATRIX,
-	CAMERA_POSITION,
+	TRANSFORM,
+	PREVIOUS_TRANSFORM,
+	ROTATION,
 	GLOBAL_SAMPLER,
 
 	COUNT,
@@ -386,6 +378,12 @@ public:
 		return m_perInstanceUboBinding;
 	}
 
+	U32 getGlobalUniformsUniformBlockBinding() const
+	{
+		ANKI_ASSERT(m_globalUniformsUboBinding != MAX_U32);
+		return m_globalUniformsUboBinding;
+	}
+
 	const MaterialVariant& getOrCreateVariant(const RenderingKey& key) const;
 
 	U32 getShaderGroupHandleIndex(RayType type) const
@@ -434,6 +432,7 @@ private:
 	U32 m_perInstanceUboBinding = MAX_U32;
 	U32 m_boneTrfsBinding = MAX_U32;
 	U32 m_prevFrameBoneTrfsBinding = MAX_U32;
+	U32 m_globalUniformsUboBinding = MAX_U32;
 
 	/// Matrix of variants.
 	mutable Array5d<MaterialVariant, U(Pass::COUNT), MAX_LOD_COUNT, 2, 2, 2> m_variantMatrix;
@@ -489,7 +488,9 @@ private:
 		return const_cast<MaterialVariable*>(tryFindVariableInternal(name));
 	}
 
-	Error parseRtMaterial(XmlElement rootEl);
+	ANKI_USE_RESULT Error parseRtMaterial(XmlElement rootEl);
+
+	ANKI_USE_RESULT Error findGlobalUniformsUbo();
 };
 /// @}
 

+ 5 - 6
AnKi/Scene/Components/GpuParticleEmitterComponent.cpp

@@ -208,19 +208,18 @@ void GpuParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
 		cmdb->bindShaderProgram(prog);
 
 		// Resources
-		static const Mat4 identity = Mat4::getIdentity();
+		static const Array<Mat3x4, 1> identity = {Mat3x4::getIdentity()};
 
-		RenderComponent::allocateAndSetupUniforms(m_particleEmitterResource->getMaterial(), ctx,
-												  ConstWeakArray<Mat4>(&identity, 1),
-												  ConstWeakArray<Mat4>(&identity, 1), *ctx.m_stagingGpuAllocator);
+		RenderComponent::allocateAndSetupUniforms(m_particleEmitterResource->getMaterial(), ctx, identity, identity,
+												  *ctx.m_stagingGpuAllocator);
 
-		cmdb->bindStorageBuffer(0, 1, m_particlesBuff, 0, MAX_PTR_SIZE);
+		cmdb->bindStorageBuffer(0, 2, m_particlesBuff, 0, MAX_PTR_SIZE);
 
 		StagingGpuMemoryToken token;
 		Vec4* extraUniforms = static_cast<Vec4*>(
 			ctx.m_stagingGpuAllocator->allocateFrame(sizeof(Vec4), StagingGpuMemoryType::UNIFORM, token));
 		*extraUniforms = ctx.m_cameraTransform.getColumn(2);
-		cmdb->bindUniformBuffer(0, 2, token.m_buffer, token.m_offset, token.m_range);
+		cmdb->bindUniformBuffer(0, 3, token.m_buffer, token.m_offset, token.m_range);
 
 		// Draw
 		cmdb->setLineWidth(8.0f);

+ 1 - 1
AnKi/Scene/Components/ParticleEmitterComponent.cpp

@@ -411,7 +411,7 @@ void ParticleEmitterComponent::draw(RenderQueueDrawContext& ctx) const
 		cmdb->bindVertexBuffer(0, token.m_buffer, token.m_offset, VERTEX_SIZE, VertexStepRate::INSTANCE);
 
 		// Uniforms
-		Array<Mat4, 1> trf = {Mat4::getIdentity()};
+		Array<Mat3x4, 1> trf = {Mat3x4::getIdentity()};
 		RenderComponent::allocateAndSetupUniforms(m_particleEmitterResource->getMaterial(), ctx, trf, trf,
 												  *ctx.m_stagingGpuAllocator);
 

+ 23 - 82
AnKi/Scene/Components/RenderComponent.cpp

@@ -14,7 +14,7 @@ namespace anki {
 ANKI_SCENE_COMPONENT_STATICS(RenderComponent)
 
 void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, const RenderQueueDrawContext& ctx,
-											   ConstWeakArray<Mat4> transforms, ConstWeakArray<Mat4> prevTransforms,
+											   ConstWeakArray<Mat3x4> transforms, ConstWeakArray<Mat3x4> prevTransforms,
 											   StagingGpuMemoryPool& alloc)
 {
 	ANKI_ASSERT(transforms.getSize() <= MAX_INSTANCE_COUNT);
@@ -50,6 +50,10 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 											   token1.m_offset, token1.m_range);
 	}
 
+	ctx.m_commandBuffer->bindUniformBuffer(set, mtl->getGlobalUniformsUniformBlockBinding(),
+										   ctx.m_globalUniforms.m_buffer, ctx.m_globalUniforms.m_offset,
+										   ctx.m_globalUniforms.m_range);
+
 	// Iterate variables
 	for(const MaterialVariable& mvar : mtl->getVariables())
 	{
@@ -82,12 +86,6 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 				variant.writeShaderBlockMemory(mvar, &val, 1, perDrawUniformsBegin, perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::CAMERA_POSITION:
-			{
-				const Vec3 val = ctx.m_cameraTransform.getTranslationPart().xyz();
-				variant.writeShaderBlockMemory(mvar, &val, 1, perDrawUniformsBegin, perDrawUniformsEnd);
-				break;
-			}
 			default:
 				ANKI_ASSERT(0);
 			}
@@ -110,24 +108,7 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 				variant.writeShaderBlockMemory(mvar, &val, 1, perDrawUniformsBegin, perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::NORMAL_MATRIX:
-			{
-				ANKI_ASSERT(transforms.getSize() > 0);
-
-				Array<Mat3, MAX_INSTANCE_COUNT> normMats;
-				for(U32 i = 0; i < transforms.getSize(); i++)
-				{
-					const Mat4 mv = ctx.m_viewMatrix * transforms[i];
-					normMats[i] = mv.getRotationPart();
-					normMats[i].reorthogonalize();
-				}
-
-				variant.writeShaderBlockMemory(mvar, &normMats[0], transforms.getSize(),
-											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
-											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
-				break;
-			}
-			case BuiltinMaterialVariableId::ROTATION_MATRIX:
+			case BuiltinMaterialVariableId::ROTATION:
 			{
 				ANKI_ASSERT(transforms.getSize() > 0);
 
@@ -142,12 +123,6 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::CAMERA_ROTATION_MATRIX:
-			{
-				const Mat3 rot = ctx.m_cameraTransform.getRotationPart();
-				variant.writeShaderBlockMemory(mvar, &rot, 1, perDrawUniformsBegin, perDrawUniformsEnd);
-				break;
-			}
 			default:
 				ANKI_ASSERT(0);
 			}
@@ -164,70 +139,36 @@ void RenderComponent::allocateAndSetupUniforms(const MaterialResourcePtr& mtl, c
 				variant.writeShaderBlockMemory(mvar, &val, 1, perDrawUniformsBegin, perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::MODEL_VIEW_PROJECTION_MATRIX:
-			{
-				ANKI_ASSERT(transforms.getSize() > 0);
-
-				Array<Mat4, MAX_INSTANCE_COUNT> mvp;
-				for(U32 i = 0; i < transforms.getSize(); i++)
-				{
-					mvp[i] = ctx.m_viewProjectionMatrix * transforms[i];
-				}
-
-				variant.writeShaderBlockMemory(mvar, &mvp[0], transforms.getSize(),
-											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
-											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
-				break;
+			default:
+				ANKI_ASSERT(0);
 			}
-			case BuiltinMaterialVariableId::PREVIOUS_MODEL_VIEW_PROJECTION_MATRIX:
-			{
-				ANKI_ASSERT(prevTransforms.getSize() > 0);
-
-				Array<Mat4, MAX_INSTANCE_COUNT> mvp;
-				for(U32 i = 0; i < prevTransforms.getSize(); i++)
-				{
-					mvp[i] = ctx.m_previousViewProjectionMatrix * prevTransforms[i];
-				}
 
-				variant.writeShaderBlockMemory(mvar, &mvp[0], prevTransforms.getSize(),
-											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
-											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
-				break;
-			}
-			case BuiltinMaterialVariableId::MODEL_VIEW_MATRIX:
+			break;
+		}
+		case ShaderVariableDataType::MAT3X4:
+		{
+			switch(mvar.getBuiltin())
 			{
-				ANKI_ASSERT(transforms.getSize() > 0);
-
-				Array<Mat4, MAX_INSTANCE_COUNT> mv;
-				for(U32 i = 0; i < transforms.getSize(); i++)
-				{
-					mv[i] = ctx.m_viewMatrix * transforms[i];
-				}
-
-				variant.writeShaderBlockMemory(mvar, &mv[0], transforms.getSize(),
-											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
-											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
+			case BuiltinMaterialVariableId::NONE:
+			{
+				const Mat3x4 val = mvar.getValue<Mat3x4>();
+				variant.writeShaderBlockMemory(mvar, &val, 1, perDrawUniformsBegin, perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::MODEL_MATRIX:
+			case BuiltinMaterialVariableId::TRANSFORM:
 			{
 				ANKI_ASSERT(transforms.getSize() > 0);
-
 				variant.writeShaderBlockMemory(mvar, &transforms[0], transforms.getSize(),
 											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
 											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
 				break;
 			}
-			case BuiltinMaterialVariableId::VIEW_PROJECTION_MATRIX:
-			{
-				ANKI_ASSERT(transforms.getSize() == 0 && "Cannot have transform");
-				variant.writeShaderBlockMemory(mvar, &ctx.m_viewProjectionMatrix, 1, perDrawUniformsBegin,
-											   perDrawUniformsEnd);
-				break;
-			}
-			case BuiltinMaterialVariableId::VIEW_MATRIX:
+			case BuiltinMaterialVariableId::PREVIOUS_TRANSFORM:
 			{
-				variant.writeShaderBlockMemory(mvar, &ctx.m_viewMatrix, 1, perDrawUniformsBegin, perDrawUniformsEnd);
+				ANKI_ASSERT(prevTransforms.getSize() > 0);
+				variant.writeShaderBlockMemory(mvar, &prevTransforms[0], prevTransforms.getSize(),
+											   (mvar.isInstanced()) ? perInstanceUniformsBegin : perDrawUniformsBegin,
+											   (mvar.isInstanced()) ? perInstanceUniformsEnd : perDrawUniformsEnd);
 				break;
 			}
 			default:

+ 1 - 1
AnKi/Scene/Components/RenderComponent.h

@@ -102,7 +102,7 @@ public:
 
 	/// Helper function.
 	static void allocateAndSetupUniforms(const MaterialResourcePtr& mtl, const RenderQueueDrawContext& ctx,
-										 ConstWeakArray<Mat4> transforms, ConstWeakArray<Mat4> prevTransforms,
+										 ConstWeakArray<Mat3x4> transforms, ConstWeakArray<Mat3x4> prevTransforms,
 										 StagingGpuMemoryPool& alloc);
 
 private:

+ 7 - 7
AnKi/Scene/ModelNode.cpp

@@ -206,11 +206,11 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 		const SkinComponent& skinc = getFirstComponentOfType<SkinComponent>();
 
 		// Transforms
-		Array<Mat4, MAX_INSTANCE_COUNT> trfs;
-		Array<Mat4, MAX_INSTANCE_COUNT> prevTrfs;
+		Array<Mat3x4, MAX_INSTANCE_COUNT> trfs;
+		Array<Mat3x4, MAX_INSTANCE_COUNT> prevTrfs;
 		const MoveComponent& movec = getFirstComponentOfType<MoveComponent>();
-		trfs[0] = Mat4(movec.getWorldTransform());
-		prevTrfs[0] = Mat4(movec.getPreviousWorldTransform());
+		trfs[0] = Mat3x4(movec.getWorldTransform());
+		prevTrfs[0] = Mat3x4(movec.getPreviousWorldTransform());
 		Bool moved = trfs[0] != prevTrfs[0];
 		for(U32 i = 1; i < instanceCount; ++i)
 		{
@@ -222,8 +222,8 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 			ANKI_ASSERT(otherNodeModelPatchIdx == modelPatchIdx);
 
 			const MoveComponent& otherNodeMovec = otherNode.getFirstComponentOfType<MoveComponent>();
-			trfs[i] = Mat4(otherNodeMovec.getWorldTransform());
-			prevTrfs[i] = Mat4(otherNodeMovec.getPreviousWorldTransform());
+			trfs[i] = Mat3x4(otherNodeMovec.getWorldTransform());
+			prevTrfs[i] = Mat3x4(otherNodeMovec.getPreviousWorldTransform());
 
 			moved = moved || (trfs[i] != prevTrfs[i]);
 		}
@@ -262,7 +262,7 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 		// Uniforms
 		RenderComponent::allocateAndSetupUniforms(
 			modelc.getModelResource()->getModelPatches()[modelPatchIdx].getMaterial(), ctx,
-			ConstWeakArray<Mat4>(&trfs[0], instanceCount), ConstWeakArray<Mat4>(&prevTrfs[0], instanceCount),
+			ConstWeakArray<Mat3x4>(&trfs[0], instanceCount), ConstWeakArray<Mat3x4>(&prevTrfs[0], instanceCount),
 			*ctx.m_stagingGpuAllocator);
 
 		// Set attributes

+ 1 - 1
AnKi/ShaderCompiler/ShaderProgramParser.cpp

@@ -176,7 +176,7 @@ static const char SHADER_HEADER[] = R"(#version 460 core
 #define Mat4 mat4
 #define _ANKI_SIZEOF_mat4 64u
 
-#define Mat3x4 mat3x4
+#define Mat3x4 mat4x3 // GLSL has the column number first and then the rows
 #define _ANKI_SIZEOF_mat3x4 48u
 
 #define Bool bool

+ 10 - 6
AnKi/ShaderCompiler/ShaderProgramReflection.cpp

@@ -294,8 +294,8 @@ Error SpirvReflector::structReflection(uint32_t id, const spirv_cross::SPIRType&
 			{
 			}
 #define ANKI_SVDT_MACRO(capital, type, baseType_, rowCount, columnCount) \
-	else if(ShaderVariableDataType::baseType_ == baseType && isMatrix && memberType.vecsize == columnCount \
-			&& memberType.columns == rowCount) \
+	else if(ShaderVariableDataType::baseType_ == baseType && isMatrix && memberType.vecsize == rowCount \
+			&& memberType.columns == columnCount) \
 	{ \
 		actualType = ShaderVariableDataType::capital; \
 		memberSize = sizeof(type); \
@@ -496,12 +496,16 @@ Error SpirvReflector::blockVariableReflection(const spirv_cross::SPIRType& type,
 			if(0)
 			{
 			}
-#define ANKI_SVDT_MACRO(capital, type, baseType_, rowCount, columnCount) \
-	else if(ShaderVariableDataType::baseType_ == baseType && isMatrix && memberType.vecsize == columnCount \
-			&& memberType.columns == rowCount) \
+#define ANKI_SVDT_MACRO(capital, type_, baseType_, rowCount, columnCount) \
+	else if(ShaderVariableDataType::baseType_ == baseType && isMatrix && memberType.vecsize == rowCount \
+			&& memberType.columns == columnCount) \
 	{ \
 		var.m_type = ShaderVariableDataType::capital; \
-		var.m_blockInfo.m_matrixStride = 16; \
+		auto it = ir.meta.find(type.self); \
+		ANKI_ASSERT(it != ir.meta.end()); \
+		const spirv_cross::Vector<spirv_cross::Meta::Decoration>& memberDecorations = it->second.members; \
+		ANKI_ASSERT(i < memberDecorations.size()); \
+		var.m_blockInfo.m_matrixStride = I16(memberDecorations[i].matrix_stride); \
 	} \
 	else if(ShaderVariableDataType::baseType_ == baseType && !isMatrix && memberType.vecsize == rowCount) \
 	{ \

+ 25 - 12
AnKi/Shaders/ForwardShadingCommonFrag.glsl → AnKi/Shaders/ForwardShadingCommon.glsl

@@ -5,20 +5,31 @@
 
 #pragma once
 
-// Common code for all fragment shaders of FS
 #include <AnKi/Shaders/Common.glsl>
 #include <AnKi/Shaders/Functions.glsl>
 #include <AnKi/Shaders/Include/ModelTypes.h>
+#include <AnKi/Shaders/Include/MaterialTypes.h>
 
+//
+// Vert
+//
+#if defined(ANKI_VERTEX_SHADER)
+layout(location = VERTEX_ATTRIBUTE_ID_POSITION) in Vec3 in_position;
+#endif
+
+//
+// Frag
+//
+#if defined(ANKI_FRAGMENT_SHADER)
 // Global resources
 layout(set = 0, binding = 0) uniform sampler u_linearAnyClampSampler;
 layout(set = 0, binding = 1) uniform texture2D u_gbufferDepthRt;
 layout(set = 0, binding = 2) uniform ANKI_RP texture3D u_lightVol;
-#define CLUSTERED_SHADING_SET 0
-#define CLUSTERED_SHADING_UNIFORMS_BINDING 3
-#define CLUSTERED_SHADING_LIGHTS_BINDING 4
-#define CLUSTERED_SHADING_CLUSTERS_BINDING 7
-#include <AnKi/Shaders/ClusteredShadingCommon.glsl>
+#	define CLUSTERED_SHADING_SET 0
+#	define CLUSTERED_SHADING_UNIFORMS_BINDING 3
+#	define CLUSTERED_SHADING_LIGHTS_BINDING 4
+#	define CLUSTERED_SHADING_CLUSTERS_BINDING 7
+#	include <AnKi/Shaders/ClusteredShadingCommon.glsl>
 
 layout(location = 0) out Vec4 out_color;
 
@@ -55,15 +66,15 @@ Vec3 computeLightColorHigh(Vec3 diffCol, Vec3 worldPos)
 		const Vec3 frag2Light = light.m_position - worldPos;
 		const F32 att = computeAttenuationFactor(light.m_squareRadiusOverOne, frag2Light);
 
-#if LOD > 1
+#	if LOD > 1
 		const F32 shadow = 1.0;
-#else
+#	else
 		F32 shadow = 1.0;
 		if(light.m_shadowAtlasTileScale >= 0.0)
 		{
 			shadow = computeShadowFactorPointLight(light, frag2Light, u_shadowAtlasTex, u_linearAnyClampSampler);
 		}
-#endif
+#	endif
 
 		outColor += diffC * (att * shadow);
 	}
@@ -84,15 +95,15 @@ Vec3 computeLightColorHigh(Vec3 diffCol, Vec3 worldPos)
 
 		const F32 spot = computeSpotFactor(l, light.m_outerCos, light.m_innerCos, light.m_direction);
 
-#if LOD > 1
+#	if LOD > 1
 		const F32 shadow = 1.0;
-#else
+#	else
 		F32 shadow = 1.0;
 		ANKI_BRANCH if(light.m_shadowLayer != MAX_U32)
 		{
 			shadow = computeShadowFactorSpotLight(light, worldPos, u_shadowAtlasTex, u_linearAnyClampSampler);
 		}
-#endif
+#	endif
 
 		outColor += diffC * (att * spot * shadow);
 	}
@@ -136,3 +147,5 @@ void fog(ANKI_RP Vec3 color, ANKI_RP F32 fogAlphaScale, ANKI_RP F32 fogDistanceO
 
 	packGBuffer(Vec4(color, zFeatherFactor * fogAlphaScale));
 }
+
+#endif // defined(ANKI_FRAGMENT_SHADER)

+ 0 - 13
AnKi/Shaders/ForwardShadingCommonVert.glsl

@@ -1,13 +0,0 @@
-// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
-// All rights reserved.
-// Code licensed under the BSD License.
-// http://www.anki3d.org/LICENSE
-
-#pragma once
-
-// Common code for all vertex shaders of FS
-#include <AnKi/Shaders/Common.glsl>
-#include <AnKi/Shaders/Include/ModelTypes.h>
-
-// In/out
-layout(location = VERTEX_ATTRIBUTE_ID_POSITION) in Vec3 in_position;

+ 16 - 7
AnKi/Shaders/ForwardShadingFog.ankiprog

@@ -3,36 +3,45 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
+#include <AnKi/Shaders/ForwardShadingCommon.glsl>
+
 struct PerDraw
 {
-	Mat4 m_ankiMvp;
-	Mat4 m_ankiModelViewMatrix;
+	Mat3x4 m_ankiTransform;
 	ANKI_RP Vec3 m_fogColor;
 	ANKI_RP F32 m_fogAlphaScale;
 	ANKI_RP F32 m_fogDistanceOfMaxThikness;
 };
 
 #pragma anki reflect b_ankiPerDraw
-layout(set = 1, binding = 0, row_major) uniform b_ankiPerDraw
+layout(set = 1, binding = 0, row_major, scalar) uniform b_ankiPerDraw
 {
 	PerDraw u_ankiPerDraw;
 };
 
+#pragma anki reflect b_ankiGlobalUniforms
+layout(set = 1, binding = 1, row_major, scalar) uniform b_ankiGlobalUniforms
+{
+	MaterialGlobalUniforms u_ankiGlobals;
+};
+
 #pragma anki start vert
-#include <AnKi/Shaders/ForwardShadingCommonVert.glsl>
 
 layout(location = 0) out F32 out_zVSpace;
 
 void main()
 {
-	gl_Position = u_ankiPerDraw.m_ankiMvp * Vec4(in_position, 1.0);
-	out_zVSpace = (u_ankiPerDraw.m_ankiModelViewMatrix * Vec4(in_position, 1.0)).z;
+	const Vec3 worldPos = u_ankiPerDraw.m_ankiTransform * Vec4(in_position, 1.0);
+
+	gl_Position = u_ankiGlobals.m_viewProjectionMatrix * Vec4(worldPos, 1.0);
+
+	const Vec3 viewPos = u_ankiGlobals.m_viewMatrix * Vec4(worldPos, 1.0);
+	out_zVSpace = viewPos.z;
 }
 
 #pragma anki end
 
 #pragma anki start frag
-#include <AnKi/Shaders/ForwardShadingCommonFrag.glsl>
 
 layout(location = 0) in F32 in_zVSpace;
 

+ 16 - 10
AnKi/Shaders/ForwardShadingParticles.ankiprog

@@ -6,10 +6,11 @@
 #pragma anki mutator ANIMATED_TEXTURE 0 1
 #pragma anki mutator LIGHT 0 1
 
+#include <AnKi/Shaders/ForwardShadingCommon.glsl>
+
 struct PerDraw
 {
-	Mat4 m_ankiMvp;
-	Mat3 m_ankiCameraRotationMatrix;
+	Mat3x4 m_ankiTransform;
 #if ANIMATED_TEXTURE == 1
 	F32 m_animationPeriod;
 #endif
@@ -18,24 +19,29 @@ struct PerDraw
 };
 
 #pragma anki reflect b_ankiPerDraw
-layout(set = 1, binding = 0, row_major) uniform b_ankiPerDraw
+layout(set = 1, binding = 0, row_major, scalar) uniform b_ankiPerDraw
 {
 	PerDraw u_ankiPerDraw;
 };
 
+#pragma anki reflect b_ankiGlobalUniforms
+layout(set = 1, binding = 1, row_major, scalar) uniform b_ankiGlobalUniforms
+{
+	MaterialGlobalUniforms u_ankiGlobals;
+};
+
 #pragma anki reflect u_ankiGlobalSampler
-layout(set = 1, binding = 1) uniform sampler u_ankiGlobalSampler;
+layout(set = 1, binding = 2) uniform sampler u_ankiGlobalSampler;
 #if ANIMATED_TEXTURE == 0
 #	pragma anki reflect u_diffuseMap
-layout(set = 1, binding = 2) uniform ANKI_RP texture2D u_diffuseMap;
+layout(set = 1, binding = 3) uniform ANKI_RP texture2D u_diffuseMap;
 #endif
 #if ANIMATED_TEXTURE == 1
 #	pragma anki reflect u_diffuseMapArr
-layout(set = 1, binding = 2) uniform ANKI_RP texture2DArray u_diffuseMapArr;
+layout(set = 1, binding = 3) uniform ANKI_RP texture2DArray u_diffuseMapArr;
 #endif
 
 #pragma anki start vert
-#include <AnKi/Shaders/ForwardShadingCommonVert.glsl>
 
 layout(location = VERTEX_ATTRIBUTE_ID_SCALE) in F32 in_scale;
 layout(location = VERTEX_ATTRIBUTE_ID_ALPHA) in F32 in_alpha;
@@ -48,15 +54,15 @@ void main()
 {
 	out_uv = Vec2(gl_VertexID & 1, gl_VertexID >> 1);
 
-	out_worldPos = u_ankiPerDraw.m_ankiCameraRotationMatrix * Vec3((out_uv - 0.5) * in_scale, 0.0) + in_position;
-	gl_Position = u_ankiPerDraw.m_ankiMvp * Vec4(out_worldPos, 1.0);
+	out_worldPos = u_ankiGlobals.m_cameraRotationMatrix * Vec3((out_uv - 0.5) * in_scale, 0.0) + in_position;
+	gl_Position =
+		u_ankiGlobals.m_viewProjectionMatrix * Vec4(u_ankiPerDraw.m_ankiTransform * Vec4(out_worldPos, 1.0), 1.0);
 
 	out_alpha = in_alpha;
 }
 #pragma anki end
 
 #pragma anki start frag
-#include <AnKi/Shaders/ForwardShadingCommonFrag.glsl>
 
 layout(location = 0) flat in ANKI_RP F32 in_alpha;
 layout(location = 1) in Vec2 in_uv;

+ 1 - 0
AnKi/Shaders/GBufferCommon.glsl

@@ -9,6 +9,7 @@
 
 #include <AnKi/Shaders/PackFunctions.glsl>
 #include <AnKi/Shaders/Include/ModelTypes.h>
+#include <AnKi/Shaders/Include/MaterialTypes.h>
 
 //
 // Vert input

+ 35 - 29
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -45,39 +45,39 @@
 #include <AnKi/Shaders/GBufferCommon.glsl>
 
 #pragma anki reflect u_ankiGlobalSampler
-layout(set = 0, binding = 2) uniform sampler u_ankiGlobalSampler;
+layout(set = 0, binding = 3) uniform sampler u_ankiGlobalSampler;
 #if DIFFUSE_TEX == 1 && (ANKI_PASS == PASS_GB || ALPHA_TEST)
 #	pragma anki reflect u_diffTex
-layout(set = 0, binding = 3) uniform ANKI_RP texture2D u_diffTex;
+layout(set = 0, binding = 4) uniform ANKI_RP texture2D u_diffTex;
 #	define USING_DIFF_TEX 1
 #endif
 #if SPECULAR_TEX == 1 && ANKI_PASS == PASS_GB
 #	pragma anki reflect u_specTex
-layout(set = 0, binding = 4) uniform ANKI_RP texture2D u_specTex;
+layout(set = 0, binding = 5) uniform ANKI_RP texture2D u_specTex;
 #	define USING_SPECULAR_TEX 1
 #endif
 #if ROUGHNESS_TEX == 1 && ANKI_PASS == PASS_GB
 #	pragma anki reflect u_roughnessTex
-layout(set = 0, binding = 5) uniform ANKI_RP texture2D u_roughnessTex;
+layout(set = 0, binding = 6) uniform ANKI_RP texture2D u_roughnessTex;
 #	define USING_ROUGHNESS_TEX 1
 #endif
 #if NORMAL_TEX == 1 && ANKI_PASS == PASS_GB && ANKI_LOD < 2
 #	pragma anki reflect u_normalTex
-layout(set = 0, binding = 6) uniform ANKI_RP texture2D u_normalTex;
+layout(set = 0, binding = 7) uniform ANKI_RP texture2D u_normalTex;
 #	define USING_NORMAL_TEX 1
 #endif
 #if METAL_TEX == 1 && ANKI_PASS == PASS_GB
 #	pragma anki reflect u_metallicTex
-layout(set = 0, binding = 7) uniform ANKI_RP texture2D u_metallicTex;
+layout(set = 0, binding = 8) uniform ANKI_RP texture2D u_metallicTex;
 #	define USING_METALLIC_TEX 1
 #endif
 #if REALLY_USING_PARALLAX
 #	pragma anki reflect u_heightTex
-layout(set = 0, binding = 8) uniform ANKI_RP texture2D u_heightTex;
+layout(set = 0, binding = 9) uniform ANKI_RP texture2D u_heightTex;
 #endif
 #if EMISSIVE_TEX == 1 && ANKI_PASS == PASS_GB
 #	pragma anki reflect u_emissiveTex
-layout(set = 0, binding = 9) uniform ANKI_RP texture2D u_emissiveTex;
+layout(set = 0, binding = 10) uniform ANKI_RP texture2D u_emissiveTex;
 #	define USING_EMISSIVE_TEX 1
 #endif
 
@@ -110,41 +110,44 @@ struct PerDraw
 
 struct PerInstance
 {
-	Mat4 m_ankiMvp;
+	Mat3x4 m_ankiTransform;
 #if ANKI_PASS == PASS_GB
-	Mat3 m_ankiRotationMatrix;
-#endif
-#if REALLY_USING_PARALLAX
-	Mat4 m_ankiModelViewMatrix;
+	Mat3 m_ankiRotation;
 #endif
 #if ANKI_PASS == PASS_GB && ANKI_VELOCITY == 1
-	Mat4 m_ankiPreviousMvp;
+	Mat3x4 m_ankiPreviousTransform;
 #endif
 };
 
 #if ANKI_PASS == PASS_GB
 #	pragma anki reflect b_ankiPerDraw
-layout(set = 0, binding = 0, row_major, std140) uniform b_ankiPerDraw
+layout(set = 0, binding = 0, row_major, scalar) uniform b_ankiPerDraw
 {
 	PerDraw u_ankiPerDraw;
 };
 #endif
 
 #pragma anki reflect b_ankiPerInstance
-layout(set = 0, binding = 1, row_major, std140) uniform b_ankiPerInstance
+layout(set = 0, binding = 1, row_major, scalar) uniform b_ankiPerInstance
 {
 	PerInstance u_ankiPerInstance[MAX_INSTANCE_COUNT];
 };
 
+#pragma anki reflect b_ankiGlobalUniforms
+layout(set = 0, binding = 2, row_major, scalar) uniform b_ankiGlobalUniforms
+{
+	MaterialGlobalUniforms u_ankiGlobals;
+};
+
 #if ANKI_BONES
 #	pragma anki reflect b_ankiBoneTransforms
-layout(set = 0, binding = 10, row_major, std140) readonly buffer b_ankiBoneTransforms
+layout(set = 0, binding = 11, row_major, std140) readonly buffer b_ankiBoneTransforms
 {
 	Mat4 u_ankiBoneTransforms[];
 };
 
 #	pragma anki reflect b_ankiPrevFrameBoneTransforms
-layout(set = 0, binding = 11, row_major, std140) readonly buffer b_ankiPrevFrameBoneTransforms
+layout(set = 0, binding = 12, row_major, std140) readonly buffer b_ankiPrevFrameBoneTransforms
 {
 	Mat4 u_ankiPrevFrameBoneTransforms[];
 };
@@ -195,9 +198,10 @@ void skinning()
 #if ANKI_PASS == PASS_GB
 void positionUvNormalTangent()
 {
-	gl_Position = u_ankiPerInstance[INSTANCE_ID].m_ankiMvp * Vec4(g_position, 1.0);
-	out_normal = u_ankiPerInstance[INSTANCE_ID].m_ankiRotationMatrix * g_normal.xyz;
-	out_tangent = u_ankiPerInstance[INSTANCE_ID].m_ankiRotationMatrix * g_tangent.xyz;
+	gl_Position = u_ankiGlobals.m_viewProjectionMatrix
+				  * Vec4(u_ankiPerInstance[INSTANCE_ID].m_ankiTransform * Vec4(g_position, 1.0), 1.0);
+	out_normal = u_ankiPerInstance[INSTANCE_ID].m_ankiRotation * g_normal;
+	out_tangent = u_ankiPerInstance[INSTANCE_ID].m_ankiRotation * g_tangent.xyz;
 	out_bitangent = cross(out_normal, out_tangent) * g_tangent.w;
 	out_uv = g_uv;
 }
@@ -207,15 +211,16 @@ void positionUvNormalTangent()
 #if REALLY_USING_PARALLAX
 void parallax()
 {
-	const Mat4 modelViewMat = u_ankiPerInstance[INSTANCE_ID].m_ankiModelViewMatrix;
 	const Vec3 n = in_normal;
 	const Vec3 t = in_tangent.xyz;
 	const Vec3 b = cross(n, t) * in_tangent.w;
 
-	const Mat3 normalMat = Mat3(modelViewMat);
-	const Mat3 invTbn = transpose(normalMat * Mat3(t, b, n));
+	const Mat3 invTbn =
+		transpose(u_ankiGlobals.m_viewRotationMatrix * u_ankiPerInstance[INSTANCE_ID].m_ankiRotation * Mat3(t, b, n));
 
-	const Vec3 viewPos = (modelViewMat * Vec4(g_position, 1.0)).xyz;
+	const Vec3 viewPos =
+		(u_ankiGlobals.m_viewMatrix * Vec4(u_ankiPerInstance[INSTANCE_ID].m_ankiTransform * Vec4(g_position, 1.0), 1.0))
+			.xyz;
 	out_distFromTheCamera = viewPos.z;
 
 	out_eyeTangentSpace = invTbn * viewPos;
@@ -229,12 +234,12 @@ void velocity()
 	const Vec3 prevLocalPos = g_prevPosition;
 
 #	if ANKI_VELOCITY
-	const Mat4 mvp = u_ankiPerInstance[INSTANCE_ID].m_ankiPreviousMvp;
+	const Mat3x4 trf = u_ankiPerInstance[INSTANCE_ID].m_ankiPreviousTransform;
 #	else
-	const Mat4 mvp = u_ankiPerInstance[INSTANCE_ID].m_ankiMvp;
+	const Mat3x4 trf = u_ankiPerInstance[INSTANCE_ID].m_ankiTransform;
 #	endif
 
-	const Vec4 v4 = mvp * Vec4(prevLocalPos, 1.0);
+	const Vec4 v4 = u_ankiGlobals.m_viewProjectionMatrix * Vec4(trf * Vec4(prevLocalPos, 1.0), 1.0);
 
 	const Vec2 prevNdc = v4.xy / v4.w;
 
@@ -262,7 +267,8 @@ void main()
 	velocity();
 #	endif
 #else
-	gl_Position = u_ankiPerInstance[INSTANCE_ID].m_ankiMvp * Vec4(g_position, 1.0);
+	gl_Position = u_ankiGlobals.m_viewProjectionMatrix
+				  * Vec4(u_ankiPerInstance[INSTANCE_ID].m_ankiTransform * Vec4(g_position, 1.0), 1.0);
 
 #	if ALPHA_TEST
 	out_uv = g_uv;

+ 16 - 8
AnKi/Shaders/GBufferGpuParticles.ankiprog

@@ -7,10 +7,12 @@
 #pragma anki mutator ANKI_VELOCITY 0 1
 
 #include <AnKi/Shaders/Include/ParticleTypes.h>
+#include <AnKi/Shaders/Include/MaterialTypes.h>
+#include <AnKi/Shaders/Common.glsl>
 
 struct PerDraw
 {
-	Mat4 m_ankiMvp;
+	Mat3x4 m_ankiTransform;
 	ANKI_RP Vec3 m_diffColor;
 	ANKI_RP F32 m_roughness;
 	ANKI_RP Vec3 m_specColor;
@@ -20,25 +22,29 @@ struct PerDraw
 };
 
 #pragma anki reflect b_ankiPerDraw
-layout(set = 0, binding = 0, std140, row_major) uniform b_ankiPerDraw
+layout(set = 0, binding = 0, scalar, row_major) uniform b_ankiPerDraw
 {
 	PerDraw u_ankiPerDraw;
 };
 
-layout(set = 0, binding = 1) buffer b_particles
+#pragma anki reflect b_ankiGlobalUniforms
+layout(set = 0, binding = 1, row_major, scalar) uniform b_ankiGlobalUniforms
+{
+	MaterialGlobalUniforms u_ankiGlobals;
+};
+
+layout(set = 0, binding = 2) buffer b_particles
 {
 	GpuParticle u_particles[];
 };
 
-layout(set = 0, binding = 2) uniform b_extra
+layout(set = 0, binding = 3) uniform b_extra
 {
 	Vec3 u_minusCameraZ;
 };
 
 #pragma anki start vert
 
-#include <AnKi/Shaders/Common.glsl>
-
 layout(location = 0) out Vec2 out_velocity;
 layout(location = 1) flat out F32 out_lifeFactor;
 
@@ -46,8 +52,10 @@ void main()
 {
 	const GpuParticle part = u_particles[gl_VertexID / 2];
 
-	const Vec4 crntClipPos = u_ankiPerDraw.m_ankiMvp * Vec4(part.m_newWorldPosition, 1.0);
-	const Vec4 prevClipPos = u_ankiPerDraw.m_ankiMvp * Vec4(part.m_oldWorldPosition, 1.0);
+	const Vec4 crntClipPos = u_ankiGlobals.m_viewProjectionMatrix
+							 * Vec4(u_ankiPerDraw.m_ankiTransform * Vec4(part.m_newWorldPosition, 1.0), 1.0);
+	const Vec4 prevClipPos = u_ankiGlobals.m_viewProjectionMatrix
+							 * Vec4(u_ankiPerDraw.m_ankiTransform * Vec4(part.m_oldWorldPosition, 1.0), 1.0);
 
 	gl_Position = ((gl_VertexID & 1) == 0) ? crntClipPos : prevClipPos;
 

+ 26 - 0
AnKi/Shaders/Include/MaterialTypes.h

@@ -0,0 +1,26 @@
+// Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <AnKi/Shaders/Include/Common.h>
+
+ANKI_BEGIN_NAMESPACE
+
+/// Per flare information
+struct MaterialGlobalUniforms
+{
+#if __cplusplus
+	Array<F32, 16> m_viewProjectionMatrix;
+	Array<F32, 12> m_viewMatrix;
+#else
+	Mat4 m_viewProjectionMatrix;
+	Mat3x4 m_viewMatrix;
+#endif
+	Mat3 m_viewRotationMatrix; ///< Essentially the rotation part of the view matrix
+	Mat3 m_cameraRotationMatrix;
+};
+
+ANKI_END_NAMESPACE

+ 4 - 7
AnKi/Util/Ptr.h

@@ -445,14 +445,11 @@ public:
 	/// Set a new pointer. Will destroy the previous.
 	void reset(T* ptr)
 	{
-		if(ptr != m_ptr)
+		destroy();
+		if(ptr)
 		{
-			destroy();
-			if(ptr)
-			{
-				ptr->getRefcount().fetchAdd(1);
-				m_ptr = ptr;
-			}
+			ptr->getRefcount().fetchAdd(1);
+			m_ptr = ptr;
 		}
 	}
 

+ 2 - 1
Samples/PhysicsPlayground/Main.cpp

@@ -224,7 +224,8 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(getInput().getKey(KeyCode::U) == 1)
 	{
-		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "SSGI") ? "" : "SSGI");
+		renderer.setCurrentDebugRenderTarget(
+			(renderer.getCurrentDebugRenderTarget() == "IndirectDiffuse") ? "" : "IndirectDiffuse");
 	}
 
 	if(getInput().getKey(KeyCode::F1) == 1)

+ 2 - 2
Sandbox/Main.cpp

@@ -157,10 +157,10 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		renderer.getDbg().switchDepthTestEnabled();
 	}
 
-	/*if(in.getKey(KeyCode::F12) == 1)
+	if(in.getKey(KeyCode::F11) == 1)
 	{
 		TracerSingleton::get().setEnabled(!TracerSingleton::get().getEnabled());
-	}*/
+	}
 
 #if !PLAYER
 	static F32 dist = 0.1f;