/*------------------------------------------------------------------------- * drawElements Quality Program Random Shader Generator * ---------------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Utilities. *//*--------------------------------------------------------------------*/ #include "rsgUtils.hpp" #include <set> #include <string> using std::set; using std::string; using std::vector; namespace rsg { void addNewUniforms (vector<const ShaderInput*>& uniforms, set<string>& addedUniforms, const Shader& shader) { const vector<ShaderInput*>& shaderUniforms = shader.getUniforms(); for (vector<ShaderInput*>::const_iterator i = shaderUniforms.begin(); i != shaderUniforms.end(); i++) { const ShaderInput* uniform = *i; if (addedUniforms.find(uniform->getVariable()->getName()) == addedUniforms.end()) { addedUniforms.insert(uniform->getVariable()->getName()); uniforms.push_back(uniform); } } } void computeUnifiedUniforms (const Shader& vertexShader, const Shader& fragmentShader, std::vector<const ShaderInput*>& uniforms) { set<string> addedUniforms; addNewUniforms(uniforms, addedUniforms, vertexShader); addNewUniforms(uniforms, addedUniforms, fragmentShader); } void computeRandomValue (de::Random& rnd, ValueAccess dst, ConstValueRangeAccess valueRange) { const VariableType& type = dst.getType(); switch (type.getBaseType()) { case VariableType::TYPE_FLOAT: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { const float quantizeStep = 1.0f/8.0f; float minVal = valueRange.component(ndx).getMin().asFloat(); float maxVal = valueRange.component(ndx).getMax().asFloat(); dst.component(ndx).asFloat() = getQuantizedFloat(rnd, minVal, maxVal, quantizeStep); } break; case VariableType::TYPE_BOOL: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { int minVal = valueRange.component(ndx).getMin().asBool() ? 1 : 0; int maxVal = valueRange.component(ndx).getMin().asBool() ? 1 : 0; dst.component(ndx).asBool() = rnd.getInt(minVal, maxVal) == 1; } break; case VariableType::TYPE_INT: case VariableType::TYPE_SAMPLER_2D: case VariableType::TYPE_SAMPLER_CUBE: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { int minVal = valueRange.component(ndx).getMin().asInt(); int maxVal = valueRange.component(ndx).getMax().asInt(); dst.component(ndx).asInt() = rnd.getInt(minVal, maxVal); } break; case VariableType::TYPE_ARRAY: { int numElements = type.getNumElements(); for (int ndx = 0; ndx < numElements; ndx++) computeRandomValue(rnd, dst.arrayElement(ndx), valueRange.arrayElement(ndx)); break; } case VariableType::TYPE_STRUCT: { int numMembers = (int)type.getMembers().size(); for (int ndx = 0; ndx < numMembers; ndx++) computeRandomValue(rnd, dst.member(ndx), valueRange.member(ndx)); break; } default: TCU_FAIL("Invalid type"); } } void computeUniformValues (de::Random& rnd, std::vector<VariableValue>& values, const std::vector<const ShaderInput*>& uniforms) { DE_ASSERT(values.empty()); for (vector<const ShaderInput*>::const_iterator i = uniforms.begin(); i != uniforms.end(); i++) { const ShaderInput* uniform = *i; values.push_back(VariableValue(uniform->getVariable())); computeRandomValue(rnd, values[values.size()-1].getValue(), uniform->getValueRange()); } } bool isUndefinedValueRange (ConstValueRangeAccess valueRange) { switch (valueRange.getType().getBaseType()) { case VariableType::TYPE_FLOAT: case VariableType::TYPE_INT: { bool isFloat = valueRange.getType().getBaseType() == VariableType::TYPE_FLOAT; Scalar infMin = isFloat ? Scalar::min<float>() : Scalar::min<int>(); Scalar infMax = isFloat ? Scalar::max<float>() : Scalar::max<int>(); for (int ndx = 0; ndx < valueRange.getType().getNumElements(); ndx++) { if (valueRange.getMin().component(ndx).asScalar() != infMin || valueRange.getMax().component(ndx).asScalar() != infMax) return false; } return true; } case VariableType::TYPE_BOOL: return false; default: TCU_FAIL("Unsupported type"); } } VariableType computeRandomType (GeneratorState& state, int maxScalars) { DE_ASSERT(maxScalars >= 1); static const VariableType::Type baseTypes[] = { VariableType::TYPE_BOOL, VariableType::TYPE_INT, VariableType::TYPE_FLOAT // \todo [pyry] Other types }; VariableType::Type baseType = VariableType::TYPE_LAST; state.getRandom().choose(baseTypes, baseTypes + DE_LENGTH_OF_ARRAY(baseTypes), &baseType, 1); switch (baseType) { case VariableType::TYPE_BOOL: case VariableType::TYPE_INT: case VariableType::TYPE_FLOAT: { const int minVecLength = 1; const int maxVecLength = 4; return VariableType(baseType, state.getRandom().getInt(minVecLength, de::min(maxScalars, maxVecLength))); } default: DE_ASSERT(DE_FALSE); throw Exception("computeRandomType(): Unsupported type"); } } void computeRandomValueRange (GeneratorState& state, ValueRangeAccess valueRange) { const VariableType& type = valueRange.getType(); de::Random& rnd = state.getRandom(); switch (type.getBaseType()) { case VariableType::TYPE_BOOL: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { bool minVal = rnd.getBool(); bool maxVal = minVal ? true : rnd.getBool(); valueRange.getMin().component(ndx).asBool() = minVal; valueRange.getMax().component(ndx).asBool() = maxVal; } break; case VariableType::TYPE_INT: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { const int minIntVal = -16; const int maxIntVal = 16; const int maxRangeLen = maxIntVal - minIntVal; int rangeLen = rnd.getInt(0, maxRangeLen); int minVal = minIntVal + rnd.getInt(0, maxRangeLen-rangeLen); int maxVal = minVal + rangeLen; valueRange.getMin().component(ndx).asInt() = minVal; valueRange.getMax().component(ndx).asInt() = maxVal; } break; case VariableType::TYPE_FLOAT: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { const float step = 0.1f; const int maxSteps = 320; const float minFloatVal = -16.0f; int rangeLen = rnd.getInt(0, maxSteps); int minStep = rnd.getInt(0, maxSteps-rangeLen); float minVal = minFloatVal + step*(float)minStep; float maxVal = minVal + step*(float)rangeLen; valueRange.getMin().component(ndx).asFloat() = minVal; valueRange.getMax().component(ndx).asFloat() = maxVal; } break; default: DE_ASSERT(DE_FALSE); throw Exception("computeRandomValueRange(): Unsupported type"); } } int getTypeConstructorDepth (const VariableType& type) { switch (type.getBaseType()) { case VariableType::TYPE_STRUCT: { const vector<VariableType::Member>& members = type.getMembers(); int maxDepth = 0; for (vector<VariableType::Member>::const_iterator i = members.begin(); i != members.end(); i++) { const VariableType& memberType = i->getType(); int depth = 0; switch (memberType.getBaseType()) { case VariableType::TYPE_STRUCT: depth = getTypeConstructorDepth(memberType); break; case VariableType::TYPE_BOOL: case VariableType::TYPE_FLOAT: case VariableType::TYPE_INT: depth = memberType.getNumElements() == 1 ? 1 : 2; break; default: DE_ASSERT(DE_FALSE); break; } maxDepth = de::max(maxDepth, depth); } return maxDepth + 1; } case VariableType::TYPE_BOOL: case VariableType::TYPE_FLOAT: case VariableType::TYPE_INT: return 2; // One node for ctor, another for value default: DE_ASSERT(DE_FALSE); return 0; } } int getConservativeValueExprDepth (const GeneratorState& state, ConstValueRangeAccess valueRange) { // \todo [2011-03-22 pyry] Do a look-up into variable manager? DE_UNREF(state); return getTypeConstructorDepth(valueRange.getType()); } static float computeRangeLengthSum (ConstValueRangeAccess valueRange) { const VariableType& type = valueRange.getType(); float rangeLength = 0.0f; switch (type.getBaseType()) { case VariableType::TYPE_FLOAT: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { float minVal = valueRange.component(ndx).getMin().asFloat(); float maxVal = valueRange.component(ndx).getMax().asFloat(); rangeLength += maxVal - minVal; } break; case VariableType::TYPE_BOOL: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { int minVal = valueRange.component(ndx).getMin().asBool() ? 1 : 0; int maxVal = valueRange.component(ndx).getMin().asBool() ? 1 : 0; rangeLength += (float)(maxVal - minVal); } break; case VariableType::TYPE_INT: case VariableType::TYPE_SAMPLER_2D: case VariableType::TYPE_SAMPLER_CUBE: for (int ndx = 0; ndx < type.getNumElements(); ndx++) { int minVal = valueRange.component(ndx).getMin().asInt(); int maxVal = valueRange.component(ndx).getMax().asInt(); rangeLength += (float)(maxVal - minVal); } break; case VariableType::TYPE_ARRAY: { int numElements = type.getNumElements(); for (int ndx = 0; ndx < numElements; ndx++) rangeLength += computeRangeLengthSum(valueRange.arrayElement(ndx)); break; } case VariableType::TYPE_STRUCT: { int numMembers = (int)type.getMembers().size(); for (int ndx = 0; ndx < numMembers; ndx++) rangeLength += computeRangeLengthSum(valueRange.member(ndx)); break; } default: TCU_FAIL("Invalid type"); } return rangeLength; } float computeDynamicRangeWeight (ConstValueRangeAccess valueRange) { const VariableType& type = valueRange.getType(); float rangeLenSum = computeRangeLengthSum(valueRange); int numScalars = type.getScalarSize(); return rangeLenSum / (float)numScalars; } } // rsg