vulkan/metal: fix Shader:send(name, DataObject) truncating the data in some cases.

Fixes #2313
This commit is contained in:
Sasha Szpakowski
2026-05-02 16:06:08 -03:00
parent 6fbc7ebde5
commit f542481995
6 changed files with 36 additions and 23 deletions
+9 -1
View File
@@ -1701,6 +1701,14 @@ std::string Shader::canonicaliizeUniformName(const std::string &n)
return name;
}
size_t Shader::getUniformDataSizePacked(const UniformInfo &u)
{
if (u.baseType == UNIFORM_MATRIX)
return sizeof(uint32) * u.matrix.rows * u.matrix.columns * u.count;
else
return sizeof(uint32) * u.components * u.count;
}
void Shader::handleUnknownUniformName(const char */*name*/)
{
// TODO: do something here?
@@ -1717,7 +1725,7 @@ void Shader::copyToUniformBuffer(const UniformInfo *info, const void *src, void
// 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))
if (elementsize * info->count == info->dataSizeAllocated || (count == 1 && info->baseType != UNIFORM_MATRIX))
{
memcpy(dst, src, elementsize * count);
}
+3 -1
View File
@@ -169,7 +169,8 @@ public:
unsigned int *uints;
};
size_t dataSize;
size_t dataSizeAllocated;
size_t dataSizePacked;
};
union LocalUniformValue
@@ -328,6 +329,7 @@ protected:
void flushBatchedDraws() const;
static std::string canonicaliizeUniformName(const std::string &name);
static size_t getUniformDataSizePacked(const UniformInfo &u);
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, Reflection &reflection);
static DataBaseType getDataBaseType(PixelFormat format);
static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b);
+7 -4
View File
@@ -326,10 +326,13 @@ void Shader::buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv
UniformInfo &u = *(uniformit->second);
u.active = true;
if (u.dataSize > 0)
if (u.dataSizeAllocated > 0)
continue;
u.dataSize = membersize;
// get_declared_struct_member_size should be the padded size, which can be larger than
// the tightly packed size that external code will use with UniformInfo.
u.dataSizeAllocated = memberSize;
u.dataSizePacked = getUniformDataSizePacked(u);
u.data = localUniformStagingData + offset;
const auto &reflectionit = reflection.localUniformInitializerValues.find(u.name);
@@ -337,7 +340,7 @@ void Shader::buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv
{
const auto &values = reflectionit->second;
if (!values.empty())
memcpy(u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
memcpy(u.data, values.data(), std::min(u.dataSizePacked, values.size() * sizeof(LocalUniformValue)));
}
BuiltinUniform builtin = BUILTIN_MAX_ENUM;
@@ -742,7 +745,7 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const
void Shader::updateUniform(const UniformInfo *info, int count)
{
if (info->dataSize == 0)
if (info->dataSizePacked == 0)
return;
if (current == this)
+8 -12
View File
@@ -164,22 +164,18 @@ void Shader::mapActiveUniforms()
storageTextureBindings.push_back(binding);
}
if (u.dataSize == 0)
if (u.dataSizeAllocated == 0)
{
if (u.baseType == UNIFORM_MATRIX)
u.dataSize = sizeof(uint32) * u.matrix.rows * u.matrix.columns * u.count;
else
u.dataSize = sizeof(uint32) * u.components * u.count;
u.data = malloc(u.dataSize);
memset(u.data, 0, u.dataSize);
u.dataSizePacked = u.dataSizeAllocated = getUniformDataSizePacked(u);
u.data = malloc(u.dataSizeAllocated);
memset(u.data, 0, u.dataSizeAllocated);
const auto &valuesit = reflection.localUniformInitializerValues.find(u.name);
if (valuesit != reflection.localUniformInitializerValues.end())
{
const auto &values = valuesit->second;
if (!values.empty())
memcpy(u.data, values.data(), std::min(u.dataSize, sizeof(LocalUniformValue) * values.size()));
memcpy(u.data, values.data(), std::min(u.dataSizePacked, sizeof(LocalUniformValue) * values.size()));
}
}
@@ -237,10 +233,10 @@ void Shader::mapActiveUniforms()
u.active = true;
if (u.dataSize == 0)
if (u.dataSizeAllocated == 0)
{
u.dataSize = sizeof(int) * u.count;
u.data = malloc(u.dataSize);
u.dataSizePacked = u.dataSizeAllocated = sizeof(int) * u.count;
u.data = malloc(u.dataSizeAllocated);
for (int i = 0; i < u.count; i++)
u.ints[i] = -1;
}
+6 -2
View File
@@ -541,7 +541,11 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::
UniformInfo &u = *(uniformit->second);
u.active = true;
u.dataSize = memberSize;
// get_declared_struct_member_size should be the padded size, which can be larger than
// the tightly packed size that external code will use with UniformInfo.
u.dataSizeAllocated = memberSize;
u.dataSizePacked = getUniformDataSizePacked(u);
u.data = localUniformStagingData.data() + offset;
const auto &valuesit = reflection.localUniformInitializerValues.find(name);
@@ -553,7 +557,7 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::
memcpy(
u.data,
values.data(),
std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
std::min(u.dataSizePacked, values.size() * sizeof(LocalUniformValue)));
uint8 *dst = localUniformData.data() + offset;
copyToUniformBuffer(&u, u.data, dst, u.count);
+3 -3
View File
@@ -371,7 +371,7 @@ static int w_Shader_sendData(lua_State *L, int startidx, Shader *shader, const S
else if ((size_t) offset >= size)
return luaL_error(L, "Offset must be less than the size of the Data.");
size_t uniformstride = info->dataSize / info->count;
size_t uniformstride = info->dataSizePacked / info->count;
if (!lua_isnoneornil(L, startidx + 2))
{
@@ -382,7 +382,7 @@ static int w_Shader_sendData(lua_State *L, int startidx, Shader *shader, const S
return luaL_error(L, "Size and offset must fit within the Data's bounds.");
else if (sizearg % uniformstride != 0)
return luaL_error(L, "Size (%d) must be a multiple of the uniform's size in bytes (%d).", sizearg, uniformstride);
else if ((size_t) sizearg > info->dataSize)
else if ((size_t) sizearg > info->dataSizePacked)
return luaL_error(L, "Size must not be greater than the uniform's total size in bytes.");
size = (size_t) sizearg;
@@ -390,7 +390,7 @@ static int w_Shader_sendData(lua_State *L, int startidx, Shader *shader, const S
else
{
size -= offset;
size = std::min((size / uniformstride) * uniformstride, info->dataSize);
size = std::min((size / uniformstride) * uniformstride, info->dataSizePacked);
}
if (size == 0)