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