metal: support constant initializer values for local uniforms.

This commit is contained in:
Alex Szpakowski
2022-01-01 15:28:42 -04:00
parent be6736cba5
commit e602f08c24
5 changed files with 110 additions and 9 deletions
+62
View File
@@ -792,6 +792,24 @@ static PixelFormat getPixelFormat(glslang::TLayoutFormat format)
}
}
template <typename T>
static T convertData(const glslang::TConstUnion &data)
{
switch (data.getType())
{
case glslang::EbtInt: return (T) data.getIConst();
case glslang::EbtUint: return (T) data.getUConst();
case glslang::EbtDouble: return (T) data.getDConst();
case glslang::EbtInt8: return (T) data.getI8Const();
case glslang::EbtInt16: return (T) data.getI16Const();
case glslang::EbtInt64: return (T) data.getI64Const();
case glslang::EbtUint8: return (T) data.getU8Const();
case glslang::EbtUint16: return (T) data.getU16Const();
case glslang::EbtUint64: return (T) data.getU64Const();
default: return 0;
}
}
bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err, ValidationReflection &reflection)
{
glslang::TProgram program;
@@ -871,6 +889,50 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
reflection.storageTextures[info.name] = texreflection;
}
else if (!type->isOpaque())
{
LocalUniform u = {};
auto &values = u.initializerValues;
const glslang::TConstUnionArray *constarray = info.getConstArray();
// Store initializer values for local uniforms. Some love graphics
// backends strip these out of the shader so we need to be able to
// access them (to re-send them) by getting them here.
switch (type->getBasicType())
{
case glslang::EbtFloat:
u.dataType = DATA_BASETYPE_FLOAT;
if (constarray != nullptr)
{
values.resize(constarray->size());
for (int i = 0; i < constarray->size(); i++)
values[i].f = convertData<float>((*constarray)[i]);
}
break;
case glslang::EbtUint:
u.dataType = DATA_BASETYPE_UINT;
if (constarray != nullptr)
{
values.resize(constarray->size());
for (int i = 0; i < constarray->size(); i++)
values[i].u = convertData<uint32>((*constarray)[i]);
}
break;
case glslang::EbtInt:
case glslang::EbtBool:
default:
u.dataType = DATA_BASETYPE_INT;
if (constarray != nullptr)
{
values.resize(constarray->size());
for (int i = 0; i < constarray->size(); i++)
values[i].i = convertData<int32>((*constarray)[i]);
}
break;
}
reflection.localUniforms[info.name] = u;
}
}
for (int i = 0; i < program.getNumBufferBlocks(); i++)
+14
View File
@@ -158,6 +158,13 @@ public:
};
};
union LocalUniformValue
{
float f;
int32 i;
uint32 u;
};
// The members in here must respect uniform buffer alignment/padding rules.
struct BuiltinUniformData
{
@@ -259,10 +266,17 @@ protected:
Access access;
};
struct LocalUniform
{
DataBaseType dataType;
std::vector<LocalUniformValue> initializerValues;
};
struct ValidationReflection
{
std::map<std::string, BufferReflection> storageBuffers;
std::map<std::string, StorageTextureReflection> storageTextures;
std::map<std::string, LocalUniform> localUniforms;
int localThreadgroupSize[3];
bool usesPointSize;
};
+12
View File
@@ -565,6 +565,16 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
u.matrix.rows = membertype.vecsize;
u.matrix.columns = membertype.columns;
}
if (validationReflection.localUniforms.find(u.name) != validationReflection.localUniforms.end())
{
const auto &ru = validationReflection.localUniforms.find(u.name);
const auto &values = ru->second.initializerValues;
if (!values.empty())
{
memcpy(u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue)));
}
}
updateUniform(&u, u.count);
break;
case SPIRType::Struct:
// TODO
@@ -582,6 +592,8 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
builtinUniformDataOffset = offset;
builtinUniformInfo[builtin] = &uniforms[u.name];
}
}
}
else