Add CTS test for OpenGL ES 3.1 and GL_ANDROID_extension_pack_es31a
Change-Id: Ie44284fbf0a2b718c661001e17b955d47cbd573c
diff --git a/tests/src/android/opengl/cts/OpenGlEsVersionStubActivity.java b/tests/src/android/opengl/cts/OpenGlEsVersionStubActivity.java
index 488c8bd..2b96c5d 100644
--- a/tests/src/android/opengl/cts/OpenGlEsVersionStubActivity.java
+++ b/tests/src/android/opengl/cts/OpenGlEsVersionStubActivity.java
@@ -18,8 +18,11 @@
import android.app.Activity;
import android.content.Intent;
+import android.opengl.GLES31;
+import android.opengl.GLES31Ext;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
+import android.util.Log;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -32,6 +35,7 @@
* OpenGL ES is supported and returns what the GL version string reports.
*/
public class OpenGlEsVersionStubActivity extends Activity {
+ private static String TAG = "OpenGlEsVersionStubActivity";
private static final String EGL_CONTEXT_CLIENT_VERSION = "eglContextClientVersion";
@@ -41,6 +45,12 @@
/** Version string reported by glGetString. */
private String mVersionString;
+ /** Extensions string reported by glGetString. */
+ private String mExtensionsString;
+
+ /** Whether GL_ANDROID_extension_pack_es31a is correctly supported. */
+ private boolean mAepEs31Support = false;
+
/** Latch that is unlocked when the activity is done finding the version. */
private CountDownLatch mSurfaceCreatedLatch = new CountDownLatch(1);
@@ -73,12 +83,108 @@
}
}
+ public String getExtensionsString() throws InterruptedException {
+ mSurfaceCreatedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ synchronized (this) {
+ return mExtensionsString;
+ }
+ }
+
+ public boolean getAepEs31Support() throws InterruptedException {
+ mSurfaceCreatedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
+ synchronized (this) {
+ return mAepEs31Support;
+ }
+ }
+
+ public static boolean hasExtension(String extensions, String name) {
+ int start = extensions.indexOf(name);
+ while (start >= 0) {
+ // check that we didn't find a prefix of a longer extension name
+ int end = start + name.length();
+ if (end == extensions.length() || extensions.charAt(end) == ' ') {
+ return true;
+ }
+ start = extensions.indexOf(name, end);
+ }
+ return false;
+ }
+
private class Renderer implements GLSurfaceView.Renderer {
+ /**
+ * These shaders test at least one feature of each of the underlying extension, to verify
+ * that enabling GL_ANDROID_extension_pack_es31a correctly enables all of them.
+ */
+ private final String mAepEs31VertexShader =
+ "#version 310 es\n" +
+ "#extension GL_ANDROID_extension_pack_es31a : require\n" +
+ "void main() {\n" +
+ " gl_Position = vec4(1, 0, 0, 1);\n" +
+ "}\n";
+
+ private final String mAepEs31TessellationControlShader =
+ "#version 310 es\n" +
+ "#extension GL_ANDROID_extension_pack_es31a : require\n" +
+ "layout(vertices = 3) out;\n" + // GL_EXT_tessellation_shader
+ "void main() {\n" +
+ " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" + // GL_EXT_shader_io_blocks
+ " if (gl_InvocationID == 0) {\n" +
+ " gl_BoundingBoxEXT[0] = gl_in[0].gl_Position;\n" + // GL_EXT_primitive_bounding_box
+ " gl_BoundingBoxEXT[1] = gl_in[1].gl_Position;\n" +
+ " }\n" +
+ "}\n";
+
+ private final String mAepEs31TessellationEvaluationShader =
+ "#version 310 es\n" +
+ "#extension GL_ANDROID_extension_pack_es31a : require\n" +
+ "layout(triangles, equal_spacing, cw) in;\n" +
+ "void main() {\n" +
+ " gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n" +
+ " gl_in[1].gl_Position * gl_TessCoord.y +\n" +
+ " gl_in[2].gl_Position * gl_TessCoord.z;\n" +
+ "}\n";
+
+ private final String mAepEs31GeometryShader =
+ "#version 310 es\n" +
+ "#extension GL_ANDROID_extension_pack_es31a : require\n" +
+ "layout(triangles) in;\n" + // GL_EXT_geometry_shader
+ "layout(triangle_strip, max_vertices = 3) out;\n" +
+ "sample out vec4 perSampleColor;\n" +
+ "void main() {\n" +
+ " for (int i = 0; i < gl_in.length(); ++i) {\n" +
+ " gl_Position = gl_in[i].gl_Position;\n" +
+ " perSampleColor = gl_in[i].gl_Position;\n" +
+ " EmitVertex();\n" +
+ " }\n" +
+ "}\n";
+
+ private final String mAepEs31FragmentShader =
+ "#version 310 es\n" +
+ "#extension GL_ANDROID_extension_pack_es31a : require\n" +
+ "precision mediump float;\n" +
+ "layout(blend_support_all_equations) out;\n" + // GL_KHR_blend_equation_advanced
+ "sample in vec4 perSampleColor;\n" + // GL_OES_shader_multisample_interpolation
+ "layout(r32ui) coherent uniform mediump uimage2D image;\n" +
+ "uniform mediump sampler2DMSArray mySamplerMSArray;\n" + // GL_OES_texture_storage_multisample_2d_array
+ "uniform mediump samplerBuffer mySamplerBuffer;\n" + // GL_EXT_texture_buffer
+ "uniform mediump samplerCubeArray mySamplerCubeArray;\n" + // GL_EXT_texture_cube_map_array
+ "out vec4 color;\n" +
+ "void main() {\n" +
+ " imageAtomicAdd(image, ivec2(1, 1), 1u);\n" + // GL_OES_shader_image_atomic
+ " vec4 color = vec4(gl_SamplePosition.x, 0, 0, 1);\n" + // GL_OES_sample_variables
+ " vec4 color2 = texelFetch(mySamplerMSArray, ivec3(1, 1, 1), 3);\n" +
+ " vec4 color3 = texelFetch(mySamplerBuffer, 3);\n" +
+ " vec4 color4 = texture(mySamplerCubeArray, vec4(1, 1, 1, 1));\n" +
+ " color = fma(color + color2, color3 + color4, perSampleColor);" + // GL_EXT_gpu_shader5
+ "}\n";
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
synchronized (OpenGlEsVersionStubActivity.this) {
try {
mVersionString = gl.glGetString(GL10.GL_VERSION);
+ mExtensionsString = gl.glGetString(GL10.GL_EXTENSIONS);
+ if (hasExtension(mExtensionsString, "ANDROID_extension_pack_es31a"))
+ mAepEs31Support = checkAepEs31Support();
} finally {
mSurfaceCreatedLatch.countDown();
}
@@ -90,5 +196,106 @@
public void onDrawFrame(GL10 gl) {
}
+
+ private boolean compileShaderAndAttach(int program, int shaderType, String source) {
+ int shader = GLES31.glCreateShader(shaderType);
+ if (shader == 0) {
+ Log.e(TAG, "Unable to create shaders of type " + shaderType);
+ return false;
+ }
+ GLES31.glShaderSource(shader, source);
+ GLES31.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Unable to compile shader " + shaderType + ":");
+ Log.e(TAG, GLES31.glGetShaderInfoLog(shader));
+ GLES31.glDeleteShader(shader);
+ return false;
+ }
+ GLES31.glAttachShader(program, shader);
+ GLES31.glDeleteShader(shader);
+ return true;
+ }
+
+ private boolean checkAepEs31Support() {
+ final String requiredList[] = {
+ "EXT_copy_image",
+ "EXT_draw_buffers_indexed",
+ "EXT_geometry_shader",
+ "EXT_gpu_shader5",
+ "EXT_primitive_bounding_box",
+ "EXT_shader_io_blocks",
+ "EXT_tessellation_shader",
+ "EXT_texture_border_clamp",
+ "EXT_texture_buffer",
+ "EXT_texture_cube_map_array",
+ "EXT_texture_sRGB_decode",
+ "KHR_blend_equation_advanced",
+ "KHR_debug",
+ "KHR_texture_compression_astc_ldr",
+ "OES_sample_shading",
+ "OES_sample_variables",
+ "OES_shader_image_atomic",
+ "OES_shader_multisample_interpolation",
+ "OES_texture_stencil8",
+ "OES_texture_storage_multisample_2d_array"
+ };
+
+ for (int i = 0; i < requiredList.length; ++i) {
+ if (!hasExtension(mExtensionsString, requiredList[i])) {
+ Log.e(TAG,"ANDROID_extension_pack_es31a is present but extension " +
+ requiredList[i] + " is missing");
+ return false;
+ }
+ }
+
+ int[] value = new int[1];
+ GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, value, 0);
+ if (value[0] < 1) {
+ Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
+ "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS value is " + value[0] + " < 1");
+ return false;
+ }
+ GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_ATOMIC_COUNTERS, value, 0);
+ if (value[0] < 8) {
+ Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
+ "GL_MAX_FRAGMENT_ATOMIC_COUNTERS value is " + value[0] + " < 8");
+ return false;
+ }
+ GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_IMAGE_UNIFORMS, value, 0);
+ if (value[0] < 4) {
+ Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
+ "GL_MAX_FRAGMENT_IMAGE_UNIFORMS value is " + value[0] + " < 4");
+ return false;
+ }
+ GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, value, 0);
+ if (value[0] < 4) {
+ Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
+ "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS value is " + value[0] + " < 4");
+ return false;
+ }
+
+ int program = GLES31.glCreateProgram();
+ try {
+ if (!compileShaderAndAttach(program, GLES31.GL_VERTEX_SHADER, mAepEs31VertexShader) ||
+ !compileShaderAndAttach(program, GLES31Ext.GL_TESS_CONTROL_SHADER_EXT, mAepEs31TessellationControlShader) ||
+ !compileShaderAndAttach(program, GLES31Ext.GL_TESS_EVALUATION_SHADER_EXT, mAepEs31TessellationEvaluationShader) ||
+ !compileShaderAndAttach(program, GLES31Ext.GL_GEOMETRY_SHADER_EXT, mAepEs31GeometryShader) ||
+ !compileShaderAndAttach(program, GLES31.GL_FRAGMENT_SHADER, mAepEs31FragmentShader))
+ return false;
+
+ GLES31.glLinkProgram(program);
+ GLES31.glGetProgramiv(program, GLES31.GL_LINK_STATUS, value, 0);
+ if (value[0] == 0) {
+ Log.e(TAG, "Unable to link program :");
+ Log.e(TAG, GLES31.glGetProgramInfoLog(program));
+ return false;
+ }
+ } finally {
+ GLES31.glDeleteProgram(program);
+ }
+ return true;
+ }
}
}
diff --git a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
index 85159a8..1e55b51 100644
--- a/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
+++ b/tests/tests/graphics/src/android/opengl/cts/OpenGlEsVersionTest.java
@@ -58,40 +58,72 @@
}
public void testOpenGlEsVersion() throws InterruptedException {
- int detectedVersion = getDetectedVersion();
+ int detectedMajorVersion = getDetectedMajorVersion();
int reportedVersion = getVersionFromActivityManager(mActivity);
- assertEquals("Detected OpenGL ES major version " + detectedVersion
- + " but Activity Manager is reporting " + reportedVersion
- + " (Check ro.opengles.version)", detectedVersion, reportedVersion);
+ assertEquals("Detected OpenGL ES major version " + detectedMajorVersion
+ + " but Activity Manager is reporting " + getMajorVersion(reportedVersion)
+ + " (Check ro.opengles.version)",
+ detectedMajorVersion, getMajorVersion(reportedVersion));
assertEquals("Reported OpenGL ES version from ActivityManager differs from PackageManager",
reportedVersion, getVersionFromPackageManager(mActivity));
assertGlVersionString(1);
- if (detectedVersion == 2) {
+ if (detectedMajorVersion == 2) {
restartActivityWithClientVersion(2);
assertGlVersionString(2);
- } else if (detectedVersion == 3) {
+ } else if (detectedMajorVersion == 3) {
restartActivityWithClientVersion(3);
assertGlVersionString(3);
}
}
- private static boolean hasExtension(String extensions, String name) {
- int start = extensions.indexOf(name);
- while (start >= 0) {
- // check that we didn't find a prefix of a longer extension name
- int end = start + name.length();
- if (end == extensions.length() || extensions.charAt(end) == ' ') {
- return true;
- }
- start = extensions.indexOf(name, end);
+ public void testRequiredExtensions() throws InterruptedException {
+ int reportedVersion = getVersionFromActivityManager(mActivity);
+ // We only have required extensions on ES3.1
+ if (getMajorVersion(reportedVersion) != 3 || getMinorVersion(reportedVersion) != 1)
+ return;
+
+ restartActivityWithClientVersion(3);
+
+ String extensions = mActivity.getExtensionsString();
+ final String requiredList[] = {
+ "EXT_texture_sRGB_decode",
+ "KHR_blend_equation_advanced",
+ "KHR_debug",
+ "OES_shader_image_atomic",
+ "OES_texture_stencil8",
+ "OES_texture_storage_multisample_2d_array"
+ };
+
+ for (int i = 0; i < requiredList.length; ++i) {
+ assertTrue("OpenGL ES version 3.1 is missing extension " + requiredList[i],
+ hasExtension(extensions, requiredList[i]));
}
- return false;
+ }
+
+ public void testExtensionPack() throws InterruptedException {
+ int reportedVersion = getVersionFromActivityManager(mActivity);
+ // We only have the extension pack on ES3.1
+ if (getMajorVersion(reportedVersion) != 3 || getMinorVersion(reportedVersion) != 1)
+ return;
+
+ restartActivityWithClientVersion(3);
+
+ String extensions = mActivity.getExtensionsString();
+ if (!hasExtension(extensions, "ANDROID_extension_pack_es31a"))
+ return;
+
+ assertTrue("ANDROID_extension_pack_es31a is present, but support is incomplete",
+ mActivity.getAepEs31Support());
+ }
+
+ private static boolean hasExtension(String extensions, String name) {
+ return OpenGlEsVersionStubActivity.hasExtension(extensions, name);
}
/** @return OpenGL ES major version 1, 2, or 3 or some non-positive number for error */
- private static int getDetectedVersion() {
+ private static int getDetectedMajorVersion() {
/*
* Get all the device configurations and check the EGL_RENDERABLE_TYPE attribute
* to determine the highest ES version supported by any config. The
@@ -156,9 +188,9 @@
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
- return getMajorVersion(configInfo.reqGlEsVersion);
+ return configInfo.reqGlEsVersion;
} else {
- return 1; // Lack of property means OpenGL ES version 1
+ return 1 << 16; // Lack of property means OpenGL ES version 1
}
}
@@ -170,9 +202,9 @@
// Null feature name means this feature is the open gl es version feature.
if (featureInfo.name == null) {
if (featureInfo.reqGlEsVersion != FeatureInfo.GL_ES_VERSION_UNDEFINED) {
- return getMajorVersion(featureInfo.reqGlEsVersion);
+ return featureInfo.reqGlEsVersion;
} else {
- return 1; // Lack of property means OpenGL ES version 1
+ return 1 << 16; // Lack of property means OpenGL ES version 1
}
}
}
@@ -185,6 +217,11 @@
return ((glEsVersion & 0xffff0000) >> 16);
}
+ /** @see FeatureInfo#getGlEsVersion() */
+ private static int getMinorVersion(int glEsVersion) {
+ return glEsVersion & 0xffff;
+ }
+
/**
* Check that the version string has some form of "Open GL ES X.Y" in it where X is the major
* version and Y must be some digit.