/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "device_info/device_info.h" #include <sys/system_properties.h> #include <EGL/egl.h> #include <GLES3/gl32.h> #include <cstdint> #include <string> #include <sstream> #include <fstream> #include <vector> #include <set> namespace { using ProtoInfoWithErrors = androidgamesdk_deviceinfo::InfoWithErrors; using ProtoErrors = androidgamesdk_deviceinfo::Errors; using ProtoInfo = androidgamesdk_deviceinfo::Info; using ProtoCpuCore = androidgamesdk_deviceinfo::Info::CpuCore; using ProtoGl = androidgamesdk_deviceinfo::Info::Gl; // size of GL view and texture in future constexpr int VIEW_WIDTH = 8; constexpr int VIEW_HEIGHT = VIEW_WIDTH; namespace string_util { bool startsWith(const std::string& text, const std::string& start) { return text.compare(0, start.length(), start) == 0; } void splitAdd(const std::string& toSplit, char delimeter, std::set<std::string>* result) { std::istringstream istr(toSplit); std::string piece; while (std::getline(istr, piece, delimeter)) { if (piece.length() > 0) { result->insert(piece); } } } } // namespace string_util template <typename T> T readFile(const std::string& fileName, const T& error) { std::ifstream reader(fileName); if (reader.fail()) return error; T result; reader >> result; if (reader.fail()) return error; return result; } std::string readCpuPresent() { const std::string ERROR = "ERROR"; return readFile("/sys/devices/system/cpu/present", ERROR); } std::string readCpuPossible() { const std::string ERROR = "ERROR"; return readFile("/sys/devices/system/cpu/possible", ERROR); } int readCpuIndexMax() { constexpr int ERROR = -1; return readFile("/sys/devices/system/cpu/kernel_max", ERROR); } int64_t readCpuFreqMax(int cpuIndex) { const std::string fileName = "/sys/devices/system/cpu/cpu" + std::to_string(cpuIndex) + "/cpufreq/cpuinfo_max_freq"; constexpr int64_t ERROR = -1; return readFile(fileName, ERROR); } // returns number of errors int readHardware(std::vector<std::string>& result, ProtoErrors& errors) { std::ifstream f("/proc/cpuinfo"); if (f.fail()){ errors.set_hardware("Could not read."); return 1; } const std::string FIELD_KEY = "Hardware\t: "; std::string line; while (std::getline(f, line)) { if (::string_util::startsWith(line, FIELD_KEY)) { std::string val = line.substr(FIELD_KEY.length(), std::string::npos); result.push_back(val); } } return 0; } // returns number of errors int readFeatures(std::set<std::string>& result, ProtoErrors& errors) { std::ifstream f("/proc/cpuinfo"); if (f.fail()){ errors.set_features("Could not read."); return 1; } const std::string FIELD_KEY = "Features\t: "; std::string line; while (std::getline(f, line)) { if (::string_util::startsWith(line, FIELD_KEY)) { std::string features = line.substr(FIELD_KEY.length(), std::string::npos); ::string_util::splitAdd(features, ' ', &result); } } return 0; } std::string getSystemPropViaGet(const char* key, ::ProtoErrors& errors) { char buffer[PROP_VALUE_MAX + 1]; // +1 for terminator int bufferLen = __system_property_get(key, buffer); if (bufferLen > PROP_VALUE_MAX){ const std::string HEADER = "Overflow: "; errors.add_system_props(HEADER + key); return ""; } return std::string(buffer, bufferLen); } std::string getSystemPropViaReadCallback(const char* key) { const prop_info* pi = __system_property_find(key); if (pi == nullptr) { return ""; } std::string result; __system_property_read_callback(pi, [](void* cookie, const char*, const char* value, unsigned) { auto sysOut = reinterpret_cast<std::string*>(cookie); *sysOut = value; }, &result ); return result; } std::string getSystemProp(const char* key, ::ProtoErrors& errors, bool useCallbackApi) { if (useCallbackApi) { return getSystemPropViaReadCallback(key); } else { return getSystemPropViaGet(key, errors); } } // returns number of errors int addSystemProperties(::ProtoInfo& info, ::ProtoErrors& errors) { std::string sdkVersionString = getSystemPropViaGet("ro.build.version.sdk", errors); info.set_ro_build_version_sdk(sdkVersionString); int sdkVersion = atoi(sdkVersionString.c_str()); bool useCallbackApi = (26 <= sdkVersion); info.set_ro_chipname( getSystemProp("ro.chipname", errors, useCallbackApi)); info.set_ro_board_platform( getSystemProp("ro.board.platform", errors, useCallbackApi)); info.set_ro_product_board( getSystemProp("ro.product.board", errors, useCallbackApi)); info.set_ro_mediatek_platform( getSystemProp("ro.mediatek.platform", errors, useCallbackApi)); info.set_ro_arch( getSystemProp("ro.arch", errors, useCallbackApi)); info.set_ro_build_fingerprint( getSystemProp("ro.build.fingerprint", errors, useCallbackApi)); return errors.system_props_size(); } // returns number of errors int checkEglError(const char* title, ::ProtoErrors& errors) { EGLint error = eglGetError(); if (error == EGL_SUCCESS) return 0; std::stringstream ss; ss << title << ": 0x" << std::hex << (int)error << std::dec; errors.set_egl(ss.str()); return 1; } int flushGlErrors(::ProtoErrors& errors) { int numErrors = 0; while (GLenum e = glGetError() != GL_NO_ERROR) { std::stringstream ss; ss << "0x" << std::hex << (int)e << std::dec; errors.add_gl(ss.str()); numErrors++; } return numErrors; } // returns number of errors int setupEGl(::ProtoInfoWithErrors& proto) { ProtoErrors& errors = *proto.mutable_errors(); EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (int numErrors = checkEglError("eglGetDisplay", errors)){ return numErrors; } eglInitialize(display, nullptr, nullptr); // do not care about egl version if (int numErrors = checkEglError("eglInitialize", errors)){ return numErrors; } EGLint configAttribs[] = { EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_NONE }; EGLConfig config; EGLint numConfigs = -1; eglChooseConfig(display, configAttribs, &config, 1, &numConfigs); if (int numErrors = checkEglError("eglChooseConfig", errors)){ return numErrors; } EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); if (int numErrors = checkEglError("eglCreateContext", errors)){ return numErrors; } EGLint pbufferAttribs[] = { EGL_WIDTH, VIEW_WIDTH, EGL_HEIGHT, VIEW_HEIGHT, EGL_NONE }; EGLSurface surface = eglCreatePbufferSurface(display, config, pbufferAttribs); if (int numErrors = checkEglError("eglCreatePbufferSurface", errors)){ return numErrors; } eglMakeCurrent(display, surface, surface, context); if (int numErrors = checkEglError("eglMakeCurrent", errors)){ return numErrors; } return 0; } namespace gl_util { typedef const GLubyte* GlStr; typedef GlStr(*FuncTypeGlGetstringi)(GLenum, GLint); FuncTypeGlGetstringi glGetStringi = 0; const char* getStringIndexed(GLenum e, GLuint index){ return reinterpret_cast<const char*>(::gl_util::glGetStringi(e, index)); } typedef void(*FuncTypeGlGetInteger64v)(GLenum, GLint64*); FuncTypeGlGetInteger64v glGetInteger64v = 0; GLint64 getInt64(GLenum e) { GLint64 result = -1; glGetInteger64v(e, &result); return result; } typedef void(*FuncTypeGlGetIntegeri_v)(GLenum, GLuint, GLint*); FuncTypeGlGetIntegeri_v glGetIntegeri_v = 0; GLint getIntIndexed(GLenum e, GLuint index) { GLint result = -1; glGetIntegeri_v(e, index, &result); return result; } const char* getString(GLenum e){ return reinterpret_cast<const char*>(glGetString(e)); } GLfloat getFloat(GLenum e) { GLfloat result = -1; glGetFloatv(e, &result); return result; } GLint getInt(GLenum e) { GLint result = -1; glGetIntegerv(e, &result); return result; } GLboolean getBool(GLenum e) { GLboolean result = false; glGetBooleanv(e, &result); return result; } } // namespace gl_util void addGlConstsV2_0(::ProtoGl& gl) { gl.set_gl_aliased_line_width_range( ::gl_util::getFloat(GL_ALIASED_LINE_WIDTH_RANGE)); gl.set_gl_aliased_point_size_range( ::gl_util::getFloat(GL_ALIASED_POINT_SIZE_RANGE)); gl.set_gl_max_combined_texture_image_units( ::gl_util::getInt(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_cube_map_texture_size( ::gl_util::getInt(GL_MAX_CUBE_MAP_TEXTURE_SIZE)); gl.set_gl_max_fragment_uniform_vectors( ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_VECTORS)); gl.set_gl_max_renderbuffer_size( ::gl_util::getInt(GL_MAX_RENDERBUFFER_SIZE)); gl.set_gl_max_texture_image_units( ::gl_util::getInt(GL_MAX_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_texture_size( ::gl_util::getInt(GL_MAX_TEXTURE_SIZE)); gl.set_gl_max_varying_vectors( ::gl_util::getInt(GL_MAX_VARYING_VECTORS)); gl.set_gl_max_vertex_attribs( ::gl_util::getInt(GL_MAX_VERTEX_ATTRIBS)); gl.set_gl_max_vertex_texture_image_units( ::gl_util::getInt(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_vertex_uniform_vectors( ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_VECTORS)); gl.set_gl_max_viewport_dims( ::gl_util::getInt(GL_MAX_VIEWPORT_DIMS)); gl.set_gl_shader_compiler( ::gl_util::getBool(GL_SHADER_COMPILER)); gl.set_gl_subpixel_bits( ::gl_util::getInt(GL_SUBPIXEL_BITS)); GLint numCompressedFormats = ::gl_util::getInt(GL_NUM_COMPRESSED_TEXTURE_FORMATS); gl.set_gl_num_compressed_texture_formats(numCompressedFormats); std::vector<GLint> compressedFormats(numCompressedFormats); glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, &compressedFormats[0]); for (auto x : compressedFormats) { gl.add_gl_compressed_texture_formats(x); } GLint numShaderBinFormats = ::gl_util::getInt(GL_NUM_SHADER_BINARY_FORMATS); gl.set_gl_num_shader_binary_formats(numShaderBinFormats); std::vector<GLint> shaderBinFormats(numShaderBinFormats); glGetIntegerv(GL_SHADER_BINARY_FORMATS, &shaderBinFormats[0]); for (auto x : shaderBinFormats) { gl.add_gl_shader_binary_formats(x); } // shader precision formats GLint spfr = -1; // range GLint spfp = -1; // precision glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_FLOAT, &spfr, &spfp); gl.set_spf_vertex_float_low_range(spfr); gl.set_spf_vertex_float_low_prec(spfp); glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_FLOAT, &spfr, &spfp); gl.set_spf_vertex_float_med_range(spfr); gl.set_spf_vertex_float_med_prec(spfp); glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_FLOAT, &spfr, &spfp); gl.set_spf_vertex_float_hig_range(spfr); gl.set_spf_vertex_float_hig_prec(spfp); glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_LOW_INT, &spfr, &spfp); gl.set_spf_vertex_int_low_range(spfr); gl.set_spf_vertex_int_low_prec(spfp); glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_MEDIUM_INT, &spfr, &spfp); gl.set_spf_vertex_int_med_range(spfr); gl.set_spf_vertex_int_med_prec(spfp); glGetShaderPrecisionFormat(GL_VERTEX_SHADER, GL_HIGH_INT, &spfr, &spfp); gl.set_spf_vertex_int_hig_range(spfr); gl.set_spf_vertex_int_hig_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_FLOAT, &spfr, &spfp); gl.set_spf_fragment_float_low_range(spfr); gl.set_spf_fragment_float_low_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, &spfr, &spfp); gl.set_spf_fragment_float_med_range(spfr); gl.set_spf_fragment_float_med_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, &spfr, &spfp); gl.set_spf_fragment_float_hig_range(spfr); gl.set_spf_fragment_float_hig_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_INT, &spfr, &spfp); gl.set_spf_fragment_int_low_range(spfr); gl.set_spf_fragment_int_low_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_INT, &spfr, &spfp); gl.set_spf_fragment_int_med_range(spfr); gl.set_spf_fragment_int_med_prec(spfp); glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_INT, &spfr, &spfp); gl.set_spf_fragment_int_hig_range(spfr); gl.set_spf_fragment_int_hig_prec(spfp); } void addGlConstsV3_0(::ProtoGl& gl) { gl.set_gl_max_3d_texture_size( ::gl_util::getInt(GL_MAX_3D_TEXTURE_SIZE)); gl.set_gl_max_array_texture_layers( ::gl_util::getInt(GL_MAX_ARRAY_TEXTURE_LAYERS)); gl.set_gl_max_color_attachments( ::gl_util::getInt(GL_MAX_COLOR_ATTACHMENTS)); gl.set_gl_max_combined_uniform_blocks( ::gl_util::getInt(GL_MAX_COMBINED_UNIFORM_BLOCKS)); gl.set_gl_max_draw_buffers( ::gl_util::getInt(GL_MAX_DRAW_BUFFERS)); gl.set_gl_max_elements_indices( ::gl_util::getInt(GL_MAX_ELEMENTS_INDICES)); gl.set_gl_max_elements_vertices( ::gl_util::getInt(GL_MAX_ELEMENTS_VERTICES)); gl.set_gl_max_fragment_input_components( ::gl_util::getInt(GL_MAX_FRAGMENT_INPUT_COMPONENTS)); gl.set_gl_max_fragment_uniform_blocks( ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_BLOCKS)); gl.set_gl_max_fragment_uniform_components( ::gl_util::getInt(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS)); gl.set_gl_max_program_texel_offset( ::gl_util::getInt(GL_MAX_PROGRAM_TEXEL_OFFSET)); gl.set_gl_max_transform_feedback_interleaved_components( ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS)); gl.set_gl_max_transform_feedback_separate_attribs( ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)); gl.set_gl_max_transform_feedback_separate_components( ::gl_util::getInt(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS)); gl.set_gl_max_uniform_buffer_bindings( ::gl_util::getInt(GL_MAX_UNIFORM_BUFFER_BINDINGS)); gl.set_gl_max_varying_components( ::gl_util::getInt(GL_MAX_VARYING_COMPONENTS)); gl.set_gl_max_vertex_output_components( ::gl_util::getInt(GL_MAX_VERTEX_OUTPUT_COMPONENTS)); gl.set_gl_max_vertex_uniform_blocks( ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_BLOCKS)); gl.set_gl_max_vertex_uniform_components( ::gl_util::getInt(GL_MAX_VERTEX_UNIFORM_COMPONENTS)); gl.set_gl_min_program_texel_offset( ::gl_util::getInt(GL_MIN_PROGRAM_TEXEL_OFFSET)); gl.set_gl_uniform_buffer_offset_alignment( ::gl_util::getInt(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT)); gl.set_gl_max_samples( ::gl_util::getInt(GL_MAX_SAMPLES)); gl.set_gl_max_texture_lod_bias(::gl_util::getFloat(GL_MAX_TEXTURE_LOD_BIAS)); ::gl_util::glGetInteger64v = reinterpret_cast<::gl_util::FuncTypeGlGetInteger64v>( eglGetProcAddress("glGetInteger64v")); gl.set_gl_max_combined_fragment_uniform_components( ::gl_util::getInt64(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS)); gl.set_gl_max_element_index( ::gl_util::getInt64(GL_MAX_ELEMENT_INDEX)); gl.set_gl_max_server_wait_timeout( ::gl_util::getInt64(GL_MAX_SERVER_WAIT_TIMEOUT)); gl.set_gl_max_uniform_block_size( ::gl_util::getInt64(GL_MAX_UNIFORM_BLOCK_SIZE)); } void addGlConstsV3_1(::ProtoGl& gl) { gl.set_gl_max_atomic_counter_buffer_bindings( ::gl_util::getInt(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS)); gl.set_gl_max_atomic_counter_buffer_size( ::gl_util::getInt(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE)); gl.set_gl_max_color_texture_samples( ::gl_util::getInt(GL_MAX_COLOR_TEXTURE_SAMPLES)); gl.set_gl_max_combined_atomic_counters( ::gl_util::getInt(GL_MAX_COMBINED_ATOMIC_COUNTERS)); gl.set_gl_max_combined_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_combined_compute_uniform_components( ::gl_util::getInt(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS)); gl.set_gl_max_combined_image_uniforms( ::gl_util::getInt(GL_MAX_COMBINED_IMAGE_UNIFORMS)); gl.set_gl_max_combined_shader_output_resources( ::gl_util::getInt(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES)); gl.set_gl_max_combined_shader_storage_blocks( ::gl_util::getInt(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_compute_atomic_counters( ::gl_util::getInt(GL_MAX_COMPUTE_ATOMIC_COUNTERS)); gl.set_gl_max_compute_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_compute_image_uniforms( ::gl_util::getInt(GL_MAX_COMPUTE_IMAGE_UNIFORMS)); gl.set_gl_max_compute_shader_storage_blocks( ::gl_util::getInt(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_compute_shared_memory_size( ::gl_util::getInt(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE)); gl.set_gl_max_compute_texture_image_units( ::gl_util::getInt(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_compute_uniform_blocks( ::gl_util::getInt(GL_MAX_COMPUTE_UNIFORM_BLOCKS)); gl.set_gl_max_compute_uniform_components( ::gl_util::getInt(GL_MAX_COMPUTE_UNIFORM_COMPONENTS)); gl.set_gl_max_compute_work_group_invocations( ::gl_util::getInt(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS)); gl.set_gl_max_depth_texture_samples( ::gl_util::getInt(GL_MAX_DEPTH_TEXTURE_SAMPLES)); gl.set_gl_max_fragment_atomic_counters( ::gl_util::getInt(GL_MAX_FRAGMENT_ATOMIC_COUNTERS)); gl.set_gl_max_fragment_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_fragment_image_uniforms( ::gl_util::getInt(GL_MAX_FRAGMENT_IMAGE_UNIFORMS)); gl.set_gl_max_fragment_shader_storage_blocks( ::gl_util::getInt(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_framebuffer_height( ::gl_util::getInt(GL_MAX_FRAMEBUFFER_HEIGHT)); gl.set_gl_max_framebuffer_samples( ::gl_util::getInt(GL_MAX_FRAMEBUFFER_SAMPLES)); gl.set_gl_max_framebuffer_width( ::gl_util::getInt(GL_MAX_FRAMEBUFFER_WIDTH)); gl.set_gl_max_image_units( ::gl_util::getInt(GL_MAX_IMAGE_UNITS)); gl.set_gl_max_integer_samples( ::gl_util::getInt(GL_MAX_INTEGER_SAMPLES)); gl.set_gl_max_program_texture_gather_offset( ::gl_util::getInt(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET)); gl.set_gl_max_sample_mask_words( ::gl_util::getInt(GL_MAX_SAMPLE_MASK_WORDS)); gl.set_gl_max_shader_storage_buffer_bindings( ::gl_util::getInt(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS)); gl.set_gl_max_uniform_locations( ::gl_util::getInt(GL_MAX_UNIFORM_LOCATIONS)); gl.set_gl_max_vertex_atomic_counters( ::gl_util::getInt(GL_MAX_VERTEX_ATOMIC_COUNTERS)); gl.set_gl_max_vertex_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_vertex_attrib_bindings( ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_BINDINGS)); gl.set_gl_max_vertex_attrib_relative_offset( ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET)); gl.set_gl_max_vertex_attrib_stride( ::gl_util::getInt(GL_MAX_VERTEX_ATTRIB_STRIDE)); gl.set_gl_max_vertex_image_uniforms( ::gl_util::getInt(GL_MAX_VERTEX_IMAGE_UNIFORMS)); gl.set_gl_max_vertex_shader_storage_blocks( ::gl_util::getInt(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS)); gl.set_gl_min_program_texture_gather_offset( ::gl_util::getInt(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET)); gl.set_gl_shader_storage_buffer_offset_alignment( ::gl_util::getInt(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT)); gl.set_gl_max_shader_storage_block_size( ::gl_util::getInt64(GL_MAX_SHADER_STORAGE_BLOCK_SIZE)); ::gl_util::glGetIntegeri_v = reinterpret_cast<::gl_util::FuncTypeGlGetIntegeri_v>( eglGetProcAddress("glGetIntegeri_v")); gl.set_gl_max_compute_work_group_count_0( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0)); gl.set_gl_max_compute_work_group_count_1( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1)); gl.set_gl_max_compute_work_group_count_2( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2)); gl.set_gl_max_compute_work_group_size_0( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0)); gl.set_gl_max_compute_work_group_size_1( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1)); gl.set_gl_max_compute_work_group_size_2( ::gl_util::getIntIndexed(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2)); } void addGlConstsV3_2(::ProtoGl& gl) { gl.set_gl_context_flags( ::gl_util::getInt(GL_CONTEXT_FLAGS)); gl.set_gl_fragment_interpolation_offset_bits( ::gl_util::getInt(GL_FRAGMENT_INTERPOLATION_OFFSET_BITS)); gl.set_gl_layer_provoking_vertex( ::gl_util::getInt(GL_LAYER_PROVOKING_VERTEX)); gl.set_gl_max_combined_geometry_uniform_components( ::gl_util::getInt(GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS)); gl.set_gl_max_combined_tess_control_uniform_components( ::gl_util::getInt(GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS)); gl.set_gl_max_combined_tess_evaluation_uniform_components( ::gl_util::getInt(GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS)); gl.set_gl_max_debug_group_stack_depth( ::gl_util::getInt(GL_MAX_DEBUG_GROUP_STACK_DEPTH)); gl.set_gl_max_debug_logged_messages( ::gl_util::getInt(GL_MAX_DEBUG_LOGGED_MESSAGES)); gl.set_gl_max_debug_message_length( ::gl_util::getInt(GL_MAX_DEBUG_MESSAGE_LENGTH)); gl.set_gl_max_framebuffer_layers( ::gl_util::getInt(GL_MAX_FRAMEBUFFER_LAYERS)); gl.set_gl_max_geometry_atomic_counters( ::gl_util::getInt(GL_MAX_GEOMETRY_ATOMIC_COUNTERS)); gl.set_gl_max_geometry_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_geometry_image_uniforms( ::gl_util::getInt(GL_MAX_GEOMETRY_IMAGE_UNIFORMS)); gl.set_gl_max_geometry_input_components( ::gl_util::getInt(GL_MAX_GEOMETRY_INPUT_COMPONENTS)); gl.set_gl_max_geometry_output_components( ::gl_util::getInt(GL_MAX_GEOMETRY_OUTPUT_COMPONENTS)); gl.set_gl_max_geometry_output_vertices( ::gl_util::getInt(GL_MAX_GEOMETRY_OUTPUT_VERTICES)); gl.set_gl_max_geometry_shader_invocations( ::gl_util::getInt(GL_MAX_GEOMETRY_SHADER_INVOCATIONS)); gl.set_gl_max_geometry_shader_storage_blocks( ::gl_util::getInt(GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_geometry_texture_image_units( ::gl_util::getInt(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_geometry_total_output_components( ::gl_util::getInt(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS)); gl.set_gl_max_geometry_uniform_blocks( ::gl_util::getInt(GL_MAX_GEOMETRY_UNIFORM_BLOCKS)); gl.set_gl_max_geometry_uniform_components( ::gl_util::getInt(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS)); gl.set_gl_max_label_length( ::gl_util::getInt(GL_MAX_LABEL_LENGTH)); gl.set_gl_max_patch_vertices( ::gl_util::getInt(GL_MAX_PATCH_VERTICES)); gl.set_gl_max_tess_control_atomic_counters( ::gl_util::getInt(GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS)); gl.set_gl_max_tess_control_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_tess_control_image_uniforms( ::gl_util::getInt(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS)); gl.set_gl_max_tess_control_input_components( ::gl_util::getInt(GL_MAX_TESS_CONTROL_INPUT_COMPONENTS)); gl.set_gl_max_tess_control_output_components( ::gl_util::getInt(GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS)); gl.set_gl_max_tess_control_shader_storage_blocks( ::gl_util::getInt(GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_tess_control_texture_image_units( ::gl_util::getInt(GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_tess_control_total_output_components( ::gl_util::getInt(GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS)); gl.set_gl_max_tess_control_uniform_blocks( ::gl_util::getInt(GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS)); gl.set_gl_max_tess_control_uniform_components( ::gl_util::getInt(GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS)); gl.set_gl_max_tess_evaluation_atomic_counters( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS)); gl.set_gl_max_tess_evaluation_atomic_counter_buffers( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS)); gl.set_gl_max_tess_evaluation_image_uniforms( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS)); gl.set_gl_max_tess_evaluation_input_components( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS)); gl.set_gl_max_tess_evaluation_output_components( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS)); gl.set_gl_max_tess_evaluation_shader_storage_blocks( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS)); gl.set_gl_max_tess_evaluation_texture_image_units( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS)); gl.set_gl_max_tess_evaluation_uniform_blocks( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS)); gl.set_gl_max_tess_evaluation_uniform_components( ::gl_util::getInt(GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS)); gl.set_gl_max_tess_gen_level( ::gl_util::getInt(GL_MAX_TESS_GEN_LEVEL)); gl.set_gl_max_tess_patch_components( ::gl_util::getInt(GL_MAX_TESS_PATCH_COMPONENTS)); gl.set_gl_max_texture_buffer_size( ::gl_util::getInt(GL_MAX_TEXTURE_BUFFER_SIZE)); gl.set_gl_texture_buffer_offset_alignment( ::gl_util::getInt(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT)); gl.set_gl_reset_notification_strategy( ::gl_util::getInt(GL_RESET_NOTIFICATION_STRATEGY)); gl.set_gl_max_fragment_interpolation_offset( ::gl_util::getFloat(GL_MAX_FRAGMENT_INTERPOLATION_OFFSET)); gl.set_gl_min_fragment_interpolation_offset( ::gl_util::getFloat(GL_MIN_FRAGMENT_INTERPOLATION_OFFSET)); gl.set_gl_multisample_line_width_granularity( ::gl_util::getFloat(GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY)); gl.set_gl_multisample_line_width_range( ::gl_util::getFloat(GL_MULTISAMPLE_LINE_WIDTH_RANGE)); gl.set_gl_primitive_restart_for_patches_supported( ::gl_util::getBool(GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED)); } // returns number of errors int addGl(::ProtoInfoWithErrors& proto) { int numErrors = 0; ::ProtoInfo& info = *proto.mutable_info(); ::ProtoGl& gl = *info.mutable_gl(); ::ProtoErrors& errors = *proto.mutable_errors(); gl.set_renderer(::gl_util::getString(GL_RENDERER)); gl.set_vendor(::gl_util::getString(GL_VENDOR)); gl.set_version(::gl_util::getString(GL_VERSION)); gl.set_shading_language_version( ::gl_util::getString(GL_SHADING_LANGUAGE_VERSION)); numErrors += flushGlErrors(errors); GLint glVerMajor = -1; GLint glVerMinor = -1; glGetIntegerv(GL_MAJOR_VERSION, &glVerMajor); // if GL_MAJOR_VERSION is not recognized, assume version 2.0 if (glGetError() != GL_NO_ERROR) { glVerMajor = 2; glVerMinor = 0; } else { glGetIntegerv(GL_MINOR_VERSION, &glVerMinor); } gl.set_version_major(glVerMajor); gl.set_version_minor(glVerMinor); // gl extensions if (glVerMajor >= 3) { int numExts = -1; glGetIntegerv(GL_NUM_EXTENSIONS, &numExts); ::gl_util::glGetStringi = reinterpret_cast<::gl_util::FuncTypeGlGetstringi>( eglGetProcAddress("glGetStringi")); for (int i = 0; i < numExts; i++) { std::string s = ::gl_util::getStringIndexed(GL_EXTENSIONS, i); gl.add_extension(s); } } else { std::string exts = ::gl_util::getString(GL_EXTENSIONS); std::set<std::string> split; ::string_util::splitAdd(exts, ' ', &split); for (const std::string& s : split) { gl.add_extension(s); } } if (glVerMajor > 2 || (glVerMajor == 2 && glVerMinor >= 0)) { // >= gles 2.0 addGlConstsV2_0(gl); } if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 0)) { // >= gles 3.0 addGlConstsV3_0(gl); } if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 1)) { // >= gles 3.1 addGlConstsV3_1(gl); } if (glVerMajor > 3 || (glVerMajor == 3 && glVerMinor >= 2)) { // >= gles 3.2 addGlConstsV3_2(gl); } numErrors += flushGlErrors(errors); return numErrors; } } // namespace namespace androidgamesdk_deviceinfo { int createProto(::ProtoInfoWithErrors& proto) { int numErrors = 0; ProtoInfo& info = *proto.mutable_info(); info.set_version(1); int cpuIndexMax = readCpuIndexMax(); info.set_cpu_max_index(cpuIndexMax); for (int cpuIndex = 0; cpuIndex <= cpuIndexMax; cpuIndex++) { ProtoCpuCore* newCore = info.add_cpu_core(); int64_t freqMax = readCpuFreqMax(cpuIndex); if (freqMax > 0) { newCore->set_freq_max(freqMax); } } info.set_cpu_present(readCpuPresent()); info.set_cpu_possible(readCpuPossible()); ProtoErrors& errors = *proto.mutable_errors(); std::vector<std::string> hardware; numErrors += readHardware(hardware, errors); for (const std::string& s : hardware) { info.add_hardware(s); } std::set<std::string> features; numErrors += readFeatures(features, errors); for (const std::string& s : features) { info.add_cpu_extension(s); } numErrors += addSystemProperties(info, errors); int numErrorsEgl = setupEGl(proto); numErrors += numErrorsEgl; if (numErrorsEgl == 0) { numErrors += addGl(proto); } return numErrors; } } // namespace androidgamesdk_deviceinfo #include <jni.h> extern "C" { JNIEXPORT jbyteArray JNICALL Java_com_google_androidgamesdk_DeviceInfoJni_getProtoSerialized( JNIEnv *env, jobject) { androidgamesdk_deviceinfo::InfoWithErrors proto; androidgamesdk_deviceinfo::createProto(proto); size_t bufferSize = proto.ByteSize(); void* buffer = malloc(bufferSize); proto.SerializeToArray(buffer, bufferSize); jbyteArray result = env->NewByteArray(bufferSize); env->SetByteArrayRegion(result, 0, bufferSize, static_cast<jbyte*>(buffer)); free(buffer); return result; } } // extern "C"