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