예제 #1
0
    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();
    }
예제 #2
0
bool file_utils::does_file_exist(const char *pFilename)
{
    FILE *pFile = vogl_fopen(pFilename, "rb");
    if (!pFile)
        return false;
    vogl_fclose(pFile);
    return true;
}
예제 #3
0
bool file_utils::get_file_size(const char *pFilename, uint64_t &file_size)
{
    FILE *pFile = vogl_fopen(pFilename, "rb");
    if (!pFile)
        return false;
    vogl_fseek(pFile, 0, SEEK_END);
    file_size = vogl_ftell(pFile);
    vogl_fclose(pFile);
    return true;
}
예제 #4
0
void *file_utils::read_file_to_heap(const char *pPath, size_t &data_size)
{
    data_size = 0;

    FILE *pFile = vogl_fopen(pPath, "rb");
    if (!pFile)
        return NULL;

    vogl_fseek(pFile, 0, SEEK_END);
    uint64_t file_size = vogl_ftell(pFile);
    vogl_fseek(pFile, 0, SEEK_SET);

    if (file_size > VOGL_MAX_POSSIBLE_HEAP_BLOCK_SIZE)
    {
        vogl_fclose(pFile);
        return NULL;
    }

    data_size = static_cast<size_t>(file_size);
    VOGL_ASSERT(data_size == file_size);

    void *p = vogl_malloc(data_size);
    if (!p)
    {
        vogl_fclose(pFile);
        data_size = 0;
        return NULL;
    }

    bool success = (vogl_fread(p, 1, data_size, pFile) == data_size);

    vogl_fclose(pFile);

    if (!success)
    {
        vogl_free(p);
        data_size = 0;
        return NULL;
    }

    return p;
}
예제 #5
0
bool file_utils::write_buf_to_file(const char *pPath, const void *pData, size_t data_size)
{
    FILE *pFile = vogl_fopen(pPath, "wb");
    if (!pFile)
        return false;

    bool success = vogl_fwrite(pData, 1, data_size, pFile) == data_size;

    if (vogl_fclose(pFile) == EOF)
        return false;

    return success;
}
예제 #6
0
    bool data_stream::write_file_data(const char *pFilename)
    {
        uint64_t file_size;
        if (!file_utils::get_file_size(pFilename, file_size))
            return false;

        if (!file_size)
            return true;

        FILE *pFile = vogl_fopen(pFilename, "rb");
        if (!pFile)
            return false;

        uint8_vec buf(64 * 1024);

        uint64_t bytes_remaining = file_size;
        while (bytes_remaining)
        {
            uint n = static_cast<uint>(math::minimum<uint64_t>(buf.size(), bytes_remaining));

            if (vogl_fread(buf.get_ptr(), 1, n, pFile) != n)
            {
                vogl_fclose(pFile);
                return false;
            }

            if (write(buf.get_ptr(), n) != n)
            {
                vogl_fclose(pFile);
                return false;
            }

            bytes_remaining -= n;
        }

        vogl_fclose(pFile);
        return true;
    }
