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