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 "egluNativeDisplay.hpp"
22
23 #include "tcuANGLENativeDisplayFactory.h"
24
25 #include "deClock.h"
26 #include "deMemory.h"
27 #include "egluDefs.hpp"
28 #include "eglwLibrary.hpp"
29 #include "tcuTexture.hpp"
30 #include "util/OSPixmap.h"
31 #include "util/OSWindow.h"
32 #include "util/autogen/angle_features_autogen.h"
33
34 // clang-format off
35 #if (DE_OS == DE_OS_WIN32)
36 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dll"
37 #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_ANDROID)
38 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".so"
39 #elif (DE_OS == DE_OS_OSX)
40 #define ANGLE_EGL_LIBRARY_FULL_NAME ANGLE_EGL_LIBRARY_NAME ".dylib"
41 #else
42 #error "Unsupported platform"
43 #endif
44 // clang-format on
45
46 #if defined(ANGLE_USE_X11)
47 # include <X11/Xlib.h>
48 #endif
49
50 #if defined(ANGLE_USE_WAYLAND)
51 # include <wayland-client.h>
52 # include <wayland-egl-backend.h>
53 #endif
54
55 #if (DE_OS == DE_OS_ANDROID)
56 # define NATIVE_EGL_LIBRARY_FULL_NAME "libEGL.so"
57 #endif
58
59 namespace tcu
60 {
61 namespace
62 {
63
64 template <typename destType, typename sourceType>
bitCast(sourceType source)65 destType bitCast(sourceType source)
66 {
67 constexpr size_t copySize =
68 sizeof(destType) < sizeof(sourceType) ? sizeof(destType) : sizeof(sourceType);
69 destType output(0);
70 memcpy(&output, &source, copySize);
71 return output;
72 }
73
74 enum
75 {
76 DEFAULT_SURFACE_WIDTH = 400,
77 DEFAULT_SURFACE_HEIGHT = 300,
78 };
79
80 constexpr eglu::NativeDisplay::Capability kDisplayCapabilities =
81 static_cast<eglu::NativeDisplay::Capability>(
82 eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM |
83 eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_PLATFORM_EXT);
84 constexpr eglu::NativePixmap::Capability kBitmapCapabilities =
85 eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
86 constexpr eglu::NativeWindow::Capability kWindowCapabilities =
87 static_cast<eglu::NativeWindow::Capability>(
88 #if (DE_OS == DE_OS_WIN32)
89 eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS |
90 #endif
91 eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY |
92 eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE |
93 eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE |
94 eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
95 eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY |
96 eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION);
97
98 class ANGLENativeDisplay : public eglu::NativeDisplay
99 {
100 public:
101 explicit ANGLENativeDisplay(EGLNativeDisplayType display,
102 std::vector<eglw::EGLAttrib> attribs,
103 const EGLenum platformType,
104 const char *eglLibraryName);
105 ~ANGLENativeDisplay() override = default;
106
getPlatformNative()107 void *getPlatformNative() override
108 {
109 // On OSX 64bits mDeviceContext is a 32 bit integer, so we can't simply
110 // use reinterpret_cast<void*>.
111 return bitCast<void *>(mDeviceContext);
112 }
getPlatformAttributes() const113 const eglw::EGLAttrib *getPlatformAttributes() const override
114 {
115 return &mPlatformAttributes[0];
116 }
getLibrary() const117 const eglw::Library &getLibrary() const override { return mLibrary; }
118
getDeviceContext() const119 EGLNativeDisplayType getDeviceContext() const { return mDeviceContext; }
120
121 private:
122 EGLNativeDisplayType mDeviceContext;
123 eglw::DefaultLibrary mLibrary;
124 std::vector<eglw::EGLAttrib> mPlatformAttributes;
125 };
126
127 class NativePixmapFactory : public eglu::NativePixmapFactory
128 {
129 public:
130 NativePixmapFactory();
131 ~NativePixmapFactory() override = default;
132
133 eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay,
134 int width,
135 int height) const override;
136 eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay,
137 eglw::EGLDisplay display,
138 eglw::EGLConfig config,
139 const eglw::EGLAttrib *attribList,
140 int width,
141 int height) const override;
142 };
143
144 class NativePixmap : public eglu::NativePixmap
145 {
146 public:
147 NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth);
148 virtual ~NativePixmap();
149
150 eglw::EGLNativePixmapType getLegacyNative() override;
151
152 private:
153 OSPixmap *mPixmap;
154 };
155
156 class NativeWindowFactory : public eglu::NativeWindowFactory
157 {
158 public:
159 explicit NativeWindowFactory(EventState *eventState, uint32_t preRotation);
160 ~NativeWindowFactory() override = default;
161
162 eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
163 const eglu::WindowParams ¶ms) const override;
164 eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
165 eglw::EGLDisplay display,
166 eglw::EGLConfig config,
167 const eglw::EGLAttrib *attribList,
168 const eglu::WindowParams ¶ms) const override;
169
170 private:
171 EventState *mEvents;
172 uint32_t mPreRotation;
173 };
174
175 class NativeWindow : public eglu::NativeWindow
176 {
177 public:
178 NativeWindow(ANGLENativeDisplay *nativeDisplay,
179 const eglu::WindowParams ¶ms,
180 EventState *eventState,
181 uint32_t preRotation);
182 ~NativeWindow() override;
183
184 eglw::EGLNativeWindowType getLegacyNative() override;
185 void *getPlatformExtension() override;
186 IVec2 getSurfaceSize() const override;
getScreenSize() const187 IVec2 getScreenSize() const override { return getSurfaceSize(); }
188 void processEvents() override;
189 void setSurfaceSize(IVec2 size) override;
190 void setVisibility(eglu::WindowParams::Visibility visibility) override;
191 void readScreenPixels(tcu::TextureLevel *dst) const override;
192
193 private:
194 OSWindow *mWindow;
195 EventState *mEvents;
196 uint32_t mPreRotation;
197 };
198
199 // ANGLE NativeDisplay
200
ANGLENativeDisplay(EGLNativeDisplayType display,std::vector<EGLAttrib> attribs,const EGLenum platformType,const char * eglLibraryName)201 ANGLENativeDisplay::ANGLENativeDisplay(EGLNativeDisplayType display,
202 std::vector<EGLAttrib> attribs,
203 const EGLenum platformType,
204 const char *eglLibraryName)
205 : eglu::NativeDisplay(kDisplayCapabilities, platformType, "EGL_EXT_platform_base"),
206 mDeviceContext(display),
207 mLibrary(eglLibraryName),
208 mPlatformAttributes(std::move(attribs))
209 {}
210
211 // NativePixmap
212
NativePixmap(EGLNativeDisplayType display,int width,int height,int bitDepth)213 NativePixmap::NativePixmap(EGLNativeDisplayType display, int width, int height, int bitDepth)
214 : eglu::NativePixmap(kBitmapCapabilities), mPixmap(CreateOSPixmap())
215 {
216 #if (DE_OS != DE_OS_UNIX)
217 throw tcu::NotSupportedError("Pixmap not supported");
218 #else
219 if (!mPixmap)
220 {
221 throw ResourceError("Failed to create pixmap", nullptr, __FILE__, __LINE__);
222 }
223
224 if (!mPixmap->initialize(display, width, height, bitDepth))
225 {
226 throw ResourceError("Failed to initialize pixmap", nullptr, __FILE__, __LINE__);
227 }
228 #endif
229 }
230
~NativePixmap()231 NativePixmap::~NativePixmap()
232 {
233 delete mPixmap;
234 }
235
getLegacyNative()236 eglw::EGLNativePixmapType NativePixmap::getLegacyNative()
237 {
238 return reinterpret_cast<eglw::EGLNativePixmapType>(mPixmap->getNativePixmap());
239 }
240
241 // NativePixmapFactory
242
NativePixmapFactory()243 NativePixmapFactory::NativePixmapFactory()
244 : eglu::NativePixmapFactory("bitmap", "ANGLE Bitmap", kBitmapCapabilities)
245 {}
246
createPixmap(eglu::NativeDisplay * nativeDisplay,eglw::EGLDisplay display,eglw::EGLConfig config,const eglw::EGLAttrib * attribList,int width,int height) const247 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay,
248 eglw::EGLDisplay display,
249 eglw::EGLConfig config,
250 const eglw::EGLAttrib *attribList,
251 int width,
252 int height) const
253 {
254 const eglw::Library &egl = nativeDisplay->getLibrary();
255 int nativeVisual = 0;
256
257 DE_ASSERT(display != EGL_NO_DISPLAY);
258
259 egl.getConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &nativeVisual);
260 EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
261
262 return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(),
263 width, height, nativeVisual);
264 }
265
createPixmap(eglu::NativeDisplay * nativeDisplay,int width,int height) const266 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay,
267 int width,
268 int height) const
269 {
270 const int defaultDepth = 32;
271 return new NativePixmap(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay)->getDeviceContext(),
272 width, height, defaultDepth);
273 }
274
275 // NativeWindowFactory
276
NativeWindowFactory(EventState * eventState,uint32_t preRotation)277 NativeWindowFactory::NativeWindowFactory(EventState *eventState, uint32_t preRotation)
278 : eglu::NativeWindowFactory("window", "ANGLE Window", kWindowCapabilities),
279 mEvents(eventState),
280 mPreRotation(preRotation)
281 {}
282
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const283 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
284 const eglu::WindowParams ¶ms) const
285 {
286 DE_ASSERT(false);
287 return nullptr;
288 }
289
createWindow(eglu::NativeDisplay * nativeDisplay,eglw::EGLDisplay display,eglw::EGLConfig config,const eglw::EGLAttrib * attribList,const eglu::WindowParams & params) const290 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
291 eglw::EGLDisplay display,
292 eglw::EGLConfig config,
293 const eglw::EGLAttrib *attribList,
294 const eglu::WindowParams ¶ms) const
295 {
296 return new NativeWindow(dynamic_cast<ANGLENativeDisplay *>(nativeDisplay), params, mEvents,
297 mPreRotation);
298 }
299
300 // NativeWindow
301
NativeWindow(ANGLENativeDisplay * nativeDisplay,const eglu::WindowParams & params,EventState * eventState,uint32_t preRotation)302 NativeWindow::NativeWindow(ANGLENativeDisplay *nativeDisplay,
303 const eglu::WindowParams ¶ms,
304 EventState *eventState,
305 uint32_t preRotation)
306 : eglu::NativeWindow(kWindowCapabilities),
307 mWindow(OSWindow::New()),
308 mEvents(eventState),
309 mPreRotation(preRotation)
310 {
311 int osWindowWidth =
312 params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width;
313 int osWindowHeight = params.height == eglu::WindowParams::SIZE_DONT_CARE
314 ? DEFAULT_SURFACE_HEIGHT
315 : params.height;
316
317 if (mPreRotation == 90 || mPreRotation == 270)
318 {
319 std::swap(osWindowWidth, osWindowHeight);
320 }
321
322 mWindow->setNativeDisplay(nativeDisplay->getDeviceContext());
323 bool initialized = mWindow->initialize("dEQP ANGLE Tests", osWindowWidth, osWindowHeight);
324 TCU_CHECK(initialized);
325
326 if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
327 NativeWindow::setVisibility(params.visibility);
328 }
329
setVisibility(eglu::WindowParams::Visibility visibility)330 void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility)
331 {
332 switch (visibility)
333 {
334 case eglu::WindowParams::VISIBILITY_HIDDEN:
335 mWindow->setVisible(false);
336 break;
337
338 case eglu::WindowParams::VISIBILITY_VISIBLE:
339 case eglu::WindowParams::VISIBILITY_FULLSCREEN:
340 mWindow->setVisible(true);
341 break;
342
343 default:
344 DE_ASSERT(false);
345 }
346 }
347
~NativeWindow()348 NativeWindow::~NativeWindow()
349 {
350 OSWindow::Delete(&mWindow);
351 }
352
getLegacyNative()353 eglw::EGLNativeWindowType NativeWindow::getLegacyNative()
354 {
355 return reinterpret_cast<eglw::EGLNativeWindowType>(mWindow->getNativeWindow());
356 }
357
getPlatformExtension()358 void *NativeWindow::getPlatformExtension()
359 {
360 return mWindow->getPlatformExtension();
361 }
362
getSurfaceSize() const363 IVec2 NativeWindow::getSurfaceSize() const
364 {
365 int width = mWindow->getWidth();
366 int height = mWindow->getHeight();
367
368 if (mPreRotation == 90 || mPreRotation == 270)
369 {
370 // Return the original dimensions dEQP asked for. This ensures that the dEQP code is never
371 // aware of the window actually being rotated.
372 std::swap(width, height);
373 }
374
375 return IVec2(width, height);
376 }
377
processEvents()378 void NativeWindow::processEvents()
379 {
380 mWindow->messageLoop();
381
382 // Look for a quit event to forward to the EventState
383 Event event = {};
384 while (mWindow->popEvent(&event))
385 {
386 if (event.Type == Event::EVENT_CLOSED)
387 {
388 mEvents->signalQuitEvent();
389 }
390 }
391 }
392
setSurfaceSize(IVec2 size)393 void NativeWindow::setSurfaceSize(IVec2 size)
394 {
395 int osWindowWidth = size.x();
396 int osWindowHeight = size.y();
397
398 if (mPreRotation == 90 || mPreRotation == 270)
399 {
400 std::swap(osWindowWidth, osWindowHeight);
401 }
402
403 mWindow->resize(osWindowWidth, osWindowHeight);
404 }
405
readScreenPixels(tcu::TextureLevel * dst) const406 void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const
407 {
408 dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8),
409 mWindow->getWidth(), mWindow->getHeight());
410 if (!mWindow->takeScreenshot(reinterpret_cast<uint8_t *>(dst->getAccess().getDataPtr())))
411 {
412 throw InternalError("Failed to read screen pixels", nullptr, __FILE__, __LINE__);
413 }
414
415 if (mPreRotation != 0)
416 {
417 throw InternalError("Read screen pixels with prerotation is not supported", nullptr,
418 __FILE__, __LINE__);
419 }
420 }
421
422 } // namespace
423
ANGLENativeDisplayFactory(const std::string & name,const std::string & description,std::vector<eglw::EGLAttrib> platformAttributes,EventState * eventState,const EGLenum platformType)424 ANGLENativeDisplayFactory::ANGLENativeDisplayFactory(
425 const std::string &name,
426 const std::string &description,
427 std::vector<eglw::EGLAttrib> platformAttributes,
428 EventState *eventState,
429 const EGLenum platformType)
430 : eglu::NativeDisplayFactory(name,
431 description,
432 kDisplayCapabilities,
433 platformType,
434 "EGL_EXT_platform_base"),
435 mNativeDisplay(bitCast<eglw::EGLNativeDisplayType>(EGL_DEFAULT_DISPLAY)),
436 mPlatformAttributes(std::move(platformAttributes)),
437 mPlatformType(platformType)
438 {
439 #if (DE_OS == DE_OS_UNIX)
440 # if defined(ANGLE_USE_X11)
441 // Make sure to only open the X display once so that it can be used by the EGL display as well
442 // as pixmaps
443 mNativeDisplay = bitCast<eglw::EGLNativeDisplayType>(XOpenDisplay(nullptr));
444 # endif // ANGLE_USE_X11
445
446 # if defined(ANGLE_USE_WAYLAND)
447 if (mNativeDisplay == 0)
448 {
449 mNativeDisplay = bitCast<eglw::EGLNativeDisplayType>(wl_display_connect(nullptr));
450 }
451 # endif // ANGLE_USE_WAYLAND
452 #endif // (DE_OS == DE_OS_UNIX)
453
454 // If pre-rotating, let NativeWindowFactory know.
455 uint32_t preRotation = 0;
456 for (size_t attrIndex = 0;
457 attrIndex < mPlatformAttributes.size() && mPlatformAttributes[attrIndex] != EGL_NONE;
458 attrIndex += 2)
459 {
460 if (mPlatformAttributes[attrIndex] != EGL_FEATURE_OVERRIDES_ENABLED_ANGLE)
461 {
462 continue;
463 }
464
465 const char **enabledFeatures =
466 reinterpret_cast<const char **>(mPlatformAttributes[attrIndex + 1]);
467 DE_ASSERT(enabledFeatures != nullptr && *enabledFeatures != nullptr);
468
469 for (; *enabledFeatures; ++enabledFeatures)
470 {
471 if (strcmp(enabledFeatures[0],
472 angle::GetFeatureName(angle::Feature::EmulatedPrerotation90)) == 0)
473 {
474 preRotation = 90;
475 }
476 else if (strcmp(enabledFeatures[0],
477 angle::GetFeatureName(angle::Feature::EmulatedPrerotation180)) == 0)
478 {
479 preRotation = 180;
480 }
481 else if (strcmp(enabledFeatures[0],
482 angle::GetFeatureName(angle::Feature::EmulatedPrerotation270)) == 0)
483 {
484 preRotation = 270;
485 }
486 }
487 break;
488 }
489
490 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(eventState, preRotation));
491 m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
492 }
493
494 ANGLENativeDisplayFactory::~ANGLENativeDisplayFactory() = default;
495
createDisplay(const eglw::EGLAttrib * attribList) const496 eglu::NativeDisplay *ANGLENativeDisplayFactory::createDisplay(
497 const eglw::EGLAttrib *attribList) const
498 {
499 DE_UNREF(attribList);
500 if (mPlatformType == EGL_PLATFORM_ANGLE_ANGLE)
501 {
502 return new ANGLENativeDisplay(bitCast<EGLNativeDisplayType>(mNativeDisplay),
503 mPlatformAttributes, mPlatformType,
504 ANGLE_EGL_LIBRARY_FULL_NAME);
505 }
506 #if (DE_OS == DE_OS_ANDROID)
507 else if (mPlatformType == EGL_PLATFORM_ANDROID_KHR)
508 {
509 return new ANGLENativeDisplay(bitCast<EGLNativeDisplayType>(mNativeDisplay),
510 mPlatformAttributes, mPlatformType,
511 NATIVE_EGL_LIBRARY_FULL_NAME);
512 }
513 #endif
514 else
515 {
516 throw InternalError("unsupported platform type", nullptr, __FILE__, __LINE__);
517 }
518 }
519
520 } // namespace tcu
521