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