You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
10 KiB
363 lines
10 KiB
/*-------------------------------------------------------------------------
|
|
* 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
|