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