• 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  * \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)(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(const char * libraryPath)197 	VulkanLibrary (const char* libraryPath)
198 		: m_library	(libraryPath != DE_NULL ? libraryPath : "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 
setMinimized(bool minimized)239 	void setMinimized(bool minimized)
240 	{
241 		DE_UNREF(minimized);
242 		TCU_THROW(NotSupportedError, "Minimized on Android is not implemented");
243 	}
244 
~VulkanWindow(void)245 	~VulkanWindow (void)
246 	{
247 		m_window.release();
248 	}
249 
250 private:
251 	tcu::Android::Window&	m_window;
252 };
253 
254 class VulkanDisplay : public vk::wsi::Display
255 {
256 public:
VulkanDisplay(WindowRegistry & windowRegistry)257 	VulkanDisplay (WindowRegistry& windowRegistry)
258 		: m_windowRegistry(windowRegistry)
259 	{
260 	}
261 
createWindow(const Maybe<UVec2> & initialSize) const262 	vk::wsi::Window* createWindow (const Maybe<UVec2>& initialSize) const
263 	{
264 		Window* const	window	= m_windowRegistry.tryAcquireWindow();
265 
266 		if (window)
267 		{
268 			try
269 			{
270 				if (initialSize)
271 					window->setBuffersGeometry((int)initialSize->x(), (int)initialSize->y(), WINDOW_FORMAT_RGBA_8888);
272 
273 				return new VulkanWindow(*window);
274 			}
275 			catch (...)
276 			{
277 				window->release();
278 				throw;
279 			}
280 		}
281 		else
282 			TCU_THROW(ResourceError, "Native window is not available");
283 	}
284 
285 private:
286 	WindowRegistry&		m_windowRegistry;
287 };
288 
getTotalSystemMemory(ANativeActivity * activity)289 static size_t getTotalSystemMemory (ANativeActivity* activity)
290 {
291 	const size_t	MiB		= (size_t)(1<<20);
292 
293 	try
294 	{
295 		const size_t totalMemory = getTotalAndroidSystemMemory(activity);
296 		print("Device has %.2f MiB of system memory\n", static_cast<double>(totalMemory) / static_cast<double>(MiB));
297 		return totalMemory;
298 	}
299 	catch (const std::exception& e)
300 	{
301 		// Use relatively high fallback size to encourage CDD-compliant behavior
302 		const size_t	fallbackSize	= (sizeof(void*) == sizeof(deUint64)) ? 2048*MiB : 1024*MiB;
303 
304 		print("WARNING: Failed to determine system memory size required by CDD: %s\n", e.what());
305 		print("WARNING: Using fall-back size of %.2f MiB\n", double(fallbackSize) / double(MiB));
306 
307 		return fallbackSize;
308 	}
309 }
310 
311 // Platform
312 
Platform(NativeActivity & activity)313 Platform::Platform (NativeActivity& activity)
314 	: m_activity			(activity)
315 	, m_totalSystemMemory	(getTotalSystemMemory(activity.getNativeActivity()))
316 {
317 	m_nativeDisplayFactoryRegistry.registerFactory(new NativeDisplayFactory(m_windowRegistry));
318 	m_contextFactoryRegistry.registerFactory(new eglu::GLContextFactory(m_nativeDisplayFactoryRegistry));
319 }
320 
~Platform(void)321 Platform::~Platform (void)
322 {
323 }
324 
processEvents(void)325 bool Platform::processEvents (void)
326 {
327 	m_windowRegistry.garbageCollect();
328 	return true;
329 }
330 
createLibrary(const char * libraryPath) const331 vk::Library* Platform::createLibrary (const char* libraryPath) const
332 {
333 	return new VulkanLibrary(libraryPath);
334 }
335 
describePlatform(std::ostream & dst) const336 void Platform::describePlatform (std::ostream& dst) const
337 {
338 	tcu::Android::describePlatform(m_activity.getNativeActivity(), dst);
339 }
340 
getMemoryLimits(tcu::PlatformMemoryLimits & limits) const341 void Platform::getMemoryLimits (tcu::PlatformMemoryLimits& limits) const
342 {
343 	// Worst-case estimates
344 	const size_t	MiB				= (size_t)(1<<20);
345 	const size_t	baseMemUsage	= 400*MiB;
346 
347 #if (DE_PTR_SIZE == 4)
348 	// Some tests, such as:
349 	//
350 	// dEQP-VK.api.object_management.max_concurrent.*
351 	// dEQP-VK.memory.allocation.random.*
352 	//
353 	// when run in succession, can lead to system memory fragmentation. It depends on the allocator, and on some 32-bit
354 	// systems can lead to out of memory errors. As a workaround, we use a smaller amount of memory on 32-bit systems,
355 	// as this typically avoids out of memory errors caused by fragmentation.
356 	const double	safeUsageRatio	= 0.1;
357 #else
358 	const double	safeUsageRatio	= 0.25;
359 #endif
360 
361 	limits.totalSystemMemory					= de::max((size_t)(double(deInt64(m_totalSystemMemory)-deInt64(baseMemUsage)) * safeUsageRatio), 16*MiB);
362 
363 	// Assume UMA architecture
364 	limits.totalDeviceLocalMemory				= 0;
365 
366 	// Reasonable worst-case estimates
367 	limits.deviceMemoryAllocationGranularity	= 64*1024;
368 	limits.devicePageSize						= 4096;
369 	limits.devicePageTableEntrySize				= 8;
370 	limits.devicePageTableHierarchyLevels		= 3;
371 }
372 
createWsiDisplay(vk::wsi::Type wsiType) const373 vk::wsi::Display* Platform::createWsiDisplay (vk::wsi::Type wsiType) const
374 {
375 	if (wsiType == vk::wsi::TYPE_ANDROID)
376 		return new VulkanDisplay(const_cast<WindowRegistry&>(m_windowRegistry));
377 	else
378 		TCU_THROW(NotSupportedError, "WSI type not supported on Android");
379 }
380 
hasDisplay(vk::wsi::Type wsiType) const381 bool Platform::hasDisplay (vk::wsi::Type wsiType) const
382 {
383 	if (wsiType == vk::wsi::TYPE_ANDROID)
384 		return true;
385 
386 	return false;
387 }
388 
389 } // Android
390 } // tcu
391