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 platform.
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)(eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY |
52 eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM |
53 eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_PLATFORM_EXTENSION |
54 eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
55 eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE);
56
57 class NativeDisplay : public eglu::NativeDisplay
58 {
59 public:
NativeDisplay(void)60 NativeDisplay (void) : eglu::NativeDisplay(DISPLAY_CAPABILITIES), m_library("libEGL.so") {}
~NativeDisplay(void)61 virtual ~NativeDisplay (void) {}
62
getLegacyNative(void)63 virtual EGLNativeDisplayType getLegacyNative (void) { return EGL_DEFAULT_DISPLAY; }
getLibrary(void) const64 virtual const eglw::Library& getLibrary (void) const { return m_library; }
65
66 private:
67 eglw::DefaultLibrary m_library;
68 };
69
70 class NativeDisplayFactory : public eglu::NativeDisplayFactory
71 {
72 public:
73 NativeDisplayFactory (WindowRegistry& windowRegistry);
~NativeDisplayFactory(void)74 ~NativeDisplayFactory (void) {}
75
76 virtual eglu::NativeDisplay* createDisplay (const EGLAttrib* attribList) const;
77 };
78
79 class NativeWindow : public eglu::NativeWindow
80 {
81 public:
82 NativeWindow (Window* window, int width, int height, int32_t format);
83 virtual ~NativeWindow (void);
84
getLegacyNative(void)85 virtual EGLNativeWindowType getLegacyNative (void) { return m_window->getNativeWindow(); }
getPlatformExtension(void)86 virtual EGLNativeWindowType getPlatformExtension (void) { return m_window->getNativeWindow(); }
getPlatformNative(void)87 virtual EGLNativeWindowType getPlatformNative (void) { return m_window->getNativeWindow(); }
getScreenSize(void) const88 IVec2 getScreenSize (void) const { return m_window->getSize(); }
89
90 void setSurfaceSize (IVec2 size);
91
92 virtual void processEvents (void);
93
94 private:
95 Window* m_window;
96 int32_t m_format;
97 };
98
99 class NativeWindowFactory : public eglu::NativeWindowFactory
100 {
101 public:
102 NativeWindowFactory (WindowRegistry& windowRegistry);
103 ~NativeWindowFactory (void);
104
105 virtual eglu::NativeWindow* createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
106 virtual eglu::NativeWindow* createWindow (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, const eglu::WindowParams& params) const;
107
108 private:
109 virtual eglu::NativeWindow* createWindow (const eglu::WindowParams& params, int32_t format) const;
110
111 WindowRegistry& m_windowRegistry;
112 };
113
114 // NativeWindow
115
NativeWindow(Window * window,int width,int height,int32_t format)116 NativeWindow::NativeWindow (Window* window, int width, int height, int32_t format)
117 : eglu::NativeWindow (WINDOW_CAPABILITIES)
118 , m_window (window)
119 , m_format (format)
120 {
121 // Set up buffers.
122 setSurfaceSize(IVec2(width, height));
123 }
124
~NativeWindow(void)125 NativeWindow::~NativeWindow (void)
126 {
127 m_window->release();
128 }
129
processEvents(void)130 void NativeWindow::processEvents (void)
131 {
132 if (m_window->isPendingDestroy())
133 throw eglu::WindowDestroyedError("Window has been destroyed");
134 }
135
setSurfaceSize(tcu::IVec2 size)136 void NativeWindow::setSurfaceSize (tcu::IVec2 size)
137 {
138 m_window->setBuffersGeometry(size.x() != eglu::WindowParams::SIZE_DONT_CARE ? size.x() : 0,
139 size.y() != eglu::WindowParams::SIZE_DONT_CARE ? size.y() : 0,
140 m_format);
141 }
142
143 // NativeWindowFactory
144
NativeWindowFactory(WindowRegistry & windowRegistry)145 NativeWindowFactory::NativeWindowFactory (WindowRegistry& windowRegistry)
146 : eglu::NativeWindowFactory ("default", "Default display", WINDOW_CAPABILITIES)
147 , m_windowRegistry (windowRegistry)
148 {
149 }
150
~NativeWindowFactory(void)151 NativeWindowFactory::~NativeWindowFactory (void)
152 {
153 }
154
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const155 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
156 {
157 DE_UNREF(nativeDisplay);
158 return createWindow(params, WINDOW_FORMAT_RGBA_8888);
159 }
160
createWindow(eglu::NativeDisplay * nativeDisplay,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList,const eglu::WindowParams & params) const161 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, const eglu::WindowParams& params) const
162 {
163 const int32_t format = (int32_t)eglu::getConfigAttribInt(nativeDisplay->getLibrary(), display, config, EGL_NATIVE_VISUAL_ID);
164 DE_UNREF(nativeDisplay && attribList);
165 return createWindow(params, format);
166 }
167
createWindow(const eglu::WindowParams & params,int32_t format) const168 eglu::NativeWindow* NativeWindowFactory::createWindow (const eglu::WindowParams& params, int32_t format) const
169 {
170 Window* window = m_windowRegistry.tryAcquireWindow();
171
172 if (!window)
173 throw ResourceError("Native window is not available", DE_NULL, __FILE__, __LINE__);
174
175 return new NativeWindow(window, params.width, params.height, format);
176 }
177
178 // NativeDisplayFactory
179
NativeDisplayFactory(WindowRegistry & windowRegistry)180 NativeDisplayFactory::NativeDisplayFactory (WindowRegistry& windowRegistry)
181 : eglu::NativeDisplayFactory("default", "Default display", DISPLAY_CAPABILITIES)
182 {
183 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(windowRegistry));
184 }
185
createDisplay(const EGLAttrib * attribList) const186 eglu::NativeDisplay* NativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
187 {
188 DE_UNREF(attribList);
189 return new NativeDisplay();
190 }
191
192 // Vulkan
193
194 class VulkanLibrary : public vk::Library
195 {
196 public:
VulkanLibrary(void)197 VulkanLibrary (void)
198 : m_library ("libvulkan.so")
199 , m_driver (m_library)
200 {
201 }
202
getPlatformInterface(void) const203 const vk::PlatformInterface& getPlatformInterface (void) const
204 {
205 return m_driver;
206 }
207
getFunctionLibrary(void) const208 const tcu::FunctionLibrary& getFunctionLibrary (void) const
209 {
210 return m_library;
211 }
212
213 private:
214 const tcu::DynamicFunctionLibrary m_library;
215 const vk::PlatformDriver m_driver;
216 };
217
218 DE_STATIC_ASSERT(sizeof(vk::pt::AndroidNativeWindowPtr) == sizeof(ANativeWindow*));
219
220 class VulkanWindow : public vk::wsi::AndroidWindowInterface
221 {
222 public:
VulkanWindow(tcu::Android::Window & window)223 VulkanWindow (tcu::Android::Window& window)
224 : vk::wsi::AndroidWindowInterface (vk::pt::AndroidNativeWindowPtr(window.getNativeWindow()))
225 , m_window (window)
226 {
227 }
228
setVisible(bool visible)229 void setVisible(bool visible)
230 {
231 DE_UNREF(visible);
232 }
233
resize(const UVec2 & newSize)234 void resize(const UVec2& newSize)
235 {
236 DE_UNREF(newSize);
237 }
238
~VulkanWindow(void)239 ~VulkanWindow (void)
240 {
241 m_window.release();
242 }
243
244 private:
245 tcu::Android::Window& m_window;
246 };
247
248 class VulkanDisplay : public vk::wsi::Display
249 {
250 public:
VulkanDisplay(WindowRegistry & windowRegistry)251 VulkanDisplay (WindowRegistry& windowRegistry)
252 : m_windowRegistry(windowRegistry)
253 {
254 }
255
createWindow(const Maybe<UVec2> & initialSize) const256 vk::wsi::Window* createWindow (const Maybe<UVec2>& initialSize) const
257 {
258 Window* const window = m_windowRegistry.tryAcquireWindow();
259
260 if (window)
261 {
262 try
263 {
264 if (initialSize)
265 window->setBuffersGeometry((int)initialSize->x(), (int)initialSize->y(), WINDOW_FORMAT_RGBA_8888);
266
267 return new VulkanWindow(*window);
268 }
269 catch (...)
270 {
271 window->release();
272 throw;
273 }
274 }
275 else
276 TCU_THROW(ResourceError, "Native window is not available");
277 }
278
279 private:
280 WindowRegistry& m_windowRegistry;
281 };
282
getTotalSystemMemory(ANativeActivity * activity)283 static size_t getTotalSystemMemory (ANativeActivity* activity)
284 {
285 const size_t MiB = (size_t)(1<<20);
286
287 try
288 {
289 const size_t totalMemory = getTotalAndroidSystemMemory(activity);
290 print("Device has %.2f MiB of system memory\n", static_cast<double>(totalMemory) / static_cast<double>(MiB));
291 return totalMemory;
292 }
293 catch (const std::exception& e)
294 {
295 // Use relatively high fallback size to encourage CDD-compliant behavior
296 const size_t fallbackSize = (sizeof(void*) == sizeof(deUint64)) ? 2048*MiB : 1024*MiB;
297
298 print("WARNING: Failed to determine system memory size required by CDD: %s\n", e.what());
299 print("WARNING: Using fall-back size of %.2f MiB\n", double(fallbackSize) / double(MiB));
300
301 return fallbackSize;
302 }
303 }
304
305 // Platform
306
Platform(NativeActivity & activity)307 Platform::Platform (NativeActivity& activity)
308 : m_activity (activity)
309 , m_totalSystemMemory (getTotalSystemMemory(activity.getNativeActivity()))
310 {
311 m_nativeDisplayFactoryRegistry.registerFactory(new NativeDisplayFactory(m_windowRegistry));
312 m_contextFactoryRegistry.registerFactory(new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
313 }
314
~Platform(void)315 Platform::~Platform (void)
316 {
317 }
318
processEvents(void)319 bool Platform::processEvents (void)
320 {
321 m_windowRegistry.garbageCollect();
322 return true;
323 }
324
createLibrary(void) const325 vk::Library* Platform::createLibrary (void) const
326 {
327 return new VulkanLibrary();
328 }
329
describePlatform(std::ostream & dst) const330 void Platform::describePlatform (std::ostream& dst) const
331 {
332 tcu::Android::describePlatform(m_activity.getNativeActivity(), dst);
333 }
334
getMemoryLimits(vk::PlatformMemoryLimits & limits) const335 void Platform::getMemoryLimits (vk::PlatformMemoryLimits& limits) const
336 {
337 // Worst-case estimates
338 const size_t MiB = (size_t)(1<<20);
339 const size_t baseMemUsage = 400*MiB;
340 const double safeUsageRatio = 0.25;
341
342 limits.totalSystemMemory = de::max((size_t)(double(deInt64(m_totalSystemMemory)-deInt64(baseMemUsage)) * safeUsageRatio), 16*MiB);
343
344 // Assume UMA architecture
345 limits.totalDeviceLocalMemory = 0;
346
347 // Reasonable worst-case estimates
348 limits.deviceMemoryAllocationGranularity = 64*1024;
349 limits.devicePageSize = 4096;
350 limits.devicePageTableEntrySize = 8;
351 limits.devicePageTableHierarchyLevels = 3;
352 }
353
createWsiDisplay(vk::wsi::Type wsiType) const354 vk::wsi::Display* Platform::createWsiDisplay (vk::wsi::Type wsiType) const
355 {
356 if (wsiType == vk::wsi::TYPE_ANDROID)
357 return new VulkanDisplay(const_cast<WindowRegistry&>(m_windowRegistry));
358 else
359 TCU_THROW(NotSupportedError, "WSI type not supported on Android");
360 }
361
hasDisplay(vk::wsi::Type wsiType) const362 bool Platform::hasDisplay (vk::wsi::Type wsiType) const
363 {
364 if (wsiType == vk::wsi::TYPE_ANDROID)
365 return true;
366
367 return false;
368 }
369
370 } // Android
371 } // tcu
372