예제 #7
0
    // init_uuid() is slow (~40ms, maybe slower), and forces a disk flush on a file, so don't call it more than once.
    // I'm a paranoid nut so this hashes a bunch of shit. It's probably completely overkill for my needs - I should stop reading RFC's.
    static md5_hash init_uuid()
    {
        static uint64_t s_counter;

        // Get as much entropy as we can here

        const uint N = 2;
        void *p[N];
        memset(p, 0, sizeof(p));

        md5_hash_gen gen;
        timer_ticks tick_hist[N];
        for (uint i = 0; i < N; i++)
        {
            uint64_t start_rdtsc = utils::RDTSC();
            gen.update(start_rdtsc);

            gen.update(s_counter);
            gen.update((uint64_t) & s_counter);
            s_counter++;

            // Hash stack address of gen_uuid
            gen.update((uint64_t) & gen_uuid);

            // Hash the initial timer ticks, and time(NULL)
            gen.update(timer::get_init_ticks());
            gen.update((uint64_t)time(NULL));

            // Hash user ID, name, shell, home dir
            uid_t uid = geteuid();
            gen.update(uid);
            struct passwd *pw = getpwuid(uid);
            gen.update((uint64_t) & pw);
            if (pw)
            {
                gen.update(pw, sizeof(struct passwd));
                if (pw->pw_name)
                    gen.update(pw->pw_name, vogl_strlen(pw->pw_name));
                if (pw->pw_passwd)
                    gen.update(pw->pw_passwd, vogl_strlen(pw->pw_passwd));
                if (pw->pw_shell)
                    gen.update(pw->pw_shell, vogl_strlen(pw->pw_shell));
                if (pw->pw_dir)
                    gen.update(pw->pw_dir, vogl_strlen(pw->pw_dir));
                if (pw->pw_gecos)
                    gen.update(pw->pw_gecos, vogl_strlen(pw->pw_gecos));
            }

            uint8_vec buf;

            timer_ticks ticks = timer::get_ticks();
            gen.update(ticks);

            // This is obviously expensive (and questionable?), only do it once. But it helps us get some entropy from the disk subsystem.
            // This is also by far the slowest component of this function (~35ms out of ~40ms).
            if (!i)
            {
                uint64_t st = utils::RDTSC();
                timer tm;
                tm.start();

                const char *pFilename = "!_!_!_!_!_!_!_vogl_temp!_!_!_!_!_!_!_!_.txt";
                FILE *pFile = vogl_fopen(pFilename, "wb");
                gen.update_obj_bits(pFile);
                if (pFile)
                {
                    fwrite("X", 1, 1, pFile);
                    fflush(pFile);
                    fsync(fileno(pFile));
                    vogl_fclose(pFile);
                    remove(pFilename);
                }

                uint64_t t = utils::RDTSC() - st;
                gen.update(t);

                tm.stop();

                gen.update(tm.get_elapsed_ticks());
            }

            // Grab some bits from /dev/urandom (not /dev/random - it may block for a long time)
            {
                const uint N = 64;
                char buf[N];
                FILE *fp = vogl_fopen("/dev/urandom", "rb");
                gen.update_obj_bits(fp);
                if (fp)
                {
                    size_t n = fread(buf, 1, N, fp);
                    VOGL_NOTE_UNUSED(n);
                    vogl_fclose(fp);

                    gen.update(buf, sizeof(buf));
                }
            }

// It's fine if some/most/all of these files don't exist, the true/false results get fed into the hash too.
// TODO: Double check that all the files we should be able to read are actually getting read and hashed here.
#define HASH_FILE(filename)                                               \
    do                                                                    \
    {                                                                     \
        bool success = cfile_stream::read_file_into_array(filename, buf); \
        gen.update_obj_bits(success);                                     \
        gen.update(buf);                                                  \
    } while (0)
            HASH_FILE("/proc/sys/kernel/random/entropy_avail");
            HASH_FILE("/proc/self/statm");
            HASH_FILE("/proc/self/mounts");
            HASH_FILE("/proc/self/io");
            HASH_FILE("/proc/self/smaps");
            HASH_FILE("/proc/self/stack");
            HASH_FILE("/proc/self/status");
            HASH_FILE("/proc/self/maps");
            HASH_FILE("/proc/self/stat");
            HASH_FILE("/proc/self/stat");
            HASH_FILE("/proc/cpuinfo");
            HASH_FILE("/proc/meminfo");
            HASH_FILE("/proc/stat");
            HASH_FILE("/proc/misc");
            HASH_FILE("/proc/swaps");
            HASH_FILE("/proc/version");
            HASH_FILE("/proc/loadavg");
            HASH_FILE("/proc/interrupts");
            HASH_FILE("/proc/ioports");
            HASH_FILE("/proc/partitions");
            HASH_FILE("/proc/driver/rtc");
            HASH_FILE("/proc/self/net/wireless");
            HASH_FILE("/proc/self/net/netstat");
            HASH_FILE("/proc/self/net/netlink");
            HASH_FILE("/sys/class/net/eth0/address");
            HASH_FILE("/sys/class/net/eth1/address");
            HASH_FILE("/sys/class/net/wlan0/address");
#undef HASH_FILE

            gen.update(utils::RDTSC());

            // Hash thread, process ID's, etc.
            pid_t tid = (pid_t)syscall(SYS_gettid);
            gen.update_obj_bits(tid);

            pid_t pid = getpid();
            gen.update_obj_bits(pid);

            pid = getppid();
            gen.update_obj_bits(pid);
            gen.update((uint64_t) & pid);

            ticks -= timer::get_ticks();
            tick_hist[i] = ticks;
            gen.update(ticks);

            ticks = timer::get_ticks();

            // Get some entropy from the stack.
            char purposely_uninitialized_buf[256];
            gen.update(purposely_uninitialized_buf, sizeof(purposely_uninitialized_buf));

            // Get some entropy from the heap.
            p[i] = vogl_malloc(65536 * (i + 1));
            gen.update_obj_bits(p[i]);
            if (p[i])
            {
                for (uint j = 0; j < 16; j++)
                    gen.update_obj_bits(reinterpret_cast<const uint64_t *>(p)[j]);
            }

            struct timeval tv;
            gettimeofday(&tv, NULL);
            gen.update_obj_bits(tv);

            // Hash the current environment
            uint e = 0;
            while (environ[e])
            {
                gen.update(environ[e], vogl_strlen(environ[e]));
                ++e;
            }

            uint64_t s = utils::RDTSC();

            // Try to get some entropy from the scheduler.
            vogl_sleep(2);

            gen.update(utils::RDTSC() - s);

            ticks -= timer::get_ticks();
            gen.update(ticks);

            gen.update(utils::RDTSC() - start_rdtsc);
        }

        for (uint i = 1; i < N; i++)
        {
            uint64_t t = tick_hist[i] - tick_hist[i - 1];
            gen.update(t);
        }

        for (uint i = 0; i < N; i++)
            vogl_free(p[i]);

        return gen.finalize();
    }
