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