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 android.app.Activity;
20 import android.content.Intent;
21 import android.opengl.GLES31;
22 import android.opengl.GLES31Ext;
23 import android.opengl.GLSurfaceView;
24 import android.os.Bundle;
25 import android.util.Log;
26 
27 import java.util.concurrent.CountDownLatch;
28 import java.util.concurrent.TimeUnit;
29 
30 import javax.microedition.khronos.egl.EGLConfig;
31 import javax.microedition.khronos.opengles.GL10;
32 
33 /**
34  * {@link Activity} that queries the device's display attributes to determine what version of
35  * OpenGL ES is supported and returns what the GL version string reports.
36  */
37 public class OpenGlEsVersionCtsActivity extends Activity {
38     private static String TAG = "OpenGlEsVersionCtsActivity";
39 
40     private static final String EGL_CONTEXT_CLIENT_VERSION = "eglContextClientVersion";
41 
42     /** Timeout to wait for the surface to be created and the version queried. */
43     private static final int TIMEOUT_SECONDS = 10;
44 
45     /** Version string reported by glGetString. */
46     private String mVersionString;
47 
48     /** Extensions string reported by glGetString. */
49     private String mExtensionsString;
50 
51     /** Whether GL_ANDROID_extension_pack_es31a is correctly supported. */
52     private boolean mAepEs31Support = false;
53 
54     /** Latch that is unlocked when the activity is done finding the version. */
55     private CountDownLatch mSurfaceCreatedLatch = new CountDownLatch(1);
56 
57     private GLSurfaceView mView;
58 
createIntent(int eglContextClientVersion)59     public static Intent createIntent(int eglContextClientVersion) {
60         Intent intent = new Intent(Intent.ACTION_MAIN);
61         intent.putExtra(EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion);
62         return intent;
63     }
64 
65     @Override
onCreate(Bundle savedInstanceState)66     protected void onCreate(Bundle savedInstanceState) {
67         super.onCreate(savedInstanceState);
68 
69         mView = new GLSurfaceView(this);
70 
71         Intent intent = getIntent();
72         int eglContextClientVersion = intent.getIntExtra(EGL_CONTEXT_CLIENT_VERSION, -1);
73         if (eglContextClientVersion > 0) {
74             mView.setEGLContextClientVersion(eglContextClientVersion);
75         }
76 
77         mView.setRenderer(new Renderer());
78         setContentView(mView);
79     }
80 
81     @Override
onPause()82     protected void onPause() {
83         mView.onPause();
84         super.onPause();
85     }
86 
getVersionString()87     public String getVersionString() throws InterruptedException {
88         mSurfaceCreatedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
89         synchronized (this) {
90             return mVersionString;
91         }
92     }
93 
getExtensionsString()94     public String getExtensionsString() throws InterruptedException {
95         mSurfaceCreatedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
96         synchronized (this) {
97             return mExtensionsString;
98         }
99     }
100 
getAepEs31Support()101     public boolean getAepEs31Support() throws InterruptedException {
102         mSurfaceCreatedLatch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
103         synchronized (this) {
104             return mAepEs31Support;
105         }
106     }
107 
hasExtension(String extensions, String name)108     public static boolean hasExtension(String extensions, String name) {
109         int start = extensions.indexOf(name);
110         while (start >= 0) {
111             // check that we didn't find a prefix of a longer extension name
112             int end = start + name.length();
113             if (end == extensions.length() || extensions.charAt(end) == ' ') {
114                 return true;
115             }
116             start = extensions.indexOf(name, end);
117         }
118         return false;
119     }
120 
121     private class Renderer implements GLSurfaceView.Renderer {
122         /**
123          * These shaders test at least one feature of each of the underlying extension, to verify
124          * that enabling GL_ANDROID_extension_pack_es31a correctly enables all of them.
125          */
126         private final String mAepEs31VertexShader =
127                 "#version 310 es\n" +
128                 "#extension GL_ANDROID_extension_pack_es31a : require\n" +
129                 "void main() {\n" +
130                 "  gl_Position = vec4(1, 0, 0, 1);\n" +
131                 "}\n";
132 
133         private final String mAepEs31TessellationControlShader =
134                 "#version 310 es\n" +
135                 "#extension GL_ANDROID_extension_pack_es31a : require\n" +
136                 "layout(vertices = 3) out;\n" +  // GL_EXT_tessellation_shader
137                 "void main() {\n" +
138                 "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" +  // GL_EXT_shader_io_blocks
139                 "  if (gl_InvocationID == 0) {\n" +
140                 "    gl_BoundingBoxEXT[0] = gl_in[0].gl_Position;\n" +  // GL_EXT_primitive_bounding_box
141                 "    gl_BoundingBoxEXT[1] = gl_in[1].gl_Position;\n" +
142                 "  }\n" +
143                 "}\n";
144 
145         private final String mAepEs31TessellationEvaluationShader =
146                 "#version 310 es\n" +
147                 "#extension GL_ANDROID_extension_pack_es31a : require\n" +
148                 "layout(triangles, equal_spacing, cw) in;\n" +
149                 "void main() {\n" +
150                 "  gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n" +
151                 "      gl_in[1].gl_Position * gl_TessCoord.y +\n" +
152                 "      gl_in[2].gl_Position * gl_TessCoord.z;\n" +
153                 "}\n";
154 
155         private final String mAepEs31GeometryShader =
156                 "#version 310 es\n" +
157                 "#extension GL_ANDROID_extension_pack_es31a : require\n" +
158                 "layout(triangles) in;\n" +  // GL_EXT_geometry_shader
159                 "layout(triangle_strip, max_vertices = 3) out;\n" +
160                 "sample out vec4 perSampleColor;\n" +
161                 "void main() {\n" +
162                 "  for (int i = 0; i < gl_in.length(); ++i) {\n" +
163                 "    gl_Position = gl_in[i].gl_Position;\n" +
164                 "    perSampleColor = gl_in[i].gl_Position;\n" +
165                 "    EmitVertex();\n" +
166                 "  }\n" +
167                 "}\n";
168 
169         private final String mAepEs31FragmentShader =
170                 "#version 310 es\n" +
171                 "#extension GL_ANDROID_extension_pack_es31a : require\n" +
172                 "precision mediump float;\n" +
173                 "layout(blend_support_all_equations) out;\n" +  // GL_KHR_blend_equation_advanced
174                 "sample in vec4 perSampleColor;\n" +  // GL_OES_shader_multisample_interpolation
175                 "layout(r32ui) coherent uniform mediump uimage2D image;\n" +
176                 "uniform mediump sampler2DMSArray mySamplerMSArray;\n" +  // GL_OES_texture_storage_multisample_2d_array
177                 "uniform mediump samplerBuffer mySamplerBuffer;\n" +  // GL_EXT_texture_buffer
178                 "uniform mediump samplerCubeArray mySamplerCubeArray;\n" +  // GL_EXT_texture_cube_map_array
179                 "out vec4 color;\n" +
180                 "void main() {\n" +
181                 "  imageAtomicAdd(image, ivec2(1, 1), 1u);\n" +  // GL_OES_shader_image_atomic
182                 "  vec4 color = vec4(gl_SamplePosition.x, 0, 0, 1);\n" +  // GL_OES_sample_variables
183                 "  vec4 color2 = texelFetch(mySamplerMSArray, ivec3(1, 1, 1), 3);\n" +
184                 "  vec4 color3 = texelFetch(mySamplerBuffer, 3);\n" +
185                 "  vec4 color4 = texture(mySamplerCubeArray, vec4(1, 1, 1, 1));\n" +
186                 "  color = fma(color + color2, color3 + color4, perSampleColor);" +  // GL_EXT_gpu_shader5
187                 "}\n";
188 
onSurfaceCreated(GL10 gl, EGLConfig config)189         public void onSurfaceCreated(GL10 gl, EGLConfig config) {
190             synchronized (OpenGlEsVersionCtsActivity.this) {
191                 try {
192                     mVersionString = gl.glGetString(GL10.GL_VERSION);
193                     mExtensionsString = gl.glGetString(GL10.GL_EXTENSIONS);
194                     if (hasExtension(mExtensionsString, "ANDROID_extension_pack_es31a"))
195                         mAepEs31Support = checkAepEs31Support();
196                 } finally {
197                     mSurfaceCreatedLatch.countDown();
198                 }
199             }
200         }
201 
onSurfaceChanged(GL10 gl, int width, int height)202         public void onSurfaceChanged(GL10 gl, int width, int height) {
203         }
204 
onDrawFrame(GL10 gl)205         public void onDrawFrame(GL10 gl) {
206         }
207 
compileShaderAndAttach(int program, int shaderType, String source)208         private boolean compileShaderAndAttach(int program, int shaderType, String source) {
209             int shader = GLES31.glCreateShader(shaderType);
210             if (shader == 0) {
211                 Log.e(TAG, "Unable to create shaders of type " + shaderType);
212                 return false;
213             }
214             GLES31.glShaderSource(shader, source);
215             GLES31.glCompileShader(shader);
216             int[] compiled = new int[1];
217             GLES31.glGetShaderiv(shader, GLES31.GL_COMPILE_STATUS, compiled, 0);
218             if (compiled[0] == 0) {
219                 Log.e(TAG, "Unable to compile shader " + shaderType + ":");
220                 Log.e(TAG, GLES31.glGetShaderInfoLog(shader));
221                 GLES31.glDeleteShader(shader);
222                 return false;
223             }
224             GLES31.glAttachShader(program, shader);
225             GLES31.glDeleteShader(shader);
226             return true;
227         }
228 
checkAepEs31Support()229         private boolean checkAepEs31Support() {
230             final String requiredList[] = {
231                 "EXT_copy_image",
232                 "EXT_draw_buffers_indexed",
233                 "EXT_geometry_shader",
234                 "EXT_gpu_shader5",
235                 "EXT_primitive_bounding_box",
236                 "EXT_shader_io_blocks",
237                 "EXT_tessellation_shader",
238                 "EXT_texture_border_clamp",
239                 "EXT_texture_buffer",
240                 "EXT_texture_cube_map_array",
241                 "EXT_texture_sRGB_decode",
242                 "KHR_blend_equation_advanced",
243                 "KHR_debug",
244                 "KHR_texture_compression_astc_ldr",
245                 "OES_sample_shading",
246                 "OES_sample_variables",
247                 "OES_shader_image_atomic",
248                 "OES_shader_multisample_interpolation",
249                 "OES_texture_stencil8",
250                 "OES_texture_storage_multisample_2d_array"
251             };
252 
253             for (int i = 0; i < requiredList.length; ++i) {
254                 if (!hasExtension(mExtensionsString, requiredList[i])) {
255                     Log.e(TAG,"ANDROID_extension_pack_es31a is present but extension " +
256                             requiredList[i] + " is missing");
257                     return false;
258                 }
259             }
260 
261             int[] value = new int[1];
262             GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, value, 0);
263             if (value[0] < 1) {
264                 Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
265                         "GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS value is " + value[0] + " < 1");
266                 return false;
267             }
268             GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_ATOMIC_COUNTERS, value, 0);
269             if (value[0] < 8) {
270                 Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
271                         "GL_MAX_FRAGMENT_ATOMIC_COUNTERS value is " + value[0] + " < 8");
272                 return false;
273             }
274             GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_IMAGE_UNIFORMS, value, 0);
275             if (value[0] < 4) {
276                 Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
277                         "GL_MAX_FRAGMENT_IMAGE_UNIFORMS value is " + value[0] + " < 4");
278                 return false;
279             }
280             GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, value, 0);
281             if (value[0] < 4) {
282                 Log.e(TAG, "ANDROID_extension_pack_es31a is present, but the " +
283                         "GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS value is " + value[0] + " < 4");
284                 return false;
285             }
286 
287             int program = GLES31.glCreateProgram();
288             try {
289                 if (!compileShaderAndAttach(program, GLES31.GL_VERTEX_SHADER, mAepEs31VertexShader) ||
290                     !compileShaderAndAttach(program, GLES31Ext.GL_TESS_CONTROL_SHADER_EXT, mAepEs31TessellationControlShader) ||
291                     !compileShaderAndAttach(program, GLES31Ext.GL_TESS_EVALUATION_SHADER_EXT, mAepEs31TessellationEvaluationShader) ||
292                     !compileShaderAndAttach(program, GLES31Ext.GL_GEOMETRY_SHADER_EXT, mAepEs31GeometryShader) ||
293                     !compileShaderAndAttach(program, GLES31.GL_FRAGMENT_SHADER, mAepEs31FragmentShader))
294                     return false;
295 
296                 GLES31.glLinkProgram(program);
297                 GLES31.glGetProgramiv(program, GLES31.GL_LINK_STATUS, value, 0);
298                 if (value[0] == 0) {
299                     Log.e(TAG, "Unable to link program :");
300                     Log.e(TAG, GLES31.glGetProgramInfoLog(program));
301                     return false;
302                 }
303             } finally {
304                 GLES31.glDeleteProgram(program);
305             }
306             return true;
307         }
308     }
309 }
310