예제 #8
0
//----------------------------------------------------------------------------------------------------------------------
// vogl_devel_dump_internal_texture_formats
// This func is only for testing various internal GL format related API's
// This func is used to generate vogl_internal_texture_formats.inc
//----------------------------------------------------------------------------------------------------------------------
void vogl_devel_dump_internal_texture_formats(const vogl_context_info &context_info)
{
    VOGL_FUNC_TRACER

    VOGL_CHECK_GL_ERROR;

    vogl_scoped_binding_state orig_texture;
    orig_texture.save_textures(&context_info);

    vogl_scoped_state_saver state_saver(cGSTPixelStore, cGSTPixelTransfer);

    vogl_reset_pixel_store_states();
    vogl_reset_pixel_transfer_states(context_info);

#if 0
	// silly experiment
	{
		GLuint handle;
		ACTUAL_GL_ENTRYPOINT(glGenTextures)(1, &handle);
		VOGL_CHECK_GL_ERROR;

		ACTUAL_GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
		VOGL_CHECK_GL_ERROR;

		for (uint32_t i = 0; i < 256; i++)
		{
			uint8_t vals[4] = { i, 0, 0, 0 };
			//ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_R8_SNORM, 1, 1, 0, GL_RED, GL_BYTE, vals);

			//float vals[1] = { ( i - 128.0f) / 127.0f };
			//float vals[1] = { i / 255.0f };

			//ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, .5f);
			//ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.5f);

			ACTUAL_GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, GL_RGB8UI, 1, 1, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, vals);

			//ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_SCALE, 1.0f);
			//ACTUAL_GL_ENTRYPOINT(glPixelTransferf)(GL_RED_BIAS, 0.0f);

			VOGL_CHECK_GL_ERROR;

			uint16_t gvals[4] = { 0, 0, 0, 0 };
			ACTUAL_GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, GL_RGB_INTEGER, GL_UNSIGNED_BYTE, gvals);
			VOGL_CHECK_GL_ERROR;

			printf("%u %u %u %u, %u %u %u %u\n", vals[0], vals[1], vals[2], vals[3],
			       gvals[0], gvals[1], gvals[2], gvals[3]);
		}


		ACTUAL_GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
	}
