• 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 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