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