1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.opengl.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertTrue; 22 23 import android.app.ActivityManager; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ConfigurationInfo; 27 import android.content.pm.FeatureInfo; 28 import android.content.pm.PackageManager; 29 import android.content.res.Configuration; 30 import android.util.Log; 31 32 import androidx.test.filters.LargeTest; 33 import androidx.test.rule.ActivityTestRule; 34 import androidx.test.runner.AndroidJUnit4; 35 36 import com.android.compatibility.common.util.CddTest; 37 38 import org.junit.Assume; 39 import org.junit.Before; 40 import org.junit.Rule; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 44 import java.util.regex.Matcher; 45 import java.util.regex.Pattern; 46 47 import javax.microedition.khronos.egl.EGL10; 48 import javax.microedition.khronos.egl.EGLConfig; 49 import javax.microedition.khronos.egl.EGLContext; 50 import javax.microedition.khronos.egl.EGLDisplay; 51 52 /** 53 * Test for checking whether the ro.opengles.version property is set to the correct value. 54 */ 55 @LargeTest 56 @RunWith(AndroidJUnit4.class) 57 public class OpenGlEsVersionTest { 58 59 private static final String TAG = OpenGlEsVersionTest.class.getSimpleName(); 60 61 // TODO: switch to android.opengl.EGL14/EGLExt and use the constants from there 62 private static final int EGL_OPENGL_ES_BIT = 0x0001; 63 private static final int EGL_OPENGL_ES2_BIT = 0x0004; 64 private static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040; 65 66 private OpenGlEsVersionCtsActivity mActivity; 67 68 @Rule 69 public ActivityTestRule<OpenGlEsVersionCtsActivity> mActivityRule = 70 new ActivityTestRule<>(OpenGlEsVersionCtsActivity.class); 71 72 @Rule 73 public ActivityTestRule<OpenGlEsVersionCtsActivity> mActivityRelaunchRule = 74 new ActivityTestRule<>(OpenGlEsVersionCtsActivity.class, false, false); 75 76 @Before setup()77 public void setup() { 78 mActivity = mActivityRule.getActivity(); 79 } 80 81 @CddTest(requirement="7.1.4.1/C-0-1") 82 @Test testOpenGlEsVersion()83 public void testOpenGlEsVersion() throws InterruptedException { 84 int detectedMajorVersion = getDetectedMajorVersion(); 85 int reportedVersion = getVersionFromActivityManager(mActivity); 86 87 assertEquals("Reported OpenGL ES version from ActivityManager differs from PackageManager", 88 reportedVersion, getVersionFromPackageManager(mActivity)); 89 90 verifyGlVersionString(1, 1); 91 if (detectedMajorVersion == 2) { 92 restartActivityWithClientVersion(2); 93 verifyGlVersionString(2, getMinorVersion(reportedVersion)); 94 } else if (detectedMajorVersion == 3) { 95 restartActivityWithClientVersion(3); 96 verifyGlVersionString(3, getMinorVersion(reportedVersion)); 97 } 98 } 99 100 @CddTest(requirement="7.1.4.1/C-2-2") 101 @Test testRequiredExtensions()102 public void testRequiredExtensions() throws InterruptedException { 103 int reportedVersion = getVersionFromActivityManager(mActivity); 104 105 if (getMajorVersion(reportedVersion) < 3) 106 return; 107 108 restartActivityWithClientVersion(3); 109 110 String extensions = mActivity.getExtensionsString(); 111 112 if (getMajorVersion(reportedVersion) != 3 || getMinorVersion(reportedVersion) < 1) 113 return; 114 115 final String es31RequiredList[] = { 116 "EXT_texture_sRGB_decode", 117 "KHR_blend_equation_advanced", 118 "KHR_debug", 119 "OES_shader_image_atomic", 120 "OES_texture_stencil8", 121 "OES_texture_storage_multisample_2d_array" 122 }; 123 124 for (int i = 0; i < es31RequiredList.length; ++i) { 125 assertTrue("OpenGL ES version 3.1+ is missing extension " + es31RequiredList[i], 126 hasExtension(extensions, es31RequiredList[i])); 127 } 128 } 129 130 @CddTest(requirement="7.1.4.1/C-2-1,C-5-1,C-4-1") 131 @Test testExtensionPack()132 public void testExtensionPack() throws InterruptedException { 133 // Requirements: 134 // 1. If the device claims support for the system feature, the extension must be available. 135 // 2. If the extension is available, the device must claim support for it. 136 // 3. If the extension is available, it must be correct: 137 // - ES 3.1+ must be supported 138 // - All included extensions must be available 139 140 int reportedVersion = getVersionFromActivityManager(mActivity); 141 boolean hasAepFeature = mActivity.getPackageManager().hasSystemFeature( 142 PackageManager.FEATURE_OPENGLES_EXTENSION_PACK); 143 144 if (getMajorVersion(reportedVersion) != 3 || getMinorVersion(reportedVersion) < 1) { 145 assertFalse("FEATURE_OPENGLES_EXTENSION_PACK is available without OpenGL ES 3.1+", 146 hasAepFeature); 147 return; 148 } 149 150 restartActivityWithClientVersion(3); 151 152 String extensions = mActivity.getExtensionsString(); 153 boolean hasAepExtension = hasExtension(extensions, "GL_ANDROID_extension_pack_es31a"); 154 assertEquals("System feature FEATURE_OPENGLES_EXTENSION_PACK is " 155 + (hasAepFeature ? "" : "not ") + "available, but extension GL_ANDROID_extension_pack_es31a is " 156 + (hasAepExtension ? "" : "not ") + "in the OpenGL ES extension list.", 157 hasAepFeature, hasAepExtension); 158 } 159 @CddTest(requirement="7.9.2/C-1-4") 160 @Test testOpenGlEsVersionForVrHighPerformance()161 public void testOpenGlEsVersionForVrHighPerformance() throws InterruptedException { 162 if (!supportsVrHighPerformance()) 163 return; 164 restartActivityWithClientVersion(3); 165 166 int reportedVersion = getVersionFromActivityManager(mActivity); 167 int major = getMajorVersion(reportedVersion); 168 int minor = getMinorVersion(reportedVersion); 169 170 assertTrue("OpenGL ES version 3.2 or higher is required for VR high-performance devices " + 171 " but this device supports only version " + major + "." + minor, 172 (major == 3 && minor >= 2) || major > 3); 173 } 174 175 @CddTest(requirement="7.9.2/C-1-6,C-1-8") 176 @Test testRequiredExtensionsForVrHighPerformance()177 public void testRequiredExtensionsForVrHighPerformance() throws InterruptedException { 178 if (!supportsVrHighPerformance()) 179 return; 180 restartActivityWithClientVersion(3); 181 final boolean isVrHeadset = (mActivity.getResources().getConfiguration().uiMode 182 & Configuration.UI_MODE_TYPE_MASK) == Configuration.UI_MODE_TYPE_VR_HEADSET; 183 184 String extensions = mActivity.getExtensionsString(); 185 final String requiredList[] = { 186 "GL_EXT_multisampled_render_to_texture", 187 "GL_EXT_protected_textures", 188 "GL_OVR_multiview", 189 "GL_OVR_multiview2", 190 "GL_OVR_multiview_multisampled_render_to_texture", 191 }; 192 final String vrHeadsetRequiredList[] = { 193 "GL_EXT_EGL_image_array", 194 "GL_EXT_external_buffer", 195 "GL_EXT_multisampled_render_to_texture2", 196 }; 197 198 for (String requiredExtension : requiredList) { 199 assertTrue("Required extension for VR high-performance is missing: " + requiredExtension, 200 hasExtension(extensions, requiredExtension)); 201 } 202 if (isVrHeadset) { 203 for (String requiredExtension : vrHeadsetRequiredList) { 204 assertTrue("Required extension for VR high-performance is missing: " + requiredExtension, 205 hasExtension(extensions, requiredExtension)); 206 } 207 } 208 209 EGL10 egl = (EGL10) EGLContext.getEGL(); 210 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 211 extensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS); 212 final String requiredEglList[] = { 213 "EGL_ANDROID_front_buffer_auto_refresh", 214 "EGL_ANDROID_get_native_client_buffer", 215 "EGL_EXT_protected_content", 216 "EGL_IMG_context_priority", 217 "EGL_KHR_fence_sync", 218 "EGL_KHR_mutable_render_buffer", 219 "EGL_KHR_wait_sync", 220 }; 221 final String vrHeadsetRequiredEglList[] = { 222 "EGL_EXT_image_gl_colorspace", 223 }; 224 225 for (String requiredExtension : requiredEglList) { 226 assertTrue("Required EGL extension for VR high-performance is missing: " + requiredExtension, 227 hasExtension(extensions, requiredExtension)); 228 } 229 if (isVrHeadset) { 230 for (String requiredExtension : vrHeadsetRequiredEglList) { 231 assertTrue("Required EGL extension for VR high-performance is missing: " + requiredExtension, 232 hasExtension(extensions, requiredExtension)); 233 } 234 } 235 } 236 @CddTest(requirement="7.1.4.1/C-6-1") 237 @Test testRequiredEglExtensions()238 public void testRequiredEglExtensions() { 239 // See CDD section 7.1.4 240 final String requiredEglList[] = { 241 "EGL_KHR_image", 242 "EGL_KHR_image_base", 243 "EGL_ANDROID_image_native_buffer", 244 "EGL_ANDROID_get_native_client_buffer", 245 "EGL_KHR_wait_sync", 246 "EGL_KHR_get_all_proc_addresses", 247 "EGL_ANDROID_presentation_time", 248 "EGL_KHR_swap_buffers_with_damage" 249 }; 250 251 EGL10 egl = (EGL10) EGLContext.getEGL(); 252 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 253 254 if (egl.eglInitialize(display, null)) { 255 try { 256 String eglExtensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS); 257 for (int i = 0; i < requiredEglList.length; ++i) { 258 assertTrue("EGL Extension required by CDD section 7.1.4 missing: " + 259 requiredEglList[i], hasExtension(eglExtensions, requiredEglList[i])); 260 } 261 if (hasExtension(eglExtensions, "EGL_KHR_mutable_render_buffer")) { 262 assertTrue("Devices exposes EGL_KHR_mutable_render_buffer but not EGL_ANDROID_front_buffer_auto_refresh", hasExtension(eglExtensions, "EGL_ANDROID_front_buffer_auto_refresh")); 263 } 264 } finally { 265 egl.eglTerminate(display); 266 } 267 } else { 268 Log.e(TAG, "Couldn't initialize EGL."); 269 } 270 } 271 272 @CddTest(requirement="7.1.4.5/H-1-1") 273 @Test testRequiredEglExtensionsForHdrCapableDisplay()274 public void testRequiredEglExtensionsForHdrCapableDisplay() { 275 // See CDD section 7.1.4 276 // This test covers the EGL portion of the CDD requirement. The VK portion of the 277 // requirement is covered elsewhere. 278 final String requiredEglList[] = { 279 "EGL_EXT_gl_colorspace_bt2020_pq", 280 "EGL_EXT_surface_SMPTE2086_metadata", 281 "EGL_EXT_surface_CTA861_3_metadata", 282 }; 283 284 // This requirement only applies if device is handheld and claims to be HDR capable. 285 boolean isHdrCapable = mActivity.getResources().getConfiguration().isScreenHdr(); 286 if (!isHdrCapable || !isHandheld()) 287 return; 288 289 EGL10 egl = (EGL10) EGLContext.getEGL(); 290 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 291 292 if (egl.eglInitialize(display, null)) { 293 try { 294 String eglExtensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS); 295 for (int i = 0; i < requiredEglList.length; ++i) { 296 assertTrue("EGL extension required by CDD section 7.1.4.5 missing: " + 297 requiredEglList[i], hasExtension(eglExtensions, requiredEglList[i])); 298 } 299 } finally { 300 egl.eglTerminate(display); 301 } 302 } else { 303 Log.e(TAG, "Couldn't initialize EGL."); 304 } 305 } 306 307 @CddTest(requirement="7.1.4.5/C-1-4") 308 @Test testRequiredGLESVersion()309 public void testRequiredGLESVersion() { 310 // This requirement only applies if device claims to be wide color capable. 311 boolean isWideColorCapable = 312 mActivity.getResources().getConfiguration().isScreenWideColorGamut(); 313 if (!isWideColorCapable) 314 return; 315 316 int reportedVersion = getVersionFromActivityManager(mActivity); 317 assertEquals("Reported OpenGL ES major version doesn't meet the requirement of" + 318 " CDD 7.1.4.5/C-1-4", 3, getMajorVersion(reportedVersion)); 319 assertTrue("Reported OpenGL ES minor version doesn't meet the requirement of" + 320 " CDD 7.1.4.5/C-1-4", 1 == getMinorVersion(reportedVersion) || 321 2 == getMinorVersion(reportedVersion)); 322 } 323 324 @CddTest(requirement="7.1.4.5/C-1-5") 325 @Test testRequiredEglExtensionsForWideColorDisplay()326 public void testRequiredEglExtensionsForWideColorDisplay() { 327 // See CDD section 7.1.4.5 328 // This test covers the EGL portion of the CDD requirement. The VK portion of the 329 // requirement is covered elsewhere. 330 final String requiredEglList[] = { 331 "EGL_KHR_no_config_context", 332 "EGL_EXT_pixel_format_float", 333 "EGL_KHR_gl_colorspace", 334 "EGL_EXT_gl_colorspace_scrgb", 335 "EGL_EXT_gl_colorspace_scrgb_linear", 336 "EGL_EXT_gl_colorspace_display_p3", 337 "EGL_EXT_gl_colorspace_display_p3_linear", 338 "EGL_EXT_gl_colorspace_display_p3_passthrough", 339 }; 340 341 // This requirement only applies if device claims to be wide color capable. 342 boolean isWideColorCapable = mActivity.getResources().getConfiguration().isScreenWideColorGamut(); 343 if (!isWideColorCapable) 344 return; 345 346 EGL10 egl = (EGL10) EGLContext.getEGL(); 347 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 348 349 if (egl.eglInitialize(display, null)) { 350 try { 351 String eglExtensions = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS); 352 for (int i = 0; i < requiredEglList.length; ++i) { 353 assertTrue("EGL extension required by CDD section 7.1.4.5 missing: " + 354 requiredEglList[i], hasExtension(eglExtensions, requiredEglList[i])); 355 } 356 } finally { 357 egl.eglTerminate(display); 358 } 359 } else { 360 Log.e(TAG, "Couldn't initialize EGL."); 361 } 362 } 363 isHandheld()364 private boolean isHandheld() { 365 // handheld nature is not exposed to package manager, for now 366 // we check for touchscreen and NOT watch and NOT tv 367 PackageManager pm = mActivity.getPackageManager(); 368 return pm.hasSystemFeature(pm.FEATURE_TOUCHSCREEN) 369 && !pm.hasSystemFeature(pm.FEATURE_WATCH) 370 && !pm.hasSystemFeature(pm.FEATURE_TELEVISION); 371 } 372 hasExtension(String extensions, String name)373 private static boolean hasExtension(String extensions, String name) { 374 return OpenGlEsVersionCtsActivity.hasExtension(extensions, name); 375 } 376 377 /** @return OpenGL ES major version 1, 2, or 3 or some non-positive number for error */ getDetectedMajorVersion()378 private static int getDetectedMajorVersion() { 379 /* 380 * Get all the device configurations and check the EGL_RENDERABLE_TYPE attribute 381 * to determine the highest ES version supported by any config. The 382 * EGL_KHR_create_context extension is required to check for ES3 support; if the 383 * extension is not present this test will fail to detect ES3 support. This 384 * effectively makes the extension mandatory for ES3-capable devices. 385 */ 386 387 EGL10 egl = (EGL10) EGLContext.getEGL(); 388 EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); 389 int[] numConfigs = new int[1]; 390 391 if (egl.eglInitialize(display, null)) { 392 try { 393 boolean checkES3 = hasExtension(egl.eglQueryString(display, EGL10.EGL_EXTENSIONS), 394 "EGL_KHR_create_context"); 395 if (egl.eglGetConfigs(display, null, 0, numConfigs)) { 396 EGLConfig[] configs = new EGLConfig[numConfigs[0]]; 397 if (egl.eglGetConfigs(display, configs, numConfigs[0], numConfigs)) { 398 int highestEsVersion = 0; 399 int[] value = new int[1]; 400 for (int i = 0; i < numConfigs[0]; i++) { 401 if (egl.eglGetConfigAttrib(display, configs[i], 402 EGL10.EGL_RENDERABLE_TYPE, value)) { 403 if (checkES3 && ((value[0] & EGL_OPENGL_ES3_BIT_KHR) == 404 EGL_OPENGL_ES3_BIT_KHR)) { 405 if (highestEsVersion < 3) highestEsVersion = 3; 406 } else if ((value[0] & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT) { 407 if (highestEsVersion < 2) highestEsVersion = 2; 408 } else if ((value[0] & EGL_OPENGL_ES_BIT) == EGL_OPENGL_ES_BIT) { 409 if (highestEsVersion < 1) highestEsVersion = 1; 410 } 411 } else { 412 Log.w(TAG, "Getting config attribute with " 413 + "EGL10#eglGetConfigAttrib failed " 414 + "(" + i + "/" + numConfigs[0] + "): " 415 + egl.eglGetError()); 416 } 417 } 418 return highestEsVersion; 419 } else { 420 Log.e(TAG, "Getting configs with EGL10#eglGetConfigs failed: " 421 + egl.eglGetError()); 422 return -1; 423 } 424 } else { 425 Log.e(TAG, "Getting number of configs with EGL10#eglGetConfigs failed: " 426 + egl.eglGetError()); 427 return -2; 428 } 429 } finally { 430 egl.eglTerminate(display); 431 } 432 } else { 433 Log.e(TAG, "Couldn't initialize EGL."); 434 return -3; 435 } 436 } 437 getVersionFromActivityManager(Context context)438 private static int getVersionFromActivityManager(Context context) { 439 ActivityManager activityManager = 440 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 441 ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo(); 442 if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) { 443 return configInfo.reqGlEsVersion; 444 } else { 445 return 1 << 16; // Lack of property means OpenGL ES version 1 446 } 447 } 448 getVersionFromPackageManager(Context context)449 private static int getVersionFromPackageManager(Context context) { 450 PackageManager packageManager = context.getPackageManager(); 451 FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures(); 452 if (featureInfos != null && featureInfos.length > 0) { 453 for (FeatureInfo featureInfo : featureInfos) { 454 // Null feature name means this feature is the open gl es version feature. 455 if (featureInfo.name == null) { 456 if (featureInfo.reqGlEsVersion != FeatureInfo.GL_ES_VERSION_UNDEFINED) { 457 return featureInfo.reqGlEsVersion; 458 } else { 459 return 1 << 16; // Lack of property means OpenGL ES version 1 460 } 461 } 462 } 463 } 464 return 1; 465 } 466 467 /** @see FeatureInfo#getGlEsVersion() */ getMajorVersion(int glEsVersion)468 private static int getMajorVersion(int glEsVersion) { 469 return ((glEsVersion & 0xffff0000) >> 16); 470 } 471 472 /** @see FeatureInfo#getGlEsVersion() */ getMinorVersion(int glEsVersion)473 private static int getMinorVersion(int glEsVersion) { 474 return glEsVersion & 0xffff; 475 } 476 477 /** 478 * Check that the version string has the form "OpenGL ES(-CM)? (\d+)\.(\d+)", where the two 479 * numbers match the major and minor parameters. 480 */ 481 @CddTest(requirement="7.1.4.1/C-0-1") verifyGlVersionString(int major, int minor)482 private void verifyGlVersionString(int major, int minor) throws InterruptedException { 483 Matcher matcher = Pattern.compile("OpenGL ES(?:-CM)? (\\d+)\\.(\\d+).*") 484 .matcher(mActivity.getVersionString()); 485 assertTrue("OpenGL ES version string is not of the required form " 486 + "'OpenGL ES(-CM)? (\\d+)\\.(\\d+).*'", 487 matcher.matches()); 488 int stringMajor = Integer.parseInt(matcher.group(1)); 489 int stringMinor = Integer.parseInt(matcher.group(2)); 490 assertEquals("GL_VERSION string doesn't match ActivityManager major version (check ro.opengles.version property)", 491 major, stringMajor); 492 assertEquals("GL_VERSION string doesn't match ActivityManager minor version (check ro.opengles.version property)", 493 minor, stringMinor); 494 } 495 496 /** Restart {@link GLSurfaceViewCtsActivity} with a specific client version. */ restartActivityWithClientVersion(int version)497 private void restartActivityWithClientVersion(int version) { 498 mActivity.finish(); 499 500 Intent intent = OpenGlEsVersionCtsActivity.createIntent(version); 501 mActivity = mActivityRelaunchRule.launchActivity(intent); 502 } 503 504 /** 505 * Return whether the system supports FEATURE_VR_MODE_HIGH_PERFORMANCE. 506 * This is used to skip some tests. 507 */ supportsVrHighPerformance()508 private boolean supportsVrHighPerformance() { 509 PackageManager pm = mActivity.getPackageManager(); 510 return pm.hasSystemFeature(PackageManager.FEATURE_VR_MODE_HIGH_PERFORMANCE); 511 } 512 } 513