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