Skip to content

Commit

Permalink
vulkan: fix uniform vec3 array alignment
Browse files Browse the repository at this point in the history
  • Loading branch information
slime73 committed Apr 2, 2024
1 parent dc945d7 commit e08004d
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 36 deletions.
37 changes: 37 additions & 0 deletions src/modules/graphics/Shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1478,6 +1478,43 @@ void Shader::handleUnknownUniformName(const char */*name*/)
// TODO: do something here?
}

void Shader::copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const
{
count = std::min(count, info->count);

size_t elementsize = info->components * 4;
if (info->baseType == UNIFORM_MATRIX)
elementsize = info->matrix.columns * info->matrix.rows * 4;

// 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(dst, src, 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 *isrc = (const int *) src;
int *idst = (int *) dst;

for (int i = 0; i < veccount; i++)
{
for (int c = 0; c < comp; c++)
idst[i * 4 + c] = isrc[i * comp + c];
}
}
}

bool Shader::initialize()
{
bool success = glslang::InitializeProcess();
Expand Down
3 changes: 3 additions & 0 deletions src/modules/graphics/Shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ class Shader : public Object, public Resource

void handleUnknownUniformName(const char *name);

// std140 uniform buffer alignment-aware copy.
void copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const;

static std::string canonicaliizeUniformName(const std::string &name);
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, Reflection &reflection);
static DataBaseType getDataBaseType(PixelFormat format);
Expand Down
34 changes: 2 additions & 32 deletions src/modules/graphics/metal/Shader.mm
Original file line number Diff line number Diff line change
Expand Up @@ -708,40 +708,10 @@ static EShLanguage getGLSLangStage(ShaderStageType stage)

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;
uint8 *dst = localUniformBufferData + offset;

// 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];
}
}
copyToUniformBuffer(info, info->data, dst, count);
}

void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
Expand Down
17 changes: 13 additions & 4 deletions src/modules/graphics/vulkan/Shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,14 @@ void Shader::updateUniform(const UniformInfo *info, int count)
if (current == this)
Graphics::flushBatchedDrawsGlobal();

if (usesLocalUniformData(info))
memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
count = std::min(count, info->count);

if (info->data != nullptr)
{
size_t offset = (const uint8*)info->data - localUniformStagingData.data();
uint8 *dst = localUniformData.data() + offset;
copyToUniformBuffer(info, info->data, dst, count);
}
}

void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
Expand Down Expand Up @@ -453,10 +459,15 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::
{
const auto &values = valuesit->second;
if (!values.empty())
{
memcpy(
u.data,
values.data(),
std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));

uint8 *dst = localUniformData.data() + offset;
copyToUniformBuffer(&u, u.data, dst, u.count);
}
}

BuiltinUniform builtin = BUILTIN_MAX_ENUM;
Expand Down Expand Up @@ -588,8 +599,6 @@ void Shader::compileShaders()

std::string basename("");
buildLocalUniforms(comp, type, 0, basename);

memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size());
}
else
throw love::Exception("unimplemented: non default uniform blocks.");
Expand Down

0 comments on commit e08004d

Please sign in to comment.