Hash :
2ad1c490
Author :
Date :
2016-12-07T14:46:18
D3D: Fix overflow in varying packing. Also add a more robust set of unit tests for this internal class. Because the GL spec allows for succeess when packing any set of varyings, it's impossible to write negative end to end tests. This CL also rewrites our disabled varying packing GLSL tests as unit tests. BUG=angleproject:1296 BUG=angleproject:1638 Change-Id: I78153742517d5c72ddb13ff59dc44ddc4af42fc2 Reviewed-on: https://chromium-review.googlesource.com/415555 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Geoff Lang <geofflang@chromium.org>
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
//
// Copyright 2016 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.
//
// VaryingPacking_unittest.cpp:
// Tests for ANGLE's internal varying packing algorithm.
//
#include "libANGLE/renderer/d3d/hlsl/VaryingPacking.h"
#include <gtest/gtest.h>
#include "libANGLE/Program.h"
namespace
{
class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
{
protected:
VaryingPackingTest() {}
bool testVaryingPacking(const std::vector<sh::Varying> &shVaryings,
rx::VaryingPacking *varyingPacking)
{
std::vector<rx::PackedVarying> packedVaryings;
for (const auto &shVarying : shVaryings)
{
packedVaryings.push_back(rx::PackedVarying(shVarying, shVarying.interpolation));
}
gl::InfoLog infoLog;
std::vector<std::string> transformFeedbackVaryings;
if (!varyingPacking->packUserVaryings(infoLog, packedVaryings, transformFeedbackVaryings))
return false;
return varyingPacking->validateBuiltins();
}
bool packVaryings(GLuint maxVaryings, const std::vector<sh::Varying> &shVaryings)
{
rx::VaryingPacking varyingPacking(maxVaryings);
return testVaryingPacking(shVaryings, &varyingPacking);
}
const int kMaxVaryings = GetParam();
};
std::vector<sh::Varying> MakeVaryings(GLenum type, size_t count, size_t arraySize)
{
std::vector<sh::Varying> varyings;
for (size_t index = 0; index < count; ++index)
{
std::stringstream strstr;
strstr << type << index;
sh::Varying varying;
varying.type = type;
varying.precision = GL_MEDIUM_FLOAT;
varying.name = strstr.str();
varying.mappedName = strstr.str();
varying.arraySize = static_cast<unsigned int>(arraySize);
varying.staticUse = true;
varying.interpolation = sh::INTERPOLATION_FLAT;
varying.isInvariant = false;
varyings.push_back(varying);
}
return varyings;
}
void AddVaryings(std::vector<sh::Varying> *varyings, GLenum type, size_t count, size_t arraySize)
{
const auto &newVaryings = MakeVaryings(type, count, arraySize);
varyings->insert(varyings->end(), newVaryings.begin(), newVaryings.end());
}
// Test that a single varying can't overflow the packing.
TEST_P(VaryingPackingTest, OneVaryingLargerThanMax)
{
ASSERT_FALSE(packVaryings(1, MakeVaryings(GL_FLOAT_MAT4, 1, 0)));
}
// Tests that using FragCoord as a user varying will eat up a register.
TEST_P(VaryingPackingTest, MaxVaryingVec4PlusFragCoord)
{
const std::string &userSemantic = rx::GetVaryingSemantic(4, false);
rx::VaryingPacking varyingPacking(kMaxVaryings);
unsigned int reservedSemanticIndex = varyingPacking.getMaxSemanticIndex();
varyingPacking.builtins(rx::SHADER_PIXEL)
.glFragCoord.enable(userSemantic, reservedSemanticIndex);
const auto &varyings = MakeVaryings(GL_FLOAT_VEC4, kMaxVaryings, 0);
ASSERT_FALSE(testVaryingPacking(varyings, &varyingPacking));
}
// Tests that using PointCoord as a user varying will eat up a register.
TEST_P(VaryingPackingTest, MaxVaryingVec4PlusPointCoord)
{
const std::string &userSemantic = rx::GetVaryingSemantic(4, false);
rx::VaryingPacking varyingPacking(kMaxVaryings);
unsigned int reservedSemanticIndex = varyingPacking.getMaxSemanticIndex();
varyingPacking.builtins(rx::SHADER_PIXEL)
.glPointCoord.enable(userSemantic, reservedSemanticIndex);
const auto &varyings = MakeVaryings(GL_FLOAT_VEC4, kMaxVaryings, 0);
ASSERT_FALSE(testVaryingPacking(varyings, &varyingPacking));
}
// This will overflow the available varying space.
TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3)
{
ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings + 1, 0)));
}
// This will overflow the available varying space.
TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec3Array)
{
ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2 + 1, 2)));
}
// This will overflow the available varying space.
TEST_P(VaryingPackingTest, MaxVaryingVec3AndOneVec2)
{
std::vector<sh::Varying> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings, 0);
AddVaryings(&varyings, GL_FLOAT_VEC2, 1, 0);
ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
}
// This should work since two vec2s are packed in a single register.
TEST_P(VaryingPackingTest, MaxPlusOneVaryingVec2)
{
ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings + 1, 0)));
}
// Same for this one as above.
TEST_P(VaryingPackingTest, TwiceMaxVaryingVec2)
{
ASSERT_TRUE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2, 0)));
}
// This should not work since it overflows available varying space.
TEST_P(VaryingPackingTest, TooManyVaryingVec2)
{
ASSERT_FALSE(packVaryings(kMaxVaryings, MakeVaryings(GL_FLOAT_VEC2, kMaxVaryings * 2 + 1, 0)));
}
// This should work according to the example GL packing rules - the float varyings are slotted
// into the end of the vec3 varying arrays.
TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndFloatArrays)
{
std::vector<sh::Varying> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2, 2);
ASSERT_TRUE(packVaryings(kMaxVaryings, varyings));
}
// This should not work - it has one too many float arrays.
TEST_P(VaryingPackingTest, MaxVaryingVec3ArrayAndMaxPlusOneFloatArray)
{
std::vector<sh::Varying> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2 + 1, 2);
ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
}
// Makes separate tests for different values of kMaxVaryings.
INSTANTIATE_TEST_CASE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8));
} // anonymous namespace