diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 31b8f5687..5e3af7567 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/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)