private void loadCapabilitiesCommon() {
        extensions = loadExtensions();

        limits.put(Limits.VertexTextureUnits, getInteger(GL.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS));
        if (limits.get(Limits.VertexTextureUnits) > 0) {
            caps.add(Caps.VertexTextureFetch);
        }

        limits.put(Limits.FragmentTextureUnits, getInteger(GL.GL_MAX_TEXTURE_IMAGE_UNITS));

        if (caps.contains(Caps.OpenGLES20)) {
            limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_VECTORS));
            limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_VECTORS));
        } else {
            limits.put(Limits.FragmentUniformVectors, getInteger(GL.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4);
            limits.put(Limits.VertexUniformVectors, getInteger(GL.GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4);
        }

        limits.put(Limits.VertexAttributes, getInteger(GL.GL_MAX_VERTEX_ATTRIBS));
        limits.put(Limits.TextureSize, getInteger(GL.GL_MAX_TEXTURE_SIZE));
        limits.put(Limits.CubemapSize, getInteger(GL.GL_MAX_CUBE_MAP_TEXTURE_SIZE));

        if (hasExtension("GL_ARB_draw_instanced") &&
                hasExtension("GL_ARB_instanced_arrays")) {
            // TODO: If there were a way to call the EXT extension for GLES2, should check also (hasExtension("GL_EXT_draw_instanced") && hasExtension("GL_EXT_instanced_arrays"))
            caps.add(Caps.MeshInstancing);
        }

        if (hasExtension("GL_OES_element_index_uint") || gl2 != null) {
            caps.add(Caps.IntegerIndexBuffer);
        }

        if (hasExtension("GL_ARB_texture_buffer_object")) {
            caps.add(Caps.TextureBuffer);
        }

        // == texture format extensions ==

        boolean hasFloatTexture;

        hasFloatTexture = hasExtension("GL_OES_texture_half_float") &&
                hasExtension("GL_OES_texture_float");

        if (!hasFloatTexture) {
            hasFloatTexture = hasExtension("GL_ARB_texture_float") &&
                    hasExtension("GL_ARB_half_float_pixel");

            if (!hasFloatTexture) {
                hasFloatTexture = caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30);
            }
        }

        if (hasFloatTexture) {
            caps.add(Caps.FloatTexture);
        }

        // integer texture format extensions
        if(hasExtension("GL_EXT_texture_integer") || caps.contains(Caps.OpenGL30))
            caps.add(Caps.IntegerTexture);

        if (hasExtension("GL_OES_depth_texture") || gl2 != null) {
            caps.add(Caps.DepthTexture);
        }

        if (hasExtension("GL_OES_depth24")) {
            caps.add(Caps.Depth24);
        }

        if (hasExtension("GL_OES_rgb8_rgba8") ||
                hasExtension("GL_ARM_rgba8") ||
                hasExtension("GL_EXT_texture_format_BGRA8888")) {
            caps.add(Caps.Rgba8);
        }

        if (caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30) || hasExtension("GL_OES_packed_depth_stencil")) {
            caps.add(Caps.PackedDepthStencilBuffer);
        }

        if (hasExtension("GL_ARB_color_buffer_float") &&
                hasExtension("GL_ARB_half_float_pixel")
                ||caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30)) {
            // XXX: Require both 16- and 32-bit float support for FloatColorBuffer.
            caps.add(Caps.FloatColorBuffer);
            caps.add(Caps.FloatColorBufferRGBA);
            if (!caps.contains(Caps.OpenGLES30)) {
                caps.add(Caps.FloatColorBufferRGB);
            }
        }

        if (caps.contains(Caps.OpenGLES30) || hasExtension("GL_ARB_depth_buffer_float")) {
            caps.add(Caps.FloatDepthBuffer);
        }

        if ((hasExtension("GL_EXT_packed_float") && hasFloatTexture) ||
                caps.contains(Caps.OpenGL30)) {
            // Either OpenGL3 is available or both packed_float & half_float_pixel.
            caps.add(Caps.PackedFloatColorBuffer);
            caps.add(Caps.PackedFloatTexture);
        }

        if (hasExtension("GL_EXT_texture_shared_exponent") || caps.contains(Caps.OpenGL30)) {
            caps.add(Caps.SharedExponentTexture);
        }

        if (hasExtension("GL_EXT_texture_compression_s3tc")) {
            caps.add(Caps.TextureCompressionS3TC);
        }

        if (hasExtension("GL_ARB_texture_compression_bptc")) {
            caps.add(Caps.TextureCompressionBPTC);
        }

        if (hasExtension("GL_EXT_texture_compression_rgtc")) {
            caps.add(Caps.TextureCompressionRGTC);
        }

        if (hasExtension("GL_ARB_ES3_compatibility")) {
            caps.add(Caps.TextureCompressionETC2);
            caps.add(Caps.TextureCompressionETC1);
        } else if (hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
            caps.add(Caps.TextureCompressionETC1);
        }

        // == end texture format extensions ==

        if (hasExtension("GL_ARB_vertex_array_object") || caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30) ) {
            caps.add(Caps.VertexBufferArray);
        }

        if (hasExtension("GL_ARB_texture_non_power_of_two") ||
                hasExtension("GL_OES_texture_npot") ||
                caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30)) {
            caps.add(Caps.NonPowerOfTwoTextures);
        } else {
            logger.log(Level.WARNING, "Your graphics card does not "
                    + "support non-power-of-2 textures. "
                    + "Some features might not work.");
        }

        if (caps.contains(Caps.OpenGLES20)) {
            // OpenGL ES 2 has some limited support for NPOT textures
            caps.add(Caps.PartialNonPowerOfTwoTextures);
        }

        if (hasExtension("GL_EXT_texture_array") || caps.contains(Caps.OpenGL30) ||  caps.contains(Caps.OpenGLES30)) {
            caps.add(Caps.TextureArray);
        }

        if (hasExtension("GL_EXT_texture_filter_anisotropic")) {
            caps.add(Caps.TextureFilterAnisotropic);
            limits.put(Limits.TextureAnisotropy, getInteger(GLExt.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT));
        }

        if (hasExtension("GL_EXT_framebuffer_object")
                || caps.contains(Caps.OpenGL30)
                || caps.contains(Caps.OpenGLES20)) {
            caps.add(Caps.FrameBuffer);

            limits.put(Limits.RenderBufferSize, getInteger(GLFbo.GL_MAX_RENDERBUFFER_SIZE_EXT));
            limits.put(Limits.FrameBufferAttachments, getInteger(GLFbo.GL_MAX_COLOR_ATTACHMENTS_EXT));

            if (hasExtension("GL_EXT_framebuffer_blit") || caps.contains(Caps.OpenGL30)  || caps.contains(Caps.OpenGLES30)) {
                caps.add(Caps.FrameBufferBlit);
            }

            if (hasExtension("GL_EXT_framebuffer_multisample") || caps.contains(Caps.OpenGLES30)) {
                caps.add(Caps.FrameBufferMultisample);
                limits.put(Limits.FrameBufferSamples, getInteger(GLExt.GL_MAX_SAMPLES_EXT));
            }

            if (hasExtension("GL_ARB_texture_multisample") || caps.contains(Caps.OpenGLES31)) { // GLES31 does not fully support it
                caps.add(Caps.TextureMultisample);
                limits.put(Limits.ColorTextureSamples, getInteger(GLExt.GL_MAX_COLOR_TEXTURE_SAMPLES));
                limits.put(Limits.DepthTextureSamples, getInteger(GLExt.GL_MAX_DEPTH_TEXTURE_SAMPLES));
                if (!limits.containsKey(Limits.FrameBufferSamples)) {
                    // In case they want to query samples on main FB ...
                    limits.put(Limits.FrameBufferSamples, limits.get(Limits.ColorTextureSamples));
                }
            }

            if (hasExtension("GL_ARB_draw_buffers") || caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30)) {
                limits.put(Limits.FrameBufferMrtAttachments, getInteger(GLExt.GL_MAX_DRAW_BUFFERS_ARB));
                if (limits.get(Limits.FrameBufferMrtAttachments) > 1) {
                    caps.add(Caps.FrameBufferMRT);
                }
            } else {
                limits.put(Limits.FrameBufferMrtAttachments, 1);
            }
        }

        if (hasExtension("GL_ARB_multisample") /*|| caps.contains(Caps.OpenGLES20)*/) {
            boolean available = getInteger(GLExt.GL_SAMPLE_BUFFERS_ARB) != 0;
            int samples = getInteger(GLExt.GL_SAMPLES_ARB);
            logger.log(Level.FINER, "Samples: {0}", samples);
            boolean enabled = gl.glIsEnabled(GLExt.GL_MULTISAMPLE_ARB);
            if (samples > 0 && available && !enabled) {
                // Doesn't seem to be necessary. OGL spec says it's always
                // set by default?
                gl.glEnable(GLExt.GL_MULTISAMPLE_ARB);
            }
            caps.add(Caps.Multisample);
        }

        // Supports sRGB pipeline.
        if ( (hasExtension("GL_ARB_framebuffer_sRGB") && hasExtension("GL_EXT_texture_sRGB"))
                || caps.contains(Caps.OpenGL30) || caps.contains(Caps.OpenGLES30)) {
            caps.add(Caps.Srgb);
        }

        // Supports seamless cubemap
        if (hasExtension("GL_ARB_seamless_cube_map") || caps.contains(Caps.OpenGL32)) {
            caps.add(Caps.SeamlessCubemap);
        }

        if ((caps.contains(Caps.OpenGLES30) || caps.contains(Caps.OpenGL32)) && !hasExtension("GL_ARB_compatibility")) {
            if (JmeSystem.getPlatform().getOs() != Platform.Os.iOS) { // some features are not supported on iOS
                caps.add(Caps.CoreProfile);
            }
        }

        if (hasExtension("GL_ARB_get_program_binary")) {
            int binaryFormats = getInteger(GLExt.GL_NUM_PROGRAM_BINARY_FORMATS);
            if (binaryFormats > 0) {
                caps.add(Caps.BinaryShader);
            }
        }

        if (hasExtension("GL_OES_geometry_shader") || hasExtension("GL_EXT_geometry_shader")) {
            caps.add(Caps.GeometryShader);
        }

        if (hasExtension("GL_OES_tessellation_shader") || hasExtension("GL_EXT_tessellation_shader")) {
            caps.add(Caps.TesselationShader);
        }

        if (hasExtension("GL_ARB_shader_storage_buffer_object")) {
            caps.add(Caps.ShaderStorageBufferObject);
            limits.put(Limits.ShaderStorageBufferObjectMaxBlockSize,
                    getInteger(GL4.GL_MAX_SHADER_STORAGE_BLOCK_SIZE));
            // Commented out until we support ComputeShaders and the ComputeShader Cap
            // limits.put(Limits.ShaderStorageBufferObjectMaxComputeBlocks, getInteger(GL4.GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS));
            if (caps.contains(Caps.GeometryShader)) {
                limits.put(Limits.ShaderStorageBufferObjectMaxGeometryBlocks,
                        getInteger(GL4.GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS));
            }
            limits.put(Limits.ShaderStorageBufferObjectMaxFragmentBlocks,
                    getInteger(GL4.GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS));
            limits.put(Limits.ShaderStorageBufferObjectMaxVertexBlocks,
                    getInteger(GL4.GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS));
            if (caps.contains(Caps.TesselationShader)) {
                limits.put(Limits.ShaderStorageBufferObjectMaxTessControlBlocks,
                        getInteger(GL4.GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS));
                limits.put(Limits.ShaderStorageBufferObjectMaxTessEvaluationBlocks,
                        getInteger(GL4.GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS));
            }
            limits.put(Limits.ShaderStorageBufferObjectMaxCombineBlocks,
                    getInteger(GL4.GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS));
        }

        if (hasExtension("GL_ARB_uniform_buffer_object")) {
            caps.add(Caps.UniformBufferObject);
            limits.put(Limits.UniformBufferObjectMaxBlockSize,
                    getInteger(GL3.GL_MAX_UNIFORM_BLOCK_SIZE));
            if (caps.contains(Caps.GeometryShader)) {
                limits.put(Limits.UniformBufferObjectMaxGeometryBlocks,
                        getInteger(GL3.GL_MAX_GEOMETRY_UNIFORM_BLOCKS));
            }
            limits.put(Limits.UniformBufferObjectMaxFragmentBlocks,
                    getInteger(GL3.GL_MAX_FRAGMENT_UNIFORM_BLOCKS));
            limits.put(Limits.UniformBufferObjectMaxVertexBlocks,
                    getInteger(GL3.GL_MAX_VERTEX_UNIFORM_BLOCKS));
        }

        if (caps.contains(Caps.OpenGL20)) {
            caps.add(Caps.UnpackRowLength);
        }

        if (caps.contains(Caps.OpenGL43) || hasExtension("GL_KHR_debug") || caps.contains(Caps.WebGL)) {
            caps.add(Caps.GLDebug);
        }

        // Print context information
        logger.log(Level.INFO, "OpenGL Renderer Information\n" +
                        " * Vendor: {0}\n" +
                        " * Renderer: {1}\n" +
                        " * OpenGL Version: {2}\n" +
                        " * GLSL Version: {3}\n" +
                        " * Profile: {4}",
                new Object[]{
                        gl.glGetString(GL.GL_VENDOR),
                        gl.glGetString(GL.GL_RENDERER),
                        gl.glGetString(GL.GL_VERSION),
                        gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION),
                        caps.contains(Caps.CoreProfile) ? "Core" : "Compatibility"
                });

        // Print capabilities (if fine logging is enabled)
        if (logger.isLoggable(Level.FINE)) {
            StringBuilder sb = new StringBuilder();
            sb.append("Supported capabilities: \n");
            for (Caps cap : caps)
            {
                sb.append("\t").append(cap.toString()).append("\n");
            }

            sb.append("\nHardware limits: \n");
            for (Limits limit : Limits.values()) {
                Integer value = limits.get(limit);
                if (value == null) {
                    value = 0;
                }
                sb.append("\t").append(limit.name()).append(" = ")
                  .append(value).append("\n");
            }

            logger.log(Level.FINE, sb.toString());
        }

        texUtil.initialize(caps);
    }
Enable/Disable default automatic generation of mipmaps for framebuffers
@param v  Default is true
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java