mirror of
https://github.com/love2d/love.git
synced 2026-08-28 18:26:55 +02:00
vulkan/metal: fix Shader:send(name, DataObject) truncating the data in some cases.
Fixes #2313
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user