summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp625
1 files changed, 625 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp
new file mode 100644
index 0000000000..85d87e2be4
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/ShaderVars.cpp
@@ -0,0 +1,625 @@
+//
+// Copyright 2014 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.
+//
+// ShaderVars.cpp:
+// Methods for GL variable types (varyings, uniforms, etc)
+//
+
+#include <GLSLANG/ShaderLang.h>
+
+#include "common/debug.h"
+#include "common/utilities.h"
+
+namespace sh
+{
+
+namespace
+{
+
+InterpolationType GetNonAuxiliaryInterpolationType(InterpolationType interpolation)
+{
+ return (interpolation == INTERPOLATION_CENTROID ? INTERPOLATION_SMOOTH : interpolation);
+}
+} // namespace
+// The ES 3.0 spec is not clear on this point, but the ES 3.1 spec, and discussion
+// on Khronos.org, clarifies that a smooth/flat mismatch produces a link error,
+// but auxiliary qualifier mismatch (centroid) does not.
+bool InterpolationTypesMatch(InterpolationType a, InterpolationType b)
+{
+ return (GetNonAuxiliaryInterpolationType(a) == GetNonAuxiliaryInterpolationType(b));
+}
+
+ShaderVariable::ShaderVariable() : ShaderVariable(GL_NONE) {}
+
+ShaderVariable::ShaderVariable(GLenum typeIn)
+ : type(typeIn),
+ precision(0),
+ staticUse(false),
+ active(false),
+ isRowMajorLayout(false),
+ location(-1),
+ hasImplicitLocation(false),
+ binding(-1),
+ imageUnitFormat(GL_NONE),
+ offset(-1),
+ rasterOrdered(false),
+ readonly(false),
+ writeonly(false),
+ isFragmentInOut(false),
+ index(-1),
+ yuv(false),
+ interpolation(INTERPOLATION_SMOOTH),
+ isInvariant(false),
+ isShaderIOBlock(false),
+ isPatch(false),
+ texelFetchStaticUse(false),
+ flattenedOffsetInParentArrays(-1)
+{}
+
+ShaderVariable::ShaderVariable(GLenum typeIn, unsigned int arraySizeIn) : ShaderVariable(typeIn)
+{
+ ASSERT(arraySizeIn != 0);
+ arraySizes.push_back(arraySizeIn);
+}
+
+ShaderVariable::~ShaderVariable() {}
+
+ShaderVariable::ShaderVariable(const ShaderVariable &other)
+ : type(other.type),
+ precision(other.precision),
+ name(other.name),
+ mappedName(other.mappedName),
+ arraySizes(other.arraySizes),
+ staticUse(other.staticUse),
+ active(other.active),
+ fields(other.fields),
+ structOrBlockName(other.structOrBlockName),
+ mappedStructOrBlockName(other.mappedStructOrBlockName),
+ isRowMajorLayout(other.isRowMajorLayout),
+ location(other.location),
+ hasImplicitLocation(other.hasImplicitLocation),
+ binding(other.binding),
+ imageUnitFormat(other.imageUnitFormat),
+ offset(other.offset),
+ rasterOrdered(other.rasterOrdered),
+ readonly(other.readonly),
+ writeonly(other.writeonly),
+ isFragmentInOut(other.isFragmentInOut),
+ index(other.index),
+ yuv(other.yuv),
+ interpolation(other.interpolation),
+ isInvariant(other.isInvariant),
+ isShaderIOBlock(other.isShaderIOBlock),
+ isPatch(other.isPatch),
+ texelFetchStaticUse(other.texelFetchStaticUse),
+ flattenedOffsetInParentArrays(other.flattenedOffsetInParentArrays)
+{}
+
+ShaderVariable &ShaderVariable::operator=(const ShaderVariable &other)
+{
+ type = other.type;
+ precision = other.precision;
+ name = other.name;
+ mappedName = other.mappedName;
+ arraySizes = other.arraySizes;
+ staticUse = other.staticUse;
+ active = other.active;
+ fields = other.fields;
+ structOrBlockName = other.structOrBlockName;
+ mappedStructOrBlockName = other.mappedStructOrBlockName;
+ isRowMajorLayout = other.isRowMajorLayout;
+ flattenedOffsetInParentArrays = other.flattenedOffsetInParentArrays;
+ location = other.location;
+ hasImplicitLocation = other.hasImplicitLocation;
+ binding = other.binding;
+ imageUnitFormat = other.imageUnitFormat;
+ offset = other.offset;
+ rasterOrdered = other.rasterOrdered;
+ readonly = other.readonly;
+ writeonly = other.writeonly;
+ isFragmentInOut = other.isFragmentInOut;
+ index = other.index;
+ yuv = other.yuv;
+ interpolation = other.interpolation;
+ isInvariant = other.isInvariant;
+ isShaderIOBlock = other.isShaderIOBlock;
+ isPatch = other.isPatch;
+ texelFetchStaticUse = other.texelFetchStaticUse;
+ return *this;
+}
+
+bool ShaderVariable::operator==(const ShaderVariable &other) const
+{
+ if (type != other.type || precision != other.precision || name != other.name ||
+ mappedName != other.mappedName || arraySizes != other.arraySizes ||
+ staticUse != other.staticUse || active != other.active ||
+ fields.size() != other.fields.size() || structOrBlockName != other.structOrBlockName ||
+ mappedStructOrBlockName != other.mappedStructOrBlockName ||
+ isRowMajorLayout != other.isRowMajorLayout || location != other.location ||
+ hasImplicitLocation != other.hasImplicitLocation || binding != other.binding ||
+ imageUnitFormat != other.imageUnitFormat || offset != other.offset ||
+ rasterOrdered != other.rasterOrdered || readonly != other.readonly ||
+ writeonly != other.writeonly || index != other.index || yuv != other.yuv ||
+ interpolation != other.interpolation || isInvariant != other.isInvariant ||
+ isShaderIOBlock != other.isShaderIOBlock || isPatch != other.isPatch ||
+ texelFetchStaticUse != other.texelFetchStaticUse ||
+ isFragmentInOut != other.isFragmentInOut)
+ {
+ return false;
+ }
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (fields[ii] != other.fields[ii])
+ return false;
+ }
+ return true;
+}
+
+void ShaderVariable::setArraySize(unsigned int size)
+{
+ arraySizes.clear();
+ if (size != 0)
+ {
+ arraySizes.push_back(size);
+ }
+}
+
+unsigned int ShaderVariable::getInnerArraySizeProduct() const
+{
+ return gl::InnerArraySizeProduct(arraySizes);
+}
+
+unsigned int ShaderVariable::getArraySizeProduct() const
+{
+ return gl::ArraySizeProduct(arraySizes);
+}
+
+void ShaderVariable::indexIntoArray(unsigned int arrayIndex)
+{
+ ASSERT(isArray());
+ flattenedOffsetInParentArrays = arrayIndex + getOutermostArraySize() * parentArrayIndex();
+ arraySizes.pop_back();
+}
+
+unsigned int ShaderVariable::getNestedArraySize(unsigned int arrayNestingIndex) const
+{
+ ASSERT(arraySizes.size() > arrayNestingIndex);
+ unsigned int arraySize = arraySizes[arraySizes.size() - 1u - arrayNestingIndex];
+
+ if (arraySize == 0)
+ {
+ // Unsized array, so give it at least 1 entry
+ arraySize = 1;
+ }
+
+ return arraySize;
+}
+
+unsigned int ShaderVariable::getBasicTypeElementCount() const
+{
+ // GLES 3.1 Nov 2016 section 7.3.1.1 page 77 specifies that a separate entry should be generated
+ // for each array element when dealing with an array of arrays or an array of structs.
+ ASSERT(!isArrayOfArrays());
+ ASSERT(!isStruct() || !isArray());
+
+ // GLES 3.1 Nov 2016 page 82.
+ if (isArray())
+ {
+ return getOutermostArraySize();
+ }
+ return 1u;
+}
+
+unsigned int ShaderVariable::getExternalSize() const
+{
+ unsigned int memorySize = 0;
+
+ if (isStruct())
+ {
+ // Have a structure, need to compute the structure size.
+ for (const auto &field : fields)
+ {
+ memorySize += field.getExternalSize();
+ }
+ }
+ else
+ {
+ memorySize += gl::VariableExternalSize(type);
+ }
+
+ // multiply by array size to get total memory size of this variable / struct.
+ memorySize *= getArraySizeProduct();
+
+ return memorySize;
+}
+
+bool ShaderVariable::findInfoByMappedName(const std::string &mappedFullName,
+ const ShaderVariable **leafVar,
+ std::string *originalFullName) const
+{
+ ASSERT(leafVar && originalFullName);
+ // There are three cases:
+ // 1) the top variable is of struct type;
+ // 2) the top variable is an array;
+ // 3) otherwise.
+ size_t pos = mappedFullName.find_first_of(".[");
+
+ if (pos == std::string::npos)
+ {
+ // Case 3.
+ if (mappedFullName != this->mappedName)
+ return false;
+ *originalFullName = this->name;
+ *leafVar = this;
+ return true;
+ }
+ else
+ {
+ std::string topName = mappedFullName.substr(0, pos);
+ if (topName != this->mappedName)
+ return false;
+ std::string originalName = this->name;
+ std::string remaining;
+ if (mappedFullName[pos] == '[')
+ {
+ // Case 2.
+ size_t closePos = mappedFullName.find_first_of(']');
+ if (closePos < pos || closePos == std::string::npos)
+ return false;
+ // Append '[index]'.
+ originalName += mappedFullName.substr(pos, closePos - pos + 1);
+ if (closePos + 1 == mappedFullName.size())
+ {
+ *originalFullName = originalName;
+ *leafVar = this;
+ return true;
+ }
+ else
+ {
+ // In the form of 'a[0].b', so after ']', '.' is expected.
+ if (mappedFullName[closePos + 1] != '.')
+ return false;
+ remaining = mappedFullName.substr(closePos + 2); // Skip "]."
+ }
+ }
+ else
+ {
+ // Case 1.
+ remaining = mappedFullName.substr(pos + 1); // Skip "."
+ }
+ for (size_t ii = 0; ii < this->fields.size(); ++ii)
+ {
+ const ShaderVariable *fieldVar = nullptr;
+ std::string originalFieldName;
+ bool found = fields[ii].findInfoByMappedName(remaining, &fieldVar, &originalFieldName);
+ if (found)
+ {
+ *originalFullName = originalName + "." + originalFieldName;
+ *leafVar = fieldVar;
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+const sh::ShaderVariable *ShaderVariable::findField(const std::string &fullName,
+ uint32_t *fieldIndexOut) const
+{
+ if (fields.empty())
+ {
+ return nullptr;
+ }
+ size_t pos = fullName.find_first_of(".");
+ std::string topName, fieldName;
+ if (pos == std::string::npos)
+ {
+ // If this is a shader I/O block without an instance name, return the field given only the
+ // field name.
+ if (!isShaderIOBlock || !name.empty())
+ {
+ return nullptr;
+ }
+
+ fieldName = fullName;
+ }
+ else
+ {
+ std::string baseName = isShaderIOBlock ? structOrBlockName : name;
+ topName = fullName.substr(0, pos);
+ if (topName != baseName)
+ {
+ return nullptr;
+ }
+ fieldName = fullName.substr(pos + 1);
+ }
+ if (fieldName.empty())
+ {
+ return nullptr;
+ }
+ for (size_t field = 0; field < fields.size(); ++field)
+ {
+ if (fields[field].name == fieldName)
+ {
+ *fieldIndexOut = static_cast<GLuint>(field);
+ return &fields[field];
+ }
+ }
+ return nullptr;
+}
+
+bool ShaderVariable::isBuiltIn() const
+{
+ return gl::IsBuiltInName(name);
+}
+
+bool ShaderVariable::isEmulatedBuiltIn() const
+{
+ return isBuiltIn() && name != mappedName;
+}
+
+bool ShaderVariable::isSameVariableAtLinkTime(const ShaderVariable &other,
+ bool matchPrecision,
+ bool matchName) const
+{
+ if (type != other.type)
+ return false;
+ if (matchPrecision && precision != other.precision)
+ return false;
+ if (matchName && name != other.name)
+ return false;
+ ASSERT(!matchName || mappedName == other.mappedName);
+ if (arraySizes != other.arraySizes)
+ return false;
+ if (isRowMajorLayout != other.isRowMajorLayout)
+ return false;
+ if (fields.size() != other.fields.size())
+ return false;
+
+ // [OpenGL ES 3.1 SPEC Chapter 7.4.1]
+ // Variables declared as structures are considered to match in type if and only if structure
+ // members match in name, type, qualification, and declaration order.
+ for (size_t ii = 0; ii < fields.size(); ++ii)
+ {
+ if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii], matchPrecision, true))
+ {
+ return false;
+ }
+ }
+ if (structOrBlockName != other.structOrBlockName ||
+ mappedStructOrBlockName != other.mappedStructOrBlockName)
+ return false;
+ return true;
+}
+
+void ShaderVariable::updateEffectiveLocation(const sh::ShaderVariable &parent)
+{
+ if ((location < 0 || hasImplicitLocation) && !parent.hasImplicitLocation)
+ {
+ location = parent.location;
+ }
+}
+
+void ShaderVariable::resetEffectiveLocation()
+{
+ if (hasImplicitLocation)
+ {
+ location = -1;
+ }
+}
+
+bool ShaderVariable::isSameUniformAtLinkTime(const ShaderVariable &other) const
+{
+ // Enforce a consistent match.
+ // https://cvs.khronos.org/bugzilla/show_bug.cgi?id=16261
+ if (binding != -1 && other.binding != -1 && binding != other.binding)
+ {
+ return false;
+ }
+ if (imageUnitFormat != other.imageUnitFormat)
+ {
+ return false;
+ }
+ if (location != -1 && other.location != -1 && location != other.location)
+ {
+ return false;
+ }
+ if (offset != other.offset)
+ {
+ return false;
+ }
+ if (rasterOrdered != other.rasterOrdered)
+ {
+ return false;
+ }
+ if (readonly != other.readonly || writeonly != other.writeonly)
+ {
+ return false;
+ }
+ return ShaderVariable::isSameVariableAtLinkTime(other, true, true);
+}
+
+bool ShaderVariable::isSameInterfaceBlockFieldAtLinkTime(const ShaderVariable &other) const
+{
+ return (ShaderVariable::isSameVariableAtLinkTime(other, true, true));
+}
+
+bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other) const
+{
+ return isSameVaryingAtLinkTime(other, 100);
+}
+
+bool ShaderVariable::isSameVaryingAtLinkTime(const ShaderVariable &other, int shaderVersion) const
+{
+ return ShaderVariable::isSameVariableAtLinkTime(other, false, false) &&
+ InterpolationTypesMatch(interpolation, other.interpolation) &&
+ (shaderVersion >= 300 || isInvariant == other.isInvariant) &&
+ (isPatch == other.isPatch) && location == other.location &&
+ (isSameNameAtLinkTime(other) || (shaderVersion >= 310 && location >= 0));
+}
+
+bool ShaderVariable::isSameNameAtLinkTime(const ShaderVariable &other) const
+{
+ if (isShaderIOBlock != other.isShaderIOBlock)
+ {
+ return false;
+ }
+
+ if (isShaderIOBlock)
+ {
+ // Shader I/O blocks match by block name.
+ return structOrBlockName == other.structOrBlockName;
+ }
+
+ // Otherwise match by name.
+ return name == other.name;
+}
+
+InterfaceBlock::InterfaceBlock()
+ : arraySize(0),
+ layout(BLOCKLAYOUT_PACKED),
+ isRowMajorLayout(false),
+ binding(-1),
+ staticUse(false),
+ active(false),
+ blockType(BlockType::BLOCK_UNIFORM)
+{}
+
+InterfaceBlock::~InterfaceBlock() {}
+
+InterfaceBlock::InterfaceBlock(const InterfaceBlock &other)
+ : name(other.name),
+ mappedName(other.mappedName),
+ instanceName(other.instanceName),
+ arraySize(other.arraySize),
+ layout(other.layout),
+ isRowMajorLayout(other.isRowMajorLayout),
+ binding(other.binding),
+ staticUse(other.staticUse),
+ active(other.active),
+ blockType(other.blockType),
+ fields(other.fields)
+{}
+
+InterfaceBlock &InterfaceBlock::operator=(const InterfaceBlock &other)
+{
+ name = other.name;
+ mappedName = other.mappedName;
+ instanceName = other.instanceName;
+ arraySize = other.arraySize;
+ layout = other.layout;
+ isRowMajorLayout = other.isRowMajorLayout;
+ binding = other.binding;
+ staticUse = other.staticUse;
+ active = other.active;
+ blockType = other.blockType;
+ fields = other.fields;
+ return *this;
+}
+
+std::string InterfaceBlock::fieldPrefix() const
+{
+ return instanceName.empty() ? "" : name;
+}
+
+std::string InterfaceBlock::fieldMappedPrefix() const
+{
+ return instanceName.empty() ? "" : mappedName;
+}
+
+bool InterfaceBlock::isSameInterfaceBlockAtLinkTime(const InterfaceBlock &other) const
+{
+ if (name != other.name || mappedName != other.mappedName || arraySize != other.arraySize ||
+ layout != other.layout || isRowMajorLayout != other.isRowMajorLayout ||
+ binding != other.binding || blockType != other.blockType ||
+ fields.size() != other.fields.size())
+ {
+ return false;
+ }
+
+ for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
+ {
+ if (!fields[fieldIndex].isSameInterfaceBlockFieldAtLinkTime(other.fields[fieldIndex]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool InterfaceBlock::isBuiltIn() const
+{
+ return gl::IsBuiltInName(name);
+}
+
+void WorkGroupSize::fill(int fillValue)
+{
+ localSizeQualifiers[0] = fillValue;
+ localSizeQualifiers[1] = fillValue;
+ localSizeQualifiers[2] = fillValue;
+}
+
+void WorkGroupSize::setLocalSize(int localSizeX, int localSizeY, int localSizeZ)
+{
+ localSizeQualifiers[0] = localSizeX;
+ localSizeQualifiers[1] = localSizeY;
+ localSizeQualifiers[2] = localSizeZ;
+}
+
+// check that if one of them is less than 1, then all of them are.
+// Or if one is positive, then all of them are positive.
+bool WorkGroupSize::isLocalSizeValid() const
+{
+ return (
+ (localSizeQualifiers[0] < 1 && localSizeQualifiers[1] < 1 && localSizeQualifiers[2] < 1) ||
+ (localSizeQualifiers[0] > 0 && localSizeQualifiers[1] > 0 && localSizeQualifiers[2] > 0));
+}
+
+bool WorkGroupSize::isAnyValueSet() const
+{
+ return localSizeQualifiers[0] > 0 || localSizeQualifiers[1] > 0 || localSizeQualifiers[2] > 0;
+}
+
+bool WorkGroupSize::isDeclared() const
+{
+ bool localSizeDeclared = localSizeQualifiers[0] > 0;
+ ASSERT(isLocalSizeValid());
+ return localSizeDeclared;
+}
+
+bool WorkGroupSize::isWorkGroupSizeMatching(const WorkGroupSize &right) const
+{
+ for (size_t i = 0u; i < size(); ++i)
+ {
+ bool result = (localSizeQualifiers[i] == right.localSizeQualifiers[i] ||
+ (localSizeQualifiers[i] == 1 && right.localSizeQualifiers[i] == -1) ||
+ (localSizeQualifiers[i] == -1 && right.localSizeQualifiers[i] == 1));
+ if (!result)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+int &WorkGroupSize::operator[](size_t index)
+{
+ ASSERT(index < size());
+ return localSizeQualifiers[index];
+}
+
+int WorkGroupSize::operator[](size_t index) const
+{
+ ASSERT(index < size());
+ return localSizeQualifiers[index];
+}
+
+size_t WorkGroupSize::size() const
+{
+ return 3u;
+}
+
+} // namespace sh