• 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 <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 &params) 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 &params) 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 &params,
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 &params) 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 &params) 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 &params,
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