#endif

    typedef vogl::map<GLenum, vogl_internal_tex_format> tex_format_map;
    tex_format_map internal_formats;

    // Iterate through the base internal fmts, which need some special handling (argh) because the actual internal fmt != the requested internal fmt
    GLenum base_internal_formats[] =
        {
            GL_DEPTH_COMPONENT,
            GL_DEPTH_STENCIL,
            GL_ALPHA,
            GL_RED,
            GL_RG,
            GL_RGB,
            GL_RGBA,
            GL_LUMINANCE,
            GL_LUMINANCE_ALPHA,
            GL_INTENSITY,
            GL_SLUMINANCE,
            GL_SLUMINANCE_ALPHA,
            GL_SRGB,
            GL_SRGB_ALPHA
        };

    for (uint32_t i = 0; i < VOGL_ARRAY_SIZE(base_internal_formats); i++)
    {
        printf("%s\n", get_gl_enums().find_gl_name(base_internal_formats[i]));

        GLuint handle;
        GL_ENTRYPOINT(glGenTextures)(1, &handle);
        VOGL_CHECK_GL_ERROR;

        GLenum target = GL_TEXTURE_2D;

        GL_ENTRYPOINT(glBindTexture)(target, handle);

        GLenum base_internal_fmt = base_internal_formats[i];

        vogl_internal_tex_format f;
        GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type);
        GL_ENTRYPOINT(glGetInternalformativ)(target, base_internal_fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt);
        VOGL_CHECK_GL_ERROR;

        GLenum &get_fmt = f.m_optimum_get_image_fmt;
        GLenum &get_type = f.m_optimum_get_image_type;

        // manual fixups, ARGH
        switch (base_internal_fmt)
        {
            case GL_DEPTH_COMPONENT:
            {
                get_fmt = GL_DEPTH_COMPONENT;
                get_type = GL_FLOAT;
                break;
            }
            case GL_RG:
            {
                get_fmt = GL_RG;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_RGB:
            {
                get_fmt = GL_RGB;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_RED:
            {
                get_fmt = GL_RED;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_COMPRESSED_LUMINANCE:
            {
                get_fmt = GL_LUMINANCE;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_COMPRESSED_LUMINANCE_ALPHA:
            {
                get_fmt = GL_LUMINANCE_ALPHA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_COMPRESSED_RGB:
            {
                get_fmt = GL_RGBA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_COMPRESSED_RGBA:
            {
                get_fmt = GL_RGBA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_LUMINANCE_ALPHA:
            {
                get_fmt = GL_LUMINANCE_ALPHA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_SLUMINANCE_ALPHA:
            {
                get_fmt = GL_LUMINANCE_ALPHA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_SRGB:
            {
                get_fmt = GL_RGB;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            case GL_SRGB_ALPHA:
            {
                get_fmt = GL_RGBA;
                get_type = GL_UNSIGNED_BYTE;
                break;
            }
            default:
            {
                break;
            }
        }

        VOGL_VERIFY(get_fmt != GL_NONE);
        VOGL_VERIFY(get_type != GL_NONE);

        GL_ENTRYPOINT(glTexImage2D)(target, 0, base_internal_fmt, 32, 32, 0, get_fmt, get_type, NULL);
        VOGL_VERIFY(!vogl_check_gl_error());

//bool any_gl_errors = false;

#define GET_INT(dst, gl_enum)                                                  \
    do                                                                         \
    {                                                                          \
        int values[4];                                                         \
        utils::zero_object(values);                                            \
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
        (dst) = values[0];                                                     \
    } while (0)

#define GET_BOOL(dst, gl_enum)                                                 \
    do                                                                         \
    {                                                                          \
        int values[4];                                                         \
        utils::zero_object(values);                                            \
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
        (dst) = values[0] != 0;                                                \
    } while (0)


        GLenum actual_internal_fmt;
        GET_INT(actual_internal_fmt, GL_TEXTURE_INTERNAL_FORMAT);

        f.m_tex_image_flags = ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4));
        f.m_fmt = base_internal_fmt;
        f.m_actual_internal_fmt = actual_internal_fmt;
        f.m_name = get_gl_enums().find_name(base_internal_fmt, "gl");

        GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE);
        GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE);
        GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE);
        GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE);
        GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE);
        GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE);
        GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE);
        GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE);

        GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE);
        GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE);
        GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE);
        GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE);
        GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE);
        GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE);
        GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE);

        GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE);
        GET_BOOL(f.m_compressed, GL_TEXTURE_COMPRESSED);

        printf("base_internal_fmt: %s get_fmt: %s get_type: %s, actual_internal_fmt: %s compressed: %u\n",
               get_gl_enums().find_gl_name(base_internal_fmt), get_gl_enums().find_gl_name(get_fmt), get_gl_enums().find_gl_name(get_type),
               get_gl_enums().find_gl_name(actual_internal_fmt),
               f.m_compressed);
