1 /* 2 * Copyright (C) 2015 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 package com.android.compatibility.common.deviceinfo; 17 18 import android.app.Activity; 19 import android.app.ActivityManager; 20 import android.app.Instrumentation; 21 import android.content.Context; 22 import android.content.pm.ConfigurationInfo; 23 import android.content.res.Configuration; 24 import android.os.Bundle; 25 import android.view.Window; 26 import android.view.WindowManager; 27 import android.opengl.GLES20; 28 import android.opengl.GLES30; 29 import android.opengl.GLSurfaceView; 30 import android.util.Log; 31 32 import java.lang.reflect.Field; 33 import java.nio.FloatBuffer; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.HashSet; 38 import java.util.HashMap; 39 import java.util.Scanner; 40 import java.util.Set; 41 import java.util.concurrent.CountDownLatch; 42 43 import javax.microedition.khronos.egl.EGLConfig; 44 import javax.microedition.khronos.opengles.GL10; 45 46 /** Stub activity to collect data from the GlesView */ 47 public final class GlesStubActivity extends Activity { 48 49 private static final String LOG_TAG = "GlesStubActivity"; 50 private int mVersion = -1; 51 private GraphicsDeviceInfo mGraphicsDeviceInfo; 52 private CountDownLatch mDone = new CountDownLatch(1); 53 private HashSet<String> mOpenGlExtensions = new HashSet<String>(); 54 private HashSet<String> mFormats = new HashSet<String>(); 55 private HashMap<String, Object> mImplVariables = new HashMap<String, Object>(); 56 private HashSet<String> mDynamicArrayVariables = new HashSet<String>(); 57 private String mGraphicsVendor; 58 private String mGraphicsRenderer; 59 60 @Override onCreate(Bundle bundle)61 public void onCreate(Bundle bundle) { 62 // Dismiss keyguard and keep screen on while this test is on. 63 Window window = getWindow(); 64 window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | 65 WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | 66 WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 67 68 super.onCreate(bundle); 69 70 window.setFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, 71 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); 72 73 ActivityManager activityManager = 74 (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); 75 ConfigurationInfo info = activityManager.getDeviceConfigurationInfo(); 76 77 mVersion = (info.reqGlEsVersion & 0xffff0000) >> 16; 78 79 new Thread() { 80 @Override 81 public void run() { 82 runIterations(mVersion); 83 } 84 }.start(); 85 } 86 87 /** 88 * Wait for this activity to finish gathering information 89 */ waitForActivityToFinish()90 public void waitForActivityToFinish() { 91 try { 92 mDone.await(); 93 } catch (InterruptedException e) { 94 // just move on 95 } 96 } 97 runIterations(int glVersion)98 private void runIterations(int glVersion) { 99 for (int i = 1; i <= glVersion; i++) { 100 final CountDownLatch done = new CountDownLatch(1); 101 final int version = i; 102 GlesStubActivity.this.runOnUiThread(new Runnable() { 103 @Override 104 public void run() { 105 setContentView(new GlesSurfaceView(GlesStubActivity.this, version, done)); 106 } 107 }); 108 try { 109 done.await(); 110 } catch (InterruptedException e) { 111 // just move on 112 } 113 } 114 mDone.countDown(); 115 } 116 getGlVersion()117 int getGlVersion() { 118 return mVersion; 119 } 120 getOpenGlExtensions()121 List<String> getOpenGlExtensions() { 122 return new ArrayList<>(mOpenGlExtensions); 123 } 124 addOpenGlExtension(String openGlExtension)125 void addOpenGlExtension(String openGlExtension) { 126 mOpenGlExtensions.add(openGlExtension); 127 } 128 getCompressedTextureFormats()129 List<String> getCompressedTextureFormats() { 130 return new ArrayList<>(mFormats); 131 } 132 addCompressedTextureFormat(String format)133 void addCompressedTextureFormat(String format) { 134 mFormats.add(format); 135 } 136 getVendor()137 String getVendor() { 138 return mGraphicsVendor; 139 } 140 setVendor(String vendor)141 void setVendor(String vendor) { 142 mGraphicsVendor = vendor; 143 } 144 getRenderer()145 String getRenderer() { 146 return mGraphicsRenderer; 147 } 148 setRenderer(String renderer)149 void setRenderer(String renderer) { 150 mGraphicsRenderer = renderer; 151 } 152 getImplementationVariableNames()153 public Set<String> getImplementationVariableNames() { 154 return mImplVariables.keySet(); 155 } 156 getImplementationVariable(String name)157 public Object getImplementationVariable(String name) { 158 return mImplVariables.get(name); 159 } 160 isDynamicArrayVariable(String name)161 public boolean isDynamicArrayVariable(String name) { 162 return mDynamicArrayVariables.contains(name); 163 } 164 addImplementationVariable(String name, Object value, boolean isDynamicArray)165 void addImplementationVariable(String name, Object value, boolean isDynamicArray) { 166 mImplVariables.put(name, value); 167 if (isDynamicArray) { 168 mDynamicArrayVariables.add(name); 169 } 170 } 171 172 static class GlesSurfaceView extends GLSurfaceView { 173 GlesSurfaceView(GlesStubActivity parent, int glVersion, CountDownLatch done)174 public GlesSurfaceView(GlesStubActivity parent, int glVersion, CountDownLatch done) { 175 super(parent); 176 177 if (glVersion > 1) { 178 // Default is 1 so only set if bigger than 1 179 setEGLContextClientVersion(glVersion); 180 } 181 setRenderer(new OpenGlesRenderer(parent, glVersion, done)); 182 } 183 } 184 185 static abstract class ImplementationVariable { 186 private Field mField; ImplementationVariable(String fieldName)187 public ImplementationVariable(String fieldName) { 188 try { 189 mField = GLES30.class.getField(fieldName); 190 } catch (NoSuchFieldException e) { 191 Log.e(LOG_TAG, "Failed to get field reflection", e); 192 } 193 } 194 getName()195 public String getName() { 196 return mField.getName(); 197 } 198 getFieldIdValue()199 public int getFieldIdValue() throws IllegalAccessException { 200 return mField.getInt(null); 201 } 202 getValue()203 abstract public Object getValue(); 204 getIntValues(int fieldId, int count)205 static protected int[] getIntValues(int fieldId, int count) throws IllegalAccessException{ 206 int[] resultInts = new int[count]; 207 GLES20.glGetIntegerv(fieldId, resultInts, 0); 208 return resultInts; 209 } 210 } 211 212 static class IntVectorValue extends ImplementationVariable { 213 private int mCount; 214 IntVectorValue(String fieldName, int count)215 public IntVectorValue(String fieldName, int count) { 216 super(fieldName); 217 mCount = count; 218 } 219 220 @Override getValue()221 public Object getValue() { 222 Log.i(LOG_TAG, "Getting : " + this.getName() + " " + mCount); 223 try { 224 return getIntValues(this.getFieldIdValue(), mCount); 225 } catch (IllegalAccessException e) { 226 Log.e(LOG_TAG, "Failed to read the GL field", e); 227 } 228 return null; 229 } 230 } 231 232 static class DynamicIntVectorValue extends ImplementationVariable { 233 private Field mCountField; 234 DynamicIntVectorValue(String fieldName, String countFieldName)235 public DynamicIntVectorValue(String fieldName, String countFieldName) { 236 super(fieldName); 237 try { 238 mCountField = GLES30.class.getField(countFieldName); 239 } catch (NoSuchFieldException e) { 240 Log.e(LOG_TAG, "Failed to get field reflection", e); 241 } 242 } 243 244 @Override getValue()245 public Object getValue() { 246 Log.i(LOG_TAG, "Getting : " + this.getName() + " " + mCountField.getName()); 247 try { 248 int[] count = new int[] {0}; 249 GLES20.glGetIntegerv(mCountField.getInt(null), count, 0); 250 Log.i(LOG_TAG, "Getting : " + mCountField.getName() + " " + count[0]); 251 return getIntValues(this.getFieldIdValue(), count[0]); 252 } catch (IllegalAccessException e) { 253 Log.e(LOG_TAG, "Failed to read the GL field", e); 254 } 255 return null; 256 } 257 } 258 259 static class FloatVectorValue extends ImplementationVariable { 260 private int mCount; 261 FloatVectorValue(String fieldName, int count)262 public FloatVectorValue(String fieldName, int count) { 263 super(fieldName); 264 mCount = count; 265 } 266 267 @Override getValue()268 public Object getValue() { 269 Log.i(LOG_TAG, "Getting : " + this.getName() + " " + mCount); 270 try { 271 float[] result = new float[mCount]; 272 GLES20.glGetFloatv(getFieldIdValue(), result, 0); 273 return result; 274 } catch (IllegalAccessException e) { 275 Log.e(LOG_TAG, "Failed to read the GL field", e); 276 } 277 return null; 278 } 279 } 280 281 static class LongVectorValue extends ImplementationVariable { 282 private int mCount; 283 LongVectorValue(String fieldName, int count)284 public LongVectorValue(String fieldName, int count) { 285 super(fieldName); 286 mCount = count; 287 } 288 289 @Override getValue()290 public Object getValue() { 291 Log.i(LOG_TAG, "Getting : " + this.getName() + " " + mCount); 292 try { 293 long result[] = new long[mCount]; 294 GLES30.glGetInteger64v(getFieldIdValue(), result, 0); 295 return result; 296 } catch (IllegalAccessException e) { 297 Log.e(LOG_TAG, "Failed to read the GL field", e); 298 } 299 return null; 300 } 301 } 302 303 static class StringValue extends ImplementationVariable { StringValue(String fieldName)304 public StringValue(String fieldName) { 305 super(fieldName); 306 } 307 308 @Override getValue()309 public Object getValue() { 310 Log.i(LOG_TAG, "Getting : " + this.getName()); 311 String result = null; 312 try { 313 result = GLES20.glGetString(this.getFieldIdValue()); 314 } catch (IllegalAccessException e) { 315 Log.e(LOG_TAG, "Failed to read the GL field", e); 316 } 317 return result; 318 } 319 } 320 321 // NOTE: Changes to the types of the variables will carry over to 322 // GraphicsDeviceInfo proto via GraphicsDeviceInfo. See 323 // go/edi-userguide for details. 324 static ImplementationVariable[] GLES2_IMPLEMENTATION_VARIABLES = { 325 new IntVectorValue("GL_SUBPIXEL_BITS", 1), 326 new IntVectorValue("GL_MAX_TEXTURE_SIZE", 1), 327 new IntVectorValue("GL_MAX_CUBE_MAP_TEXTURE_SIZE", 1), 328 new IntVectorValue("GL_MAX_VIEWPORT_DIMS", 2), 329 new FloatVectorValue("GL_ALIASED_POINT_SIZE_RANGE", 2), 330 new FloatVectorValue("GL_ALIASED_LINE_WIDTH_RANGE", 2), 331 new DynamicIntVectorValue("GL_COMPRESSED_TEXTURE_FORMATS", "GL_NUM_COMPRESSED_TEXTURE_FORMATS"), 332 new DynamicIntVectorValue("GL_SHADER_BINARY_FORMATS", "GL_NUM_SHADER_BINARY_FORMATS"), 333 new IntVectorValue("GL_SHADER_COMPILER", 1), 334 new StringValue("GL_SHADING_LANGUAGE_VERSION"), 335 new StringValue("GL_VERSION"), 336 new IntVectorValue("GL_MAX_VERTEX_ATTRIBS", 1), 337 new IntVectorValue("GL_MAX_VERTEX_UNIFORM_VECTORS", 1), 338 new IntVectorValue("GL_MAX_VARYING_VECTORS", 1), 339 new IntVectorValue("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS", 1), 340 new IntVectorValue("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS", 1), 341 new IntVectorValue("GL_MAX_TEXTURE_IMAGE_UNITS", 1), 342 new IntVectorValue("GL_MAX_FRAGMENT_UNIFORM_VECTORS", 1), 343 new IntVectorValue("GL_MAX_RENDERBUFFER_SIZE", 1) 344 }; 345 346 static ImplementationVariable[] GLES3_IMPLEMENTATION_VARIABLES = { 347 new LongVectorValue("GL_MAX_ELEMENT_INDEX", 1), 348 new IntVectorValue("GL_MAX_3D_TEXTURE_SIZE", 1), 349 new IntVectorValue("GL_MAX_ARRAY_TEXTURE_LAYERS", 1), 350 new FloatVectorValue("GL_MAX_TEXTURE_LOD_BIAS", 1), 351 new IntVectorValue("GL_MAX_DRAW_BUFFERS", 1), 352 new IntVectorValue("GL_MAX_COLOR_ATTACHMENTS", 1), 353 new IntVectorValue("GL_MAX_ELEMENTS_INDICES", 1), 354 new IntVectorValue("GL_MAX_ELEMENTS_VERTICES", 1), 355 new DynamicIntVectorValue("GL_PROGRAM_BINARY_FORMATS", "GL_NUM_PROGRAM_BINARY_FORMATS"), 356 new LongVectorValue("GL_MAX_SERVER_WAIT_TIMEOUT", 1), 357 new IntVectorValue("GL_MAJOR_VERSION", 1), 358 new IntVectorValue("GL_MINOR_VERSION", 1), 359 new IntVectorValue("GL_MAX_VERTEX_UNIFORM_COMPONENTS", 1), 360 new IntVectorValue("GL_MAX_VERTEX_UNIFORM_BLOCKS", 1), 361 new IntVectorValue("GL_MAX_VERTEX_OUTPUT_COMPONENTS", 1), 362 new IntVectorValue("GL_MAX_FRAGMENT_UNIFORM_COMPONENTS", 1), 363 new IntVectorValue("GL_MAX_FRAGMENT_UNIFORM_BLOCKS", 1), 364 new IntVectorValue("GL_MAX_FRAGMENT_INPUT_COMPONENTS", 1), 365 new IntVectorValue("GL_MIN_PROGRAM_TEXEL_OFFSET", 1), 366 new IntVectorValue("GL_MAX_PROGRAM_TEXEL_OFFSET", 1), 367 new IntVectorValue("GL_MAX_UNIFORM_BUFFER_BINDINGS", 1), 368 new LongVectorValue("GL_MAX_UNIFORM_BLOCK_SIZE", 1), 369 new IntVectorValue("GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT", 1), 370 new IntVectorValue("GL_MAX_COMBINED_UNIFORM_BLOCKS", 1), 371 new LongVectorValue("GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", 1), 372 new LongVectorValue("GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", 1), 373 new IntVectorValue("GL_MAX_VARYING_COMPONENTS", 1), 374 new IntVectorValue("GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", 1), 375 new IntVectorValue("GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", 1), 376 new IntVectorValue("GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", 1) 377 }; 378 379 static class OpenGlesRenderer implements GLSurfaceView.Renderer { 380 381 private final GlesStubActivity mParent; 382 private final int mGlVersion; 383 private final CountDownLatch mDone; 384 OpenGlesRenderer(GlesStubActivity parent, int glVersion, CountDownLatch done)385 OpenGlesRenderer(GlesStubActivity parent, int glVersion, CountDownLatch done) { 386 mParent = parent; 387 mGlVersion = glVersion; 388 mDone = done; 389 } 390 391 @Override onSurfaceCreated(GL10 gl, EGLConfig config)392 public void onSurfaceCreated(GL10 gl, EGLConfig config) { 393 String extensions; 394 String vendor; 395 String renderer; 396 if (mGlVersion == 2) { 397 extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS); 398 vendor = GLES20.glGetString(GLES20.GL_VENDOR); 399 renderer = GLES20.glGetString(GLES20.GL_RENDERER); 400 collectImplementationVariables(GLES2_IMPLEMENTATION_VARIABLES); 401 } else if (mGlVersion == 3) { 402 extensions = GLES30.glGetString(GLES30.GL_EXTENSIONS); 403 vendor = GLES30.glGetString(GLES30.GL_VENDOR); 404 renderer = GLES30.glGetString(GLES30.GL_RENDERER); 405 collectImplementationVariables(GLES3_IMPLEMENTATION_VARIABLES); 406 } else { 407 extensions = gl.glGetString(GL10.GL_EXTENSIONS); 408 vendor = gl.glGetString(GL10.GL_VENDOR); 409 renderer = gl.glGetString(GL10.GL_RENDERER); 410 } 411 mParent.setVendor(vendor); 412 mParent.setRenderer(renderer); 413 Scanner scanner = new Scanner(extensions); 414 scanner.useDelimiter(" "); 415 while (scanner.hasNext()) { 416 String ext = scanner.next(); 417 mParent.addOpenGlExtension(ext); 418 if (ext.contains("texture")) { 419 if (ext.contains("compression") || ext.contains("compressed")) { 420 mParent.addCompressedTextureFormat(ext); 421 } 422 } 423 } 424 scanner.close(); 425 426 mDone.countDown(); 427 } 428 429 @Override onSurfaceChanged(GL10 gl, int width, int height)430 public void onSurfaceChanged(GL10 gl, int width, int height) {} 431 432 @Override onDrawFrame(GL10 gl)433 public void onDrawFrame(GL10 gl) {} 434 collectImplementationVariables(ImplementationVariable[] variables)435 private void collectImplementationVariables(ImplementationVariable[] variables) { 436 for (int i = 0; i < variables.length; i++) { 437 String name = variables[i].getName(); 438 Object value = variables[i].getValue(); 439 boolean dynamicArray = variables[i] instanceof DynamicIntVectorValue; 440 mParent.addImplementationVariable(name, value, dynamicArray); 441 } 442 } 443 } 444 } 445