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