1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
4 *
5 * Copyright 2014 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */
20
21 #include "tcuANGLEPlatform.h"
22
23 #include "egluGLContextFactory.hpp"
24 #include "gluPlatform.hpp"
25 #include "tcuANGLENativeDisplayFactory.h"
26 #include "tcuDefs.hpp"
27 #include "tcuNullContextFactory.hpp"
28 #include "tcuPlatform.hpp"
29 #include "util/autogen/angle_features_autogen.h"
30 #include "util/test_utils.h"
31
32 #ifndef _EGLUPLATFORM_HPP
33 # include "egluPlatform.hpp"
34 #endif
35
36 #include <EGL/egl.h>
37 #include <EGL/eglext.h>
38
39 #include "angle_deqp_libtester.h"
40
41 #if (DE_OS == DE_OS_WIN32)
42 # include "tcuWGLContextFactory.hpp"
43 # include "tcuWin32EGLNativeDisplayFactory.hpp"
44 #endif // (DE_OS == DE_OS_WIN32)
45
46 #if (DE_OS == DE_OS_UNIX)
47 # include "tcuLnxX11EglDisplayFactory.hpp"
48 #endif // (DE_OKS == DE_OS_UNIX)
49
50 static_assert(EGL_DONT_CARE == -1, "Unexpected value for EGL_DONT_CARE");
51
52 namespace tcu
53 {
54 class ANGLEPlatform : public tcu::Platform, private glu::Platform, private eglu::Platform
55 {
56 public:
57 ANGLEPlatform(angle::LogErrorFunc logErrorFunc,
58 uint32_t preRotation,
59 dEQPDriverOption driverOption);
60 ~ANGLEPlatform();
61
62 bool processEvents() override;
63
getGLPlatform() const64 const glu::Platform &getGLPlatform() const override
65 {
66 return static_cast<const glu::Platform &>(*this);
67 }
getEGLPlatform() const68 const eglu::Platform &getEGLPlatform() const override
69 {
70 return static_cast<const eglu::Platform &>(*this);
71 }
72
73 private:
74 // Note: -1 represents EGL_DONT_CARE, but we don't have the EGL headers here.
75 std::vector<eglw::EGLAttrib> initAttribs(eglw::EGLAttrib type,
76 eglw::EGLAttrib deviceType = -1,
77 eglw::EGLAttrib majorVersion = -1,
78 eglw::EGLAttrib minorVersion = -1);
79
80 EventState mEvents;
81 angle::PlatformMethods mPlatformMethods;
82 std::vector<const char *> mEnableFeatureOverrides;
83
84 #if (DE_OS == DE_OS_UNIX)
85 lnx::EventState mLnxEventState;
86 #endif
87 };
88
ANGLEPlatform(angle::LogErrorFunc logErrorFunc,uint32_t preRotation,dEQPDriverOption driverOption)89 ANGLEPlatform::ANGLEPlatform(angle::LogErrorFunc logErrorFunc,
90 uint32_t preRotation,
91 dEQPDriverOption driverOption)
92 {
93 angle::SetLowPriorityProcess();
94
95 mPlatformMethods.logError = logErrorFunc;
96
97 // Enable non-conformant ES versions and extensions for testing. Our test expectations would
98 // suppress failing tests, but allowing continuous testing of the pieces that are implemented.
99 mEnableFeatureOverrides.push_back(
100 angle::GetFeatureName(angle::Feature::ExposeNonConformantExtensionsAndVersions));
101
102 // Create pre-rotation attributes.
103 switch (preRotation)
104 {
105 case 90:
106 mEnableFeatureOverrides.push_back(
107 angle::GetFeatureName(angle::Feature::EmulatedPrerotation90));
108 break;
109 case 180:
110 mEnableFeatureOverrides.push_back(
111 angle::GetFeatureName(angle::Feature::EmulatedPrerotation180));
112 break;
113 case 270:
114 mEnableFeatureOverrides.push_back(
115 angle::GetFeatureName(angle::Feature::EmulatedPrerotation270));
116 break;
117 default:
118 break;
119 }
120
121 mEnableFeatureOverrides.push_back(nullptr);
122
123 #if (DE_OS == DE_OS_WIN32)
124 {
125 std::vector<eglw::EGLAttrib> d3d11Attribs = initAttribs(
126 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
127
128 auto *d3d11Factory = new ANGLENativeDisplayFactory("angle-d3d11", "ANGLE D3D11 Display",
129 d3d11Attribs, &mEvents);
130 m_nativeDisplayFactoryRegistry.registerFactory(d3d11Factory);
131 }
132
133 {
134 std::vector<eglw::EGLAttrib> d3d11Attribs =
135 initAttribs(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
136 EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE);
137
138 auto *d3d11Factory = new ANGLENativeDisplayFactory(
139 "angle-d3d11-ref", "ANGLE D3D11 Reference Display", d3d11Attribs, &mEvents);
140 m_nativeDisplayFactoryRegistry.registerFactory(d3d11Factory);
141 }
142
143 {
144 std::vector<eglw::EGLAttrib> d3d9Attribs = initAttribs(
145 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
146
147 auto *d3d9Factory = new ANGLENativeDisplayFactory("angle-d3d9", "ANGLE D3D9 Display",
148 d3d9Attribs, &mEvents);
149 m_nativeDisplayFactoryRegistry.registerFactory(d3d9Factory);
150 }
151
152 m_nativeDisplayFactoryRegistry.registerFactory(
153 new win32::EGLNativeDisplayFactory(GetModuleHandle(nullptr)));
154 #endif // (DE_OS == DE_OS_WIN32)
155
156 #if defined(ANGLE_USE_GBM) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_WIN32)
157 {
158 std::vector<eglw::EGLAttrib> glesAttribs =
159 initAttribs(EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE);
160
161 auto *glesFactory = new ANGLENativeDisplayFactory("angle-gles", "ANGLE OpenGL ES Display",
162 glesAttribs, &mEvents);
163 m_nativeDisplayFactoryRegistry.registerFactory(glesFactory);
164 }
165 #endif
166
167 {
168 std::vector<eglw::EGLAttrib> glAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE);
169
170 auto *glFactory =
171 new ANGLENativeDisplayFactory("angle-gl", "ANGLE OpenGL Display", glAttribs, &mEvents);
172 m_nativeDisplayFactoryRegistry.registerFactory(glFactory);
173 }
174
175 #if (DE_OS == DE_OS_ANDROID)
176 {
177 if (driverOption == dEQPDriverOption::ANGLE)
178 {
179 std::vector<eglw::EGLAttrib> vkAttribs =
180 initAttribs(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
181 auto *vkFactory =
182 new ANGLENativeDisplayFactory("angle-vulkan", "ANGLE Vulkan Display", vkAttribs,
183 &mEvents, EGL_PLATFORM_ANGLE_ANGLE);
184 m_nativeDisplayFactoryRegistry.registerFactory(vkFactory);
185 }
186 else
187 {
188 std::vector<eglw::EGLAttrib> nativeGlesAttribs = {EGL_NONE};
189 auto *nativeGLESFactory = new ANGLENativeDisplayFactory(
190 "native-gles", "Native GLES Display", nativeGlesAttribs, &mEvents,
191 EGL_PLATFORM_ANDROID_KHR);
192 m_nativeDisplayFactoryRegistry.registerFactory(nativeGLESFactory);
193 }
194 }
195 #endif
196
197 #if ((DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX))
198 {
199 std::vector<eglw::EGLAttrib> vkAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
200
201 auto *vkFactory = new ANGLENativeDisplayFactory("angle-vulkan", "ANGLE Vulkan Display",
202 vkAttribs, &mEvents);
203 m_nativeDisplayFactoryRegistry.registerFactory(vkFactory);
204 }
205 #endif
206
207 #if (DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
208 {
209 std::vector<eglw::EGLAttrib> swsAttribs = initAttribs(
210 EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE);
211 m_nativeDisplayFactoryRegistry.registerFactory(new ANGLENativeDisplayFactory(
212 "angle-swiftshader", "ANGLE SwiftShader Display", swsAttribs, &mEvents));
213 }
214 #endif
215
216 #if (DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
217 {
218 std::vector<eglw::EGLAttrib> webgpuAttribs =
219 initAttribs(EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE);
220
221 auto *webgpuFactory = new ANGLENativeDisplayFactory("angle-webgpu", "ANGLE WebGPU Display",
222 webgpuAttribs, &mEvents);
223 m_nativeDisplayFactoryRegistry.registerFactory(webgpuFactory);
224 }
225 #endif
226
227 #if (DE_OS == DE_OS_OSX)
228 {
229 std::vector<eglw::EGLAttrib> mtlAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE);
230
231 auto *mtlFactory = new ANGLENativeDisplayFactory("angle-metal", "ANGLE Metal Display",
232 mtlAttribs, &mEvents);
233 m_nativeDisplayFactoryRegistry.registerFactory(mtlFactory);
234 }
235 #endif
236
237 {
238 std::vector<eglw::EGLAttrib> nullAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE);
239
240 auto *nullFactory = new ANGLENativeDisplayFactory("angle-null", "ANGLE NULL Display",
241 nullAttribs, &mEvents);
242 m_nativeDisplayFactoryRegistry.registerFactory(nullFactory);
243 }
244
245 #if (DE_OS == DE_OS_UNIX)
246 m_nativeDisplayFactoryRegistry.registerFactory(
247 lnx::x11::egl::createDisplayFactory(mLnxEventState));
248 #endif
249
250 m_contextFactoryRegistry.registerFactory(
251 new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
252
253 // Add Null context type for use in generating case lists
254 m_contextFactoryRegistry.registerFactory(new null::NullGLContextFactory());
255
256 #if (DE_OS == DE_OS_WIN32)
257 // The wgl::ContextFactory can throw an exception when it fails to load WGL extension functions.
258 // Fail gracefully by catching the exception, which prevents adding the factory to the registry.
259 try
260 {
261 m_contextFactoryRegistry.registerFactory(new wgl::ContextFactory(GetModuleHandle(nullptr)));
262 }
263 catch (tcu::Exception e)
264 {}
265 #endif
266 }
267
~ANGLEPlatform()268 ANGLEPlatform::~ANGLEPlatform() {}
269
processEvents()270 bool ANGLEPlatform::processEvents()
271 {
272 return !mEvents.quitSignaled();
273 }
274
initAttribs(eglw::EGLAttrib type,eglw::EGLAttrib deviceType,eglw::EGLAttrib majorVersion,eglw::EGLAttrib minorVersion)275 std::vector<eglw::EGLAttrib> ANGLEPlatform::initAttribs(eglw::EGLAttrib type,
276 eglw::EGLAttrib deviceType,
277 eglw::EGLAttrib majorVersion,
278 eglw::EGLAttrib minorVersion)
279 {
280 std::vector<eglw::EGLAttrib> attribs;
281
282 attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
283 attribs.push_back(type);
284
285 if (deviceType != EGL_DONT_CARE)
286 {
287 attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
288 attribs.push_back(deviceType);
289 }
290
291 if (majorVersion != EGL_DONT_CARE)
292 {
293 attribs.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
294 attribs.push_back(majorVersion);
295 }
296
297 if (minorVersion != EGL_DONT_CARE)
298 {
299 attribs.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
300 attribs.push_back(minorVersion);
301 }
302
303 if (mPlatformMethods.logError)
304 {
305 static_assert(sizeof(eglw::EGLAttrib) == sizeof(angle::PlatformMethods *),
306 "Unexpected pointer size");
307 attribs.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
308 attribs.push_back(reinterpret_cast<eglw::EGLAttrib>(&mPlatformMethods));
309 }
310
311 if (!mEnableFeatureOverrides.empty())
312 {
313 attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
314 attribs.push_back(reinterpret_cast<EGLAttrib>(mEnableFeatureOverrides.data()));
315 }
316
317 attribs.push_back(EGL_NONE);
318 return attribs;
319 }
320 } // namespace tcu
321
322 // Create platform
CreateANGLEPlatform(angle::LogErrorFunc logErrorFunc,uint32_t preRotation,dEQPDriverOption driverOption)323 tcu::Platform *CreateANGLEPlatform(angle::LogErrorFunc logErrorFunc,
324 uint32_t preRotation,
325 dEQPDriverOption driverOption)
326 {
327 return new tcu::ANGLEPlatform(logErrorFunc, preRotation, driverOption);
328 }
329
createPlatform()330 tcu::Platform *createPlatform()
331 {
332 return CreateANGLEPlatform(nullptr, 0, dEQPDriverOption::ANGLE);
333 }
334