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