Hash :
0f2b1560
Author :
Date :
2016-05-13T16:15:35
Fix GenerateMipmap when base level or max level are set According to GLES 3.0.4 section 3.8.10, GenerateMipmap should generate levels based on the base level, and generate them at most up to the max level. Levels outside the base/max level range should be unchanged by GenerateMipmap. The Texture class is fixed so that the image descs are set only for the changed mipmap range when GenerateMipmap is called. The D3D backend is fixed so that mipmap generation is correctly started from the base level instead of level 0, and making sure that mipmaps are generated only up to the max level. Generating mipmaps for array textures is also fixed for cases where the base level depth >= max(width, height) * 2. The GL backend is fixed to sync texture state before GenerateMipmap is called, so that base level and max level are set correctly in the driver. The GenerateMipmap entry point is refactored so that it has a separate validation function and a context function which does the work. Validation for out-of-range base levels is added. New tests are added to verify the functionality. One corner case in the tests fails on NVIDIA GL drivers likely due to a driver bug - similar rules for GenerateMipmap are found from newer GLES specs and also OpenGL specs (checked versions 3.3 and 4.4). BUG=angleproject:596 TEST=angle_end2end_tests Change-Id: Ifc7b4126281967fc4f6dc4f9452e5b01e39f83d7 Reviewed-on: https://chromium-review.googlesource.com/344514 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// mathutil_unittest:
// Unit tests for the utils defined in mathutil.h
//
#include "mathutil.h"
#include <gtest/gtest.h>
using namespace gl;
namespace
{
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions.
// For floats f1 and f2, unpackSnorm2x16(packSnorm2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest, packAndUnpackSnorm2x16)
{
const float input[8][2] =
{
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
{ -1.0f, 1.0f },
{ -1.0f, -1.0f },
{ 0.875f, 0.75f },
{ 0.00392f, -0.99215f },
{ -0.000675f, 0.004954f },
{ -0.6937f, -0.02146f }
};
const float floatFaultTolerance = 0.0001f;
float outputVal1, outputVal2;
for (size_t i = 0; i < 8; i++)
{
unpackSnorm2x16(packSnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance);
EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance);
}
}
// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions with infinity values,
// result should be clamped to [-1, 1].
TEST(MathUtilTest, packAndUnpackSnorm2x16Infinity)
{
const float floatFaultTolerance = 0.0001f;
float outputVal1, outputVal2;
unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance);
unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance);
unpackSnorm2x16(packSnorm2x16(-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(-1.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance);
}
// Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions.
// For floats f1 and f2, unpackUnorm2x16(packUnorm2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest, packAndUnpackUnorm2x16)
{
const float input[8][2] =
{
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
{ -1.0f, 1.0f },
{ -1.0f, -1.0f },
{ 0.875f, 0.75f },
{ 0.00392f, -0.99215f },
{ -0.000675f, 0.004954f },
{ -0.6937f, -0.02146f }
};
const float floatFaultTolerance = 0.0001f;
float outputVal1, outputVal2;
for (size_t i = 0; i < 8; i++)
{
unpackUnorm2x16(packUnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
float expected = input[i][0] < 0.0f ? 0.0f : input[i][0];
EXPECT_NEAR(expected, outputVal1, floatFaultTolerance);
expected = input[i][1] < 0.0f ? 0.0f : input[i][1];
EXPECT_NEAR(expected, outputVal2, floatFaultTolerance);
}
}
// Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions with infinity values,
// result should be clamped to [0, 1].
TEST(MathUtilTest, packAndUnpackUnorm2x16Infinity)
{
const float floatFaultTolerance = 0.0001f;
float outputVal1, outputVal2;
unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance);
unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance);
unpackUnorm2x16(packUnorm2x16(-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2);
EXPECT_NEAR(0.0f, outputVal1, floatFaultTolerance);
EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance);
}
// Test the correctness of packHalf2x16 and unpackHalf2x16 functions.
// For floats f1 and f2, unpackHalf2x16(packHalf2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest, packAndUnpackHalf2x16)
{
const float input[8][2] =
{
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
{ -1.0f, 1.0f },
{ -1.0f, -1.0f },
{ 0.875f, 0.75f },
{ 0.00392f, -0.99215f },
{ -0.000675f, 0.004954f },
{ -0.6937f, -0.02146f },
};
const float floatFaultTolerance = 0.0005f;
float outputVal1, outputVal2;
for (size_t i = 0; i < 8; i++)
{
unpackHalf2x16(packHalf2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance);
EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance);
}
}
// Test the correctness of gl::isNaN function.
TEST(MathUtilTest, isNaN)
{
EXPECT_TRUE(isNaN(bitCast<float>(0xffu << 23 | 1u)));
EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 1u)));
EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u)));
EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu)));
EXPECT_FALSE(isNaN(0.0f));
EXPECT_FALSE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23)));
EXPECT_FALSE(isNaN(bitCast<float>(0xffu << 23)));
}
// Test the correctness of gl::isInf function.
TEST(MathUtilTest, isInf)
{
EXPECT_TRUE(isInf(bitCast<float>(0xffu << 23)));
EXPECT_TRUE(isInf(bitCast<float>(1u << 31 | 0xffu << 23)));
EXPECT_FALSE(isInf(0.0f));
EXPECT_FALSE(isInf(bitCast<float>(0xffu << 23 | 1u)));
EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 1u)));
EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u)));
EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu)));
EXPECT_FALSE(isInf(bitCast<float>(0xfeu << 23 | 0x7fffffu)));
EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xfeu << 23 | 0x7fffffu)));
}
TEST(MathUtilTest, CountLeadingZeros)
{
for (unsigned int i = 0; i < 32u; ++i)
{
uint32_t iLeadingZeros = 1u << (31u - i);
EXPECT_EQ(i, CountLeadingZeros(iLeadingZeros));
}
EXPECT_EQ(32u, CountLeadingZeros(0));
}
}