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