1 /*
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14 
15 #include "device_info/device_info.h"
16 
17 #include <sys/system_properties.h>
18 #include <EGL/egl.h>
19 #include <GLES3/gl32.h>
20 
21 #include <cstdint>
22 #include <string>
23 #include <sstream>
24 #include <fstream>
25 #include <vector>
26 #include <set>
27 
28 namespace {
29 using ProtoInfoWithErrors = androidgamesdk_deviceinfo::InfoWithErrors;
30 using ProtoErrors         = androidgamesdk_deviceinfo::Errors;
31 using ProtoInfo           = androidgamesdk_deviceinfo::Info;
32 using ProtoCpuCore        = androidgamesdk_deviceinfo::Info::CpuCore;
33 using ProtoGl             = androidgamesdk_deviceinfo::Info::Gl;
34 
35 // size of GL view and texture in future
36 constexpr int VIEW_WIDTH = 8;
37 constexpr int VIEW_HEIGHT = VIEW_WIDTH;
38 
39 namespace string_util {
startsWith(const std::string & text,const std::string & start)40 bool startsWith(const std::string& text, const std::string& start) {
41   return text.compare(0, start.length(), start) == 0;
42 }
43 
splitAdd(const std::string & toSplit,char delimeter,std::set<std::string> * result)44 void splitAdd(const std::string& toSplit, char delimeter,
45               std::set<std::string>* result) {
46   std::istringstream istr(toSplit);
47   std::string piece;
48   while (std::getline(istr, piece, delimeter)) {
49     if (piece.length() > 0) {
50       result->insert(piece);
51     }
52   }
53 }
54 }  // namespace string_util
55 
56 template <typename T>
readFile(const std::string & fileName,const T & error)57 T readFile(const std::string& fileName, const T& error) {
58   std::ifstream reader(fileName);
59   if (reader.fail()) return error;
60   T result;
61   reader >> result;
62   if (reader.fail()) return error;
63   return result;
64 }
65 
readCpuPresent()66 std::string readCpuPresent() {
67   const std::string ERROR = "ERROR";
68   return readFile("/sys/devices/system/cpu/present", ERROR);
69 }
readCpuPossible()70 std::string readCpuPossible() {
71   const std::string ERROR = "ERROR";
72   return readFile("/sys/devices/system/cpu/possible", ERROR);
73 }
readCpuIndexMax()74 int readCpuIndexMax() {
75   constexpr int ERROR = -1;
76   return readFile("/sys/devices/system/cpu/kernel_max", ERROR);
77 }
readCpuFreqMax(int cpuIndex)78 int64_t readCpuFreqMax(int cpuIndex) {
79   const std::string fileName =
80     "/sys/devices/system/cpu/cpu" +
81     std::to_string(cpuIndex) +
82     "/cpufreq/cpuinfo_max_freq";
83   constexpr int64_t ERROR = -1;
84   return readFile(fileName, ERROR);
85 }
86 
87 // returns number of errors
readHardware(std::vector<std::string> & result,ProtoErrors & errors)88 int readHardware(std::vector<std::string>& result, ProtoErrors& errors) {
89   std::ifstream f("/proc/cpuinfo");
90   if (f.fail()){
91     errors.set_hardware("Could not read.");
92     return 1;
93   }
94   const std::string FIELD_KEY = "Hardware\t: ";
95   std::string line;
96   while (std::getline(f, line)) {
97     if (::string_util::startsWith(line, FIELD_KEY)) {
98       std::string val = line.substr(FIELD_KEY.length(), std::string::npos);
99       result.push_back(val);
100     }
101   }
102   return 0;
103 }
104 
105 // returns number of errors
readFeatures(std::set<std::string> & result,ProtoErrors & errors)106 int readFeatures(std::set<std::string>& result, ProtoErrors& errors) {
107   std::ifstream f("/proc/cpuinfo");
108   if (f.fail()){
109     errors.set_features("Could not read.");
110     return 1;
111   }
112   const std::string FIELD_KEY = "Features\t: ";
113   std::string line;
114   while (std::getline(f, line)) {
115     if (::string_util::startsWith(line, FIELD_KEY)) {
116       std::string features = line.substr(FIELD_KEY.length(), std::string::npos);
117       ::string_util::splitAdd(features, ' ', &result);
118     }
119   }
120   return 0;
121 }
122 
getSystemPropViaGet(const char * key,::ProtoErrors & errors)123 std::string getSystemPropViaGet(const char* key, ::ProtoErrors& errors) {
124   char buffer[PROP_VALUE_MAX + 1];  // +1 for terminator
125   int bufferLen = __system_property_get(key, buffer);
126   if (bufferLen > PROP_VALUE_MAX){
127     const std::string HEADER = "Overflow: ";
128     errors.add_system_props(HEADER + key);
129     return "";
130   }
131   return std::string(buffer, bufferLen);
132 }
133 
getSystemPropViaReadCallback(const char * key)134 std::string getSystemPropViaReadCallback(const char* key) {
135   const prop_info* pi = __system_property_find(key);
136   if (pi == nullptr) {
137     return "";
138   }
139   std::string result;
140   __system_property_read_callback(pi,
141     [](void* cookie, const char*, const char* value, unsigned) {
142       auto sysOut = reinterpret_cast<std::string*>(cookie);
143       *sysOut = value;
144     },
145     &result
146   );
147   return result;
148 }
149 
getSystemProp(const char * key,::ProtoErrors & errors,bool useCallbackApi)150 std::string getSystemProp(const char* key,
151   ::ProtoErrors& errors, bool useCallbackApi) {
152   if (useCallbackApi) {
153     return getSystemPropViaReadCallback(key);
154   } else {
155     return getSystemPropViaGet(key, errors);
156   }
157 }
158 
159 // returns number of errors
addSystemProperties(::ProtoInfo & info,::ProtoErrors & errors)160 int addSystemProperties(::ProtoInfo& info, ::ProtoErrors& errors) {
161   std::string sdkVersionString =
162     getSystemPropViaGet("ro.build.version.sdk", errors);
163   info.set_ro_build_version_sdk(sdkVersionString);
164 
165   int sdkVersion = atoi(sdkVersionString.c_str());
166   bool useCallbackApi = (26 <= sdkVersion);
167   info.set_ro_chipname(
168     getSystemProp("ro.chipname", errors, useCallbackApi));
169   info.set_ro_board_platform(
170     getSystemProp("ro.board.platform", errors, useCallbackApi));
171   info.set_ro_product_board(
172     getSystemProp("ro.product.board", errors, useCallbackApi));
173   info.set_ro_mediatek_platform(
174     getSystemProp("ro.mediatek.platform", errors, useCallbackApi));
175   info.set_ro_arch(
176     getSystemProp("ro.arch", errors, useCallbackApi));
177   info.set_ro_build_fingerprint(
178     getSystemProp("ro.build.fingerprint", errors, useCallbackApi));
179 
180   return errors.system_props_size();
181 }
182 
183 // returns number of errors
checkEglError(const char * title,::ProtoErrors & errors)184 int checkEglError(const char* title, ::ProtoErrors& errors) {
185   EGLint error = eglGetError();
186   if (error == EGL_SUCCESS) return 0;
187   std::stringstream ss;
188   ss << title << ": 0x" << std::hex << (int)error << std::dec;
189   errors.set_egl(ss.str());
190   return 1;
191 }
192 
flushGlErrors(::ProtoErrors & errors)193 int flushGlErrors(::ProtoErrors& errors) {
194   int numErrors = 0;
195   while (GLenum e = glGetError() != GL_NO_ERROR) {
196     std::stringstream ss;
197     ss << "0x" << std::hex << (int)e << std::dec;
198     errors.add_gl(ss.str());
199     numErrors++;
200   }
201   return numErrors;
202 }
203 
204 // returns number of errors
setupEGl(::ProtoInfoWithErrors & proto)205 int setupEGl(::ProtoInfoWithErrors& proto) {
206   ProtoErrors& errors = *proto.mutable_errors();
207 
208   EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
209   if (int numErrors = checkEglError("eglGetDisplay", errors)){
210     return numErrors;
211   }
212 
213   eglInitialize(display, nullptr, nullptr);  // do not care about egl version
214   if (int numErrors = checkEglError("eglInitialize", errors)){
215     return numErrors;
216   }
217 
218   EGLint configAttribs[] = {
219     EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
220     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
221     EGL_RED_SIZE, 8,
222     EGL_GREEN_SIZE, 8,
223     EGL_BLUE_SIZE, 8,
224     EGL_ALPHA_SIZE, 8,
225     EGL_NONE
226   };
227   EGLConfig config;
228   EGLint numConfigs = -1;
229   eglChooseConfig(display, configAttribs, &config, 1, &numConfigs);
230   if (int numErrors = checkEglError("eglChooseConfig", errors)){
231     return numErrors;
232   }
233 
234   EGLint contextAttribs[] = {
235     EGL_CONTEXT_CLIENT_VERSION, 2,
236     EGL_NONE
237   };
238   EGLContext context =
239     eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
240   if (int numErrors = checkEglError("eglCreateContext", errors)){
241     return numErrors;
242   }
243 
244   EGLint pbufferAttribs[] = {
245     EGL_WIDTH,  VIEW_WIDTH,
246     EGL_HEIGHT, VIEW_HEIGHT,
247     EGL_NONE
248   };
249   EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttribs);
250   if (int numErrors = checkEglError("eglCreatePbufferSurface", errors)){
251     return numErrors;
252   }
253 
254   eglMakeCurrent(display, surface, surface, context);
255   if (int numErrors = checkEglError("eglMakeCurrent", errors)){
256     return numErrors;
257   }
258 
259   return 0;
260 }
261 
262 namespace gl_util {
263 typedef const GLubyte* GlStr;
264 typedef GlStr(*FuncTypeGlGetstringi)(GLenum, GLint);
265 FuncTypeGlGetstringi glGetStringi = 0;
getStringIndexed(GLenum e,GLuint index)266 const char* getStringIndexed(GLenum e, GLuint index){
267   return reinterpret_cast<const char*>(::gl_util::glGetStringi(e, index));
268 }
269 
270 typedef void(*FuncTypeGlGetInteger64v)(GLenum, GLint64*);
271 FuncTypeGlGetInteger64v glGetInteger64v = 0;
getInt64(GLenum e)272 GLint64 getInt64(GLenum e) {
273   GLint64 result = -1;
274   glGetInteger64v(e, &result);
275   return result;
276 }
277 
278 typedef void(*FuncTypeGlGetIntegeri_v)(GLenum, GLuint, GLint*);
279 FuncTypeGlGetIntegeri_v glGetIntegeri_v = 0;
getIntIndexed(GLenum e,GLuint index)280 GLint getIntIndexed(GLenum e, GLuint index) {
281   GLint result = -1;
282   glGetIntegeri_v(e, index, &result);
283   return result;
284 }
285 
getString(GLenum e)286 const char* getString(GLenum e){
287   return reinterpret_cast<const char*>(glGetString(e));
288 }
289 
getFloat(GLenum e)290 GLfloat getFloat(GLenum e) {
291   GLfloat result = -1;
292   glGetFloatv(e, &result);
293   return result;
294 }
getInt(GLenum e)295 GLint getInt(GLenum e) {
296   GLint result = -1;
297   glGetIntegerv(e, &result);
298   return result;
299 }
getBool(GLenum e)300 GLboolean getBool(GLenum e) {
301   GLboolean result = false;
302   glGetBooleanv(e, &result);
303   return result;
304 }
305 }  // namespace gl_util
306 
addGlConstsV2_0(::ProtoGl & gl)307 void addGlConstsV2_0(::ProtoGl& gl) {
308   gl.set_gl_aliased_line_width_range(
309     ::gl_util::getFloat(GL_ALIASED_LINE_WIDTH_RANGE));
310   gl.set_gl_aliased_point_size_range(
311     ::gl_util::getFloat(GL_ALIASED_POINT_SIZE_RANGE));
312   gl.set_gl_max_combined_texture_image_units(
313     ::gl_util::getInt(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS));
314   gl.set_gl_max_cube_map_texture_size(
315     ::gl_util::getInt(GL_MAX_CUBE_MAP_TEXTURE_SIZE));
316   gl.set_gl_max_fragment_uniform_vectors(
317     ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_VECTORS));
318   gl.set_gl_max_renderbuffer_size(
319     ::gl_util::getInt(GL_MAX_RENDERBUFFER_SIZE));
320   gl.set_gl_max_texture_image_units(
321     ::gl_util::getInt(GL_MAX_TEXTURE_IMAGE_UNITS));
322   gl.set_gl_max_texture_size(
323     ::gl_util::getInt(GL_MAX_TEXTURE_SIZE));
324   gl.set_gl_max_varying_vectors(
325     ::gl_util::getInt(GL_MAX_VARYING_VECTORS));
326   gl.set_gl_max_vertex_attribs(
327     ::gl_util::getInt(GL_MAX_VERTEX_ATTRIBS));
328   gl.set_gl_max_vertex_texture_image_units(
329     ::gl_util::getInt(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS));
330   gl.set_gl_max_vertex_uniform_vectors(
331     ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_VECTORS));
332   gl.set_gl_max_viewport_dims(
333     ::gl_util::getInt(GL_MAX_VIEWPORT_DIMS));
334   gl.set_gl_shader_compiler(
335     ::gl_util::getBool(GL_SHADER_COMPILER));
336   gl.set_gl_subpixel_bits(
337     ::gl_util::getInt(GL_SUBPIXEL_BITS));
338 
339   GLint numCompressedFormats =
340     ::gl_util::getInt(GL_NUM_COMPRESSED_TEXTURE_FORMATS);
341   gl.set_gl_num_compressed_texture_formats(numCompressedFormats);
342   std::vector<GLint> compressedFormats(numCompressedFormats);
343   glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &compressedFormats[0]);
344   for (auto x : compressedFormats) {
345     gl.add_gl_compressed_texture_formats(x);
346   }
347 
348   GLint numShaderBinFormats = ::gl_util::getInt(GL_NUM_SHADER_BINARY_FORMATS);
349   gl.set_gl_num_shader_binary_formats(numShaderBinFormats);
350   std::vector<GLint> shaderBinFormats(numShaderBinFormats);
351   glGetIntegerv(GL_SHADER_BINARY_FORMATS, &shaderBinFormats[0]);
352   for (auto x : shaderBinFormats) {
353     gl.add_gl_shader_binary_formats(x);
354   }
355 
356   // shader precision formats
357   GLint spfr = -1;  // range
358   GLint spfp = -1;  // precision
359   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_FLOAT, &spfr, &spfp);
360   gl.set_spf_vertex_float_low_range(spfr);
361   gl.set_spf_vertex_float_low_prec(spfp);
362   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_FLOAT, &spfr, &spfp);
363   gl.set_spf_vertex_float_med_range(spfr);
364   gl.set_spf_vertex_float_med_prec(spfp);
365   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_FLOAT, &spfr, &spfp);
366   gl.set_spf_vertex_float_hig_range(spfr);
367   gl.set_spf_vertex_float_hig_prec(spfp);
368   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_INT, &spfr, &spfp);
369   gl.set_spf_vertex_int_low_range(spfr);
370   gl.set_spf_vertex_int_low_prec(spfp);
371   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_INT, &spfr, &spfp);
372   gl.set_spf_vertex_int_med_range(spfr);
373   gl.set_spf_vertex_int_med_prec(spfp);
374   glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_INT, &spfr, &spfp);
375   gl.set_spf_vertex_int_hig_range(spfr);
376   gl.set_spf_vertex_int_hig_prec(spfp);
377   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_FLOAT, &spfr, &spfp);
378   gl.set_spf_fragment_float_low_range(spfr);
379   gl.set_spf_fragment_float_low_prec(spfp);
380   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, &spfr, &spfp);
381   gl.set_spf_fragment_float_med_range(spfr);
382   gl.set_spf_fragment_float_med_prec(spfp);
383   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, &spfr, &spfp);
384   gl.set_spf_fragment_float_hig_range(spfr);
385   gl.set_spf_fragment_float_hig_prec(spfp);
386   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_INT, &spfr, &spfp);
387   gl.set_spf_fragment_int_low_range(spfr);
388   gl.set_spf_fragment_int_low_prec(spfp);
389   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_INT, &spfr, &spfp);
390   gl.set_spf_fragment_int_med_range(spfr);
391   gl.set_spf_fragment_int_med_prec(spfp);
392   glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_INT, &spfr, &spfp);
393   gl.set_spf_fragment_int_hig_range(spfr);
394   gl.set_spf_fragment_int_hig_prec(spfp);
395 }
addGlConstsV3_0(::ProtoGl & gl)396 void addGlConstsV3_0(::ProtoGl& gl) {
397   gl.set_gl_max_3d_texture_size(
398     ::gl_util::getInt(GL_MAX_3D_TEXTURE_SIZE));
399   gl.set_gl_max_array_texture_layers(
400     ::gl_util::getInt(GL_MAX_ARRAY_TEXTURE_LAYERS));
401   gl.set_gl_max_color_attachments(
402     ::gl_util::getInt(GL_MAX_COLOR_ATTACHMENTS));
403   gl.set_gl_max_combined_uniform_blocks(
404     ::gl_util::getInt(GL_MAX_COMBINED_UNIFORM_BLOCKS));
405   gl.set_gl_max_draw_buffers(
406     ::gl_util::getInt(GL_MAX_DRAW_BUFFERS));
407   gl.set_gl_max_elements_indices(
408     ::gl_util::getInt(GL_MAX_ELEMENTS_INDICES));
409   gl.set_gl_max_elements_vertices(
410     ::gl_util::getInt(GL_MAX_ELEMENTS_VERTICES));
411   gl.set_gl_max_fragment_input_components(
412     ::gl_util::getInt(GL_MAX_FRAGMENT_INPUT_COMPONENTS));
413   gl.set_gl_max_fragment_uniform_blocks(
414     ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_BLOCKS));
415   gl.set_gl_max_fragment_uniform_components(
416     ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS));
417   gl.set_gl_max_program_texel_offset(
418     ::gl_util::getInt(GL_MAX_PROGRAM_TEXEL_OFFSET));
419   gl.set_gl_max_transform_feedback_interleaved_components(
420     ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS));
421   gl.set_gl_max_transform_feedback_separate_attribs(
422     ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS));
423   gl.set_gl_max_transform_feedback_separate_components(
424     ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS));
425   gl.set_gl_max_uniform_buffer_bindings(
426     ::gl_util::getInt(GL_MAX_UNIFORM_BUFFER_BINDINGS));
427   gl.set_gl_max_varying_components(
428     ::gl_util::getInt(GL_MAX_VARYING_COMPONENTS));
429   gl.set_gl_max_vertex_output_components(
430     ::gl_util::getInt(GL_MAX_VERTEX_OUTPUT_COMPONENTS));
431   gl.set_gl_max_vertex_uniform_blocks(
432     ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_BLOCKS));
433   gl.set_gl_max_vertex_uniform_components(
434     ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_COMPONENTS));
435   gl.set_gl_min_program_texel_offset(
436     ::gl_util::getInt(GL_MIN_PROGRAM_TEXEL_OFFSET));
437   gl.set_gl_uniform_buffer_offset_alignment(
438     ::gl_util::getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT));
439   gl.set_gl_max_samples(
440     ::gl_util::getInt(GL_MAX_SAMPLES));
441 
442   gl.set_gl_max_texture_lod_bias(::gl_util::getFloat(GL_MAX_TEXTURE_LOD_BIAS));
443 
444   ::gl_util::glGetInteger64v =
445     reinterpret_cast<::gl_util::FuncTypeGlGetInteger64v>(
446       eglGetProcAddress("glGetInteger64v"));
447   gl.set_gl_max_combined_fragment_uniform_components(
448     ::gl_util::getInt64(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS));
449   gl.set_gl_max_element_index(
450     ::gl_util::getInt64(GL_MAX_ELEMENT_INDEX));
451   gl.set_gl_max_server_wait_timeout(
452     ::gl_util::getInt64(GL_MAX_SERVER_WAIT_TIMEOUT));
453   gl.set_gl_max_uniform_block_size(
454     ::gl_util::getInt64(GL_MAX_UNIFORM_BLOCK_SIZE));
455 }
addGlConstsV3_1(::ProtoGl & gl)456 void addGlConstsV3_1(::ProtoGl& gl) {
457   gl.set_gl_max_atomic_counter_buffer_bindings(
458     ::gl_util::getInt(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS));
459   gl.set_gl_max_atomic_counter_buffer_size(
460     ::gl_util::getInt(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE));
461   gl.set_gl_max_color_texture_samples(
462     ::gl_util::getInt(GL_MAX_COLOR_TEXTURE_SAMPLES));
463   gl.set_gl_max_combined_atomic_counters(
464     ::gl_util::getInt(GL_MAX_COMBINED_ATOMIC_COUNTERS));
465   gl.set_gl_max_combined_atomic_counter_buffers(
466     ::gl_util::getInt(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS));
467   gl.set_gl_max_combined_compute_uniform_components(
468     ::gl_util::getInt(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS));
469   gl.set_gl_max_combined_image_uniforms(
470     ::gl_util::getInt(GL_MAX_COMBINED_IMAGE_UNIFORMS));
471   gl.set_gl_max_combined_shader_output_resources(
472     ::gl_util::getInt(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES));
473   gl.set_gl_max_combined_shader_storage_blocks(
474     ::gl_util::getInt(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS));
475   gl.set_gl_max_compute_atomic_counters(
476     ::gl_util::getInt(GL_MAX_COMPUTE_ATOMIC_COUNTERS));
477   gl.set_gl_max_compute_atomic_counter_buffers(
478     ::gl_util::getInt(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS));
479   gl.set_gl_max_compute_image_uniforms(
480     ::gl_util::getInt(GL_MAX_COMPUTE_IMAGE_UNIFORMS));
481   gl.set_gl_max_compute_shader_storage_blocks(
482     ::gl_util::getInt(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS));
483   gl.set_gl_max_compute_shared_memory_size(
484     ::gl_util::getInt(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE));
485   gl.set_gl_max_compute_texture_image_units(
486     ::gl_util::getInt(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS));
487   gl.set_gl_max_compute_uniform_blocks(
488     ::gl_util::getInt(GL_MAX_COMPUTE_UNIFORM_BLOCKS));
489   gl.set_gl_max_compute_uniform_components(
490     ::gl_util::getInt(GL_MAX_COMPUTE_UNIFORM_COMPONENTS));
491   gl.set_gl_max_compute_work_group_invocations(
492     ::gl_util::getInt(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS));
493   gl.set_gl_max_depth_texture_samples(
494     ::gl_util::getInt(GL_MAX_DEPTH_TEXTURE_SAMPLES));
495   gl.set_gl_max_fragment_atomic_counters(
496     ::gl_util::getInt(GL_MAX_FRAGMENT_ATOMIC_COUNTERS));
497   gl.set_gl_max_fragment_atomic_counter_buffers(
498     ::gl_util::getInt(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS));
499   gl.set_gl_max_fragment_image_uniforms(
500     ::gl_util::getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS));
501   gl.set_gl_max_fragment_shader_storage_blocks(
502     ::gl_util::getInt(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS));
503   gl.set_gl_max_framebuffer_height(
504     ::gl_util::getInt(GL_MAX_FRAMEBUFFER_HEIGHT));
505   gl.set_gl_max_framebuffer_samples(
506     ::gl_util::getInt(GL_MAX_FRAMEBUFFER_SAMPLES));
507   gl.set_gl_max_framebuffer_width(
508     ::gl_util::getInt(GL_MAX_FRAMEBUFFER_WIDTH));
509   gl.set_gl_max_image_units(
510     ::gl_util::getInt(GL_MAX_IMAGE_UNITS));
511   gl.set_gl_max_integer_samples(
512     ::gl_util::getInt(GL_MAX_INTEGER_SAMPLES));
513   gl.set_gl_max_program_texture_gather_offset(
514     ::gl_util::getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET));
515   gl.set_gl_max_sample_mask_words(
516     ::gl_util::getInt(GL_MAX_SAMPLE_MASK_WORDS));
517   gl.set_gl_max_shader_storage_buffer_bindings(
518     ::gl_util::getInt(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS));
519   gl.set_gl_max_uniform_locations(
520     ::gl_util::getInt(GL_MAX_UNIFORM_LOCATIONS));
521   gl.set_gl_max_vertex_atomic_counters(
522     ::gl_util::getInt(GL_MAX_VERTEX_ATOMIC_COUNTERS));
523   gl.set_gl_max_vertex_atomic_counter_buffers(
524     ::gl_util::getInt(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS));
525   gl.set_gl_max_vertex_attrib_bindings(
526     ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_BINDINGS));
527   gl.set_gl_max_vertex_attrib_relative_offset(
528     ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET));
529   gl.set_gl_max_vertex_attrib_stride(
530     ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_STRIDE));
531   gl.set_gl_max_vertex_image_uniforms(
532     ::gl_util::getInt(GL_MAX_VERTEX_IMAGE_UNIFORMS));
533   gl.set_gl_max_vertex_shader_storage_blocks(
534     ::gl_util::getInt(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS));
535   gl.set_gl_min_program_texture_gather_offset(
536     ::gl_util::getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET));
537   gl.set_gl_shader_storage_buffer_offset_alignment(
538     ::gl_util::getInt(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT));
539 
540   gl.set_gl_max_shader_storage_block_size(
541     ::gl_util::getInt64(GL_MAX_SHADER_STORAGE_BLOCK_SIZE));
542 
543   ::gl_util::glGetIntegeri_v =
544     reinterpret_cast<::gl_util::FuncTypeGlGetIntegeri_v>(
545       eglGetProcAddress("glGetIntegeri_v"));
546   gl.set_gl_max_compute_work_group_count_0(
547     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0));
548   gl.set_gl_max_compute_work_group_count_1(
549     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1));
550   gl.set_gl_max_compute_work_group_count_2(
551     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2));
552   gl.set_gl_max_compute_work_group_size_0(
553     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0));
554   gl.set_gl_max_compute_work_group_size_1(
555     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1));
556   gl.set_gl_max_compute_work_group_size_2(
557     ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2));
558 }
addGlConstsV3_2(::ProtoGl & gl)559 void addGlConstsV3_2(::ProtoGl& gl) {
560   gl.set_gl_context_flags(
561     ::gl_util::getInt(GL_CONTEXT_FLAGS));
562   gl.set_gl_fragment_interpolation_offset_bits(
563     ::gl_util::getInt(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS));
564   gl.set_gl_layer_provoking_vertex(
565     ::gl_util::getInt(GL_LAYER_PROVOKING_VERTEX));
566   gl.set_gl_max_combined_geometry_uniform_components(
567     ::gl_util::getInt(GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS));
568   gl.set_gl_max_combined_tess_control_uniform_components(
569     ::gl_util::getInt(GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS));
570   gl.set_gl_max_combined_tess_evaluation_uniform_components(
571     ::gl_util::getInt(GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS));
572   gl.set_gl_max_debug_group_stack_depth(
573     ::gl_util::getInt(GL_MAX_DEBUG_GROUP_STACK_DEPTH));
574   gl.set_gl_max_debug_logged_messages(
575     ::gl_util::getInt(GL_MAX_DEBUG_LOGGED_MESSAGES));
576   gl.set_gl_max_debug_message_length(
577     ::gl_util::getInt(GL_MAX_DEBUG_MESSAGE_LENGTH));
578   gl.set_gl_max_framebuffer_layers(
579     ::gl_util::getInt(GL_MAX_FRAMEBUFFER_LAYERS));
580   gl.set_gl_max_geometry_atomic_counters(
581     ::gl_util::getInt(GL_MAX_GEOMETRY_ATOMIC_COUNTERS));
582   gl.set_gl_max_geometry_atomic_counter_buffers(
583     ::gl_util::getInt(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS));
584   gl.set_gl_max_geometry_image_uniforms(
585     ::gl_util::getInt(GL_MAX_GEOMETRY_IMAGE_UNIFORMS));
586   gl.set_gl_max_geometry_input_components(
587     ::gl_util::getInt(GL_MAX_GEOMETRY_INPUT_COMPONENTS));
588   gl.set_gl_max_geometry_output_components(
589     ::gl_util::getInt(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS));
590   gl.set_gl_max_geometry_output_vertices(
591     ::gl_util::getInt(GL_MAX_GEOMETRY_OUTPUT_VERTICES));
592   gl.set_gl_max_geometry_shader_invocations(
593     ::gl_util::getInt(GL_MAX_GEOMETRY_SHADER_INVOCATIONS));
594   gl.set_gl_max_geometry_shader_storage_blocks(
595     ::gl_util::getInt(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS));
596   gl.set_gl_max_geometry_texture_image_units(
597     ::gl_util::getInt(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS));
598   gl.set_gl_max_geometry_total_output_components(
599     ::gl_util::getInt(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS));
600   gl.set_gl_max_geometry_uniform_blocks(
601     ::gl_util::getInt(GL_MAX_GEOMETRY_UNIFORM_BLOCKS));
602   gl.set_gl_max_geometry_uniform_components(
603     ::gl_util::getInt(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS));
604   gl.set_gl_max_label_length(
605     ::gl_util::getInt(GL_MAX_LABEL_LENGTH));
606   gl.set_gl_max_patch_vertices(
607     ::gl_util::getInt(GL_MAX_PATCH_VERTICES));
608   gl.set_gl_max_tess_control_atomic_counters(
609     ::gl_util::getInt(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS));
610   gl.set_gl_max_tess_control_atomic_counter_buffers(
611     ::gl_util::getInt(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS));
612   gl.set_gl_max_tess_control_image_uniforms(
613     ::gl_util::getInt(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS));
614   gl.set_gl_max_tess_control_input_components(
615     ::gl_util::getInt(GL_MAX_TESS_CONTROL_INPUT_COMPONENTS));
616   gl.set_gl_max_tess_control_output_components(
617     ::gl_util::getInt(GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS));
618   gl.set_gl_max_tess_control_shader_storage_blocks(
619     ::gl_util::getInt(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS));
620   gl.set_gl_max_tess_control_texture_image_units(
621     ::gl_util::getInt(GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS));
622   gl.set_gl_max_tess_control_total_output_components(
623     ::gl_util::getInt(GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS));
624   gl.set_gl_max_tess_control_uniform_blocks(
625     ::gl_util::getInt(GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS));
626   gl.set_gl_max_tess_control_uniform_components(
627     ::gl_util::getInt(GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS));
628   gl.set_gl_max_tess_evaluation_atomic_counters(
629     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS));
630   gl.set_gl_max_tess_evaluation_atomic_counter_buffers(
631     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS));
632   gl.set_gl_max_tess_evaluation_image_uniforms(
633     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS));
634   gl.set_gl_max_tess_evaluation_input_components(
635     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS));
636   gl.set_gl_max_tess_evaluation_output_components(
637     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS));
638   gl.set_gl_max_tess_evaluation_shader_storage_blocks(
639     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS));
640   gl.set_gl_max_tess_evaluation_texture_image_units(
641     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS));
642   gl.set_gl_max_tess_evaluation_uniform_blocks(
643     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS));
644   gl.set_gl_max_tess_evaluation_uniform_components(
645     ::gl_util::getInt(GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS));
646   gl.set_gl_max_tess_gen_level(
647     ::gl_util::getInt(GL_MAX_TESS_GEN_LEVEL));
648   gl.set_gl_max_tess_patch_components(
649     ::gl_util::getInt(GL_MAX_TESS_PATCH_COMPONENTS));
650   gl.set_gl_max_texture_buffer_size(
651     ::gl_util::getInt(GL_MAX_TEXTURE_BUFFER_SIZE));
652   gl.set_gl_texture_buffer_offset_alignment(
653     ::gl_util::getInt(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT));
654   gl.set_gl_reset_notification_strategy(
655     ::gl_util::getInt(GL_RESET_NOTIFICATION_STRATEGY));
656   gl.set_gl_max_fragment_interpolation_offset(
657     ::gl_util::getFloat(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET));
658   gl.set_gl_min_fragment_interpolation_offset(
659     ::gl_util::getFloat(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET));
660   gl.set_gl_multisample_line_width_granularity(
661     ::gl_util::getFloat(GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY));
662   gl.set_gl_multisample_line_width_range(
663     ::gl_util::getFloat(GL_MULTISAMPLE_LINE_WIDTH_RANGE));
664 
665   gl.set_gl_primitive_restart_for_patches_supported(
666     ::gl_util::getBool(GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED));
667 }
668 
669 // returns number of errors
addGl(::ProtoInfoWithErrors & proto)670 int addGl(::ProtoInfoWithErrors& proto) {
671   int numErrors = 0;
672 
673   ::ProtoInfo& info = *proto.mutable_info();
674   ::ProtoGl& gl = *info.mutable_gl();
675   ::ProtoErrors& errors = *proto.mutable_errors();
676 
677   gl.set_renderer(::gl_util::getString(GL_RENDERER));
678   gl.set_vendor(::gl_util::getString(GL_VENDOR));
679   gl.set_version(::gl_util::getString(GL_VERSION));
680   gl.set_shading_language_version(
681     ::gl_util::getString(GL_SHADING_LANGUAGE_VERSION));
682 
683   numErrors += flushGlErrors(errors);
684 
685   GLint glVerMajor = -1;
686   GLint glVerMinor = -1;
687   glGetIntegerv(GL_MAJOR_VERSION, &glVerMajor);
688   // if GL_MAJOR_VERSION is not recognized, assume version 2.0
689   if (glGetError() != GL_NO_ERROR) {
690     glVerMajor = 2;
691     glVerMinor = 0;
692   } else {
693     glGetIntegerv(GL_MINOR_VERSION, &glVerMinor);
694   }
695   gl.set_version_major(glVerMajor);
696   gl.set_version_minor(glVerMinor);
697 
698   // gl extensions
699   if (glVerMajor >= 3) {
700     int numExts = -1;
701     glGetIntegerv(GL_NUM_EXTENSIONS, &numExts);
702     ::gl_util::glGetStringi = reinterpret_cast<::gl_util::FuncTypeGlGetstringi>(
703                                 eglGetProcAddress("glGetStringi"));
704     for (int i = 0; i < numExts; i++) {
705       std::string s = ::gl_util::getStringIndexed(GL_EXTENSIONS, i);
706       gl.add_extension(s);
707     }
708   } else {
709     std::string exts = ::gl_util::getString(GL_EXTENSIONS);
710     std::set<std::string> split;
711     ::string_util::splitAdd(exts, ' ', &split);
712     for (const std::string& s : split) {
713       gl.add_extension(s);
714     }
715   }
716 
717   if (glVerMajor > 2 || (glVerMajor == 2 && glVerMinor >= 0)) {  // >= gles 2.0
718     addGlConstsV2_0(gl);
719   }
720   if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 0)) {  // >= gles 3.0
721     addGlConstsV3_0(gl);
722   }
723   if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 1)) {  // >= gles 3.1
724     addGlConstsV3_1(gl);
725   }
726   if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 2)) {  // >= gles 3.2
727     addGlConstsV3_2(gl);
728   }
729 
730   numErrors += flushGlErrors(errors);
731   return numErrors;
732 }
733 }  // namespace
734 
735 namespace androidgamesdk_deviceinfo {
createProto(::ProtoInfoWithErrors & proto)736 int createProto(::ProtoInfoWithErrors& proto) {
737   int numErrors = 0;
738 
739   ProtoInfo& info = *proto.mutable_info();
740   info.set_version(1);
741 
742   int cpuIndexMax = readCpuIndexMax();
743   info.set_cpu_max_index(cpuIndexMax);
744 
745   for (int cpuIndex = 0; cpuIndex <= cpuIndexMax; cpuIndex++) {
746     ProtoCpuCore* newCore = info.add_cpu_core();
747     int64_t freqMax = readCpuFreqMax(cpuIndex);
748     if (freqMax > 0) {
749       newCore->set_freq_max(freqMax);
750     }
751   }
752 
753   info.set_cpu_present(readCpuPresent());
754   info.set_cpu_possible(readCpuPossible());
755 
756   ProtoErrors& errors = *proto.mutable_errors();
757 
758   std::vector<std::string> hardware;
759   numErrors += readHardware(hardware, errors);
760   for (const std::string& s : hardware) {
761     info.add_hardware(s);
762   }
763 
764   std::set<std::string> features;
765   numErrors += readFeatures(features, errors);
766   for (const std::string& s : features) {
767     info.add_cpu_extension(s);
768   }
769 
770   numErrors += addSystemProperties(info, errors);
771 
772   int numErrorsEgl = setupEGl(proto);
773   numErrors += numErrorsEgl;
774   if (numErrorsEgl == 0) {
775     numErrors += addGl(proto);
776   }
777 
778   return numErrors;
779 }
780 }  // namespace androidgamesdk_deviceinfo
781 
782 #include <jni.h>
783 
784 extern "C" {
785 JNIEXPORT jbyteArray JNICALL
Java_com_google_androidgamesdk_DeviceInfoJni_getProtoSerialized(JNIEnv * env,jobject)786 Java_com_google_androidgamesdk_DeviceInfoJni_getProtoSerialized(
787                                         JNIEnv *env, jobject) {
788   androidgamesdk_deviceinfo::InfoWithErrors proto;
789   androidgamesdk_deviceinfo::createProto(proto);
790 
791   size_t bufferSize = proto.ByteSize();
792   void* buffer = malloc(bufferSize);
793   proto.SerializeToArray(buffer, bufferSize);
794   jbyteArray result = env->NewByteArray(bufferSize);
795   env->SetByteArrayRegion(result, 0, bufferSize, static_cast<jbyte*>(buffer));
796   free(buffer);
797   return result;
798 }
799 }  // extern "C"
800