xref: /aosp_15_r20/external/deqp/framework/platform/android/tcuAndroidPlatform.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
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  * \file
21  * \brief Android EGL and Vulkan platforms.
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuAndroidPlatform.hpp"
25 #include "tcuAndroidUtil.hpp"
26 #include "gluRenderContext.hpp"
27 #include "egluNativeDisplay.hpp"
28 #include "egluNativeWindow.hpp"
29 #include "egluGLContextFactory.hpp"
30 #include "egluUtil.hpp"
31 #include "eglwLibrary.hpp"
32 #include "eglwEnums.hpp"
33 #include "tcuFunctionLibrary.hpp"
34 #include "vkWsiPlatform.hpp"
35 
36 // Assume no call translation is needed
37 #include <android/native_window.h>
38 struct egl_native_pixmap_t;
39 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(void *));
40 DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(struct egl_native_pixmap_t *));
41 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(ANativeWindow *));
42 
43 namespace tcu
44 {
45 namespace Android
46 {
47 
48 using namespace eglw;
49 
50 static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
51 static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES   = (eglu::NativeWindow::Capability)(
52     eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY | eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM |
53     eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION | eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
54     eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE);
55 
56 class NativeDisplay : public eglu::NativeDisplay
57 {
58 public:
NativeDisplay(void)59     NativeDisplay(void) : eglu::NativeDisplay(DISPLAY_CAPABILITIES), m_library("libEGL.so")
60     {
61     }
~NativeDisplay(void)62     virtual ~NativeDisplay(void)
63     {
64     }
65 
getLegacyNative(void)66     virtual EGLNativeDisplayType getLegacyNative(void)
67     {
68         return EGL_DEFAULT_DISPLAY;
69     }
getLibrary(void) const70     virtual const eglw::Library &getLibrary(void) const
71     {
72         return m_library;
73     }
74 
75 private:
76     eglw::DefaultLibrary m_library;
77 };
78 
79 class NativeDisplayFactory : public eglu::NativeDisplayFactory
80 {
81 public:
82     NativeDisplayFactory(WindowRegistry &windowRegistry);
~NativeDisplayFactory(void)83     ~NativeDisplayFactory(void)
84     {
85     }
86 
87     virtual eglu::NativeDisplay *createDisplay(const EGLAttrib *attribList) const;
88 };
89 
90 class NativeWindow : public eglu::NativeWindow
91 {
92 public:
93     NativeWindow(Window *window, int width, int height, int32_t format);
94     virtual ~NativeWindow(void);
95 
getLegacyNative(void)96     virtual EGLNativeWindowType getLegacyNative(void)
97     {
98         return m_window->getNativeWindow();
99     }
getPlatformExtension(void)100     virtual EGLNativeWindowType getPlatformExtension(void)
101     {
102         return m_window->getNativeWindow();
103     }
getPlatformNative(void)104     virtual EGLNativeWindowType getPlatformNative(void)
105     {
106         return m_window->getNativeWindow();
107     }
getScreenSize(void) const108     IVec2 getScreenSize(void) const
109     {
110         return m_window->getSize();
111     }
112 
113     void setSurfaceSize(IVec2 size);
114 
115     virtual void processEvents(void);
116 
117 private:
118     Window *m_window;
119     int32_t m_format;
120 };
121 
122 class NativeWindowFactory : public eglu::NativeWindowFactory
123 {
124 public:
125     NativeWindowFactory(WindowRegistry &windowRegistry);
126     ~NativeWindowFactory(void);
127 
128     virtual eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
129                                              const eglu::WindowParams &params) const;
130     virtual eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay, EGLDisplay display, EGLConfig config,
131                                              const EGLAttrib *attribList, const eglu::WindowParams &params) const;
132 
133 private:
134     virtual eglu::NativeWindow *createWindow(const eglu::WindowParams &params, int32_t format) const;
135 
136     WindowRegistry &m_windowRegistry;
137 };
138 
139 // NativeWindow
140 
NativeWindow(Window * window,int width,int height,int32_t format)141 NativeWindow::NativeWindow(Window *window, int width, int height, int32_t format)
142     : eglu::NativeWindow(WINDOW_CAPABILITIES)
143     , m_window(window)
144     , m_format(format)
145 {
146     // Set up buffers.
147     setSurfaceSize(IVec2(width, height));
148 }
149 
~NativeWindow(void)150 NativeWindow::~NativeWindow(void)
151 {
152     m_window->release();
153 }
154 
processEvents(void)155 void NativeWindow::processEvents(void)
156 {
157     if (m_window->isPendingDestroy())
158         throw eglu::WindowDestroyedError("Window has been destroyed");
159 }
160 
setSurfaceSize(tcu::IVec2 size)161 void NativeWindow::setSurfaceSize(tcu::IVec2 size)
162 {
163     m_window->setBuffersGeometry(size.x() != eglu::WindowParams::SIZE_DONT_CARE ? size.x() : 0,
164                                  size.y() != eglu::WindowParams::SIZE_DONT_CARE ? size.y() : 0, m_format);
165 }
166 
167 // NativeWindowFactory
168 
NativeWindowFactory(WindowRegistry & windowRegistry)169 NativeWindowFactory::NativeWindowFactory(WindowRegistry &windowRegistry)
170     : eglu::NativeWindowFactory("default", "Default display", WINDOW_CAPABILITIES)
171     , m_windowRegistry(windowRegistry)
172 {
173 }
174 
~NativeWindowFactory(void)175 NativeWindowFactory::~NativeWindowFactory(void)
176 {
177 }
178 
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const179 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
180                                                       const eglu::WindowParams &params) const
181 {
182     DE_UNREF(nativeDisplay);
183     return createWindow(params, WINDOW_FORMAT_RGBA_8888);
184 }
185 
createWindow(eglu::NativeDisplay * nativeDisplay,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList,const eglu::WindowParams & params) const186 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay, EGLDisplay display,
187                                                       EGLConfig config, const EGLAttrib *attribList,
188                                                       const eglu::WindowParams &params) const
189 {
190     const int32_t format =
191         (int32_t)eglu::getConfigAttribInt(nativeDisplay->getLibrary(), display, config, EGL_NATIVE_VISUAL_ID);
192     DE_UNREF(nativeDisplay && attribList);
193     return createWindow(params, format);
194 }
195 
createWindow(const eglu::WindowParams & params,int32_t format) const196 eglu::NativeWindow *NativeWindowFactory::createWindow(const eglu::WindowParams &params, int32_t format) const
197 {
198     Window *window = m_windowRegistry.tryAcquireWindow();
199 
200     if (!window)
201         throw ResourceError("Native window is not available", DE_NULL, __FILE__, __LINE__);
202 
203     return new NativeWindow(window, params.width, params.height, format);
204 }
205 
206 // NativeDisplayFactory
207 
NativeDisplayFactory(WindowRegistry & windowRegistry)208 NativeDisplayFactory::NativeDisplayFactory(WindowRegistry &windowRegistry)
209     : eglu::NativeDisplayFactory("default", "Default display", DISPLAY_CAPABILITIES)
210 {
211     m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(windowRegistry));
212 }
213 
createDisplay(const EGLAttrib * attribList) const214 eglu::NativeDisplay *NativeDisplayFactory::createDisplay(const EGLAttrib *attribList) const
215 {
216     DE_UNREF(attribList);
217     return new NativeDisplay();
218 }
219 
220 // Vulkan
221 
222 class VulkanLibrary : public vk::Library
223 {
224 public:
VulkanLibrary(const char * libraryPath)225     VulkanLibrary(const char *libraryPath)
226         : m_library(libraryPath != DE_NULL ? libraryPath : "libvulkan.so")
227         , m_driver(m_library)
228     {
229     }
230 
getPlatformInterface(void) const231     const vk::PlatformInterface &getPlatformInterface(void) const
232     {
233         return m_driver;
234     }
235 
getFunctionLibrary(void) const236     const tcu::FunctionLibrary &getFunctionLibrary(void) const
237     {
238         return m_library;
239     }
240 
241 private:
242     const tcu::DynamicFunctionLibrary m_library;
243     const vk::PlatformDriver m_driver;
244 };
245 
246 DE_STATIC_ASSERT(sizeof(vk::pt::AndroidNativeWindowPtr) == sizeof(ANativeWindow *));
247 
248 class VulkanWindow : public vk::wsi::AndroidWindowInterface
249 {
250 public:
VulkanWindow(tcu::Android::Window & window)251     VulkanWindow(tcu::Android::Window &window)
252         : vk::wsi::AndroidWindowInterface(vk::pt::AndroidNativeWindowPtr(window.getNativeWindow()))
253         , m_window(window)
254     {
255     }
256 
setVisible(bool visible)257     void setVisible(bool visible)
258     {
259         DE_UNREF(visible);
260     }
261 
resize(const UVec2 & newSize)262     void resize(const UVec2 &newSize)
263     {
264         DE_UNREF(newSize);
265     }
266 
setMinimized(bool minimized)267     void setMinimized(bool minimized)
268     {
269         DE_UNREF(minimized);
270         TCU_THROW(NotSupportedError, "Minimized on Android is not implemented");
271     }
272 
~VulkanWindow(void)273     ~VulkanWindow(void)
274     {
275         m_window.release();
276     }
277 
278 private:
279     tcu::Android::Window &m_window;
280 };
281 
282 class VulkanDisplay : public vk::wsi::Display
283 {
284 public:
VulkanDisplay(WindowRegistry & windowRegistry)285     VulkanDisplay(WindowRegistry &windowRegistry) : m_windowRegistry(windowRegistry)
286     {
287     }
288 
createWindow(const Maybe<UVec2> & initialSize) const289     vk::wsi::Window *createWindow(const Maybe<UVec2> &initialSize) const
290     {
291         Window *const window = m_windowRegistry.tryAcquireWindow();
292 
293         if (window)
294         {
295             try
296             {
297                 if (initialSize)
298                     window->setBuffersGeometry((int)initialSize->x(), (int)initialSize->y(), WINDOW_FORMAT_RGBA_8888);
299 
300                 return new VulkanWindow(*window);
301             }
302             catch (...)
303             {
304                 window->release();
305                 throw;
306             }
307         }
308         else
309             TCU_THROW(ResourceError, "Native window is not available");
310     }
311 
312 private:
313     WindowRegistry &m_windowRegistry;
314 };
315 
getTotalSystemMemory(ANativeActivity * activity)316 static size_t getTotalSystemMemory(ANativeActivity *activity)
317 {
318     const size_t MiB = (size_t)(1 << 20);
319 
320     try
321     {
322         const size_t totalMemory = getTotalAndroidSystemMemory(activity);
323         print("Device has %.2f MiB of system memory\n", static_cast<double>(totalMemory) / static_cast<double>(MiB));
324         return totalMemory;
325     }
326     catch (const std::exception &e)
327     {
328         // Use relatively high fallback size to encourage CDD-compliant behavior
329         const size_t fallbackSize = (sizeof(void *) == sizeof(uint64_t)) ? 2048 * MiB : 1024 * MiB;
330 
331         print("WARNING: Failed to determine system memory size required by CDD: %s\n", e.what());
332         print("WARNING: Using fall-back size of %.2f MiB\n", double(fallbackSize) / double(MiB));
333 
334         return fallbackSize;
335     }
336 }
337 
338 // Platform
339 
Platform(NativeActivity & activity)340 Platform::Platform(NativeActivity &activity)
341     : m_activity(activity)
342     , m_totalSystemMemory(getTotalSystemMemory(activity.getNativeActivity()))
343 {
344     m_nativeDisplayFactoryRegistry.registerFactory(new NativeDisplayFactory(m_windowRegistry));
345     m_contextFactoryRegistry.registerFactory(new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
346 }
347 
~Platform(void)348 Platform::~Platform(void)
349 {
350 }
351 
processEvents(void)352 bool Platform::processEvents(void)
353 {
354     m_windowRegistry.garbageCollect();
355     return true;
356 }
357 
createLibrary(const char * libraryPath) const358 vk::Library *Platform::createLibrary(const char *libraryPath) const
359 {
360     return new VulkanLibrary(libraryPath);
361 }
362 
describePlatform(std::ostream & dst) const363 void Platform::describePlatform(std::ostream &dst) const
364 {
365     tcu::Android::describePlatform(m_activity.getNativeActivity(), dst);
366 }
367 
getMemoryLimits(tcu::PlatformMemoryLimits & limits) const368 void Platform::getMemoryLimits(tcu::PlatformMemoryLimits &limits) const
369 {
370     // Worst-case estimates
371     const size_t MiB          = (size_t)(1 << 20);
372     const size_t baseMemUsage = 400 * MiB;
373 
374 #if (DE_PTR_SIZE == 4)
375     // Some tests, such as:
376     //
377     // dEQP-VK.api.object_management.max_concurrent.*
378     // dEQP-VK.memory.allocation.random.*
379     //
380     // when run in succession, can lead to system memory fragmentation. It depends on the allocator, and on some 32-bit
381     // systems can lead to out of memory errors. As a workaround, we use a smaller amount of memory on 32-bit systems,
382     // as this typically avoids out of memory errors caused by fragmentation.
383     const double safeUsageRatio = 0.1;
384 #else
385     const double safeUsageRatio = 0.25;
386 #endif
387 
388     limits.totalSystemMemory =
389         de::max((size_t)(double(int64_t(m_totalSystemMemory) - int64_t(baseMemUsage)) * safeUsageRatio), 16 * MiB);
390 
391     // Assume UMA architecture
392     limits.totalDeviceLocalMemory = 0;
393 
394     // Reasonable worst-case estimates
395     limits.deviceMemoryAllocationGranularity = 64 * 1024;
396     limits.devicePageSize                    = 4096;
397     limits.devicePageTableEntrySize          = 8;
398     limits.devicePageTableHierarchyLevels    = 3;
399 }
400 
createWsiDisplay(vk::wsi::Type wsiType) const401 vk::wsi::Display *Platform::createWsiDisplay(vk::wsi::Type wsiType) const
402 {
403     if (wsiType == vk::wsi::TYPE_ANDROID)
404         return new VulkanDisplay(const_cast<WindowRegistry &>(m_windowRegistry));
405     else
406         TCU_THROW(NotSupportedError, "WSI type not supported on Android");
407 }
408 
hasDisplay(vk::wsi::Type wsiType) const409 bool Platform::hasDisplay(vk::wsi::Type wsiType) const
410 {
411     if (wsiType == vk::wsi::TYPE_ANDROID)
412         return true;
413 
414     return false;
415 }
416 
417 } // namespace Android
418 } // namespace tcu
419