#undef GET_INT
#undef GET_BOOL

        //VOGL_ASSERT(!any_gl_errors);

        VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE);
        VOGL_ASSERT(f.m_optimum_get_image_fmt != GL_NONE);
        VOGL_ASSERT(f.m_optimum_get_image_type != GL_NONE);

        VOGL_ASSERT(!f.m_compressed);
        VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
        VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0);

        if (!internal_formats.insert(base_internal_fmt, f).second)
        {
            internal_formats.find_value(base_internal_fmt)->m_tex_image_flags |= ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4));
        }

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

        GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
        VOGL_CHECK_GL_ERROR;
    }

    for (uint32_t t = 0; t < 5; t++)
    {
        GLenum target = GL_NONE;
        switch (t)
        {
            case 0:
            {
                target = GL_TEXTURE_1D;
                break;
            }
            case 1:
            {
                target = GL_TEXTURE_2D;
                break;
            }
            case 2:
            {
                target = GL_TEXTURE_3D;
                break;
            }
            case 3:
            {
                target = GL_TEXTURE_2D_MULTISAMPLE;
                break;
            }
            case 4:
            {
                target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
                break;
            }
            default:
            {
                VOGL_ASSERT_ALWAYS;
                break;
            }
        }

        for (uint32_t fmt = 0; fmt <= 0xFFFF; fmt++)
        {
            GLuint handle;
            GL_ENTRYPOINT(glGenTextures)(1, &handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glBindTexture)(target, handle);

            vogl_debug_message_control(context_info, GL_INVALID_ENUM, false);
            vogl_debug_message_control(context_info, GL_INVALID_OPERATION, false);

            bool failed = false;

            switch (t)
            {
                case 0:
                {
                    GL_ENTRYPOINT(glTexStorage1D)(target, 1, fmt, 32);
                    failed = vogl_check_gl_error_suppress_message();
                    break;
                }
                case 1:
                {
                    GL_ENTRYPOINT(glTexStorage2D)(target, 1, fmt, 32, 32);
                    failed = vogl_check_gl_error_suppress_message();
                    break;
                }
                case 2:
                {
                    GL_ENTRYPOINT(glTexStorage3D)(target, 1, fmt, 32, 32, 32);
                    failed = vogl_check_gl_error_suppress_message();
                    break;
                }
                case 3:
                {
                    GL_ENTRYPOINT(glTexStorage2DMultisample)(target, 2, fmt, 32, 32, GL_TRUE);
                    failed = vogl_check_gl_error_suppress_message();
                    break;
                }
                case 4:
                {
                    GL_ENTRYPOINT(glTexStorage3DMultisample)(target, 2, fmt, 32, 32, 2, GL_TRUE);
                    failed = vogl_check_gl_error_suppress_message();
                    break;
                }
            }

            vogl_debug_message_control(context_info, GL_INVALID_ENUM, true);
            vogl_debug_message_control(context_info, GL_INVALID_OPERATION, true);

            if (failed)
                continue;

            bool any_gl_errors = false;
            VOGL_NOTE_UNUSED(any_gl_errors);

            vogl_internal_tex_format f;
            f.m_tex_image_flags = (1 << t);
            f.m_fmt = fmt;
            f.m_actual_internal_fmt = fmt; // this assumes the actual internal fmt will match here!
            f.m_name = get_gl_enums().find_name(fmt, "gl");

#define GET_INT(dst, gl_enum)                                                  \
    do                                                                         \
    {                                                                          \
        int values[4];                                                         \
        utils::zero_object(values);                                            \
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
        (dst) = values[0];                                                     \
    } while (0)

#define GET_BOOL(dst, gl_enum)                                                 \
    do                                                                         \
    {                                                                          \
        int values[4];                                                         \
        utils::zero_object(values);                                            \
        GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, 0, (gl_enum), values); \
        (dst) = values[0] != 0;                                                \
    } while (0)

            GLenum internal_fmt;
            GET_INT(internal_fmt, GL_TEXTURE_INTERNAL_FORMAT);
            VOGL_ASSERT(internal_fmt == fmt);
            GET_INT(f.m_comp_sizes[cTCRed], GL_TEXTURE_RED_SIZE);
            GET_INT(f.m_comp_sizes[cTCGreen], GL_TEXTURE_GREEN_SIZE);
            GET_INT(f.m_comp_sizes[cTCBlue], GL_TEXTURE_BLUE_SIZE);
            GET_INT(f.m_comp_sizes[cTCAlpha], GL_TEXTURE_ALPHA_SIZE);
            GET_INT(f.m_comp_sizes[cTCStencil], GL_TEXTURE_STENCIL_SIZE);
            GET_INT(f.m_comp_sizes[cTCDepth], GL_TEXTURE_DEPTH_SIZE);
            GET_INT(f.m_comp_sizes[cTCIntensity], GL_TEXTURE_INTENSITY_SIZE);
            GET_INT(f.m_comp_sizes[cTCLuminance], GL_TEXTURE_LUMINANCE_SIZE);

            GET_INT(f.m_comp_types[cTCRed], GL_TEXTURE_RED_TYPE);
            GET_INT(f.m_comp_types[cTCGreen], GL_TEXTURE_GREEN_TYPE);
            GET_INT(f.m_comp_types[cTCBlue], GL_TEXTURE_BLUE_TYPE);
            GET_INT(f.m_comp_types[cTCAlpha], GL_TEXTURE_ALPHA_TYPE);
            GET_INT(f.m_comp_types[cTCDepth], GL_TEXTURE_DEPTH_TYPE);
            GET_INT(f.m_comp_types[cTCIntensity], GL_TEXTURE_INTENSITY_TYPE);
            GET_INT(f.m_comp_types[cTCLuminance], GL_TEXTURE_LUMINANCE_TYPE);

            GET_INT(f.m_shared_size, GL_TEXTURE_SHARED_SIZE);
            GET_BOOL(f.m_compressed, GL_TEXTURE_COMPRESSED);
#undef GET_INT
#undef GET_BOOL

            VOGL_ASSERT(!any_gl_errors);

            GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_TYPE, sizeof(f.m_optimum_get_image_type), (GLint *)&f.m_optimum_get_image_type);
            GL_ENTRYPOINT(glGetInternalformativ)(target, fmt, GL_GET_TEXTURE_IMAGE_FORMAT, sizeof(f.m_optimum_get_image_fmt), (GLint *)&f.m_optimum_get_image_fmt);
            VOGL_CHECK_GL_ERROR;

            if (f.m_compressed)
            {
                f.m_optimum_get_image_fmt = GL_RGBA;
                f.m_optimum_get_image_type = GL_UNSIGNED_BYTE;
            }
            else
            {
#define HANDLE_FMT(gl_enum, fmt, type)     \
    case gl_enum:                          \
    {                                      \
        f.m_optimum_get_image_fmt = fmt;   \
        f.m_optimum_get_image_type = type; \
        break;                             \
    }
                bool unhandled = false;
                switch (fmt)
                {
                    HANDLE_FMT(GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV);
                    HANDLE_FMT(GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV);
                    HANDLE_FMT(GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
                    HANDLE_FMT(GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
                    HANDLE_FMT(GL_INTENSITY32F_ARB, GL_RED, GL_FLOAT);

                    HANDLE_FMT(2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(3, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_LUMINANCE4_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_LUMINANCE6_ALPHA2, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_LUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_LUMINANCE12_ALPHA4, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_LUMINANCE12_ALPHA12, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_LUMINANCE16_ALPHA16, GL_LUMINANCE_ALPHA, GL_UNSIGNED_SHORT);

                    HANDLE_FMT(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_RGB8I, GL_RGB_INTEGER, GL_BYTE);
                    HANDLE_FMT(GL_RGB10, GL_RGB, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RGB12, GL_RGB, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RGBA12, GL_RGB, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_RG16, GL_RG, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RG16F, GL_RG, GL_HALF_FLOAT);
                    HANDLE_FMT(GL_RG32F, GL_RG, GL_FLOAT);

                    HANDLE_FMT(GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_SLUMINANCE8_ALPHA8, GL_LUMINANCE_ALPHA, GL_BYTE);

                    HANDLE_FMT(GL_RGB32I, GL_RGB_INTEGER, GL_INT);
                    HANDLE_FMT(GL_RGB16I, GL_RGB_INTEGER, GL_SHORT);

                    HANDLE_FMT(GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
                    HANDLE_FMT(GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT);
                    HANDLE_FMT(GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
                    HANDLE_FMT(GL_SIGNED_RGBA8_NV, GL_RGBA, GL_BYTE);
                    HANDLE_FMT(GL_SIGNED_RGB8_NV, GL_RGB, GL_BYTE);
                    HANDLE_FMT(GL_SIGNED_LUMINANCE8_ALPHA8_NV, GL_LUMINANCE_ALPHA, GL_BYTE);
                    HANDLE_FMT(GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV, GL_RGBA, GL_BYTE);
                    HANDLE_FMT(GL_RG8_SNORM, GL_RG, GL_BYTE);
                    HANDLE_FMT(GL_RGB8_SNORM, GL_RGB, GL_BYTE);
                    HANDLE_FMT(GL_RG16_SNORM, GL_RG, GL_SHORT);
                    HANDLE_FMT(GL_RGB16_SNORM, GL_RGB, GL_SHORT);

                    HANDLE_FMT(GL_RGB32F, GL_RGB, GL_FLOAT);
                    HANDLE_FMT(GL_RGB16F, GL_RGB, GL_HALF_FLOAT);

                    // TODO: Research oddball formats
                    HANDLE_FMT(GL_PALETTE4_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_PALETTE4_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_PALETTE8_RGB8_OES, GL_RGB, GL_UNSIGNED_BYTE);
                    HANDLE_FMT(GL_PALETTE8_R5_G6_B5_OES, GL_RGB, GL_UNSIGNED_BYTE);

                    HANDLE_FMT(GL_HILO16_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_SIGNED_HILO16_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_DSDT8_MAG8_INTENSITY8_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_HILO8_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_SIGNED_HILO8_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_DSDT8_NV, GL_NONE, GL_NONE);
                    HANDLE_FMT(GL_DSDT8_MAG8_NV, GL_NONE, GL_NONE);

                    default:
                        unhandled = true;
                        break;
                }

                if ((unhandled) && ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE)))
                {
                    printf("INVALID: %s %s %s\n", f.m_name.get_ptr(), get_gl_enums().find_name(f.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(f.m_optimum_get_image_type, "gl"));
                }
            }

#undef HANDLE_FMT

            VOGL_ASSERT(f.m_actual_internal_fmt != GL_NONE);

            if ((f.m_optimum_get_image_fmt == GL_NONE) || (f.m_optimum_get_image_type == GL_NONE))
                vogl_warning_printf("Don't have an optimal get format/type for internal format %s\n", get_gl_enums().find_gl_name(fmt));

            VOGL_ASSERT(fmt != GL_LUMINANCE);

            VOGL_ASSERT(f.m_fmt == f.m_actual_internal_fmt);
            if (!f.m_compressed)
            {
                VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(f.m_fmt) && !ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
                VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_fmt) == 0 && ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) == 0);
            }
            else
            {
                VOGL_ASSERT(ktx_is_compressed_ogl_fmt(f.m_actual_internal_fmt));
                VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(f.m_actual_internal_fmt) != 0);
            }

            if (!internal_formats.insert(fmt, f).second)
            {
                internal_formats.find_value(fmt)->m_tex_image_flags |= (1 << t);
            }

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

            GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
            VOGL_CHECK_GL_ERROR;
        }
    }

    const char *pOutput_filename = "internal_texture_formats.inc";
    FILE *pFile = vogl_fopen(pOutput_filename, "w");
    VOGL_VERIFY(pFile);
    if (!pFile)
        return;

    for (tex_format_map::const_iterator it = internal_formats.begin(); it != internal_formats.end(); ++it)
    {
        vogl_internal_tex_format fmt(it->second);

        uint32_t actual_size = 0;

        if (!fmt.m_compressed)
        {
            VOGL_ASSERT(!ktx_is_compressed_ogl_fmt(fmt.m_fmt));
            VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) == 0);
        }
        else
        {
            VOGL_ASSERT(ktx_is_compressed_ogl_fmt(fmt.m_fmt));
            VOGL_ASSERT(ktx_get_ogl_compressed_base_internal_fmt(fmt.m_fmt) != 0);
        }

        if ((!fmt.m_compressed) && (fmt.m_optimum_get_image_fmt != GL_NONE) && (fmt.m_optimum_get_image_type != GL_NONE))
        {
            GLuint handle;
            GL_ENTRYPOINT(glGenTextures)(1, &handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
            VOGL_CHECK_GL_ERROR;

            uint8_t vals[128];
            utils::zero_object(vals);
            vals[1] = 64;
            GL_ENTRYPOINT(glTexImage2D)(GL_TEXTURE_2D, 0, fmt.m_fmt, 1, 1, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, vals);
            if (vogl_check_gl_error())
            {
                printf("glTexImage2D FAILED: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"));
            }

            uint8_t gvals[128];
            memset(gvals, 0xCD, sizeof(gvals));
            GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals);

            uint32_t actual_size0 = 0;
            for (actual_size0 = 0; actual_size0 < sizeof(gvals); actual_size0++)
                if (gvals[actual_size0] == 0xCD)
                    break;

            memset(gvals, 0x12, sizeof(gvals));
            GL_ENTRYPOINT(glGetTexImage)(GL_TEXTURE_2D, 0, fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type, gvals);

            uint32_t actual_size1 = 0;
            for (actual_size1 = 0; actual_size1 < sizeof(gvals); actual_size1++)
                if (gvals[actual_size1] == 0x12)
                    break;

            VOGL_VERIFY(actual_size0 == actual_size1);

            //printf("glGetTexImage() wrote %u bytes\n", actual_size0);

            if (vogl_check_gl_error()) // || gvals[1] != vals[1])
            {
                printf("glGetTexImage() failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"));
            }

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

            GL_ENTRYPOINT(glDeleteTextures)(1, &handle);

            actual_size = actual_size0;

            uint32_t s = vogl_get_image_format_size_in_bytes(fmt.m_optimum_get_image_fmt, fmt.m_optimum_get_image_type);
            VOGL_VERIFY(s);
            if (s != actual_size0)
            {
                VOGL_VERIFY(0);
            }

            vogl::ktx_texture ktx_tex;
            GLenum img_fmt;
            GLenum img_type;
            img_fmt = fmt.m_optimum_get_image_fmt;
            img_type = fmt.m_optimum_get_image_type;

            uint32_t block_dim, bytes_per_block;
            bool success = ktx_get_ogl_fmt_desc(img_fmt, img_type, block_dim, bytes_per_block);
            VOGL_VERIFY(success);
            VOGL_VERIFY(block_dim == 1);
            VOGL_VERIFY(bytes_per_block == actual_size);

            if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, img_fmt, img_type))
            {
                printf("ktx_texture::init_2D() failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"));
            }
        }
        else if (fmt.m_compressed)
        {
            GLuint handle;
            GL_ENTRYPOINT(glGenTextures)(1, &handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glBindTexture)(GL_TEXTURE_2D, handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glTexStorage2D)(GL_TEXTURE_2D, 1, fmt.m_fmt, 1, 1);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glGetTexLevelParameteriv)(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint *)&actual_size);
            VOGL_CHECK_GL_ERROR;

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

            GL_ENTRYPOINT(glDeleteTextures)(1, &handle);
            VOGL_CHECK_GL_ERROR;

            uint32_t block_width = 0, block_height = 0, block_size = 0;
            GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_WIDTH, sizeof(int), reinterpret_cast<GLint *>(&block_width));
            GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_HEIGHT, sizeof(int), reinterpret_cast<GLint *>(&block_height));
            GL_ENTRYPOINT(glGetInternalformativ)(GL_TEXTURE_2D, fmt.m_fmt, GL_TEXTURE_COMPRESSED_BLOCK_SIZE, sizeof(int), reinterpret_cast<GLint *>(&block_size));
            VOGL_CHECK_GL_ERROR;

            if (block_size == actual_size * 8U)
                block_size /= 8;

            uint32_t block_dim, bytes_per_block;
            bool success = ktx_get_ogl_fmt_desc(fmt.m_fmt, GL_UNSIGNED_BYTE, block_dim, bytes_per_block);
            if ((!success) || (block_dim != block_width) || (block_dim != block_height) || (bytes_per_block != actual_size) || (bytes_per_block != block_size))
            {
                printf("ktx_get_ogl_fmt_desc on compressed format failed: %s %s %s %u %i %i %i\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"), actual_size, block_width, block_height, block_size);
            }

            fmt.m_block_width = block_width;
            fmt.m_block_height = block_height;

            vogl::ktx_texture ktx_tex;
            if (!ktx_tex.init_2D(1, 1, 1, fmt.m_fmt, GL_NONE, GL_NONE))
            {
                printf("ktx_texture::init_2D() compressed failed: %s %s %s\n", fmt.m_name.get_ptr(), get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"), get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"));
            }
        }

        fmt.m_image_bytes_per_pixel_or_block = actual_size;

        fprintf(pFile, "   vogl_internal_tex_format(0x%04X, \"%s\", 0x%04X,\n", fmt.m_fmt, fmt.m_name.get_ptr(), fmt.m_actual_internal_fmt);

        fprintf(pFile, "      ");
        for (uint32_t i = 0; i < cTCTotalComponents; i++)
            fprintf(pFile, "%u, ", fmt.m_comp_sizes[i]);
        fprintf(pFile, "\n");

        fprintf(pFile, "      ");
        for (uint32_t i = 0; i < cTCTotalComponents; i++)
            fprintf(pFile, "%s, ", get_gl_enums().find_name(fmt.m_comp_types[i], "gl"));
        fprintf(pFile, "\n");

        fprintf(pFile, "      %u, 0x%02X, %u, \n", fmt.m_shared_size, fmt.m_tex_image_flags, fmt.m_compressed);
        fprintf(pFile, "      %s, %s, %u, %u, %u),\n",
                get_gl_enums().find_name(fmt.m_optimum_get_image_fmt, "gl"),
                get_gl_enums().find_name(fmt.m_optimum_get_image_type, "gl"),
                fmt.m_image_bytes_per_pixel_or_block,
                fmt.m_block_width, fmt.m_block_height);

#if 0
        uint32_t tex_formats_count;
        static const vogl_internal_tex_format *tex_formats = get_vogl_internal_texture_formats(&tex_formats_count);
		for (uint32_t q = 0; q < tex_formats_count; q++)
		{
			if (tex_formats[q].m_fmt == fmt.m_fmt)
			{
				if (!tex_formats[q].compare(fmt))
				{
					VOGL_ASSERT_ALWAYS;
				}
				break;
			}
		}
		if (q == tex_formats_count)
		{
			VOGL_ASSERT_ALWAYS;
		}
#endif
    }

    vogl_fclose(pFile);

    printf("Wrote file %s\n", pOutput_filename);
}