rhi: gl: Handle struct and array of struct uniforms
We have intentionally limited support for advanced things like arrays in a uniform block. There is one very common case however: a one dimensional array of a struct. Typical example for Qt Quick 3D: struct LightSource { vec4 position; ... }; layout (std140, binding = 1) uniform cbBufferLights { int uNumLights; LightSource lights[MAX_NUM_LIGHTS]; }; With GLSL (uniform blocks disabled) this gets turned into two structs where one has a 'lights' member that is an array of the other struct. Teach the OpenGL backend of QRhi how to handle this. This makes the QRhi port of Qt Quick3D functional with the OpenGL backend as well. Change-Id: I6a09b93276794f7ecdd38f5bfbd3491a9ef58146 Fixes: QTBUG-80628 Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
parent
53804f553d
commit
e6de661a8a
@ -2927,21 +2927,64 @@ bool QRhiGles2::linkProgram(GLuint program)
|
||||
return true;
|
||||
}
|
||||
|
||||
void QRhiGles2::gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
||||
void QRhiGles2::registerUniformIfActive(const QShaderDescription::BlockVariable &var,
|
||||
const QByteArray &namePrefix,
|
||||
int binding,
|
||||
int baseOffset,
|
||||
GLuint program,
|
||||
QVector<QGles2UniformDescription> *dst)
|
||||
{
|
||||
if (var.type == QShaderDescription::Struct) {
|
||||
qWarning("Nested structs are not supported at the moment. '%s' ignored.",
|
||||
qPrintable(var.name));
|
||||
return;
|
||||
}
|
||||
QGles2UniformDescription uniform;
|
||||
uniform.type = var.type;
|
||||
const QByteArray name = namePrefix + var.name.toUtf8();
|
||||
uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
|
||||
if (uniform.glslLocation >= 0) {
|
||||
uniform.binding = binding;
|
||||
uniform.offset = uint(baseOffset + var.offset);
|
||||
uniform.size = var.size;
|
||||
dst->append(uniform);
|
||||
}
|
||||
}
|
||||
|
||||
void QRhiGles2::gatherUniforms(GLuint program,
|
||||
const QShaderDescription::UniformBlock &ub,
|
||||
QVector<QGles2UniformDescription> *dst)
|
||||
{
|
||||
const QByteArray prefix = ub.structName.toUtf8() + '.';
|
||||
QByteArray prefix = ub.structName.toUtf8() + '.';
|
||||
for (const QShaderDescription::BlockVariable &blockMember : ub.members) {
|
||||
// ### no array support for now
|
||||
QGles2UniformDescription uniform;
|
||||
uniform.type = blockMember.type;
|
||||
const QByteArray name = prefix + blockMember.name.toUtf8();
|
||||
uniform.glslLocation = f->glGetUniformLocation(program, name.constData());
|
||||
if (uniform.glslLocation >= 0) {
|
||||
uniform.binding = ub.binding;
|
||||
uniform.offset = uint(blockMember.offset);
|
||||
uniform.size = blockMember.size;
|
||||
dst->append(uniform);
|
||||
if (blockMember.type == QShaderDescription::Struct) {
|
||||
prefix += blockMember.name.toUtf8();
|
||||
const int baseOffset = blockMember.offset;
|
||||
if (blockMember.arrayDims.isEmpty()) {
|
||||
for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
|
||||
registerUniformIfActive(structMember, prefix, ub.binding, baseOffset, program, dst);
|
||||
} else {
|
||||
if (blockMember.arrayDims.count() > 1) {
|
||||
qWarning("Array of struct '%s' has more than one dimension. Only the first dimension is used.",
|
||||
qPrintable(blockMember.name));
|
||||
}
|
||||
const int dim = blockMember.arrayDims.first();
|
||||
const int elemSize = blockMember.size / dim;
|
||||
int elemOffset = baseOffset;
|
||||
for (int di = 0; di < dim; ++di) {
|
||||
const QByteArray arrayPrefix = prefix + '[' + QByteArray::number(di) + ']' + '.';
|
||||
for (const QShaderDescription::BlockVariable &structMember : blockMember.structMembers)
|
||||
registerUniformIfActive(structMember, arrayPrefix, ub.binding, elemOffset, program, dst);
|
||||
elemOffset += elemSize;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!blockMember.arrayDims.isEmpty()) {
|
||||
qWarning("Arrays are only supported for structs at the moment. '%s' ignored.",
|
||||
qPrintable(blockMember.name));
|
||||
continue;
|
||||
}
|
||||
registerUniformIfActive(blockMember, prefix, ub.binding, 0, program, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -706,7 +706,14 @@ public:
|
||||
QByteArray shaderSource(const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||
bool compileShader(GLuint program, const QRhiShaderStage &shaderStage, int *glslVersion);
|
||||
bool linkProgram(GLuint program);
|
||||
void gatherUniforms(GLuint program, const QShaderDescription::UniformBlock &ub,
|
||||
void registerUniformIfActive(const QShaderDescription::BlockVariable &var,
|
||||
const QByteArray &namePrefix,
|
||||
int binding,
|
||||
int baseOffset,
|
||||
GLuint program,
|
||||
QVector<QGles2UniformDescription> *dst);
|
||||
void gatherUniforms(GLuint program,
|
||||
const QShaderDescription::UniformBlock &ub,
|
||||
QVector<QGles2UniformDescription> *dst);
|
||||
void gatherSamplers(GLuint program, const QShaderDescription::InOutVariable &v,
|
||||
QVector<QGles2SamplerDescription> *dst);
|
||||
|
Loading…
x
Reference in New Issue
Block a user