1 /*------------------------------------------------------------------------- 2 * drawElements Quality Program Tester Core 3 * ---------------------------------------- 4 * 5 * Copyright 2015 Intel Corporation 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 surfaceless platform 22 *//*--------------------------------------------------------------------*/ 23 24 #include "tcuSurfacelessPlatform.hpp" 25 26 #include <string> 27 #include <vector> 28 #include <sys/utsname.h> 29 30 #include "deDynamicLibrary.hpp" 31 #include "deMemory.h" 32 #include "deSTLUtil.hpp" 33 #include "egluUtil.hpp" 34 #include "egluGLUtil.hpp" 35 #include "eglwEnums.hpp" 36 #include "eglwLibrary.hpp" 37 #include "gluPlatform.hpp" 38 #include "gluRenderConfig.hpp" 39 #include "glwInitES20Direct.hpp" 40 #include "glwInitES30Direct.hpp" 41 #include "glwInitFunctions.hpp" 42 #include "tcuFunctionLibrary.hpp" 43 #include "tcuPixelFormat.hpp" 44 #include "tcuPlatform.hpp" 45 #include "tcuRenderTarget.hpp" 46 #include "vkPlatform.hpp" 47 48 #include <EGL/egl.h> 49 50 using std::string; 51 using std::vector; 52 53 #if !defined(EGL_KHR_create_context) 54 #define EGL_CONTEXT_FLAGS_KHR 0x30FC 55 #define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 56 #define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB 57 #define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002 58 #define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 59 #define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 60 #define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 61 #define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD 62 #define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD 63 #define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004 64 #define EGL_KHR_create_context 1 65 #define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF 66 #define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE 67 #define EGL_OPENGL_ES3_BIT_KHR 0x00000040 68 #endif // EGL_KHR_create_context 69 70 // Default library names 71 #if !defined(DEQP_GLES2_LIBRARY_PATH) 72 # define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so" 73 #endif 74 75 #if !defined(DEQP_GLES3_LIBRARY_PATH) 76 # define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH 77 #endif 78 79 #if !defined(DEQP_OPENGL_LIBRARY_PATH) 80 # define DEQP_OPENGL_LIBRARY_PATH "libGL.so" 81 #endif 82 83 namespace tcu 84 { 85 namespace surfaceless 86 { 87 88 class VulkanLibrary : public vk::Library 89 { 90 public: 91 VulkanLibrary (void) 92 : m_library ("libvulkan.so.1") 93 , m_driver (m_library) 94 { 95 } 96 97 const vk::PlatformInterface& getPlatformInterface (void) const 98 { 99 return m_driver; 100 } 101 102 private: 103 const tcu::DynamicFunctionLibrary m_library; 104 const vk::PlatformDriver m_driver; 105 }; 106 107 // Copied from tcuX11Platform.cpp 108 class VulkanPlatform : public vk::Platform 109 { 110 public: 111 vk::Library* createLibrary (void) const 112 { 113 return new VulkanLibrary(); 114 } 115 116 void describePlatform (std::ostream& dst) const 117 { 118 utsname sysInfo; 119 120 deMemset(&sysInfo, 0, sizeof(sysInfo)); 121 122 if (uname(&sysInfo) != 0) 123 throw std::runtime_error("uname() failed"); 124 125 dst << "OS: " << sysInfo.sysname << " " << sysInfo.release << " " << sysInfo.version << "\n"; 126 dst << "CPU: " << sysInfo.machine << "\n"; 127 } 128 129 // FINISHME: Query actual memory limits. 130 // 131 // These hard-coded memory limits were copied from tcuX11Platform.cpp, 132 // and they work well enough for Intel platforms. 133 void getMemoryLimits (vk::PlatformMemoryLimits& limits) const 134 { 135 limits.totalSystemMemory = 256*1024*1024; 136 limits.totalDeviceLocalMemory = 128*1024*1024; 137 limits.deviceMemoryAllocationGranularity = 64*1024; 138 limits.devicePageSize = 4096; 139 limits.devicePageTableEntrySize = 8; 140 limits.devicePageTableHierarchyLevels = 3; 141 } 142 }; 143 144 bool isEGLExtensionSupported( 145 const eglw::Library& egl, 146 eglw::EGLDisplay display, 147 const std::string& extName) 148 { 149 const vector<string> exts = eglu::getClientExtensions(egl); 150 return de::contains(exts.begin(), exts.end(), extName); 151 } 152 153 class GetProcFuncLoader : public glw::FunctionLoader 154 { 155 public: 156 GetProcFuncLoader(const eglw::Library& egl): m_egl(egl) 157 { 158 } 159 160 glw::GenericFuncType get(const char* name) const 161 { 162 return (glw::GenericFuncType)m_egl.getProcAddress(name); 163 } 164 protected: 165 const eglw::Library& m_egl; 166 }; 167 168 class DynamicFuncLoader : public glw::FunctionLoader 169 { 170 public: 171 DynamicFuncLoader(de::DynamicLibrary* library): m_library(library) 172 { 173 } 174 175 glw::GenericFuncType get(const char* name) const 176 { 177 return (glw::GenericFuncType)m_library->getFunction(name); 178 } 179 180 private: 181 de::DynamicLibrary* m_library; 182 }; 183 184 class Platform : public tcu::Platform, public glu::Platform 185 { 186 public: 187 Platform (void); 188 const glu::Platform& getGLPlatform (void) const { return *this; } 189 const vk::Platform& getVulkanPlatform (void) const { return m_vkPlatform; } 190 191 private: 192 VulkanPlatform m_vkPlatform; 193 }; 194 195 class ContextFactory : public glu::ContextFactory 196 { 197 public: 198 ContextFactory (void); 199 glu::RenderContext* createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const; 200 }; 201 202 class EglRenderContext : public glu::RenderContext 203 { 204 public: 205 EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine); 206 ~EglRenderContext(void); 207 208 glu::ContextType getType (void) const { return m_contextType; } 209 const glw::Functions& getFunctions (void) const { return m_glFunctions; } 210 const tcu::RenderTarget& getRenderTarget (void) const; 211 void postIterate (void); 212 213 private: 214 const eglw::DefaultLibrary m_egl; 215 const glu::ContextType m_contextType; 216 eglw::EGLDisplay m_eglDisplay; 217 eglw::EGLContext m_eglContext; 218 de::DynamicLibrary* m_glLibrary; 219 glw::Functions m_glFunctions; 220 tcu::RenderTarget m_renderTarget; 221 }; 222 223 Platform::Platform(void) 224 { 225 m_contextFactoryRegistry.registerFactory(new ContextFactory()); 226 } 227 228 ContextFactory::ContextFactory() 229 : glu::ContextFactory("default", "EGL surfaceless context") 230 {} 231 232 glu::RenderContext* ContextFactory::createContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const 233 { 234 return new EglRenderContext(config, cmdLine); 235 } 236 237 EglRenderContext::EglRenderContext(const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) 238 : m_egl("libEGL.so") 239 , m_contextType(config.type) 240 , m_eglDisplay(EGL_NO_DISPLAY) 241 , m_eglContext(EGL_NO_CONTEXT) 242 , m_renderTarget( 243 config.width, 244 config.height, 245 tcu::PixelFormat( 246 config.redBits, 247 config.greenBits, 248 config.blueBits, 249 config.alphaBits), 250 config.depthBits, 251 config.stencilBits, 252 config.numSamples) 253 254 { 255 vector<eglw::EGLint> context_attribs; 256 vector<eglw::EGLint> frame_buffer_attribs; 257 vector<eglw::EGLint> surface_attribs; 258 259 const glu::ContextType& contextType = config.type; 260 eglw::EGLint eglMajorVersion; 261 eglw::EGLint eglMinorVersion; 262 eglw::EGLint flags = 0; 263 eglw::EGLint num_configs; 264 eglw::EGLConfig egl_config; 265 eglw::EGLSurface egl_surface; 266 267 (void) cmdLine; 268 269 m_eglDisplay = m_egl.getDisplay(NULL); 270 EGLU_CHECK_MSG(m_egl, "eglGetDisplay()"); 271 if (m_eglDisplay == EGL_NO_DISPLAY) 272 throw tcu::ResourceError("eglGetDisplay() failed"); 273 274 EGLU_CHECK_CALL(m_egl, initialize(m_eglDisplay, &eglMajorVersion, &eglMinorVersion)); 275 276 frame_buffer_attribs.push_back(EGL_RENDERABLE_TYPE); 277 switch(contextType.getMajorVersion()) 278 { 279 case 3: 280 frame_buffer_attribs.push_back(EGL_OPENGL_ES3_BIT); 281 break; 282 case 2: 283 frame_buffer_attribs.push_back(EGL_OPENGL_ES2_BIT); 284 break; 285 default: 286 frame_buffer_attribs.push_back(EGL_OPENGL_ES_BIT); 287 } 288 289 frame_buffer_attribs.push_back(EGL_SURFACE_TYPE); 290 switch (config.surfaceType) 291 { 292 case glu::RenderConfig::SURFACETYPE_DONT_CARE: 293 frame_buffer_attribs.push_back(EGL_DONT_CARE); 294 break; 295 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE: 296 break; 297 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 298 frame_buffer_attribs.push_back(EGL_PBUFFER_BIT); 299 surface_attribs.push_back(EGL_WIDTH); 300 surface_attribs.push_back(config.width); 301 surface_attribs.push_back(EGL_HEIGHT); 302 surface_attribs.push_back(config.height); 303 break; 304 case glu::RenderConfig::SURFACETYPE_WINDOW: 305 throw tcu::NotSupportedError("surfaceless platform does not support --deqp-surface-type=window"); 306 case glu::RenderConfig::SURFACETYPE_LAST: 307 TCU_CHECK_INTERNAL(false); 308 } 309 310 surface_attribs.push_back(EGL_NONE); 311 312 frame_buffer_attribs.push_back(EGL_RED_SIZE); 313 frame_buffer_attribs.push_back(config.redBits); 314 315 frame_buffer_attribs.push_back(EGL_GREEN_SIZE); 316 frame_buffer_attribs.push_back(config.greenBits); 317 318 frame_buffer_attribs.push_back(EGL_BLUE_SIZE); 319 frame_buffer_attribs.push_back(config.blueBits); 320 321 frame_buffer_attribs.push_back(EGL_ALPHA_SIZE); 322 frame_buffer_attribs.push_back(config.alphaBits); 323 324 frame_buffer_attribs.push_back(EGL_DEPTH_SIZE); 325 frame_buffer_attribs.push_back(config.depthBits); 326 327 frame_buffer_attribs.push_back(EGL_STENCIL_SIZE); 328 frame_buffer_attribs.push_back(config.stencilBits); 329 330 frame_buffer_attribs.push_back(EGL_NONE); 331 332 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], NULL, 0, &num_configs)) 333 throw tcu::ResourceError("surfaceless couldn't find any config"); 334 335 if (!eglChooseConfig(m_eglDisplay, &frame_buffer_attribs[0], &egl_config, 1, &num_configs)) 336 throw tcu::ResourceError("surfaceless couldn't find any config"); 337 338 switch (config.surfaceType) 339 { 340 case glu::RenderConfig::SURFACETYPE_DONT_CARE: 341 egl_surface = EGL_NO_SURFACE; 342 break; 343 case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC: 344 egl_surface = eglCreatePbufferSurface(m_eglDisplay, egl_config, &surface_attribs[0]); 345 break; 346 } 347 348 context_attribs.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR); 349 context_attribs.push_back(contextType.getMajorVersion()); 350 context_attribs.push_back(EGL_CONTEXT_MINOR_VERSION_KHR); 351 context_attribs.push_back(contextType.getMinorVersion()); 352 353 switch (contextType.getProfile()) 354 { 355 case glu::PROFILE_ES: 356 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_ES_API)); 357 break; 358 case glu::PROFILE_CORE: 359 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API)); 360 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); 361 context_attribs.push_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR); 362 break; 363 case glu::PROFILE_COMPATIBILITY: 364 EGLU_CHECK_CALL(m_egl, bindAPI(EGL_OPENGL_API)); 365 context_attribs.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR); 366 context_attribs.push_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); 367 break; 368 case glu::PROFILE_LAST: 369 TCU_CHECK_INTERNAL(false); 370 } 371 372 if ((contextType.getFlags() & glu::CONTEXT_DEBUG) != 0) 373 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR; 374 375 if ((contextType.getFlags() & glu::CONTEXT_ROBUST) != 0) 376 flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; 377 378 if ((contextType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0) 379 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR; 380 381 context_attribs.push_back(EGL_CONTEXT_FLAGS_KHR); 382 context_attribs.push_back(flags); 383 384 context_attribs.push_back(EGL_NONE); 385 386 m_eglContext = m_egl.createContext(m_eglDisplay, egl_config, EGL_NO_CONTEXT, &context_attribs[0]); 387 EGLU_CHECK_MSG(m_egl, "eglCreateContext()"); 388 if (!m_eglContext) 389 throw tcu::ResourceError("eglCreateContext failed"); 390 391 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, egl_surface, egl_surface, m_eglContext)); 392 393 if ((eglMajorVersion == 1 && eglMinorVersion >= 5) || 394 isEGLExtensionSupported(m_egl, m_eglDisplay, "EGL_KHR_get_all_proc_addresses") || 395 isEGLExtensionSupported(m_egl, EGL_NO_DISPLAY, "EGL_KHR_client_get_all_proc_addresses")) 396 { 397 // Use eglGetProcAddress() for core functions 398 GetProcFuncLoader funcLoader(m_egl); 399 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI()); 400 } 401 #if !defined(DEQP_GLES2_RUNTIME_LOAD) 402 else if (contextType.getAPI() == glu::ApiType::es(2,0)) 403 { 404 glw::initES20Direct(&m_glFunctions); 405 } 406 #endif 407 #if !defined(DEQP_GLES3_RUNTIME_LOAD) 408 else if (contextType.getAPI() == glu::ApiType::es(3,0)) 409 { 410 glw::initES30Direct(&m_glFunctions); 411 } 412 #endif 413 else 414 { 415 const char* libraryPath = NULL; 416 417 if (glu::isContextTypeES(contextType)) 418 { 419 if (contextType.getMinorVersion() <= 2) 420 libraryPath = DEQP_GLES2_LIBRARY_PATH; 421 else 422 libraryPath = DEQP_GLES3_LIBRARY_PATH; 423 } 424 else 425 { 426 libraryPath = DEQP_OPENGL_LIBRARY_PATH; 427 } 428 429 m_glLibrary = new de::DynamicLibrary(libraryPath); 430 431 DynamicFuncLoader funcLoader(m_glLibrary); 432 glu::initCoreFunctions(&m_glFunctions, &funcLoader, contextType.getAPI()); 433 } 434 435 { 436 GetProcFuncLoader extLoader(m_egl); 437 glu::initExtensionFunctions(&m_glFunctions, &extLoader, contextType.getAPI()); 438 } 439 } 440 441 EglRenderContext::~EglRenderContext(void) 442 { 443 try 444 { 445 if (m_eglDisplay != EGL_NO_DISPLAY) 446 { 447 EGLU_CHECK_CALL(m_egl, makeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)); 448 449 if (m_eglContext != EGL_NO_CONTEXT) 450 EGLU_CHECK_CALL(m_egl, destroyContext(m_eglDisplay, m_eglContext)); 451 } 452 453 EGLU_CHECK_CALL(m_egl, terminate(m_eglDisplay)); 454 } 455 catch (...) 456 { 457 } 458 } 459 460 const tcu::RenderTarget& EglRenderContext::getRenderTarget(void) const 461 { 462 return m_renderTarget; 463 } 464 465 void EglRenderContext::postIterate(void) 466 { 467 this->getFunctions().finish(); 468 } 469 470 } // namespace surfaceless 471 } // namespace tcu 472 473 tcu::Platform* createPlatform(void) 474 { 475 return new tcu::surfaceless::Platform(); 476 } 477