static const char *get_proc_cmdline()
    {
        static bool s_inited = false;
        static vogl::vector<char> s_buf;

        if (!s_inited)
        {
            s_inited = true;

            FILE *pFile = vogl_fopen("/proc/self/cmdline", "rb");
            if (pFile)
            {
                for (;;)
                {
                    int c = vogl_fgetc(pFile);
                    if (c < 0)
                        break;
                    s_buf.push_back(static_cast<char>(c));
                }
                vogl_fclose(pFile);
            }

            s_buf.push_back(0);
            s_buf.push_back(0);
        }

        return s_buf.get_const_ptr();
    }
uint vogleditor_QProgramArbExplorer::set_program_objects(vogl::vector<vogl_context_snapshot*> sharingContexts)
{
    clear();

    m_pProgramEnvState = &(sharingContexts[0]->get_arb_program_environment_state());
    m_maxEnvParameters = sharingContexts[0]->get_context_info().get_max_arb_vertex_program_env_params();
    m_maxLocalParameters = (uint)sharingContexts[0]->get_general_state().get_value<int>(GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB);

    uint programCount = 0;
    for (uint c = 0; c < sharingContexts.size(); c++)
    {
        vogl_gl_object_state_ptr_vec programObjects;
        sharingContexts[c]->get_all_objects_of_category(cGLSTARBProgram, programObjects);

        programCount += add_program_objects(programObjects);
    }

    return programCount;
}
// One multisampled source, multiple non-multisampled destinations created by method.
bool vogl_msaa_texture_splitter::split(GLenum src_target, GLuint src_texture, vogl::vector<GLuint> &dest_textures)
{
    dest_textures.resize(0);

    if (!m_valid)
        return false;

    if ((src_target != GL_TEXTURE_2D_MULTISAMPLE) && (src_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
        return false;

    GLenum dest_target = (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? GL_TEXTURE_2D_ARRAY : GL_TEXTURE_2D;

    GL_ENTRYPOINT(glBindTexture)(src_target, src_texture);
    VOGL_CHECK_GL_ERROR;

    GLint mip_level = 0, base_level = 0, max_level = 0;

    GLenum internal_fmt = 0;
    int base_width = 0, base_height = 0, base_depth = 0, samples = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_WIDTH, &base_width);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_HEIGHT, &base_height);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_DEPTH, &base_depth);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, base_level, GL_TEXTURE_SAMPLES, &samples);
    VOGL_CHECK_GL_ERROR;

    if ((base_width < 1) || (base_height < 1) || (base_depth < 1) || (samples < 1))
        return false;

    const vogl_internal_tex_format *pInternal_tex_fmt = vogl_find_internal_texture_format(internal_fmt);
    if ((!pInternal_tex_fmt) || (pInternal_tex_fmt->m_optimum_get_image_fmt == GL_NONE) || (pInternal_tex_fmt->m_optimum_get_image_type == GL_NONE))
        return false;

    GLenum attachment_target = GL_COLOR_ATTACHMENT0;

    if ((pInternal_tex_fmt->m_comp_sizes[cTCDepth]) && (pInternal_tex_fmt->m_comp_sizes[cTCStencil]))
        attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;
    else if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
        attachment_target = GL_DEPTH_ATTACHMENT;
    else if (pInternal_tex_fmt->m_comp_sizes[cTCStencil])
        return false;

    if (attachment_target == GL_COLOR_ATTACHMENT0)
    {
        GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST);
        VOGL_CHECK_GL_ERROR;
    }
    else
    {
        GL_ENTRYPOINT(glDepthMask)(GL_TRUE);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
        VOGL_CHECK_GL_ERROR;
    }

    GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
    VOGL_CHECK_GL_ERROR;

    uint32_t width = base_width << base_level;
    uint32_t height = base_height << base_level;
    uint32_t depth = base_depth;

    uint32_t max_possible_mip_levels = utils::compute_max_mips(width, height, depth);
    int num_actual_mip_levels = math::minimum<int>(max_possible_mip_levels, max_level + 1);

    for (int sample_index = 0; sample_index < samples; sample_index++)
    {
        m_read_color_program.set_uniform("tex_sample", sample_index);
        m_read_color_array_program.set_uniform("tex_sample", sample_index);
        m_read_depth_program.set_uniform("tex_sample", sample_index);
        m_read_depth_array_program.set_uniform("tex_sample", sample_index);

        GLuint dest_texture = 0;
        GL_ENTRYPOINT(glGenTextures)(1, &dest_texture);
        VOGL_CHECK_GL_ERROR;

        dest_textures.push_back(dest_texture);

        GL_ENTRYPOINT(glBindTexture)(dest_target, dest_texture);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_BASE_LEVEL, base_level);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glTexParameteri)(dest_target, GL_TEXTURE_MAX_LEVEL, num_actual_mip_levels - 1);
        VOGL_CHECK_GL_ERROR;

        int mip_width = 0, mip_height = 0, mip_depth = 0;
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_WIDTH, &mip_width);
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_HEIGHT, &mip_height);
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_DEPTH, &mip_depth);
        if ((vogl_check_gl_error()) || (mip_width < 1) || (mip_height < 1) || (mip_depth < 1))
            goto failure;

        VOGL_ASSERT(mip_depth == base_depth);
        VOGL_NOTE_UNUSED(mip_depth);

        vogl::vector<uint8_t> ones;
        ones.resize(static_cast<uint32_t>(vogl_get_image_size(pInternal_tex_fmt->m_optimum_get_image_fmt, pInternal_tex_fmt->m_optimum_get_image_type, mip_width, mip_height, mip_depth)));
        ones.set_all(255);

        if (src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
        {
            GL_ENTRYPOINT(glTexImage3D)(dest_target,
                mip_level,
                internal_fmt,
                mip_width,
                mip_height,
                base_depth,
                0,
                pInternal_tex_fmt->m_optimum_get_image_fmt,
                pInternal_tex_fmt->m_optimum_get_image_type,
                ones.get_ptr());
            VOGL_CHECK_GL_ERROR;
        }
        else
        {
            GL_ENTRYPOINT(glTexImage2D)(dest_target,
                mip_level,
                internal_fmt,
                mip_width,
                mip_height,
                0,
                pInternal_tex_fmt->m_optimum_get_image_fmt,
                pInternal_tex_fmt->m_optimum_get_image_type,
                ones.get_ptr());
            VOGL_CHECK_GL_ERROR;
        }

        for (int layer = 0; layer < base_depth; layer++)
        {
            // Create FBO
            GLuint fbo_handle = 0;
            GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, fbo_handle);
            VOGL_CHECK_GL_ERROR;

            if (dest_target == GL_TEXTURE_2D_ARRAY)
            {
                GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_texture, mip_level, layer);
                VOGL_CHECK_GL_ERROR;
            }
            else
            {
                GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment_target, dest_target, dest_texture, mip_level);
                VOGL_CHECK_GL_ERROR;
            }

            if (attachment_target == GL_COLOR_ATTACHMENT0)
            {
                GLenum draw_buf = GL_COLOR_ATTACHMENT0;
                GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
                VOGL_CHECK_GL_ERROR;
            }
            else
            {
                GL_ENTRYPOINT(glDrawBuffer)(GL_NONE);
                VOGL_CHECK_GL_ERROR;
            }

            GLenum fbo_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_DRAW_FRAMEBUFFER);
            VOGL_CHECK_GL_ERROR;

            bool status = false;

            if (fbo_status == GL_FRAMEBUFFER_COMPLETE)
            {
                // This method reads from a multisampled texture, which does NOT support GL_SKIP_DECODE_EXT on these targets.
                // Instead, we enable sRGB writes to work around this. The source and dest use the same formats, and if the dest is not sRGB then the source shouldn't be.
                GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
                VOGL_CHECK_GL_ERROR;

                if (attachment_target == GL_COLOR_ATTACHMENT0)
                {
                    GLint encoding = 0;
                    GL_ENTRYPOINT(glGetFramebufferAttachmentParameteriv)(GL_DRAW_FRAMEBUFFER, attachment_target, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &encoding);
                    VOGL_CHECK_GL_ERROR;

                    if (encoding == GL_SRGB)
                    {
                        GL_ENTRYPOINT(glEnable)(GL_FRAMEBUFFER_SRGB);
                        VOGL_CHECK_GL_ERROR;
                    }
                }

                // Render quad to FBO
                GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glClearColor)(1.0f, 0.3f, 1.0f, 1.0f);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glClearDepth)(.25f);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glClearStencil)(64);
                VOGL_CHECK_GL_ERROR;

                if (attachment_target == GL_COLOR_ATTACHMENT0)
                {
                    GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT);
                    VOGL_CHECK_GL_ERROR;
                }
                else if (attachment_target == GL_DEPTH_ATTACHMENT)
                {
                    GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT);
                    VOGL_CHECK_GL_ERROR;
                }
                else
                {
                    GL_ENTRYPOINT(glClear)(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
                    VOGL_CHECK_GL_ERROR;
                }

                vogl_quad_vertex quad_tri_verts[3*2];
                memcpy(quad_tri_verts, get_quad_tri_verts(), sizeof(quad_tri_verts));

                for (uint32_t i = 0; i < 6; i++)
                {
                    quad_tri_verts[i].m_uv0[0] *= mip_width;
                    quad_tri_verts[i].m_uv0[1] *= mip_height;
                    quad_tri_verts[i].m_uv0[2] = 1.0f * layer;
                }

                GL_ENTRYPOINT(glBufferData)(GL_ARRAY_BUFFER, sizeof(quad_tri_verts), quad_tri_verts, GL_STATIC_DRAW);
                VOGL_CHECK_GL_ERROR;

                if (attachment_target == GL_COLOR_ATTACHMENT0)
                {
                    GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_color_array_program.get_handle() : m_read_color_program.get_handle());
                    VOGL_CHECK_GL_ERROR;
                }
                else
                {
                    GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_read_depth_array_program.get_handle() : m_read_depth_program.get_handle());
                    VOGL_CHECK_GL_ERROR;
                }

                GL_ENTRYPOINT(glDrawArrays)(GL_TRIANGLES, 0, 6);
                VOGL_CHECK_GL_ERROR;

                status = true;
            } // fbo_status

            // Delete FBO
            GL_ENTRYPOINT(glBindFramebuffer)(GL_DRAW_FRAMEBUFFER, 0);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDeleteFramebuffers)(1, &fbo_handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDrawBuffer)(GL_FRONT_LEFT);
            VOGL_CHECK_GL_ERROR;

            if (!status)
                goto failure;
        } // layer
    } // sample_index

    GL_ENTRYPOINT(glBindTexture)(src_target, 0);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
    VOGL_CHECK_GL_ERROR;

    return true;

failure:
    GL_ENTRYPOINT(glBindTexture)(src_target, 0);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindTexture)(dest_target, 0);
    VOGL_CHECK_GL_ERROR;

    if (dest_textures.size())
    {
        GL_ENTRYPOINT(glDeleteTextures)(dest_textures.size(), dest_textures.get_ptr());
        VOGL_CHECK_GL_ERROR;

        dest_textures.resize(0);
    }

    return false;
}