Commit 42ff6b15 by Alexis Hetu Committed by Alexis Hétu

Add proper in/out shader types

Fragment and Vertex inputs and outputs were treated as OpenGL ES2.0 attributes and varyings, but OpenGL ES3.0 inputs and outputs have different limitations and must be treated differently. This cl simply introduces the new types, without modifying the ES2.0 behavior and only modifying ES3.0 to allow integer varyings when they are flat. Change-Id: I965cb576bab3f505602af9e055438bcc7c18cdfd Reviewed-on: https://swiftshader-review.googlesource.com/3371Tested-by: 's avatarAlexis Hétu <sugoi@google.com> Reviewed-by: 's avatarNicolas Capens <capn@google.com>
parent bb7a1730
......@@ -342,6 +342,11 @@ enum TQualifier : unsigned char
EvqInvariantVaryingOut, // vertex shaders only read/write
EvqUniform, // Readonly, vertex and fragment
EvqVertexIn, // Vertex shader input
EvqFragmentOut, // Fragment shader output
EvqVertexOut, // Vertex shader output
EvqFragmentIn, // Fragment shader input
// pack/unpack input and output
EvqInput,
EvqOutput,
......@@ -420,6 +425,10 @@ inline const char *getQualifierString(TQualifier qualifier)
case EvqInvariantVaryingIn: return "invariant varying"; break;
case EvqInvariantVaryingOut:return "invariant varying"; break;
case EvqUniform: return "uniform"; break;
case EvqVertexIn: return "in"; break;
case EvqFragmentOut: return "out"; break;
case EvqVertexOut: return "out"; break;
case EvqFragmentIn: return "in"; break;
case EvqIn: return "in"; break;
case EvqOut: return "out"; break;
case EvqInOut: return "inout"; break;
......
......@@ -166,7 +166,7 @@ namespace glsl
{
// Vertex varyings don't have to be actively used to successfully link
// against pixel shaders that use them. So make sure they're declared.
if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut)
if(symbol->getQualifier() == EvqVaryingOut || symbol->getQualifier() == EvqInvariantVaryingOut || symbol->getQualifier() == EvqVertexOut)
{
if(symbol->getBasicType() != EbtInvariant) // Typeless declarations are not new varyings
{
......@@ -1857,6 +1857,10 @@ namespace glsl
case EvqAttribute: return sw::Shader::PARAMETER_INPUT;
case EvqVaryingIn: return sw::Shader::PARAMETER_INPUT;
case EvqVaryingOut: return sw::Shader::PARAMETER_OUTPUT;
case EvqVertexIn: return sw::Shader::PARAMETER_INPUT;
case EvqFragmentOut: return sw::Shader::PARAMETER_COLOROUT;
case EvqVertexOut: return sw::Shader::PARAMETER_OUTPUT;
case EvqFragmentIn: return sw::Shader::PARAMETER_INPUT;
case EvqInvariantVaryingIn: return sw::Shader::PARAMETER_INPUT; // FIXME: Guarantee invariance at the backend
case EvqInvariantVaryingOut: return sw::Shader::PARAMETER_OUTPUT; // FIXME: Guarantee invariance at the backend
case EvqUniform: return sw::Shader::PARAMETER_CONST;
......@@ -1893,6 +1897,10 @@ namespace glsl
case EvqAttribute: return attributeRegister(operand);
case EvqVaryingIn: return varyingRegister(operand);
case EvqVaryingOut: return varyingRegister(operand);
case EvqVertexIn: return attributeRegister(operand);
case EvqFragmentOut: return 0;
case EvqVertexOut: return varyingRegister(operand);
case EvqFragmentIn: return varyingRegister(operand);
case EvqInvariantVaryingIn: return varyingRegister(operand);
case EvqInvariantVaryingOut: return varyingRegister(operand);
case EvqUniform: return uniformRegister(operand);
......
......@@ -314,6 +314,8 @@ bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* nod
case EvqConstExpr: message = "can't modify a const"; break;
case EvqConstReadOnly: message = "can't modify a const"; break;
case EvqAttribute: message = "can't modify an attribute"; break;
case EvqFragmentIn: message = "can't modify an input"; break;
case EvqVertexIn: message = "can't modify an input"; break;
case EvqUniform: message = "can't modify a uniform"; break;
case EvqSmoothIn:
case EvqFlatIn:
......@@ -624,6 +626,8 @@ bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType
case EvqFlatIn:
case EvqCentroidIn:
case EvqAttribute:
case EvqVertexIn:
case EvqFragmentOut:
if(pType.type == EbtStruct)
{
error(line, "cannot be used with a structure", getQualifierString(pType.qualifier));
......@@ -638,9 +642,29 @@ bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType
if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform"))
return true;
// check for layout qualifier issues
const TLayoutQualifier layoutQualifier = pType.layoutQualifier;
if (pType.qualifier != EvqVertexIn && pType.qualifier != EvqFragmentOut &&
layoutLocationErrorCheck(line, pType.layoutQualifier))
{
return true;
}
return false;
}
bool TParseContext::layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier)
{
if(layoutQualifier.location != -1)
{
error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
return true;
}
return false;
}
bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type)
{
if ((qualifier == EvqOut || qualifier == EvqInOut) &&
......@@ -717,7 +741,7 @@ bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size)
//
bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type)
{
if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqConstExpr)) {
if ((type.qualifier == EvqAttribute) || (type.qualifier == EvqVertexIn) || (type.qualifier == EvqConstExpr)) {
error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str());
return true;
}
......@@ -1122,6 +1146,75 @@ bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode)
return allConstant;
}
TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier)
{
TPublicType returnType = typeSpecifier;
returnType.qualifier = qualifier;
returnType.invariant = invariant;
returnType.layoutQualifier = layoutQualifier;
if(typeSpecifier.array)
{
error(typeSpecifier.line, "not supported", "first-class array");
recover();
returnType.clearArrayness();
}
if(shaderVersion < 300)
{
if(qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
recover();
}
if((qualifier == EvqVaryingIn || qualifier == EvqVaryingOut) &&
(typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
{
error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
recover();
}
}
else
{
switch(qualifier)
{
case EvqSmoothIn:
case EvqSmoothOut:
case EvqVertexOut:
case EvqFragmentIn:
case EvqCentroidOut:
case EvqCentroidIn:
if(typeSpecifier.type == EbtBool)
{
error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
recover();
}
if(typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
{
error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
recover();
}
break;
case EvqVertexIn:
case EvqFragmentOut:
case EvqFlatIn:
case EvqFlatOut:
if(typeSpecifier.type == EbtBool)
{
error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
recover();
}
break;
default: break;
}
}
return returnType;
}
// This function is used to test for the correctness of the parameters passed to various constructor functions
// and also convert them to the right datatype if it is allowed and required.
//
......@@ -1406,7 +1499,7 @@ TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpo
{
TQualifier mergedQualifier = EvqSmoothIn;
if(storageQualifier == EvqVaryingIn) {
if(storageQualifier == EvqFragmentIn) {
if(interpolationQualifier == EvqSmooth)
mergedQualifier = EvqSmoothIn;
else if(interpolationQualifier == EvqFlat)
......@@ -1420,7 +1513,7 @@ TPublicType TParseContext::joinInterpolationQualifiers(const TSourceLoc &interpo
mergedQualifier = EvqFlatIn;
else UNREACHABLE();
}
else if(storageQualifier == EvqVaryingOut) {
else if(storageQualifier == EvqVertexOut) {
if(interpolationQualifier == EvqSmooth)
mergedQualifier = EvqSmoothOut;
else if(interpolationQualifier == EvqFlat)
......
......@@ -102,6 +102,7 @@ struct TParseContext {
bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type, TVariable*& variable);
bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
bool extensionErrorCheck(int line, const TString&);
bool layoutLocationErrorCheck(const TSourceLoc &location, const TLayoutQualifier &layoutQualifier);
const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
bool supportsExtension(const char* extension);
......@@ -115,6 +116,8 @@ struct TParseContext {
const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0);
bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType,
TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0);
TPublicType addFullySpecifiedType(TQualifier qualifier, bool invariant, TLayoutQualifier layoutQualifier, const TPublicType &typeSpecifier);
bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc);
......
......@@ -275,6 +275,7 @@ struct TPublicType
TBasicType type;
TLayoutQualifier layoutQualifier;
TQualifier qualifier;
bool invariant;
TPrecision precision;
int primarySize; // size of vector or matrix, not size of array
int secondarySize; // 1 for scalars/vectors, >1 for matrices
......@@ -288,6 +289,7 @@ struct TPublicType
type = bt;
layoutQualifier = TLayoutQualifier::create();
qualifier = q;
invariant = false;
precision = EbpUndefined;
primarySize = 1;
secondarySize = 1;
......@@ -315,6 +317,12 @@ struct TPublicType
arraySize = s;
}
void clearArrayness()
{
array = false;
arraySize = 0;
}
bool isStructureContainingArrays() const
{
if (!userDef)
......
......@@ -1573,30 +1573,14 @@ fully_specified_type
$$ = $1;
if ($1.array) {
context->error($1.line, "not supported", "first-class array");
context->recover();
$1.setArray(false);
ES3_ONLY("[]", $1.line);
if (context->getShaderVersion() != 300) {
$1.clearArrayness();
}
}
}
| type_qualifier type_specifier {
if ($2.array) {
context->error($2.line, "not supported", "first-class array");
context->recover();
$2.setArray(false);
}
if ($1.qualifier == EvqAttribute &&
($2.type == EbtBool || $2.type == EbtInt)) {
context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier));
context->recover();
}
if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) &&
($2.type == EbtBool || $2.type == EbtInt)) {
context->error($2.line, "cannot be bool or int", getQualifierString($1.qualifier));
context->recover();
}
$$ = $2;
$$.qualifier = $1.qualifier;
$$ = context->addFullySpecifiedType($1.qualifier, $1.invariant, $1.layoutQualifier, $2);
}
;
......@@ -1671,24 +1655,32 @@ storage_qualifier
}
| IN_QUAL {
ES3_ONLY("in", $1.line);
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqVaryingIn : EvqAttribute;
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
$$.line = $1.line;
}
| OUT_QUAL {
ES3_ONLY("out", $1.line);
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragColor : EvqVaryingOut;
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
$$.line = $1.line;
}
| CENTROID IN_QUAL {
ES3_ONLY("in", $1.line);
// FIXME: Handle centroid qualifier
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqVaryingIn : EvqAttribute;
ES3_ONLY("centroid in", $1.line);
if (context->shaderType == GL_VERTEX_SHADER)
{
context->error($1.line, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
context->recover();
}
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
$$.line = $2.line;
}
| CENTROID OUT_QUAL {
ES3_ONLY("out", $1.line);
// FIXME: Handle centroid qualifier
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragColor : EvqVaryingOut;
ES3_ONLY("centroid out", $1.line);
if (context->shaderType == GL_FRAGMENT_SHADER)
{
context->error($1.line, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
context->recover();
}
$$.qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
$$.line = $2.line;
}
| UNIFORM {
......
......@@ -741,21 +741,21 @@ static const yytype_uint16 yyrline[] =
1051, 1053, 1058, 1061, 1072, 1080, 1107, 1112, 1122, 1160,
1163, 1170, 1178, 1199, 1220, 1231, 1260, 1265, 1275, 1280,
1290, 1293, 1296, 1299, 1305, 1312, 1315, 1337, 1355, 1379,
1402, 1406, 1424, 1432, 1464, 1484, 1572, 1581, 1604, 1607,
1613, 1619, 1626, 1635, 1644, 1647, 1650, 1657, 1661, 1668,
1672, 1677, 1682, 1688, 1694, 1703, 1713, 1720, 1723, 1726,
1732, 1739, 1742, 1748, 1751, 1754, 1760, 1763, 1778, 1782,
1786, 1790, 1794, 1798, 1803, 1808, 1813, 1818, 1823, 1828,
1833, 1838, 1843, 1848, 1853, 1858, 1864, 1870, 1876, 1882,
1888, 1894, 1900, 1906, 1912, 1917, 1922, 1931, 1936, 1941,
1946, 1951, 1956, 1961, 1966, 1971, 1976, 1981, 1986, 1991,
1996, 2001, 2014, 2014, 2028, 2028, 2037, 2040, 2055, 2087,
2091, 2097, 2105, 2121, 2125, 2129, 2130, 2136, 2137, 2138,
2139, 2140, 2144, 2145, 2145, 2145, 2155, 2156, 2160, 2160,
2161, 2161, 2166, 2169, 2179, 2182, 2188, 2189, 2193, 2201,
2205, 2215, 2220, 2237, 2237, 2242, 2242, 2249, 2249, 2257,
2260, 2266, 2269, 2275, 2279, 2286, 2293, 2300, 2307, 2318,
2327, 2331, 2338, 2341, 2347, 2347
1402, 1406, 1424, 1432, 1464, 1484, 1572, 1582, 1588, 1591,
1597, 1603, 1610, 1619, 1628, 1631, 1634, 1641, 1645, 1652,
1656, 1661, 1666, 1676, 1686, 1695, 1705, 1712, 1715, 1718,
1724, 1731, 1734, 1740, 1743, 1746, 1752, 1755, 1770, 1774,
1778, 1782, 1786, 1790, 1795, 1800, 1805, 1810, 1815, 1820,
1825, 1830, 1835, 1840, 1845, 1850, 1856, 1862, 1868, 1874,
1880, 1886, 1892, 1898, 1904, 1909, 1914, 1923, 1928, 1933,
1938, 1943, 1948, 1953, 1958, 1963, 1968, 1973, 1978, 1983,
1988, 1993, 2006, 2006, 2020, 2020, 2029, 2032, 2047, 2079,
2083, 2089, 2097, 2113, 2117, 2121, 2122, 2128, 2129, 2130,
2131, 2132, 2136, 2137, 2137, 2137, 2147, 2148, 2152, 2152,
2153, 2153, 2158, 2161, 2171, 2174, 2180, 2181, 2185, 2193,
2197, 2207, 2212, 2229, 2229, 2234, 2234, 2241, 2241, 2249,
2252, 2258, 2261, 2267, 2271, 2278, 2285, 2292, 2299, 2310,
2319, 2323, 2330, 2333, 2339, 2339
};
#endif
......@@ -3940,9 +3940,10 @@ yyreduce:
(yyval.interm.type) = (yyvsp[(1) - (1)].interm.type);
if ((yyvsp[(1) - (1)].interm.type).array) {
context->error((yyvsp[(1) - (1)].interm.type).line, "not supported", "first-class array");
context->recover();
(yyvsp[(1) - (1)].interm.type).setArray(false);
ES3_ONLY("[]", (yyvsp[(1) - (1)].interm.type).line);
if (context->getShaderVersion() != 300) {
(yyvsp[(1) - (1)].interm.type).clearArrayness();
}
}
}
break;
......@@ -3950,24 +3951,7 @@ yyreduce:
case 117:
{
if ((yyvsp[(2) - (2)].interm.type).array) {
context->error((yyvsp[(2) - (2)].interm.type).line, "not supported", "first-class array");
context->recover();
(yyvsp[(2) - (2)].interm.type).setArray(false);
}
if ((yyvsp[(1) - (2)].interm.type).qualifier == EvqAttribute &&
((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier));
context->recover();
}
if (((yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingIn || (yyvsp[(1) - (2)].interm.type).qualifier == EvqVaryingOut) &&
((yyvsp[(2) - (2)].interm.type).type == EbtBool || (yyvsp[(2) - (2)].interm.type).type == EbtInt)) {
context->error((yyvsp[(2) - (2)].interm.type).line, "cannot be bool or int", getQualifierString((yyvsp[(1) - (2)].interm.type).qualifier));
context->recover();
}
(yyval.interm.type) = (yyvsp[(2) - (2)].interm.type);
(yyval.interm.type).qualifier = (yyvsp[(1) - (2)].interm.type).qualifier;
(yyval.interm.type) = context->addFullySpecifiedType((yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(1) - (2)].interm.type).invariant, (yyvsp[(1) - (2)].interm.type).layoutQualifier, (yyvsp[(2) - (2)].interm.type));
}
break;
......@@ -4082,7 +4066,7 @@ yyreduce:
{
ES3_ONLY("in", (yyvsp[(1) - (1)].lex).line);
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqVaryingIn : EvqAttribute;
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentIn : EvqVertexIn;
(yyval.interm.type).line = (yyvsp[(1) - (1)].lex).line;
}
break;
......@@ -4091,7 +4075,7 @@ yyreduce:
{
ES3_ONLY("out", (yyvsp[(1) - (1)].lex).line);
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragColor : EvqVaryingOut;
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqVertexOut;
(yyval.interm.type).line = (yyvsp[(1) - (1)].lex).line;
}
break;
......@@ -4099,9 +4083,13 @@ yyreduce:
case 132:
{
ES3_ONLY("in", (yyvsp[(1) - (2)].lex).line);
// FIXME: Handle centroid qualifier
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqVaryingIn : EvqAttribute;
ES3_ONLY("centroid in", (yyvsp[(1) - (2)].lex).line);
if (context->shaderType == GL_VERTEX_SHADER)
{
context->error((yyvsp[(1) - (2)].lex).line, "invalid storage qualifier", "it is an error to use 'centroid in' in the vertex shader");
context->recover();
}
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqCentroidIn : EvqVertexIn;
(yyval.interm.type).line = (yyvsp[(2) - (2)].lex).line;
}
break;
......@@ -4109,9 +4097,13 @@ yyreduce:
case 133:
{
ES3_ONLY("out", (yyvsp[(1) - (2)].lex).line);
// FIXME: Handle centroid qualifier
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragColor : EvqVaryingOut;
ES3_ONLY("centroid out", (yyvsp[(1) - (2)].lex).line);
if (context->shaderType == GL_FRAGMENT_SHADER)
{
context->error((yyvsp[(1) - (2)].lex).line, "invalid storage qualifier", "it is an error to use 'centroid out' in the fragment shader");
context->recover();
}
(yyval.interm.type).qualifier = (context->shaderType == GL_FRAGMENT_SHADER) ? EvqFragmentOut : EvqCentroidOut;
(yyval.interm.type).line = (yyvsp[(2) - (2)].lex).line;
}
break;
......
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