• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // Tests the eglQueryStringiANGLE and eglQueryDisplayAttribANGLE functions exposed by the
7 // extension EGL_ANGLE_feature_control.
8 
9 #include <gtest/gtest.h>
10 
11 #include "common/string_utils.h"
12 #include "libANGLE/Display.h"
13 #include "test_utils/ANGLETest.h"
14 
15 using namespace angle;
16 
17 class EGLFeatureControlTest : public ANGLETest
18 {
19   public:
testSetUp()20     void testSetUp() override { mDisplay = EGL_NO_DISPLAY; }
21 
testTearDown()22     void testTearDown() override
23     {
24         if (mDisplay != EGL_NO_DISPLAY)
25         {
26             eglTerminate(mDisplay);
27         }
28     }
29 
30   protected:
31     EGLDisplay mDisplay;
32 
initTest()33     bool initTest()
34     {
35         // http://anglebug.com/3629 This test sporadically times out on Win10/Intel
36         if (IsWindows() && IsIntel())
37             return false;
38 
39         EGLAttrib dispattrs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, GetParam().getRenderer(), EGL_NONE};
40         mDisplay              = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE,
41                                          reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
42         EXPECT_NE(mDisplay, EGL_NO_DISPLAY);
43 
44         EXPECT_EQ(eglInitialize(mDisplay, nullptr, nullptr), static_cast<EGLBoolean>(EGL_TRUE));
45 
46         EXPECT_TRUE(IsEGLClientExtensionEnabled("EGL_ANGLE_feature_control"));
47 
48         return true;
49     }
50 
51     using FeatureNameModifier = std::function<std::string(const std::string &)>;
52     void testOverrideFeatures(FeatureNameModifier modifyName);
53 };
54 
55 // Ensure eglQueryStringiANGLE generates EGL_BAD_DISPLAY if the display passed in is invalid.
TEST_P(EGLFeatureControlTest,InvalidDisplay)56 TEST_P(EGLFeatureControlTest, InvalidDisplay)
57 {
58     ANGLE_SKIP_TEST_IF(!initTest());
59     EXPECT_EQ(nullptr, eglQueryStringiANGLE(EGL_NO_DISPLAY, EGL_FEATURE_NAME_ANGLE, 0));
60     EXPECT_EGL_ERROR(EGL_BAD_DISPLAY);
61 }
62 
63 // Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is negative.
TEST_P(EGLFeatureControlTest,NegativeIndex)64 TEST_P(EGLFeatureControlTest, NegativeIndex)
65 {
66     ANGLE_SKIP_TEST_IF(!initTest());
67     EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE, -1));
68     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
69 }
70 
71 // Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the index is out of bounds.
TEST_P(EGLFeatureControlTest,IndexOutOfBounds)72 TEST_P(EGLFeatureControlTest, IndexOutOfBounds)
73 {
74     ANGLE_SKIP_TEST_IF(!initTest());
75     egl::Display *display = static_cast<egl::Display *>(mDisplay);
76     EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE,
77                                             display->getFeatures().size()));
78     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
79 }
80 
81 // Ensure eglQueryStringiANGLE generates EGL_BAD_PARAMETER if the name is not one of the valid
82 // options specified in EGL_ANGLE_feature_control.
TEST_P(EGLFeatureControlTest,InvalidName)83 TEST_P(EGLFeatureControlTest, InvalidName)
84 {
85     ANGLE_SKIP_TEST_IF(!initTest());
86     EXPECT_EQ(nullptr, eglQueryStringiANGLE(mDisplay, 100, 0));
87     EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
88 }
89 
90 // For each valid name and index in the feature description arrays, query the values and ensure
91 // that no error is generated, and that the values match the correct values frim ANGLE's display's
92 // FeatureList.
TEST_P(EGLFeatureControlTest,QueryAll)93 TEST_P(EGLFeatureControlTest, QueryAll)
94 {
95     ANGLE_SKIP_TEST_IF(!initTest());
96     egl::Display *display       = static_cast<egl::Display *>(mDisplay);
97     angle::FeatureList features = display->getFeatures();
98     for (size_t i = 0; i < features.size(); i++)
99     {
100         EXPECT_STREQ(features[i]->name, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_NAME_ANGLE, i));
101         EXPECT_STREQ(FeatureCategoryToString(features[i]->category),
102                      eglQueryStringiANGLE(mDisplay, EGL_FEATURE_CATEGORY_ANGLE, i));
103         EXPECT_STREQ(features[i]->description,
104                      eglQueryStringiANGLE(mDisplay, EGL_FEATURE_DESCRIPTION_ANGLE, i));
105         EXPECT_STREQ(features[i]->bug, eglQueryStringiANGLE(mDisplay, EGL_FEATURE_BUG_ANGLE, i));
106         EXPECT_STREQ(FeatureStatusToString(features[i]->enabled),
107                      eglQueryStringiANGLE(mDisplay, EGL_FEATURE_STATUS_ANGLE, i));
108         EXPECT_STREQ(features[i]->condition,
109                      eglQueryStringiANGLE(mDisplay, EGL_FEATURE_CONDITION_ANGLE, i));
110         ASSERT_EGL_SUCCESS();
111     }
112 }
113 
114 // Ensure eglQueryDisplayAttribANGLE returns the correct number of features when queried with
115 // attribute EGL_FEATURE_COUNT_ANGLE
TEST_P(EGLFeatureControlTest,FeatureCount)116 TEST_P(EGLFeatureControlTest, FeatureCount)
117 {
118     ANGLE_SKIP_TEST_IF(!initTest());
119     egl::Display *display = static_cast<egl::Display *>(mDisplay);
120     EGLAttrib value       = -1;
121     EXPECT_EQ(static_cast<EGLBoolean>(EGL_TRUE),
122               eglQueryDisplayAttribANGLE(mDisplay, EGL_FEATURE_COUNT_ANGLE, &value));
123     EXPECT_EQ(display->getFeatures().size(), static_cast<size_t>(value));
124     ASSERT_EGL_SUCCESS();
125 }
126 
testOverrideFeatures(FeatureNameModifier modifyName)127 void EGLFeatureControlTest::testOverrideFeatures(FeatureNameModifier modifyName)
128 {
129     ANGLE_SKIP_TEST_IF(!initTest());
130     egl::Display *display       = static_cast<egl::Display *>(mDisplay);
131     angle::FeatureList features = display->getFeatures();
132 
133     // Build lists of features to enable/disabled. Toggle features we know are ok to toggle based
134     // from this list.
135     std::vector<const char *> enabled            = std::vector<const char *>();
136     std::vector<const char *> disabled           = std::vector<const char *>();
137     std::vector<std::string> modifiedNameStorage = std::vector<std::string>();
138     std::vector<bool> shouldBe                   = std::vector<bool>();
139     std::vector<std::string> testedFeatures      = {
140         // Safe to toggle on GL
141         angle::GetFeatureName(angle::Feature::AddAndTrueToLoopCondition),
142         angle::GetFeatureName(angle::Feature::ClampFragDepth),
143         // Safe to toggle on GL and Vulkan
144         angle::GetFeatureName(angle::Feature::ClampPointSize),
145         // Safe to toggle on Vulkan
146         angle::GetFeatureName(angle::Feature::SupportsNegativeViewport),
147         // Safe to toggle on D3D
148         angle::GetFeatureName(angle::Feature::ZeroMaxLodWorkaround),
149         angle::GetFeatureName(angle::Feature::ExpandIntegerPowExpressions),
150         angle::GetFeatureName(angle::Feature::RewriteUnaryMinusOperator),
151     };
152     for (size_t i = 0; i < features.size(); i++)
153     {
154         modifiedNameStorage.push_back(modifyName(features[i]->name));
155     }
156     for (size_t i = 0; i < features.size(); i++)
157     {
158         bool toggle = std::find(testedFeatures.begin(), testedFeatures.end(),
159                                 std::string(features[i]->name)) != testedFeatures.end();
160         if (features[i]->enabled ^ toggle)
161         {
162             enabled.push_back(modifiedNameStorage[i].c_str());
163         }
164         else
165         {
166             disabled.push_back(modifiedNameStorage[i].c_str());
167         }
168         // Save what we expect the feature status will be when checking later.
169         shouldBe.push_back(features[i]->enabled ^ toggle);
170     }
171     disabled.push_back(0);
172     enabled.push_back(0);
173 
174     // Terminate the old display (we just used it to collect features)
175     eglTerminate(mDisplay);
176 
177     // Create a new display with these overridden features.
178     EGLAttrib dispattrs[]   = {EGL_PLATFORM_ANGLE_TYPE_ANGLE,
179                              GetParam().getRenderer(),
180                              EGL_FEATURE_OVERRIDES_ENABLED_ANGLE,
181                              reinterpret_cast<EGLAttrib>(enabled.data()),
182                              EGL_FEATURE_OVERRIDES_DISABLED_ANGLE,
183                              reinterpret_cast<EGLAttrib>(disabled.data()),
184                              EGL_NONE};
185     EGLDisplay dpy_override = eglGetPlatformDisplay(
186         EGL_PLATFORM_ANGLE_ANGLE, reinterpret_cast<void *>(EGL_DEFAULT_DISPLAY), dispattrs);
187     ASSERT_EGL_SUCCESS();
188     ASSERT_TRUE(dpy_override != EGL_NO_DISPLAY);
189     ASSERT_TRUE(eglInitialize(dpy_override, nullptr, nullptr) == EGL_TRUE);
190 
191     // Check that all features have the correct status (even the ones we toggled).
192     for (size_t i = 0; i < features.size(); i++)
193     {
194         EXPECT_STREQ(FeatureStatusToString(shouldBe[i]),
195                      eglQueryStringiANGLE(dpy_override, EGL_FEATURE_STATUS_ANGLE, i))
196             << modifiedNameStorage[i];
197     }
198 }
199 
200 // Submit a list of features to override when creating the display with eglGetPlatformDisplay, and
201 // ensure that the features are correctly overridden.
TEST_P(EGLFeatureControlTest,OverrideFeatures)202 TEST_P(EGLFeatureControlTest, OverrideFeatures)
203 {
204     testOverrideFeatures([](const std::string &featureName) { return featureName; });
205 }
206 
207 // Similar to OverrideFeatures, but ensures that camelCase variants of the name match as well.
TEST_P(EGLFeatureControlTest,OverrideFeaturesCamelCase)208 TEST_P(EGLFeatureControlTest, OverrideFeaturesCamelCase)
209 {
210     testOverrideFeatures(
211         [](const std::string &featureName) { return angle::ToCamelCase(featureName); });
212 }
213 
214 ANGLE_INSTANTIATE_TEST(EGLFeatureControlTest,
215                        WithNoFixture(ES2_D3D9()),
216                        WithNoFixture(ES2_D3D11()),
217                        WithNoFixture(ES2_OPENGL()),
218                        WithNoFixture(ES2_VULKAN()),
219                        WithNoFixture(ES3_D3D11()),
220                        WithNoFixture(ES3_OPENGL()));
221