blob: 54a1a2cefc13a66441da320e9af60cfd6ef6c544 [file] [log] [blame]
//
// Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#include "compiler/translator/util.h"
#include <limits>
#include "compiler/preprocessor/numeric_lex.h"
#include "compiler/translator/SymbolTable.h"
#include "common/utilities.h"
bool strtof_clamp(const std::string &str, float *value)
{
bool success = pp::numeric_lex_float(str, value);
if (!success)
*value = std::numeric_limits<float>::max();
return success;
}
bool atoi_clamp(const char *str, unsigned int *value)
{
bool success = pp::numeric_lex_int(str, value);
if (!success)
*value = std::numeric_limits<unsigned int>::max();
return success;
}
namespace sh
{
GLenum GLVariableType(const TType &type)
{
if (type.getBasicType() == 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();
}
}
else if (type.isMatrix())
{
switch (type.getCols())
{
case 2:
switch (type.getRows())
{
case 2: return GL_FLOAT_MAT2;
case 3: return GL_FLOAT_MAT2x3;
case 4: return GL_FLOAT_MAT2x4;
default: UNREACHABLE();
}
case 3:
switch (type.getRows())
{
case 2: return GL_FLOAT_MAT3x2;
case 3: return GL_FLOAT_MAT3;
case 4: return GL_FLOAT_MAT3x4;
default: UNREACHABLE();
}
case 4:
switch (type.getRows())
{
case 2: return GL_FLOAT_MAT4x2;
case 3: return GL_FLOAT_MAT4x3;
case 4: return GL_FLOAT_MAT4;
default: UNREACHABLE();
}
default: UNREACHABLE();
}
}
else UNREACHABLE();
}
else if (type.getBasicType() == 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();
}
}
else UNREACHABLE();
}
else if (type.getBasicType() == 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();
}
}
else UNREACHABLE();
}
else if (type.getBasicType() == 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();
}
}
else UNREACHABLE();
}
switch (type.getBasicType())
{
case EbtSampler2D: return GL_SAMPLER_2D;
case EbtSampler3D: return GL_SAMPLER_3D;
case EbtSamplerCube: return GL_SAMPLER_CUBE;
case EbtSamplerExternalOES: return GL_SAMPLER_EXTERNAL_OES;
case EbtSampler2DRect: return GL_SAMPLER_2D_RECT_ARB;
case EbtSampler2DArray: return GL_SAMPLER_2D_ARRAY;
case EbtISampler2D: return GL_INT_SAMPLER_2D;
case EbtISampler3D: return GL_INT_SAMPLER_3D;
case EbtISamplerCube: return GL_INT_SAMPLER_CUBE;
case EbtISampler2DArray: return GL_INT_SAMPLER_2D_ARRAY;
case EbtUSampler2D: return GL_UNSIGNED_INT_SAMPLER_2D;
case EbtUSampler3D: return GL_UNSIGNED_INT_SAMPLER_3D;
case EbtUSamplerCube: return GL_UNSIGNED_INT_SAMPLER_CUBE;
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;
case EbtImage2D:
return GL_IMAGE_2D;
case EbtIImage2D:
return GL_INT_IMAGE_2D;
case EbtUImage2D:
return GL_UNSIGNED_INT_IMAGE_2D;
case EbtImage2DArray:
return GL_IMAGE_2D_ARRAY;
case EbtIImage2DArray:
return GL_INT_IMAGE_2D_ARRAY;
case EbtUImage2DArray:
return GL_UNSIGNED_INT_IMAGE_2D_ARRAY;
case EbtImage3D:
return GL_IMAGE_3D;
case EbtIImage3D:
return GL_INT_IMAGE_3D;
case EbtUImage3D:
return GL_UNSIGNED_INT_IMAGE_3D;
case EbtImageCube:
return GL_IMAGE_CUBE;
case EbtIImageCube:
return GL_INT_IMAGE_CUBE;
case EbtUImageCube:
return GL_UNSIGNED_INT_IMAGE_CUBE;
default: UNREACHABLE();
}
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();
}
}
else if (type.getBasicType() == EbtInt || type.getBasicType() == EbtUInt)
{
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();
}
}
// Other types (boolean, sampler) don't have a precision
return GL_NONE;
}
TString ArrayString(const TType &type)
{
if (!type.isArray())
{
return "";
}
return "[" + str(type.getArraySize()) + "]";
}
bool IsVaryingOut(TQualifier qualifier)
{
switch (qualifier)
{
case EvqVaryingOut:
case EvqSmoothOut:
case EvqFlatOut:
case EvqCentroidOut:
case EvqVertexOut:
return true;
default: break;
}
return false;
}
bool IsVaryingIn(TQualifier qualifier)
{
switch (qualifier)
{
case EvqVaryingIn:
case EvqSmoothIn:
case EvqFlatIn:
case EvqCentroidIn:
case EvqFragmentIn:
return true;
default: break;
}
return false;
}
bool IsVarying(TQualifier qualifier)
{
return IsVaryingIn(qualifier) || IsVaryingOut(qualifier);
}
InterpolationType GetInterpolationType(TQualifier qualifier)
{
switch (qualifier)
{
case EvqFlatIn:
case EvqFlatOut:
return INTERPOLATION_FLAT;
case EvqSmoothIn:
case EvqSmoothOut:
case EvqVertexOut:
case EvqFragmentIn:
case EvqVaryingIn:
case EvqVaryingOut:
return INTERPOLATION_SMOOTH;
case EvqCentroidIn:
case EvqCentroidOut:
return INTERPOLATION_CENTROID;
default: UNREACHABLE();
return INTERPOLATION_SMOOTH;
}
}
TType GetInterfaceBlockType(const sh::InterfaceBlock &block)
{
TType type;
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (const auto &field : block.fields)
{
TType *fieldType = new TType(GetShaderVariableType(field));
fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
}
TInterfaceBlock *interfaceBlock = new TInterfaceBlock(
new TString(block.name.c_str()), fields, new TString(block.instanceName.c_str()),
block.arraySize, TLayoutQualifier::create());
type.setBasicType(EbtInterfaceBlock);
type.setInterfaceBlock(interfaceBlock);
type.setArraySize(block.arraySize);
return type;
}
TType GetShaderVariableBasicType(const sh::ShaderVariable &var)
{
switch (var.type)
{
case GL_BOOL:
return TType(EbtBool);
case GL_BOOL_VEC2:
return TType(EbtBool, 2);
case GL_BOOL_VEC3:
return TType(EbtBool, 3);
case GL_BOOL_VEC4:
return TType(EbtBool, 4);
case GL_FLOAT:
return TType(EbtFloat);
case GL_FLOAT_VEC2:
return TType(EbtFloat, 2);
case GL_FLOAT_VEC3:
return TType(EbtFloat, 3);
case GL_FLOAT_VEC4:
return TType(EbtFloat, 4);
case GL_FLOAT_MAT2:
return TType(EbtFloat, 2, 2);
case GL_FLOAT_MAT3:
return TType(EbtFloat, 3, 3);
case GL_FLOAT_MAT4:
return TType(EbtFloat, 4, 4);
case GL_FLOAT_MAT2x3:
return TType(EbtFloat, 2, 3);
case GL_FLOAT_MAT2x4:
return TType(EbtFloat, 2, 4);
case GL_FLOAT_MAT3x2:
return TType(EbtFloat, 3, 2);
case GL_FLOAT_MAT3x4:
return TType(EbtFloat, 3, 4);
case GL_FLOAT_MAT4x2:
return TType(EbtFloat, 4, 2);
case GL_FLOAT_MAT4x3:
return TType(EbtFloat, 4, 3);
case GL_INT:
return TType(EbtInt);
case GL_INT_VEC2:
return TType(EbtInt, 2);
case GL_INT_VEC3:
return TType(EbtInt, 3);
case GL_INT_VEC4:
return TType(EbtInt, 4);
case GL_UNSIGNED_INT:
return TType(EbtUInt);
case GL_UNSIGNED_INT_VEC2:
return TType(EbtUInt, 2);
case GL_UNSIGNED_INT_VEC3:
return TType(EbtUInt, 3);
case GL_UNSIGNED_INT_VEC4:
return TType(EbtUInt, 4);
default:
UNREACHABLE();
return TType();
}
}
TType GetShaderVariableType(const sh::ShaderVariable &var)
{
TType type;
if (var.isStruct())
{
TFieldList *fields = new TFieldList;
TSourceLoc loc;
for (const auto &field : var.fields)
{
TType *fieldType = new TType(GetShaderVariableType(field));
fields->push_back(new TField(fieldType, new TString(field.name.c_str()), loc));
}
TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields);
type.setBasicType(EbtStruct);
type.setStruct(structure);
}
else
{
type = GetShaderVariableBasicType(var);
}
if (var.isArray())
{
type.setArraySize(var.elementCount());
}
return type;
}
TOperator TypeToConstructorOperator(const TType &type)
{
switch (type.getBasicType())
{
case EbtFloat:
if (type.isMatrix())
{
switch (type.getCols())
{
case 2:
switch (type.getRows())
{
case 2:
return EOpConstructMat2;
case 3:
return EOpConstructMat2x3;
case 4:
return EOpConstructMat2x4;
default:
break;
}
break;
case 3:
switch (type.getRows())
{
case 2:
return EOpConstructMat3x2;
case 3:
return EOpConstructMat3;
case 4:
return EOpConstructMat3x4;
default:
break;
}
break;
case 4:
switch (type.getRows())
{
case 2:
return EOpConstructMat4x2;
case 3:
return EOpConstructMat4x3;
case 4:
return EOpConstructMat4;
default:
break;
}
break;
}
}
else
{
switch (type.getNominalSize())
{
case 1:
return EOpConstructFloat;
case 2:
return EOpConstructVec2;
case 3:
return EOpConstructVec3;
case 4:
return EOpConstructVec4;
default:
break;
}
}
break;
case EbtInt:
switch (type.getNominalSize())
{
case 1:
return EOpConstructInt;
case 2:
return EOpConstructIVec2;
case 3:
return EOpConstructIVec3;
case 4:
return EOpConstructIVec4;
default:
break;
}
break;
case EbtUInt:
switch (type.getNominalSize())
{
case 1:
return EOpConstructUInt;
case 2:
return EOpConstructUVec2;
case 3:
return EOpConstructUVec3;
case 4:
return EOpConstructUVec4;
default:
break;
}
break;
case EbtBool:
switch (type.getNominalSize())
{
case 1:
return EOpConstructBool;
case 2:
return EOpConstructBVec2;
case 3:
return EOpConstructBVec3;
case 4:
return EOpConstructBVec4;
default:
break;
}
break;
case EbtStruct:
return EOpConstructStruct;
default:
break;
}
return EOpNull;
}
GetVariableTraverser::GetVariableTraverser(const TSymbolTable &symbolTable)
: mSymbolTable(symbolTable)
{
}
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, InterfaceBlockField *variable);
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, ShaderVariable *variable);
template void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, Uniform *variable);
template<>
void GetVariableTraverser::setTypeSpecificInfo(
const TType &type, const TString& name, Varying *variable)
{
ASSERT(variable);
switch (type.getQualifier())
{
case EvqVaryingIn:
case EvqVaryingOut:
case EvqVertexOut:
case EvqSmoothOut:
case EvqFlatOut:
case EvqCentroidOut:
if (mSymbolTable.isVaryingInvariant(std::string(name.c_str())) || type.isInvariant())
{
variable->isInvariant = true;
}
break;
default:
break;
}
variable->interpolation = GetInterpolationType(type.getQualifier());
}
template <typename VarT>
void GetVariableTraverser::traverse(const TType &type,
const TString &name,
std::vector<VarT> *output)
{
const TStructure *structure = type.getStruct();
VarT variable;
variable.name = name.c_str();
variable.arraySize = type.getArraySize();
if (!structure)
{
variable.type = GLVariableType(type);
variable.precision = GLVariablePrecision(type);
}
else
{
// Note: this enum value is not exposed outside ANGLE
variable.type = GL_STRUCT_ANGLEX;
variable.structName = structure->name().c_str();
const TFieldList &fields = structure->fields();
for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
{
TField *field = fields[fieldIndex];
traverse(*field->type(), field->name(), &variable.fields);
}
}
setTypeSpecificInfo(type, name, &variable);
visitVariable(&variable);
ASSERT(output);
output->push_back(variable);
}
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<InterfaceBlockField> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<ShaderVariable> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Uniform> *);
template void GetVariableTraverser::traverse(const TType &, const TString &, std::vector<Varying> *);
// GLSL ES 1.0.17 4.6.1 The Invariant Qualifier
bool CanBeInvariantESSL1(TQualifier qualifier)
{
return IsVaryingIn(qualifier) || IsVaryingOut(qualifier) ||
IsBuiltinOutputVariable(qualifier) ||
(IsBuiltinFragmentInputVariable(qualifier) && qualifier != EvqFrontFacing);
}
// GLSL ES 3.00 Revision 6, 4.6.1 The Invariant Qualifier
// GLSL ES 3.10 Revision 4, 4.8.1 The Invariant Qualifier
bool CanBeInvariantESSL3OrGreater(TQualifier qualifier)
{
return IsVaryingOut(qualifier) || qualifier == EvqFragmentOut ||
IsBuiltinOutputVariable(qualifier);
}
bool IsBuiltinOutputVariable(TQualifier qualifier)
{
switch (qualifier)
{
case EvqPosition:
case EvqPointSize:
case EvqFragDepth:
case EvqFragDepthEXT:
case EvqFragColor:
case EvqSecondaryFragColorEXT:
case EvqFragData:
case EvqSecondaryFragDataEXT:
return true;
default:
break;
}
return false;
}
bool IsBuiltinFragmentInputVariable(TQualifier qualifier)
{
switch (qualifier)
{
case EvqFragCoord:
case EvqPointCoord:
case EvqFrontFacing:
return true;
default:
break;
}
return false;
}
} // namespace sh