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 #if (DE_OS == DE_OS_WIN32)
40 # include "tcuWGLContextFactory.hpp"
41 # include "tcuWin32EGLNativeDisplayFactory.hpp"
42 #endif // (DE_OS == DE_OS_WIN32)
43
44 #if (DE_OS == DE_OS_UNIX)
45 # include "tcuLnxX11EglDisplayFactory.hpp"
46 #endif // (DE_OKS == DE_OS_UNIX)
47
48 static_assert(EGL_DONT_CARE == -1, "Unexpected value for EGL_DONT_CARE");
49
50 namespace tcu
51 {
52 class ANGLEPlatform : public tcu::Platform, private glu::Platform, private eglu::Platform
53 {
54 public:
55 ANGLEPlatform(angle::LogErrorFunc logErrorFunc, uint32_t preRotation);
56 ~ANGLEPlatform();
57
58 bool processEvents() override;
59
getGLPlatform() const60 const glu::Platform &getGLPlatform() const override
61 {
62 return static_cast<const glu::Platform &>(*this);
63 }
getEGLPlatform() const64 const eglu::Platform &getEGLPlatform() const override
65 {
66 return static_cast<const eglu::Platform &>(*this);
67 }
68
69 private:
70 // Note: -1 represents EGL_DONT_CARE, but we don't have the EGL headers here.
71 std::vector<eglw::EGLAttrib> initAttribs(eglw::EGLAttrib type,
72 eglw::EGLAttrib deviceType = -1,
73 eglw::EGLAttrib majorVersion = -1,
74 eglw::EGLAttrib minorVersion = -1);
75
76 EventState mEvents;
77 angle::PlatformMethods mPlatformMethods;
78 std::vector<const char *> mEnableFeatureOverrides;
79
80 #if (DE_OS == DE_OS_UNIX)
81 lnx::EventState mLnxEventState;
82 #endif
83 };
84
ANGLEPlatform(angle::LogErrorFunc logErrorFunc,uint32_t preRotation)85 ANGLEPlatform::ANGLEPlatform(angle::LogErrorFunc logErrorFunc, uint32_t preRotation)
86 {
87 angle::SetLowPriorityProcess();
88
89 mPlatformMethods.logError = logErrorFunc;
90
91 // Enable non-conformant ES versions and extensions for testing. Our test expectations would
92 // suppress failing tests, but allowing continuous testing of the pieces that are implemented.
93 mEnableFeatureOverrides.push_back(
94 angle::GetFeatureName(angle::Feature::ExposeNonConformantExtensionsAndVersions));
95
96 // Create pre-rotation attributes.
97 switch (preRotation)
98 {
99 case 90:
100 mEnableFeatureOverrides.push_back(
101 angle::GetFeatureName(angle::Feature::EmulatedPrerotation90));
102 break;
103 case 180:
104 mEnableFeatureOverrides.push_back(
105 angle::GetFeatureName(angle::Feature::EmulatedPrerotation180));
106 break;
107 case 270:
108 mEnableFeatureOverrides.push_back(
109 angle::GetFeatureName(angle::Feature::EmulatedPrerotation270));
110 break;
111 default:
112 break;
113 }
114
115 mEnableFeatureOverrides.push_back(nullptr);
116
117 #if (DE_OS == DE_OS_WIN32)
118 {
119 std::vector<eglw::EGLAttrib> d3d11Attribs = initAttribs(
120 EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
121
122 auto *d3d11Factory = new ANGLENativeDisplayFactory("angle-d3d11", "ANGLE D3D11 Display",
123 d3d11Attribs, &mEvents);
124 m_nativeDisplayFactoryRegistry.registerFactory(d3d11Factory);
125 }
126
127 {
128 std::vector<eglw::EGLAttrib> d3d11Attribs =
129 initAttribs(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
130 EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE);
131
132 auto *d3d11Factory = new ANGLENativeDisplayFactory(
133 "angle-d3d11-ref", "ANGLE D3D11 Reference Display", d3d11Attribs, &mEvents);
134 m_nativeDisplayFactoryRegistry.registerFactory(d3d11Factory);
135 }
136
137 {
138 std::vector<eglw::EGLAttrib> d3d9Attribs = initAttribs(
139 EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE);
140
141 auto *d3d9Factory = new ANGLENativeDisplayFactory("angle-d3d9", "ANGLE D3D9 Display",
142 d3d9Attribs, &mEvents);
143 m_nativeDisplayFactoryRegistry.registerFactory(d3d9Factory);
144 }
145
146 m_nativeDisplayFactoryRegistry.registerFactory(
147 new win32::EGLNativeDisplayFactory(GetModuleHandle(nullptr)));
148 #endif // (DE_OS == DE_OS_WIN32)
149
150 #if defined(ANGLE_USE_GBM) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_WIN32)
151 {
152 std::vector<eglw::EGLAttrib> glesAttribs =
153 initAttribs(EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE);
154
155 auto *glesFactory = new ANGLENativeDisplayFactory("angle-gles", "ANGLE OpenGL ES Display",
156 glesAttribs, &mEvents);
157 m_nativeDisplayFactoryRegistry.registerFactory(glesFactory);
158 }
159 #endif
160
161 {
162 std::vector<eglw::EGLAttrib> glAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE);
163
164 auto *glFactory =
165 new ANGLENativeDisplayFactory("angle-gl", "ANGLE OpenGL Display", glAttribs, &mEvents);
166 m_nativeDisplayFactoryRegistry.registerFactory(glFactory);
167 }
168
169 #if (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX)
170 {
171 std::vector<eglw::EGLAttrib> vkAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
172
173 auto *vkFactory = new ANGLENativeDisplayFactory("angle-vulkan", "ANGLE Vulkan Display",
174 vkAttribs, &mEvents);
175 m_nativeDisplayFactoryRegistry.registerFactory(vkFactory);
176 }
177 #endif
178
179 #if (DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
180 {
181 std::vector<eglw::EGLAttrib> swsAttribs = initAttribs(
182 EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE);
183 m_nativeDisplayFactoryRegistry.registerFactory(new ANGLENativeDisplayFactory(
184 "angle-swiftshader", "ANGLE SwiftShader Display", swsAttribs, &mEvents));
185 }
186 #endif
187
188 #if (DE_OS == DE_OS_WIN32) || (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
189 {
190 std::vector<eglw::EGLAttrib> webgpuAttribs =
191 initAttribs(EGL_PLATFORM_ANGLE_TYPE_WEBGPU_ANGLE);
192
193 auto *webgpuFactory = new ANGLENativeDisplayFactory("angle-webgpu", "ANGLE WebGPU Display",
194 webgpuAttribs, &mEvents);
195 m_nativeDisplayFactoryRegistry.registerFactory(webgpuFactory);
196 }
197 #endif
198
199 #if (DE_OS == DE_OS_OSX)
200 {
201 std::vector<eglw::EGLAttrib> mtlAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE);
202
203 auto *mtlFactory = new ANGLENativeDisplayFactory("angle-metal", "ANGLE Metal Display",
204 mtlAttribs, &mEvents);
205 m_nativeDisplayFactoryRegistry.registerFactory(mtlFactory);
206 }
207 #endif
208
209 {
210 std::vector<eglw::EGLAttrib> nullAttribs = initAttribs(EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE);
211
212 auto *nullFactory = new ANGLENativeDisplayFactory("angle-null", "ANGLE NULL Display",
213 nullAttribs, &mEvents);
214 m_nativeDisplayFactoryRegistry.registerFactory(nullFactory);
215 }
216
217 #if (DE_OS == DE_OS_UNIX)
218 m_nativeDisplayFactoryRegistry.registerFactory(
219 lnx::x11::egl::createDisplayFactory(mLnxEventState));
220 #endif
221
222 m_contextFactoryRegistry.registerFactory(
223 new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
224
225 // Add Null context type for use in generating case lists
226 m_contextFactoryRegistry.registerFactory(new null::NullGLContextFactory());
227
228 #if (DE_OS == DE_OS_WIN32)
229 // The wgl::ContextFactory can throw an exception when it fails to load WGL extension functions.
230 // Fail gracefully by catching the exception, which prevents adding the factory to the registry.
231 try
232 {
233 m_contextFactoryRegistry.registerFactory(new wgl::ContextFactory(GetModuleHandle(nullptr)));
234 }
235 catch (tcu::Exception e)
236 {}
237 #endif
238 }
239
~ANGLEPlatform()240 ANGLEPlatform::~ANGLEPlatform() {}
241
processEvents()242 bool ANGLEPlatform::processEvents()
243 {
244 return !mEvents.quitSignaled();
245 }
246
initAttribs(eglw::EGLAttrib type,eglw::EGLAttrib deviceType,eglw::EGLAttrib majorVersion,eglw::EGLAttrib minorVersion)247 std::vector<eglw::EGLAttrib> ANGLEPlatform::initAttribs(eglw::EGLAttrib type,
248 eglw::EGLAttrib deviceType,
249 eglw::EGLAttrib majorVersion,
250 eglw::EGLAttrib minorVersion)
251 {
252 std::vector<eglw::EGLAttrib> attribs;
253
254 attribs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
255 attribs.push_back(type);
256
257 if (deviceType != EGL_DONT_CARE)
258 {
259 attribs.push_back(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE);
260 attribs.push_back(deviceType);
261 }
262
263 if (majorVersion != EGL_DONT_CARE)
264 {
265 attribs.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE);
266 attribs.push_back(majorVersion);
267 }
268
269 if (minorVersion != EGL_DONT_CARE)
270 {
271 attribs.push_back(EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE);
272 attribs.push_back(minorVersion);
273 }
274
275 if (mPlatformMethods.logError)
276 {
277 static_assert(sizeof(eglw::EGLAttrib) == sizeof(angle::PlatformMethods *),
278 "Unexpected pointer size");
279 attribs.push_back(EGL_PLATFORM_ANGLE_PLATFORM_METHODS_ANGLEX);
280 attribs.push_back(reinterpret_cast<eglw::EGLAttrib>(&mPlatformMethods));
281 }
282
283 if (!mEnableFeatureOverrides.empty())
284 {
285 attribs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
286 attribs.push_back(reinterpret_cast<EGLAttrib>(mEnableFeatureOverrides.data()));
287 }
288
289 attribs.push_back(EGL_NONE);
290 return attribs;
291 }
292 } // namespace tcu
293
294 // Create platform
CreateANGLEPlatform(angle::LogErrorFunc logErrorFunc,uint32_t preRotation)295 tcu::Platform *CreateANGLEPlatform(angle::LogErrorFunc logErrorFunc, uint32_t preRotation)
296 {
297 return new tcu::ANGLEPlatform(logErrorFunc, preRotation);
298 }
299
createPlatform()300 tcu::Platform *createPlatform()
301 {
302 return CreateANGLEPlatform(nullptr, 0);
303 }
304