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