void TOutputGLSLBase::writeLayoutQualifier(const TType &type) { if (type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) { const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); if (layoutQualifier.location >= 0) { TInfoSinkBase &out = objSink(); out << "layout(location = " << layoutQualifier.location << ") "; } } }
void TOutputGLSLBase::writeVariableType(const TType& type) { TInfoSinkBase& out = objSink(); TQualifier qualifier = type.getQualifier(); // TODO(alokp): Validate qualifier for variable declarations. if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) out << type.getQualifierString() << " "; // Declare the struct if we have not done so already. if ((type.getBasicType() == EbtStruct) && (mDeclaredStructs.find(type.getTypeName()) == mDeclaredStructs.end())) { out << "struct " << type.getTypeName() << "{\n"; const TTypeList* structure = type.getStruct(); ASSERT(structure != NULL); for (size_t i = 0; i < structure->size(); ++i) { const TType* fieldType = (*structure)[i].type; ASSERT(fieldType != NULL); if (writeVariablePrecision(fieldType->getPrecision())) out << " "; out << getTypeName(*fieldType) << " " << fieldType->getFieldName(); if (fieldType->isArray()) out << arrayBrackets(*fieldType); out << ";\n"; } out << "}"; mDeclaredStructs.insert(type.getTypeName()); } else { if (writeVariablePrecision(type.getPrecision())) out << " "; out << getTypeName(type); } }
void TOutputGLSLBase::writeVariableType(const TType &type) { TInfoSinkBase &out = objSink(); TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { out << type.getQualifierString() << " "; } // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) { TStructure *structure = type.getStruct(); declareStruct(structure); if (!structure->name().empty()) { mDeclaredStructs.insert(structure->uniqueId()); } } else { if (writeVariablePrecision(type.getPrecision())) out << " "; out << getTypeName(type); } }
int resolveInOutLocation(EShLanguage /*stage*/, const char* /*name*/, const TType& type, bool /*is_live*/) override { // kick out of not doing this if (!doAutoLocationMapping) return -1; // no locations added if already present, or a built-in variable if (type.getQualifier().hasLocation() || type.isBuiltIn()) return -1; // no locations on blocks of built-in variables if (type.isStruct()) { if (type.getStruct()->size() < 1) return -1; if ((*type.getStruct())[0].type->isBuiltIn()) return -1; } // Placeholder. // TODO: It would be nice to flesh this out using // intermediate->computeTypeLocationSize(type), or functions that call it like // intermediate->addUsedLocation() // These in turn would want the intermediate, which is not available here, but // is available in many places, and a lot of copying from it could be saved if // it were just available. return 0; }
// Recursively figure out how many locations are used up by an input or output type. // Return the size of type, as measured by "locations". int TIntermediate::computeTypeLocationSize(const TType& type) const { // "If the declared input is an array of size n and each element takes m locations, it will be assigned m * n // consecutive locations..." if (type.isArray()) { // TODO: perf: this can be flattened by using getCumulativeArraySize(), and a deref that discards all arrayness TType elementType(type, 0); if (type.isImplicitlySizedArray()) { // TODO: are there valid cases of having an implicitly-sized array with a location? If so, running this code too early. return computeTypeLocationSize(elementType); } else return type.getOuterArraySize() * computeTypeLocationSize(elementType); } // "The locations consumed by block and structure members are determined by applying the rules above // recursively..." if (type.isStruct()) { int size = 0; for (int member = 0; member < (int)type.getStruct()->size(); ++member) { TType memberType(type, member); size += computeTypeLocationSize(memberType); } return size; } // ES: "If a shader input is any scalar or vector type, it will consume a single location." // Desktop: "If a vertex shader input is any scalar or vector type, it will consume a single location. If a non-vertex // shader input is a scalar or vector type other than dvec3 or dvec4, it will consume a single location, while // types dvec3 or dvec4 will consume two consecutive locations. Inputs of type double and dvec2 will // consume only a single location, in all stages." if (type.isScalar()) return 1; if (type.isVector()) { if (language == EShLangVertex && type.getQualifier().isPipeInput()) return 1; if (type.getBasicType() == EbtDouble && type.getVectorSize() > 2) return 2; else return 1; } // "If the declared input is an n x m single- or double-precision matrix, ... // The number of locations assigned for each matrix will be the same as // for an n-element array of m-component vectors..." if (type.isMatrix()) { TType columnType(type, 0); return type.getMatrixCols() * computeTypeLocationSize(columnType); } assert(0); return 1; }
void TOutputGLSLBase::writeVariableType(const TType &type) { TInfoSinkBase &out = objSink(); if (type.isInvariant()) { out << "invariant "; } TQualifier qualifier = type.getQualifier(); if (qualifier != EvqTemporary && qualifier != EvqGlobal) { if (IsGLSL130OrNewer(mOutput)) { switch (qualifier) { case EvqAttribute: out << "in "; break; case EvqVaryingIn: out << "in "; break; case EvqVaryingOut: out << "out "; break; default: out << type.getQualifierString() << " "; break; } } else { out << type.getQualifierString() << " "; } } // Declare the struct if we have not done so already. if (type.getBasicType() == EbtStruct && !structDeclared(type.getStruct())) { TStructure *structure = type.getStruct(); declareStruct(structure); if (!structure->name().empty()) { mDeclaredStructs.insert(structure->uniqueId()); } } else { if (writeVariablePrecision(type.getPrecision())) out << " "; out << getTypeName(type); } }
// TODO(jmadill): This is not complete. void TOutputVulkanGLSL::writeLayoutQualifier(const TType &type) { TInfoSinkBase &out = objSink(); const TLayoutQualifier &layoutQualifier = type.getLayoutQualifier(); out << "layout("; if (type.getQualifier() == EvqAttribute || type.getQualifier() == EvqFragmentOut || type.getQualifier() == EvqVertexIn) { // TODO(jmadill): Multiple output locations. out << "location = " << "0"; } if (IsImage(type.getBasicType()) && layoutQualifier.imageInternalFormat != EiifUnspecified) { ASSERT(type.getQualifier() == EvqTemporary || type.getQualifier() == EvqUniform); out << getImageInternalFormatString(layoutQualifier.imageInternalFormat); } out << ") "; }
// fully_specified_type // : type_specifier // | type_qualifier type_specifier // bool HlslGrammar::acceptFullySpecifiedType(TType& type) { // type_qualifier TQualifier qualifier; qualifier.clear(); acceptQualifier(qualifier); // type_specifier if (! acceptType(type)) return false; type.getQualifier() = qualifier; return true; }
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()); }
int resolveInOutLocation(EShLanguage stage, const char* /*name*/, const TType& type, bool /*is_live*/) override { // kick out of not doing this if (!doAutoLocationMapping()) return -1; // no locations added if already present, or a built-in variable if (type.getQualifier().hasLocation() || type.isBuiltIn()) return -1; // no locations on blocks of built-in variables if (type.isStruct()) { if (type.getStruct()->size() < 1) return -1; if ((*type.getStruct())[0].type->isBuiltIn()) return -1; } // point to the right input or output location counter int& nextLocation = type.getQualifier().isPipeInput() ? nextInputLocation : nextOutputLocation; // Placeholder. This does not do proper cross-stage lining up, nor // work with mixed location/no-location declarations. int location = nextLocation; int typeLocationSize; // Don’t take into account the outer-most array if the stage’s // interface is automatically an array. if (type.getQualifier().isArrayedIo(stage)) { TType elementType(type, 0); typeLocationSize = TIntermediate::computeTypeLocationSize(elementType, stage); } else { typeLocationSize = TIntermediate::computeTypeLocationSize(type, stage); } nextLocation += typeLocationSize; return location; }
void TOutputGLSLBase::writeVariableType(const TType& type) { TInfoSinkBase& out = objSink(); TQualifier qualifier = type.getQualifier(); // TODO(alokp): Validate qualifier for variable declarations. if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal)) out << type.getQualifierString() << " "; // Declare the struct if we have not done so already. if ((type.getBasicType() == EbtStruct) && !structDeclared(type.getStruct())) { declareStruct(type.getStruct()); } else { if (writeVariablePrecision(type.getPrecision())) out << " "; out << getTypeName(type); } }
// Accumulate xfb buffer ranges and check for collisions as the accumulation is done. // // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. // int TIntermediate::addXfbBufferOffset(const TType& type) { const TQualifier& qualifier = type.getQualifier(); assert(qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()); TXfbBuffer& buffer = xfbBuffers[qualifier.layoutXfbBuffer]; // compute the range unsigned int size = computeTypeXfbSize(type, buffer.containsDouble); buffer.implicitStride = std::max(buffer.implicitStride, qualifier.layoutXfbOffset + size); TRange range(qualifier.layoutXfbOffset, qualifier.layoutXfbOffset + size - 1); // check for collisions for (size_t r = 0; r < buffer.ranges.size(); ++r) { if (range.overlap(buffer.ranges[r])) { // there is a collision; pick an example to return return std::max(range.start, buffer.ranges[r].start); } } buffer.ranges.push_back(range); return -1; // no collision }