Hash :
d654ac9b
Author :
Date :
2020-12-30T12:28:41
Program: Support multiple varying packings. Instead of using a single varying packing for all program stages, we switch to using a varying register packing for each pair of input/output shaders. This allows several valid use cases that use many varying to succeed. For instance Geometry Shaders have both an input and output varying packing. With tessellation shaders the upper bound of valid varying packings in one Program goes up even more. We keep multiple varying packings at once inside a new "ProgramVaryingPacking" class. Internally the class keeps a unique varying mapping for each input/output interface in the program. Separable programs with "open" interfaces are handled specially. Fixes a bug where varying counting was artificially limited for programs with more than two shaders. This CL also disables GS support when we're emulating line raster so we don't have to figure out the details on how to place the special position varying. Bug: angleproject:5496 Change-Id: I1f9a327c4750caef570c608d86953e9d0cc5eea3 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2606532 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Tim Van Patten <timvp@google.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
//
// 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 <gtest/gtest.h>
// 'None' is defined as 'struct None {};' in
// third_party/googletest/src/googletest/include/gtest/internal/gtest-type-util.h.
// But 'None' is also define as a numberic constant 0L in <X11/X.h>.
// So we need to include gtest first to avoid such conflict.
#include "libANGLE/Program.h"
#include "libANGLE/VaryingPacking.h"
using namespace gl;
namespace
{
class VaryingPackingTest : public ::testing::TestWithParam<GLuint>
{
protected:
VaryingPackingTest() {}
bool testVaryingPacking(GLint maxVaryings,
PackMode packMode,
const std::vector<sh::ShaderVariable> &shVaryings)
{
ProgramMergedVaryings mergedVaryings;
for (const sh::ShaderVariable &shVarying : shVaryings)
{
ProgramVaryingRef ref;
ref.frontShader = &shVarying;
ref.backShader = &shVarying;
ref.frontShaderStage = ShaderType::Vertex;
ref.backShaderStage = ShaderType::Fragment;
mergedVaryings.push_back(ref);
}
InfoLog infoLog;
std::vector<std::string> transformFeedbackVaryings;
VaryingPacking varyingPacking;
return varyingPacking.collectAndPackUserVaryings(
infoLog, maxVaryings, packMode, ShaderType::Vertex, ShaderType::Fragment,
mergedVaryings, transformFeedbackVaryings, false);
}
// Uses the "relaxed" ANGLE packing mode.
bool packVaryings(GLint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
{
return testVaryingPacking(maxVaryings, PackMode::ANGLE_RELAXED, shVaryings);
}
// Uses the stricter WebGL style packing rules.
bool packVaryingsStrict(GLint maxVaryings, const std::vector<sh::ShaderVariable> &shVaryings)
{
return testVaryingPacking(maxVaryings, PackMode::WEBGL_STRICT, shVaryings);
}
const int kMaxVaryings = GetParam();
};
std::vector<sh::ShaderVariable> MakeVaryings(GLenum type, size_t count, size_t arraySize)
{
std::vector<sh::ShaderVariable> varyings;
for (size_t index = 0; index < count; ++index)
{
std::stringstream strstr;
strstr << type << index;
sh::ShaderVariable varying;
varying.type = type;
varying.precision = GL_MEDIUM_FLOAT;
varying.name = strstr.str();
varying.mappedName = strstr.str();
if (arraySize > 0)
{
varying.arraySizes.push_back(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::ShaderVariable> *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)));
}
// 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::ShaderVariable> 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::ShaderVariable> 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::ShaderVariable> varyings = MakeVaryings(GL_FLOAT_VEC3, kMaxVaryings / 2, 2);
AddVaryings(&varyings, GL_FLOAT, kMaxVaryings / 2 + 1, 2);
ASSERT_FALSE(packVaryings(kMaxVaryings, varyings));
}
// WebGL should fail to pack max+1 vec2 arrays, unlike our more relaxed packing.
TEST_P(VaryingPackingTest, MaxPlusOneMat2VaryingsFailsWebGL)
{
auto varyings = MakeVaryings(GL_FLOAT_MAT2, kMaxVaryings / 2 + 1, 0);
ASSERT_FALSE(packVaryingsStrict(kMaxVaryings, varyings));
}
// Makes separate tests for different values of kMaxVaryings.
INSTANTIATE_TEST_SUITE_P(, VaryingPackingTest, ::testing::Values(1, 4, 8));
} // anonymous namespace