Commit 924513cd by Alexis Hetu Committed by Alexis Hétu

Structure field type validation

Uniforms and varyings structures were simply validating that both versions in fragment and vertex shaders were structures, without validating that the fields actually matched. All the structures and data required to perform the validation at link time was added. Fixes: dEQP-GLES3.functional.shaders.linkage.uniform.struct.type_conflict_1 Change-Id: Icbf888bbebf4ccf7d27f48cb98d4cd7ea5b42ca3 Reviewed-on: https://swiftshader-review.googlesource.com/15848Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com>
parent 6d12331a
...@@ -26,6 +26,183 @@ ...@@ -26,6 +26,183 @@
#include <stdlib.h> #include <stdlib.h>
namespace
{
GLenum glVariableType(const TType &type)
{
switch(type.getBasicType())
{
case EbtFloat:
if(type.isScalar())
{
return GL_FLOAT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_FLOAT_VEC2;
case 3: return GL_FLOAT_VEC3;
case 4: return GL_FLOAT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else if(type.isMatrix())
{
switch(type.getNominalSize())
{
case 2:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT2;
case 3: return GL_FLOAT_MAT2x3;
case 4: return GL_FLOAT_MAT2x4;
default: UNREACHABLE(type.getSecondarySize());
}
case 3:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT3x2;
case 3: return GL_FLOAT_MAT3;
case 4: return GL_FLOAT_MAT3x4;
default: UNREACHABLE(type.getSecondarySize());
}
case 4:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT4x2;
case 3: return GL_FLOAT_MAT4x3;
case 4: return GL_FLOAT_MAT4;
default: UNREACHABLE(type.getSecondarySize());
}
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtInt:
if(type.isScalar())
{
return GL_INT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_INT_VEC2;
case 3: return GL_INT_VEC3;
case 4: return GL_INT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtUInt:
if(type.isScalar())
{
return GL_UNSIGNED_INT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_UNSIGNED_INT_VEC2;
case 3: return GL_UNSIGNED_INT_VEC3;
case 4: return GL_UNSIGNED_INT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtBool:
if(type.isScalar())
{
return GL_BOOL;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_BOOL_VEC2;
case 3: return GL_BOOL_VEC3;
case 4: return GL_BOOL_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtSampler2D:
return GL_SAMPLER_2D;
case EbtISampler2D:
return GL_INT_SAMPLER_2D;
case EbtUSampler2D:
return GL_UNSIGNED_INT_SAMPLER_2D;
case EbtSamplerCube:
return GL_SAMPLER_CUBE;
case EbtISamplerCube:
return GL_INT_SAMPLER_CUBE;
case EbtUSamplerCube:
return GL_UNSIGNED_INT_SAMPLER_CUBE;
case EbtSamplerExternalOES:
return GL_SAMPLER_EXTERNAL_OES;
case EbtSampler3D:
return GL_SAMPLER_3D_OES;
case EbtISampler3D:
return GL_INT_SAMPLER_3D;
case EbtUSampler3D:
return GL_UNSIGNED_INT_SAMPLER_3D;
case EbtSampler2DArray:
return GL_SAMPLER_2D_ARRAY;
case EbtISampler2DArray:
return GL_INT_SAMPLER_2D_ARRAY;
case EbtUSampler2DArray:
return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
case EbtSampler2DShadow:
return GL_SAMPLER_2D_SHADOW;
case EbtSamplerCubeShadow:
return GL_SAMPLER_CUBE_SHADOW;
case EbtSampler2DArrayShadow:
return GL_SAMPLER_2D_ARRAY_SHADOW;
default:
UNREACHABLE(type.getBasicType());
break;
}
return GL_NONE;
}
GLenum glVariablePrecision(const TType &type)
{
if(type.getBasicType() == EbtFloat)
{
switch(type.getPrecision())
{
case EbpHigh: return GL_HIGH_FLOAT;
case EbpMedium: return GL_MEDIUM_FLOAT;
case EbpLow: return GL_LOW_FLOAT;
case EbpUndefined:
// Should be defined as the default precision by the parser
default: UNREACHABLE(type.getPrecision());
}
}
else if(type.getBasicType() == EbtInt)
{
switch(type.getPrecision())
{
case EbpHigh: return GL_HIGH_INT;
case EbpMedium: return GL_MEDIUM_INT;
case EbpLow: return GL_LOW_INT;
case EbpUndefined:
// Should be defined as the default precision by the parser
default: UNREACHABLE(type.getPrecision());
}
}
// Other types (boolean, sampler) don't have a precision
return GL_NONE;
}
}
namespace glsl namespace glsl
{ {
// Integer to TString conversion // Integer to TString conversion
...@@ -81,8 +258,21 @@ namespace glsl ...@@ -81,8 +258,21 @@ namespace glsl
ConstantUnion constants[4]; ConstantUnion constants[4];
}; };
Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) : ShaderVariable::ShaderVariable(const TType& type, const std::string& name, int registerIndex) :
type(type), precision(precision), name(name), arraySize(arraySize), registerIndex(registerIndex), blockId(blockId), blockInfo(blockMemberInfo) type(type.isStruct() ? GL_NONE : glVariableType(type)), precision(glVariablePrecision(type)),
name(name), arraySize(type.getArraySize()), registerIndex(registerIndex)
{
if(type.isStruct())
{
for(const auto& field : type.getStruct()->fields())
{
fields.push_back(ShaderVariable(*(field->type()), field->name().c_str(), -1));
}
}
}
Uniform::Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo) :
ShaderVariable(type, name, registerIndex), blockId(blockId), blockInfo(blockMemberInfo)
{ {
} }
...@@ -2925,15 +3115,15 @@ namespace glsl ...@@ -2925,15 +3115,15 @@ namespace glsl
{ {
if(registerIndex >= 0) if(registerIndex >= 0)
{ {
ASSERT(v->reg < 0 || v->reg == registerIndex); ASSERT(v->registerIndex < 0 || v->registerIndex == registerIndex);
v->reg = registerIndex; v->registerIndex = registerIndex;
} }
return; return;
} }
} }
activeVaryings.push_back(glsl::Varying(glVariableType(type), name, type.getArraySize(), type.getQualifier(), registerIndex, 0)); activeVaryings.push_back(glsl::Varying(type, name, registerIndex, 0));
} }
} }
...@@ -3316,10 +3506,9 @@ namespace glsl ...@@ -3316,10 +3506,9 @@ namespace glsl
shader->declareSampler(fieldRegisterIndex + i); shader->declareSampler(fieldRegisterIndex + i);
} }
} }
if(!isSampler || samplersOnly) if(isSampler == samplersOnly)
{ {
activeUniforms.push_back(Uniform(glVariableType(type), glVariablePrecision(type), name.c_str(), type.getArraySize(), activeUniforms.push_back(Uniform(type, name.c_str(), fieldRegisterIndex, blockId, blockInfo));
fieldRegisterIndex, blockId, blockInfo));
} }
} }
else if(block) else if(block)
...@@ -3357,6 +3546,9 @@ namespace glsl ...@@ -3357,6 +3546,9 @@ namespace glsl
} }
else else
{ {
// Store struct for program link time validation
shaderObject->activeUniformStructs.push_back(Uniform(type, name.c_str(), registerIndex, -1, BlockMemberInfo::getDefaultBlockInfo()));
int fieldRegisterIndex = registerIndex; int fieldRegisterIndex = registerIndex;
const TFieldList& fields = structure->fields(); const TFieldList& fields = structure->fields();
...@@ -3406,180 +3598,6 @@ namespace glsl ...@@ -3406,180 +3598,6 @@ namespace glsl
} }
} }
GLenum OutputASM::glVariableType(const TType &type)
{
switch(type.getBasicType())
{
case EbtFloat:
if(type.isScalar())
{
return GL_FLOAT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_FLOAT_VEC2;
case 3: return GL_FLOAT_VEC3;
case 4: return GL_FLOAT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else if(type.isMatrix())
{
switch(type.getNominalSize())
{
case 2:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT2;
case 3: return GL_FLOAT_MAT2x3;
case 4: return GL_FLOAT_MAT2x4;
default: UNREACHABLE(type.getSecondarySize());
}
case 3:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT3x2;
case 3: return GL_FLOAT_MAT3;
case 4: return GL_FLOAT_MAT3x4;
default: UNREACHABLE(type.getSecondarySize());
}
case 4:
switch(type.getSecondarySize())
{
case 2: return GL_FLOAT_MAT4x2;
case 3: return GL_FLOAT_MAT4x3;
case 4: return GL_FLOAT_MAT4;
default: UNREACHABLE(type.getSecondarySize());
}
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtInt:
if(type.isScalar())
{
return GL_INT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_INT_VEC2;
case 3: return GL_INT_VEC3;
case 4: return GL_INT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtUInt:
if(type.isScalar())
{
return GL_UNSIGNED_INT;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_UNSIGNED_INT_VEC2;
case 3: return GL_UNSIGNED_INT_VEC3;
case 4: return GL_UNSIGNED_INT_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtBool:
if(type.isScalar())
{
return GL_BOOL;
}
else if(type.isVector())
{
switch(type.getNominalSize())
{
case 2: return GL_BOOL_VEC2;
case 3: return GL_BOOL_VEC3;
case 4: return GL_BOOL_VEC4;
default: UNREACHABLE(type.getNominalSize());
}
}
else UNREACHABLE(0);
break;
case EbtSampler2D:
return GL_SAMPLER_2D;
case EbtISampler2D:
return GL_INT_SAMPLER_2D;
case EbtUSampler2D:
return GL_UNSIGNED_INT_SAMPLER_2D;
case EbtSamplerCube:
return GL_SAMPLER_CUBE;
case EbtISamplerCube:
return GL_INT_SAMPLER_CUBE;
case EbtUSamplerCube:
return GL_UNSIGNED_INT_SAMPLER_CUBE;
case EbtSamplerExternalOES:
return GL_SAMPLER_EXTERNAL_OES;
case EbtSampler3D:
return GL_SAMPLER_3D_OES;
case EbtISampler3D:
return GL_INT_SAMPLER_3D;
case EbtUSampler3D:
return GL_UNSIGNED_INT_SAMPLER_3D;
case EbtSampler2DArray:
return GL_SAMPLER_2D_ARRAY;
case EbtISampler2DArray:
return GL_INT_SAMPLER_2D_ARRAY;
case EbtUSampler2DArray:
return GL_UNSIGNED_INT_SAMPLER_2D_ARRAY;
case EbtSampler2DShadow:
return GL_SAMPLER_2D_SHADOW;
case EbtSamplerCubeShadow:
return GL_SAMPLER_CUBE_SHADOW;
case EbtSampler2DArrayShadow:
return GL_SAMPLER_2D_ARRAY_SHADOW;
default:
UNREACHABLE(type.getBasicType());
break;
}
return GL_NONE;
}
GLenum OutputASM::glVariablePrecision(const TType &type)
{
if(type.getBasicType() == EbtFloat)
{
switch(type.getPrecision())
{
case EbpHigh: return GL_HIGH_FLOAT;
case EbpMedium: return GL_MEDIUM_FLOAT;
case EbpLow: return GL_LOW_FLOAT;
case EbpUndefined:
// Should be defined as the default precision by the parser
default: UNREACHABLE(type.getPrecision());
}
}
else if(type.getBasicType() == EbtInt)
{
switch(type.getPrecision())
{
case EbpHigh: return GL_HIGH_INT;
case EbpMedium: return GL_MEDIUM_INT;
case EbpLow: return GL_LOW_INT;
case EbpUndefined:
// Should be defined as the default precision by the parser
default: UNREACHABLE(type.getPrecision());
}
}
// Other types (boolean, sampler) don't have a precision
return GL_NONE;
}
int OutputASM::dim(TIntermNode *v) int OutputASM::dim(TIntermNode *v)
{ {
TIntermTyped *vector = v->getAsTyped(); TIntermTyped *vector = v->getAsTyped();
......
...@@ -55,9 +55,9 @@ namespace glsl ...@@ -55,9 +55,9 @@ namespace glsl
bool isRowMajorMatrix; bool isRowMajorMatrix;
}; };
struct Uniform struct ShaderVariable
{ {
Uniform(GLenum type, GLenum precision, const std::string &name, int arraySize, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo); ShaderVariable(const TType& type, const std::string& name, int registerIndex);
GLenum type; GLenum type;
GLenum precision; GLenum precision;
...@@ -66,6 +66,13 @@ namespace glsl ...@@ -66,6 +66,13 @@ namespace glsl
int registerIndex; int registerIndex;
std::vector<ShaderVariable> fields;
};
struct Uniform : public ShaderVariable
{
Uniform(const TType& type, const std::string &name, int registerIndex, int blockId, const BlockMemberInfo& blockMemberInfo);
int blockId; int blockId;
BlockMemberInfo blockInfo; BlockMemberInfo blockInfo;
}; };
...@@ -150,10 +157,10 @@ namespace glsl ...@@ -150,10 +157,10 @@ namespace glsl
typedef std::vector<Attribute> ActiveAttributes; typedef std::vector<Attribute> ActiveAttributes;
struct Varying struct Varying : public ShaderVariable
{ {
Varying(GLenum type, const std::string &name, int arraySize, TQualifier qualifier, int reg = -1, int col = -1) Varying(const TType& type, const std::string &name, int reg = -1, int col = -1)
: type(type), name(name), arraySize(arraySize), qualifier(qualifier), reg(reg), col(col) : ShaderVariable(type, name, reg), qualifier(type.getQualifier()), col(col)
{ {
} }
...@@ -167,12 +174,7 @@ namespace glsl ...@@ -167,12 +174,7 @@ namespace glsl
return arraySize > 0 ? arraySize : 1; return arraySize > 0 ? arraySize : 1;
} }
GLenum type;
std::string name;
int arraySize;
TQualifier qualifier; TQualifier qualifier;
int reg; // First varying register, assigned during link
int col; // First register element, assigned during link int col; // First register element, assigned during link
}; };
...@@ -191,6 +193,7 @@ namespace glsl ...@@ -191,6 +193,7 @@ namespace glsl
protected: protected:
VaryingList varyings; VaryingList varyings;
ActiveUniforms activeUniforms; ActiveUniforms activeUniforms;
ActiveUniforms activeUniformStructs;
ActiveAttributes activeAttributes; ActiveAttributes activeAttributes;
ActiveUniformBlocks activeUniformBlocks; ActiveUniformBlocks activeUniformBlocks;
int shaderVersion; int shaderVersion;
...@@ -310,8 +313,6 @@ namespace glsl ...@@ -310,8 +313,6 @@ namespace glsl
void free(VariableArray &list, TIntermTyped *variable); void free(VariableArray &list, TIntermTyped *variable);
void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr); void declareUniform(const TType &type, const TString &name, int registerIndex, bool samplersOnly, int blockId = -1, BlockLayoutEncoder* encoder = nullptr);
GLenum glVariableType(const TType &type);
GLenum glVariablePrecision(const TType &type);
static int dim(TIntermNode *v); static int dim(TIntermNode *v);
static int dim2(TIntermNode *m); static int dim2(TIntermNode *m);
......
...@@ -61,11 +61,11 @@ namespace es2 ...@@ -61,11 +61,11 @@ namespace es2
} }
} }
Uniform::Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, Uniform::Uniform(const glsl::Uniform &uniform, const BlockInfo &blockInfo)
const BlockInfo &blockInfo) : type(uniform.type), precision(uniform.precision), name(uniform.name),
: type(type), precision(precision), name(name), arraySize(arraySize), blockInfo(blockInfo) arraySize(uniform.arraySize), blockInfo(blockInfo), fields(uniform.fields)
{ {
if(blockInfo.index == -1) if((blockInfo.index == -1) && uniform.fields.empty())
{ {
size_t bytes = UniformTypeSize(type) * size(); size_t bytes = UniformTypeSize(type) * size();
data = new unsigned char[bytes]; data = new unsigned char[bytes];
...@@ -267,7 +267,7 @@ namespace es2 ...@@ -267,7 +267,7 @@ namespace es2
{ {
int rowCount = VariableRowCount(input.type); int rowCount = VariableRowCount(input.type);
int colCount = VariableColumnCount(input.type); int colCount = VariableColumnCount(input.type);
return (subscript == GL_INVALID_INDEX) ? input.reg : input.reg + (rowCount > 1 ? colCount * subscript : subscript); return (subscript == GL_INVALID_INDEX) ? input.registerIndex : input.registerIndex + (rowCount > 1 ? colCount * subscript : subscript);
} }
} }
} }
...@@ -1337,6 +1337,11 @@ namespace es2 ...@@ -1337,6 +1337,11 @@ namespace es2
return false; return false;
} }
if(!areMatchingFields(input.fields, output.fields, input.name))
{
return false;
}
matched = true; matched = true;
break; break;
} }
...@@ -1358,8 +1363,8 @@ namespace es2 ...@@ -1358,8 +1363,8 @@ namespace es2
{ {
if(output.name == input.name) if(output.name == input.name)
{ {
int in = input.reg; int in = input.registerIndex;
int out = output.reg; int out = output.registerIndex;
int components = VariableRegisterSize(output.type); int components = VariableRegisterSize(output.type);
int registers = VariableRegisterCount(output.type) * output.size(); int registers = VariableRegisterCount(output.type) * output.size();
...@@ -1406,7 +1411,7 @@ namespace es2 ...@@ -1406,7 +1411,7 @@ namespace es2
if(tfVaryingName == output.name) if(tfVaryingName == output.name)
{ {
int out = output.reg; int out = output.registerIndex;
int components = VariableRegisterSize(output.type); int components = VariableRegisterSize(output.type);
int registers = VariableRegisterCount(output.type) * output.size(); int registers = VariableRegisterCount(output.type) * output.size();
...@@ -1484,7 +1489,7 @@ namespace es2 ...@@ -1484,7 +1489,7 @@ namespace es2
totalComponents += componentCount; totalComponents += componentCount;
int reg = varying.reg; int reg = varying.registerIndex;
if(hasSubscript) if(hasSubscript)
{ {
reg += rowCount > 1 ? colCount * subscript : subscript; reg += rowCount > 1 ? colCount * subscript : subscript;
...@@ -1683,12 +1688,8 @@ namespace es2 ...@@ -1683,12 +1688,8 @@ namespace es2
bool Program::linkUniforms(const Shader *shader) bool Program::linkUniforms(const Shader *shader)
{ {
const glsl::ActiveUniforms &activeUniforms = shader->activeUniforms; for(const auto &uniform : shader->activeUniforms)
for(unsigned int uniformIndex = 0; uniformIndex < activeUniforms.size(); uniformIndex++)
{ {
const glsl::Uniform &uniform = activeUniforms[uniformIndex];
unsigned int blockIndex = GL_INVALID_INDEX; unsigned int blockIndex = GL_INVALID_INDEX;
if(uniform.blockId >= 0) if(uniform.blockId >= 0)
{ {
...@@ -1697,7 +1698,15 @@ namespace es2 ...@@ -1697,7 +1698,15 @@ namespace es2
blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].name); blockIndex = getUniformBlockIndex(activeUniformBlocks[uniform.blockId].name);
ASSERT(blockIndex != GL_INVALID_INDEX); ASSERT(blockIndex != GL_INVALID_INDEX);
} }
if(!defineUniform(shader->getType(), uniform.type, uniform.precision, uniform.name, uniform.arraySize, uniform.registerIndex, Uniform::BlockInfo(uniform, blockIndex))) if(!defineUniform(shader->getType(), uniform, Uniform::BlockInfo(uniform, blockIndex)))
{
return false;
}
}
for(const auto &uniformStruct : shader->activeUniformStructs)
{
if(!validateUniformStruct(shader->getType(), uniformStruct))
{ {
return false; return false;
} }
...@@ -1706,11 +1715,11 @@ namespace es2 ...@@ -1706,11 +1715,11 @@ namespace es2
return true; return true;
} }
bool Program::defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo) bool Program::defineUniform(GLenum shader, const glsl::Uniform &glslUniform, const Uniform::BlockInfo& blockInfo)
{ {
if(IsSamplerUniform(type)) if(IsSamplerUniform(glslUniform.type))
{ {
int index = registerIndex; int index = glslUniform.registerIndex;
do do
{ {
...@@ -1720,9 +1729,9 @@ namespace es2 ...@@ -1720,9 +1729,9 @@ namespace es2
{ {
samplersVS[index].active = true; samplersVS[index].active = true;
switch(type) switch(glslUniform.type)
{ {
default: UNREACHABLE(type); default: UNREACHABLE(glslUniform.type);
case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_2D:
case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_2D_SHADOW:
...@@ -1755,9 +1764,9 @@ namespace es2 ...@@ -1755,9 +1764,9 @@ namespace es2
{ {
samplersPS[index].active = true; samplersPS[index].active = true;
switch(type) switch(glslUniform.type)
{ {
default: UNREACHABLE(type); default: UNREACHABLE(glslUniform.type);
case GL_INT_SAMPLER_2D: case GL_INT_SAMPLER_2D:
case GL_UNSIGNED_INT_SAMPLER_2D: case GL_UNSIGNED_INT_SAMPLER_2D:
case GL_SAMPLER_2D_SHADOW: case GL_SAMPLER_2D_SHADOW:
...@@ -1788,31 +1797,36 @@ namespace es2 ...@@ -1788,31 +1797,36 @@ namespace es2
index++; index++;
} }
while(index < registerIndex + static_cast<int>(arraySize)); while(index < glslUniform.registerIndex + static_cast<int>(glslUniform.arraySize));
} }
Uniform *uniform = 0; Uniform *uniform = 0;
GLint location = getUniformLocation(name); GLint location = getUniformLocation(glslUniform.name);
if(location >= 0) // Previously defined, types must match if(location >= 0) // Previously defined, types must match
{ {
uniform = uniforms[uniformIndex[location].index]; uniform = uniforms[uniformIndex[location].index];
if(uniform->type != type) if(uniform->type != glslUniform.type)
{ {
appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); appendToInfoLog("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
return false; return false;
} }
if(uniform->precision != precision) if(uniform->precision != glslUniform.precision)
{ {
appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str()); appendToInfoLog("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
return false; return false;
} }
if(!areMatchingFields(uniform->fields, glslUniform.fields, uniform->name))
{
return false;
}
} }
else else
{ {
uniform = new Uniform(type, precision, name, arraySize, blockInfo); uniform = new Uniform(glslUniform, blockInfo);
} }
if(!uniform) if(!uniform)
...@@ -1822,28 +1836,28 @@ namespace es2 ...@@ -1822,28 +1836,28 @@ namespace es2
if(shader == GL_VERTEX_SHADER) if(shader == GL_VERTEX_SHADER)
{ {
uniform->vsRegisterIndex = registerIndex; uniform->vsRegisterIndex = glslUniform.registerIndex;
} }
else if(shader == GL_FRAGMENT_SHADER) else if(shader == GL_FRAGMENT_SHADER)
{ {
uniform->psRegisterIndex = registerIndex; uniform->psRegisterIndex = glslUniform.registerIndex;
} }
else UNREACHABLE(shader); else UNREACHABLE(shader);
if(!isUniformDefined(name)) if(!isUniformDefined(glslUniform.name))
{ {
uniforms.push_back(uniform); uniforms.push_back(uniform);
unsigned int index = (blockInfo.index == -1) ? static_cast<unsigned int>(uniforms.size() - 1) : GL_INVALID_INDEX; unsigned int index = (blockInfo.index == -1) ? static_cast<unsigned int>(uniforms.size() - 1) : GL_INVALID_INDEX;
for(int i = 0; i < uniform->size(); i++) for(int i = 0; i < uniform->size(); i++)
{ {
uniformIndex.push_back(UniformLocation(name, i, index)); uniformIndex.push_back(UniformLocation(glslUniform.name, i, index));
} }
} }
if(shader == GL_VERTEX_SHADER) if(shader == GL_VERTEX_SHADER)
{ {
if(registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS) if(glslUniform.registerIndex + uniform->registerCount() > MAX_VERTEX_UNIFORM_VECTORS)
{ {
appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS); appendToInfoLog("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%d)", MAX_VERTEX_UNIFORM_VECTORS);
return false; return false;
...@@ -1851,7 +1865,7 @@ namespace es2 ...@@ -1851,7 +1865,7 @@ namespace es2
} }
else if(shader == GL_FRAGMENT_SHADER) else if(shader == GL_FRAGMENT_SHADER)
{ {
if(registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS) if(glslUniform.registerIndex + uniform->registerCount() > MAX_FRAGMENT_UNIFORM_VECTORS)
{ {
appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS); appendToInfoLog("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%d)", MAX_FRAGMENT_UNIFORM_VECTORS);
return false; return false;
...@@ -1862,6 +1876,21 @@ namespace es2 ...@@ -1862,6 +1876,21 @@ namespace es2
return true; return true;
} }
bool Program::validateUniformStruct(GLenum shader, const glsl::Uniform &newUniformStruct)
{
for(const auto &uniformStruct : uniformStructs)
{
if(uniformStruct.name == newUniformStruct.name)
{
return areMatchingFields(uniformStruct.fields, newUniformStruct.fields, newUniformStruct.name);
}
}
uniformStructs.push_back(Uniform(newUniformStruct, Uniform::BlockInfo(newUniformStruct, -1)));
return true;
}
bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2) bool Program::areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2)
{ {
// validate blocks for the same member types // validate blocks for the same member types
...@@ -1915,6 +1944,41 @@ namespace es2 ...@@ -1915,6 +1944,41 @@ namespace es2
return true; return true;
} }
bool Program::areMatchingFields(const std::vector<glsl::ShaderVariable>& fields1, const std::vector<glsl::ShaderVariable>& fields2, const std::string& name)
{
if(fields1.size() != fields2.size())
{
appendToInfoLog("Structure lengths for %s differ between vertex and fragment shaders", name.c_str());
return false;
}
for(int i = 0; i < fields1.size(); ++i)
{
if(fields1[i].name != fields2[i].name)
{
appendToInfoLog("Name mismatch for field '%d' of %s: ('%s', '%s')",
i, name.c_str(), fields1[i].name.c_str(), fields2[i].name.c_str());
return false;
}
if(fields1[i].type != fields2[i].type)
{
appendToInfoLog("Type for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
return false;
}
if(fields1[i].arraySize != fields2[i].arraySize)
{
appendToInfoLog("Array size for %s.%s differ between vertex and fragment shaders", name.c_str(), fields1[i].name.c_str());
return false;
}
if(!areMatchingFields(fields1[i].fields, fields2[i].fields, fields1[i].name))
{
return false;
}
}
return true;
}
bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader) bool Program::linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader)
{ {
const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks; const glsl::ActiveUniformBlocks &vertexUniformBlocks = vertexShader->activeUniformBlocks;
......
...@@ -49,8 +49,7 @@ namespace es2 ...@@ -49,8 +49,7 @@ namespace es2
bool isRowMajorMatrix; bool isRowMajorMatrix;
}; };
Uniform(GLenum type, GLenum precision, const std::string &name, unsigned int arraySize, Uniform(const glsl::Uniform &uniform, const BlockInfo &blockInfo);
const BlockInfo &blockInfo);
~Uniform(); ~Uniform();
...@@ -63,6 +62,7 @@ namespace es2 ...@@ -63,6 +62,7 @@ namespace es2
const std::string name; const std::string name;
const unsigned int arraySize; const unsigned int arraySize;
const BlockInfo blockInfo; const BlockInfo blockInfo;
std::vector<glsl::ShaderVariable> fields;
unsigned char *data; unsigned char *data;
bool dirty; bool dirty;
...@@ -234,7 +234,9 @@ namespace es2 ...@@ -234,7 +234,9 @@ namespace es2
bool linkUniforms(const Shader *shader); bool linkUniforms(const Shader *shader);
bool linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader); bool linkUniformBlocks(const Shader *vertexShader, const Shader *fragmentShader);
bool areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2); bool areMatchingUniformBlocks(const glsl::UniformBlock &block1, const glsl::UniformBlock &block2, const Shader *shader1, const Shader *shader2);
bool defineUniform(GLenum shader, GLenum type, GLenum precision, const std::string &_name, unsigned int arraySize, int registerIndex, const Uniform::BlockInfo& blockInfo); bool areMatchingFields(const std::vector<glsl::ShaderVariable>& fields1, const std::vector<glsl::ShaderVariable>& fields2, const std::string& name);
bool validateUniformStruct(GLenum shader, const glsl::Uniform &newUniformStruct);
bool defineUniform(GLenum shader, const glsl::Uniform &uniform, const Uniform::BlockInfo& blockInfo);
bool defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block); bool defineUniformBlock(const Shader *shader, const glsl::UniformBlock &block);
bool applyUniform(Device *device, GLint location, float* data); bool applyUniform(Device *device, GLint location, float* data);
bool applyUniform1bv(Device *device, GLint location, GLsizei count, const GLboolean *v); bool applyUniform1bv(Device *device, GLint location, GLsizei count, const GLboolean *v);
...@@ -303,6 +305,8 @@ namespace es2 ...@@ -303,6 +305,8 @@ namespace es2
typedef std::vector<Uniform*> UniformArray; typedef std::vector<Uniform*> UniformArray;
UniformArray uniforms; UniformArray uniforms;
typedef std::vector<Uniform> UniformStructArray;
UniformStructArray uniformStructs;
typedef std::vector<UniformLocation> UniformIndex; typedef std::vector<UniformLocation> UniformIndex;
UniformIndex uniformIndex; UniformIndex uniformIndex;
typedef std::vector<UniformBlock*> UniformBlockArray; typedef std::vector<UniformBlock*> UniformBlockArray;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment