Commit 629a6449 by Olli Etuaho Committed by Commit Bot

Fix HLSL integer pow workaround

The exponent should be rounded prior to casting it to an integer. Also if the exponent has a significant fractional part the expression should not be turned into a multiplication. The previous code failed to check this correctly if the exponent's fractional part was greater than 0.5. The test case is expanded to cover the previously failing cases. BUG=chromium:793115 TEST=angle_end2end_tests Change-Id: Ic72cd6ddc7f3d2495f7c87a3e3cfac5791445e72 Reviewed-on: https://chromium-review.googlesource.com/817299Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
parent c7abc080
......@@ -72,37 +72,31 @@ bool Traverser::visitAggregate(Visit visit, TIntermAggregate *node)
const TIntermSequence *sequence = node->getSequence();
ASSERT(sequence->size() == 2u);
const TIntermConstantUnion *constantNode = sequence->at(1)->getAsConstantUnion();
const TIntermConstantUnion *constantExponent = sequence->at(1)->getAsConstantUnion();
// Test 1: check for a single constant.
if (!constantNode || constantNode->getNominalSize() != 1)
if (!constantExponent || constantExponent->getNominalSize() != 1)
{
return true;
}
const TConstantUnion *constant = constantNode->getUnionArrayPointer();
ASSERT(constantExponent->getBasicType() == EbtFloat);
float exponentValue = constantExponent->getUnionArrayPointer()->getFConst();
TConstantUnion asFloat;
asFloat.cast(EbtFloat, *constant);
float value = asFloat.getFConst();
// Test 2: value is in the problematic range.
if (value < -5.0f || value > 9.0f)
// Test 2: exponentValue is in the problematic range.
if (exponentValue < -5.0f || exponentValue > 9.0f)
{
return true;
}
// Test 3: value is integer or pretty close to an integer.
float absval = std::abs(value);
float frac = absval - std::round(absval);
if (frac > 0.0001f)
// Test 3: exponentValue is integer or pretty close to an integer.
if (std::abs(exponentValue - std::round(exponentValue)) > 0.0001f)
{
return true;
}
// Test 4: skip -1, 0, and 1
int exponent = static_cast<int>(value);
int exponent = static_cast<int>(std::round(exponentValue));
int n = std::abs(exponent);
if (n < 2)
{
......
......@@ -1629,22 +1629,28 @@ std::string GenerateSmallPowShader(double base, double exponent)
// See http://anglebug.com/851
TEST_P(GLSLTest, PowOfSmallConstant)
{
std::vector<double> bads;
for (int eps = -1; eps <= 1; ++eps)
// Test with problematic exponents that are close to an integer.
std::vector<double> testExponents;
std::array<double, 5> epsilonMultipliers = {-100.0, -1.0, 0.0, 1.0, 100.0};
for (double epsilonMultiplier : epsilonMultipliers)
{
for (int i = -4; i <= 5; ++i)
{
if (i >= -1 && i <= 1)
continue;
const double epsilon = 1.0e-8;
double bad = static_cast<double>(i) + static_cast<double>(eps) * epsilon;
bads.push_back(bad);
double bad = static_cast<double>(i) + epsilonMultiplier * epsilon;
testExponents.push_back(bad);
}
}
for (double bad : bads)
// Also test with a few exponents that are not close to an integer.
testExponents.push_back(3.6);
testExponents.push_back(3.4);
for (double testExponent : testExponents)
{
const std::string &fragmentShaderSource = GenerateSmallPowShader(1.0e-6, bad);
const std::string &fragmentShaderSource = GenerateSmallPowShader(1.0e-6, testExponent);
ANGLE_GL_PROGRAM(program, mSimpleVSSource, fragmentShaderSource);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment