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