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