Home | History | Annotate | Download | only in android
      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:
     58 									NativeDisplay			(void) : eglu::NativeDisplay(DISPLAY_CAPABILITIES), m_library("libEGL.so") {}
     59 	virtual							~NativeDisplay			(void) {}
     60 
     61 	virtual EGLNativeDisplayType	getLegacyNative			(void)			{ return EGL_DEFAULT_DISPLAY;	}
     62 	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);
     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 
     83 	virtual EGLNativeWindowType		getLegacyNative			(void)			{ return m_window->getNativeWindow();	}
     84 	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 
    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 
    121 NativeWindow::~NativeWindow (void)
    122 {
    123 	m_window->release();
    124 }
    125 
    126 void NativeWindow::processEvents (void)
    127 {
    128 	if (m_window->isPendingDestroy())
    129 		throw eglu::WindowDestroyedError("Window has been destroyed");
    130 }
    131 
    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 
    141 NativeWindowFactory::NativeWindowFactory (WindowRegistry& windowRegistry)
    142 	: eglu::NativeWindowFactory	("default", "Default display", WINDOW_CAPABILITIES)
    143 	, m_windowRegistry			(windowRegistry)
    144 {
    145 }
    146 
    147 NativeWindowFactory::~NativeWindowFactory (void)
    148 {
    149 }
    150 
    151 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 
    157 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 
    164 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 
    176 NativeDisplayFactory::NativeDisplayFactory (WindowRegistry& windowRegistry)
    177 	: eglu::NativeDisplayFactory("default", "Default display", DISPLAY_CAPABILITIES)
    178 {
    179 	m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(windowRegistry));
    180 }
    181 
    182 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:
    193 	VulkanLibrary (void)
    194 		: m_library	("libvulkan.so")
    195 		, m_driver	(m_library)
    196 	{
    197 	}
    198 
    199 	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:
    214 	VulkanWindow (tcu::Android::Window& window)
    215 		: vk::wsi::AndroidWindowInterface	(vk::pt::AndroidNativeWindowPtr(window.getNativeWindow()))
    216 		, m_window							(window)
    217 	{
    218 	}
    219 
    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:
    232 	VulkanDisplay (WindowRegistry& windowRegistry)
    233 		: m_windowRegistry(windowRegistry)
    234 	{
    235 	}
    236 
    237 	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 
    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 
    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 
    298 Platform::~Platform (void)
    299 {
    300 }
    301 
    302 bool Platform::processEvents (void)
    303 {
    304 	m_windowRegistry.garbageCollect();
    305 	return true;
    306 }
    307 
    308 vk::Library* Platform::createLibrary (void) const
    309 {
    310 	return new VulkanLibrary();
    311 }
    312 
    313 void Platform::describePlatform (std::ostream& dst) const
    314 {
    315 	tcu::Android::describePlatform(m_activity.getNativeActivity(), dst);
    316 }
    317 
    318 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 
    337 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