| /*------------------------------------------------------------------------- |
| * 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(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(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(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(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++) |
| { |
| int64_t minVal = valueRange.component(ndx).getMin().asInt(); |
| int64_t maxVal = valueRange.component(ndx).getMax().asInt(); |
| rangeLength += (float)((int)(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; |
| } |
| |
| } // namespace rsg |