• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &params) 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 &params) 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 &params,
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 &params) 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 &params) 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 &params,
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