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> 38struct egl_native_pixmap_t; 39DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(void*)); 40DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(struct egl_native_pixmap_t*)); 41DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(ANativeWindow*)); 42 43namespace tcu 44{ 45namespace Android 46{ 47 48using namespace eglw; 49 50static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY; 51static 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 57class NativeDisplay : public eglu::NativeDisplay 58{ 59public: 60 NativeDisplay (void) : eglu::NativeDisplay(DISPLAY_CAPABILITIES), m_library("libEGL.so") {} 61 virtual ~NativeDisplay (void) {} 62 63 virtual EGLNativeDisplayType getLegacyNative (void) { return EGL_DEFAULT_DISPLAY; } 64 virtual const eglw::Library& getLibrary (void) const { return m_library; } 65 66private: 67 eglw::DefaultLibrary m_library; 68}; 69 70class NativeDisplayFactory : public eglu::NativeDisplayFactory 71{ 72public: 73 NativeDisplayFactory (WindowRegistry& windowRegistry); 74 ~NativeDisplayFactory (void) {} 75 76 virtual eglu::NativeDisplay* createDisplay (const EGLAttrib* attribList) const; 77}; 78 79class NativeWindow : public eglu::NativeWindow 80{ 81public: 82 NativeWindow (Window* window, int width, int height, int32_t format); 83 virtual ~NativeWindow (void); 84 85 virtual EGLNativeWindowType getLegacyNative (void) { return m_window->getNativeWindow(); } 86 virtual EGLNativeWindowType getPlatformExtension (void) { return m_window->getNativeWindow(); } 87 virtual EGLNativeWindowType getPlatformNative (void) { return m_window->getNativeWindow(); } 88 IVec2 getScreenSize (void) const { return m_window->getSize(); } 89 90 void setSurfaceSize (IVec2 size); 91 92 virtual void processEvents (void); 93 94private: 95 Window* m_window; 96 int32_t m_format; 97}; 98 99class NativeWindowFactory : public eglu::NativeWindowFactory 100{ 101public: 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 108private: 109 virtual eglu::NativeWindow* createWindow (const eglu::WindowParams& params, int32_t format) const; 110 111 WindowRegistry& m_windowRegistry; 112}; 113 114// NativeWindow 115 116NativeWindow::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 125NativeWindow::~NativeWindow (void) 126{ 127 m_window->release(); 128} 129 130void NativeWindow::processEvents (void) 131{ 132 if (m_window->isPendingDestroy()) 133 throw eglu::WindowDestroyedError("Window has been destroyed"); 134} 135 136void 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 145NativeWindowFactory::NativeWindowFactory (WindowRegistry& windowRegistry) 146 : eglu::NativeWindowFactory ("default", "Default display", WINDOW_CAPABILITIES) 147 , m_windowRegistry (windowRegistry) 148{ 149} 150 151NativeWindowFactory::~NativeWindowFactory (void) 152{ 153} 154 155eglu::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 161eglu::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 168eglu::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 180NativeDisplayFactory::NativeDisplayFactory (WindowRegistry& windowRegistry) 181 : eglu::NativeDisplayFactory("default", "Default display", DISPLAY_CAPABILITIES) 182{ 183 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(windowRegistry)); 184} 185 186eglu::NativeDisplay* NativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const 187{ 188 DE_UNREF(attribList); 189 return new NativeDisplay(); 190} 191 192// Vulkan 193 194class VulkanLibrary : public vk::Library 195{ 196public: 197 VulkanLibrary (const char* libraryPath) 198 : m_library (libraryPath != DE_NULL ? libraryPath : "libvulkan.so") 199 , m_driver (m_library) 200 { 201 } 202 203 const vk::PlatformInterface& getPlatformInterface (void) const 204 { 205 return m_driver; 206 } 207 208 const tcu::FunctionLibrary& getFunctionLibrary (void) const 209 { 210 return m_library; 211 } 212 213private: 214 const tcu::DynamicFunctionLibrary m_library; 215 const vk::PlatformDriver m_driver; 216}; 217 218DE_STATIC_ASSERT(sizeof(vk::pt::AndroidNativeWindowPtr) == sizeof(ANativeWindow*)); 219 220class VulkanWindow : public vk::wsi::AndroidWindowInterface 221{ 222public: 223 VulkanWindow (tcu::Android::Window& window) 224 : vk::wsi::AndroidWindowInterface (vk::pt::AndroidNativeWindowPtr(window.getNativeWindow())) 225 , m_window (window) 226 { 227 } 228 229 void setVisible(bool visible) 230 { 231 DE_UNREF(visible); 232 } 233 234 void resize(const UVec2& newSize) 235 { 236 DE_UNREF(newSize); 237 } 238 239 void setMinimized(bool minimized) 240 { 241 DE_UNREF(minimized); 242 TCU_THROW(NotSupportedError, "Minimized on Android is not implemented"); 243 } 244 245 ~VulkanWindow (void) 246 { 247 m_window.release(); 248 } 249 250private: 251 tcu::Android::Window& m_window; 252}; 253 254class VulkanDisplay : public vk::wsi::Display 255{ 256public: 257 VulkanDisplay (WindowRegistry& windowRegistry) 258 : m_windowRegistry(windowRegistry) 259 { 260 } 261 262 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 285private: 286 WindowRegistry& m_windowRegistry; 287}; 288 289static 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 313Platform::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 321Platform::~Platform (void) 322{ 323} 324 325bool Platform::processEvents (void) 326{ 327 m_windowRegistry.garbageCollect(); 328 return true; 329} 330 331vk::Library* Platform::createLibrary (const char* libraryPath) const 332{ 333 return new VulkanLibrary(libraryPath); 334} 335 336void Platform::describePlatform (std::ostream& dst) const 337{ 338 tcu::Android::describePlatform(m_activity.getNativeActivity(), dst); 339} 340 341void 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 373vk::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 381bool 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