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