Browse Source

metal: fix Shader:send with matrices and arrays.

Alex Szpakowski 3 years ago
parent
commit
674143175f
1 changed files with 41 additions and 9 deletions
  1. 41 9
      src/modules/graphics/metal/Shader.mm

+ 41 - 9
src/modules/graphics/metal/Shader.mm

@@ -430,14 +430,14 @@ void Shader::buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv
 			u.matrix.rows = membertype.vecsize;
 			u.matrix.columns = membertype.columns;
 		}
-		if (validationReflection.localUniforms.find(u.name) != validationReflection.localUniforms.end())
+
+		const auto &reflectionit = validationReflection.localUniforms.find(u.name);
+		if (reflectionit != validationReflection.localUniforms.end())
 		{
-			const auto &ru = validationReflection.localUniforms.find(u.name);
-			const auto &values = ru->second.initializerValues;
+			const auto &localuniform = reflectionit->second;
+			const auto &values = localuniform.initializerValues;
 			if (!values.empty())
-			{
 				memcpy(u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
-			}
 		}
 
 		uniforms[u.name] = u;
@@ -894,15 +894,47 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
 	return builtinUniformInfo[(int)builtin];
 }
 
-void Shader::updateUniform(const UniformInfo *info, int /*count*/)
+void Shader::updateUniform(const UniformInfo *info, int count)
 {
 	if (current == this)
 		Graphics::flushBatchedDrawsGlobal();
 
-	// Staging -> uniform buffer data copy needed for batch flushing to work.
-	// TODO: account for padding with 3x3 matrices etc.
+	count = std::min(count, info->count);
+
+	// TODO: store some of this in UniformInfo.
+	size_t elementsize = info->components * 4;
+	if (info->baseType == UNIFORM_MATRIX)
+		elementsize = info->matrix.columns * info->matrix.rows * 4;
+
 	size_t offset = (const uint8 *)info->data - localUniformStagingData;
-	memcpy(localUniformBufferData + offset, info->data, info->dataSize);
+
+	// Assuming std140 packing rules, the source data can only be direct-copied
+	// to the uniform buffer in certain cases because it's tightly packed whereas
+	// the buffer's data isn't.
+	if (elementsize * info->count == info->dataSize || (count == 1 && info->baseType != UNIFORM_MATRIX))
+	{
+		memcpy(localUniformBufferData + offset, info->data, elementsize * count);
+	}
+	else
+	{
+		int veccount = count;
+		int comp = info->components;
+
+		if (info->baseType == UNIFORM_MATRIX)
+		{
+			veccount *= info->matrix.rows;
+			comp = info->matrix.columns;
+		}
+
+		const int *src = info->ints;
+		int *dst = (int *) (localUniformBufferData + offset);
+
+		for (int i = 0; i < veccount; i++)
+		{
+			for (int c = 0; c < comp; c++)
+				dst[i * 4 + c] = src[i * comp + c];
+		}
+	}
 }
 
 void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)