Exemplo n.º 1
0
static uint vogl_get_vertex_attrib_uint(uint index, GLenum pname)
{
    VOGL_FUNC_TRACER

    uint values[4] = { 0, 0, 0, 0 };
    GL_ENTRYPOINT(glGetVertexAttribIuiv)(index, pname, values);
    return values[0];
}
Exemplo n.º 2
0
bool vogl_material_state::set_material_parameter(uint side, GLenum pname) const
{
    VOGL_FUNC_TRACER

    const GLenum face = get_face(side);

    const vogl_state_data *pData = m_params[side].find(pname);
    if (!pData)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    enum
    {
        cMaxElements = 4
    };
    if (pData->get_num_elements() > cMaxElements)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble))
    {
        float fvals[cMaxElements];
        pData->get_float(fvals);
        if (pData->get_num_elements() == 1)
            GL_ENTRYPOINT(glMaterialf)(face, pname, fvals[0]);
        else
            GL_ENTRYPOINT(glMaterialfv)(face, pname, fvals);
    }
    else
    {
        int ivals[cMaxElements];
        pData->get_int(ivals);
        if (pData->get_num_elements() == 1)
            GL_ENTRYPOINT(glMateriali)(face, pname, ivals[0]);
        else
            GL_ENTRYPOINT(glMaterialiv)(face, pname, ivals);
    }

    return !vogl_check_gl_error();
}
Exemplo n.º 3
0
//----------------------------------------------------------------------------------------------------------------------
// load_gl
//----------------------------------------------------------------------------------------------------------------------
static bool load_gl()
{
    VOGL_FUNC_TRACER

    g_actual_libgl_module_handle = dlopen("libGL.so.1", RTLD_LAZY);
    if (!g_actual_libgl_module_handle)
    {
        vogl_error_printf("%s: Failed loading libGL.so.1!\n", VOGL_FUNCTION_INFO_CSTR);
        return false;
    }

    GL_ENTRYPOINT(glXGetProcAddress) = reinterpret_cast<glXGetProcAddress_func_ptr_t>(dlsym(g_actual_libgl_module_handle, "glXGetProcAddress"));
    if (!GL_ENTRYPOINT(glXGetProcAddress))
    {
        vogl_error_printf("%s: Failed getting address of glXGetProcAddress() from libGL.so.1!\n", VOGL_FUNCTION_INFO_CSTR);
        return false;
    }

    return true;
}
Exemplo n.º 4
0
bool vogl_sampler_state::set_sampler_parameter(GLuint handle, GLenum pname) const
{
    VOGL_FUNC_TRACER

    const vogl_state_data *pData = m_params.find(pname);
    if (!pData)
        return false;

    enum
    {
        cMaxElements = 16
    };
    if (pData->get_num_elements() > cMaxElements)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    if ((pData->get_data_type() == cSTFloat) || (pData->get_data_type() == cSTDouble))
    {
        float fvals[cMaxElements];
        pData->get_float(fvals);
        if (pData->get_num_elements() == 1)
            GL_ENTRYPOINT(glSamplerParameterf)(handle, pname, fvals[0]);
        else
            GL_ENTRYPOINT(glSamplerParameterfv)(handle, pname, fvals);
    }
    else
    {
        int ivals[cMaxElements];
        pData->get_int(ivals);
        if (pData->get_num_elements() == 1)
            GL_ENTRYPOINT(glSamplerParameteri)(handle, pname, ivals[0]);
        else
            GL_ENTRYPOINT(glSamplerParameteriv)(handle, pname, ivals);
    }

    return !vogl_check_gl_error();
}
Exemplo n.º 5
0
bool vogl_query_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(remapper);
    VOGL_CHECK_GL_ERROR;

    clear();

    VOGL_ASSERT(handle <= cUINT32_MAX);

    m_snapshot_handle = static_cast<GLuint>(handle);
    m_target = target;
    m_has_been_begun = GL_ENTRYPOINT(glIsQuery)(static_cast<GLuint>(handle)) != 0;

    if (target != GL_NONE)
    {
        if (context_info.supports_extension("GL_ARB_timer_query") && GL_ENTRYPOINT(glGetQueryObjecti64v))
        {
            GLint64 result = 0;
            GL_ENTRYPOINT(glGetQueryObjecti64v)(m_snapshot_handle, GL_QUERY_RESULT, &result);
            m_prev_result = result;
        }
        else
        {
            GLuint prev_result32;
            GL_ENTRYPOINT(glGetQueryObjectuiv)(m_snapshot_handle, GL_QUERY_RESULT, &prev_result32);
            m_prev_result = prev_result32;
        }
    }

    m_get_result_status = vogl_check_gl_error();

    m_is_valid = true;

    return true;
}
Exemplo n.º 6
0
bool vogl_matrix_state::snapshot(const vogl_context_info &context_info)
{
    VOGL_FUNC_TRACER

    clear();

    bool any_errors = false;

    VOGL_CHECK_GL_ERROR;

    vogl_scoped_state_saver state_saver(cGSTActiveTexture, cGSTMatrixMode);

    if (vogl_check_gl_error())
        any_errors = true;

    if (!save_matrix_stack(context_info, GL_PROJECTION, 0, GL_PROJECTION_STACK_DEPTH, GL_PROJECTION_MATRIX))
        any_errors = true;

    if (!save_matrix_stack(context_info, GL_MODELVIEW, 0, GL_MODELVIEW_STACK_DEPTH, GL_MODELVIEW_MATRIX))
        any_errors = true;

    if (!save_matrix_stack(context_info, GL_COLOR, 0, GL_COLOR_MATRIX_STACK_DEPTH, GL_COLOR_MATRIX))
        any_errors = true;

    for (uint32_t texcoord_index = 0; texcoord_index < context_info.get_max_texture_coords(); texcoord_index++)
    {
        GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0 + texcoord_index);

        if (vogl_check_gl_error())
            any_errors = true;

        if (!save_matrix_stack(context_info, GL_TEXTURE, texcoord_index, GL_TEXTURE_STACK_DEPTH, GL_TEXTURE_MATRIX))
            any_errors = true;
    }

    for (uint32_t i = 0; i < context_info.get_max_arb_program_matrices(); i++)
    {
        if (!save_matrix_stack(context_info, GL_MATRIX0_ARB + i, 0, GL_CURRENT_MATRIX_STACK_DEPTH_ARB, GL_CURRENT_MATRIX_ARB))
            any_errors = true;
    }

    if (any_errors)
        clear();
    else
        m_valid = true;

    return !any_errors;
}
Exemplo n.º 7
0
bool vogl_renderbuffer_desc::restore(const vogl_context_info &context_info) const
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(context_info);

    if (!m_width)
        return false;

    VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);

    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glRenderbufferStorageMultisample)(GL_RENDERBUFFER, m_samples, m_internal_format, m_width, m_height);

    bool prev_gl_error = vogl_check_gl_error();
    VOGL_ASSERT(!prev_gl_error);

    return !prev_gl_error;
}
Exemplo n.º 8
0
bool vogl_sync_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(context_info);

    if (!m_is_valid)
        return false;

    VOGL_CHECK_GL_ERROR;

    if (!handle)
    {
        GLsync sync = GL_ENTRYPOINT(glFenceSync)(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
        if ((vogl_check_gl_error()) || (!sync))
            return false;
        handle = vogl_sync_to_handle(sync);

        remapper.declare_handle(VOGL_NAMESPACE_SYNCS, m_snapshot_handle, handle, GL_NONE);
        VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_SYNCS, m_snapshot_handle) == handle);
    }

    return true;
}
Exemplo n.º 9
0
bool vogl_vao_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
{
    VOGL_FUNC_TRACER

    VOGL_CHECK_GL_ERROR;

    if (!m_is_valid)
        return false;

    vogl_scoped_binding_state orig_binding(GL_VERTEX_ARRAY, GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER);

    if ((!m_snapshot_handle) && (!handle))
    {
        GL_ENTRYPOINT(glBindVertexArray)(0);
        VOGL_CHECK_GL_ERROR;
    }
    else
    {
        if (!handle)
        {
            GLuint handle32 = 0;
            GL_ENTRYPOINT(glGenVertexArrays)(1, &handle32);
            if ((vogl_check_gl_error()) || (!handle32))
                return false;
            handle = handle32;

            if (m_snapshot_handle)
            {
                remapper.declare_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle, handle, GL_NONE);
                VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_VERTEX_ARRAYS, m_snapshot_handle) == handle);
            }
        }

        if (m_has_been_bound)
        {
            GL_ENTRYPOINT(glBindVertexArray)(static_cast<GLuint>(handle));
            VOGL_CHECK_GL_ERROR;
        }
    }

    if (m_has_been_bound)
    {
        GL_ENTRYPOINT(glBindBuffer)(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, m_element_array_binding)));
        VOGL_CHECK_GL_ERROR;

        if (m_vertex_attribs.size() > context_info.get_max_vertex_attribs())
        {
            vogl_warning_printf("Saved VAO state has %u attribs, but context only allows %u attribs\n", m_vertex_attribs.size(), context_info.get_max_vertex_attribs());
        }

        for (uint32_t i = 0; i < math::minimum<uint32_t>(context_info.get_max_vertex_attribs(), m_vertex_attribs.size()); i++)
        {
            const vogl_vertex_attrib_desc &desc = m_vertex_attribs[i];

            GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, static_cast<GLuint>(remapper.remap_handle(VOGL_NAMESPACE_BUFFERS, desc.m_array_binding)));
            VOGL_CHECK_GL_ERROR;

            vogl_trace_ptr_value trace_ptr_val = desc.m_pointer;

            vogl_trace_ptr_value restore_ptr_val = trace_ptr_val;
            if ((!desc.m_array_binding) && (trace_ptr_val) && (context_info.is_compatibility_profile()))
                restore_ptr_val = remapper.remap_vertex_attrib_ptr(i, trace_ptr_val);

            void *pRestore_ptr = reinterpret_cast<void *>(restore_ptr_val);

            if ((handle) && (desc.m_array_binding == 0))
            {
                // If it's a non-default VAO, and there's no array binding, we can't call glVertexAttribPointer() because it's not allowed by AMD drivers (it thinks we're trying to set client side array data)
                // "OpenGL: glVertexAttribPointer failed because it is not allowed to specify a client-side vertex or element array when a non-default vertex array object is bound (GL_INVALID_OPERATION) [source=API type=ERROR severity=HIGH id=2100]"

                // Sanity checks.
                if ((pRestore_ptr != NULL) || (desc.m_stride) || (desc.m_enabled))
                {
                    vogl_warning_printf("Can't bind client side vertex array data on a non-default VAO, trace handle %u GL handle %u, restore ptr %p, size %i stride %i enabled %u\n",
                                        m_snapshot_handle, static_cast<uint32_t>(handle), pRestore_ptr, desc.m_size, desc.m_stride, desc.m_enabled);
                }
            }
            else
            {
                if (desc.m_integer)
                {
                    GL_ENTRYPOINT(glVertexAttribIPointer)(i, desc.m_size, desc.m_type, desc.m_stride, pRestore_ptr);
                    VOGL_CHECK_GL_ERROR;
                }
                else
                {
                    GL_ENTRYPOINT(glVertexAttribPointer)(i, desc.m_size, desc.m_type, desc.m_normalized, desc.m_stride, pRestore_ptr);
                    VOGL_CHECK_GL_ERROR;
                }
            }

            GL_ENTRYPOINT(glVertexAttribDivisor)(i, desc.m_divisor);
            VOGL_CHECK_GL_ERROR;

            if (desc.m_enabled)
            {
                GL_ENTRYPOINT(glEnableVertexAttribArray)(i);
                VOGL_CHECK_GL_ERROR;
            }
            else
            {
                GL_ENTRYPOINT(glDisableVertexAttribArray)(i);
                VOGL_CHECK_GL_ERROR;
            }
        }
    }

    return true;
}
bool vogl_get_default_framebuffer_attribs(vogl_default_framebuffer_attribs &attribs, uint screen)
{
    GLXDrawable pDrawable = GL_ENTRYPOINT(glXGetCurrentDrawable)();
    Display *pDisplay = GL_ENTRYPOINT(glXGetCurrentDisplay)();
    if ((!pDrawable) || (!pDisplay))
        return false;

    GLuint fbconfig_id = 0;
    GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_FBCONFIG_ID, &fbconfig_id);

    GLint attrib_list[3] = { GLX_FBCONFIG_ID, static_cast<GLint>(fbconfig_id), None };
    GLint nelements = 0;
    GLXFBConfig *pConfigs = GL_ENTRYPOINT(glXChooseFBConfig)(pDisplay, screen, attrib_list, &nelements);

    GLint red_size = 8, green_size = 8, blue_size = 8, alpha_size = 8;
    GLint doublebuffer = 1, stereo = 0, depth_size = 24, stencil_size = 8;
    GLint drawable_type = GLX_WINDOW_BIT;
    GLint render_type = GLX_RGBA_BIT;
    GLint samples = 0, sample_buffers = 0;

    if ((pConfigs) && (nelements > 0))
    {
        GLXFBConfig config = pConfigs[0];

        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DRAWABLE_TYPE, &drawable_type); // what does a drawable type of 7 mean?
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_RENDER_TYPE, &render_type);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_RED_SIZE, &red_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_GREEN_SIZE, &green_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_BLUE_SIZE, &blue_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_ALPHA_SIZE, &alpha_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DOUBLEBUFFER, &doublebuffer);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_STEREO, &stereo);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_DEPTH_SIZE, &depth_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_STENCIL_SIZE, &stencil_size);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_SAMPLES, &samples);
        GL_ENTRYPOINT(glXGetFBConfigAttrib)(pDisplay, config, GLX_SAMPLE_BUFFERS, &sample_buffers);
    }

    attribs.m_r_size = red_size;
    attribs.m_g_size = green_size;
    attribs.m_b_size = blue_size;
    attribs.m_a_size = alpha_size;
    attribs.m_depth_size = depth_size;
    attribs.m_stencil_size = stencil_size;
    attribs.m_samples = samples;
    attribs.m_double_buffered = (doublebuffer != 0);

    GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_WIDTH, &attribs.m_width);
    GL_ENTRYPOINT(glXQueryDrawable)(pDisplay, pDrawable, GLX_HEIGHT, &attribs.m_height);

    return true;
}
Exemplo n.º 11
0
bool vogl_query_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(context_info);

    if (!m_is_valid)
        return false;

    bool created_handle = false;

    if (!handle)
    {
        GLuint handle32 = 0;
        GL_ENTRYPOINT(glGenQueries)(1, &handle32);
        if ((vogl_check_gl_error()) || (!handle32))
            return false;
        handle = handle32;

        remapper.declare_handle(VOGL_NAMESPACE_QUERIES, m_snapshot_handle, handle, m_target);
        VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_QUERIES, m_snapshot_handle) == handle);

        created_handle = true;
    }

    // m_target will be GL_NONE if the query has been genned but not begun up to this point.
    if ((m_target != GL_NONE) && (m_has_been_begun))
    {
        GLuint prev_query = 0;
        GL_ENTRYPOINT(glGetQueryiv)(m_target, GL_CURRENT_QUERY, reinterpret_cast<GLint *>(&prev_query));
        VOGL_CHECK_GL_ERROR;

        VOGL_ASSERT(handle <= cUINT32_MAX);

        // Begin end the restore query, so it becomes a valid name.
        GL_ENTRYPOINT(glBeginQuery)(m_target, static_cast<GLuint>(handle));
        if (vogl_check_gl_error())
            goto handle_error;

        GL_ENTRYPOINT(glEndQuery)(m_target);
        if (vogl_check_gl_error())
            goto handle_error;

        if (prev_query)
        {
            // Now begin/end the original query so it's active again. The query API sucks.
            GL_ENTRYPOINT(glBeginQuery)(m_target, prev_query);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glEndQuery)(m_target);
            VOGL_CHECK_GL_ERROR;
        }
    }

    return true;

handle_error:
    if ((handle) && (created_handle))
    {
        remapper.delete_handle_and_object(VOGL_NAMESPACE_QUERIES, m_snapshot_handle, handle);

        //GLuint handle32 = static_cast<GLuint>(handle);
        //GL_ENTRYPOINT(glDeleteQueries)(1, &handle32);
        //VOGL_CHECK_GL_ERROR;

        handle = 0;
    }

    return false;
}
Exemplo n.º 12
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);
}
Exemplo n.º 13
0
bool vogl_replay_window::open(int width, int height, int samples)
{
    VOGL_FUNC_TRACER
    #if (VOGL_PLATFORM_HAS_GLX)

        close();

        if (!check_glx_version())
            return false;

        // TODO: These attribs (especially the sizes) should be passed in by the caller!
        int fbAttribs[64];

        int *pAttribs = fbAttribs;

        *pAttribs++ = GLX_RENDER_TYPE;      *pAttribs++ = GLX_RGBA_BIT;
        *pAttribs++ = GLX_X_RENDERABLE;     *pAttribs++ = True;
        *pAttribs++ = GLX_DRAWABLE_TYPE;    *pAttribs++ = GLX_WINDOW_BIT;
        *pAttribs++ = GLX_DOUBLEBUFFER;     *pAttribs++ = True;
        *pAttribs++ = GLX_RED_SIZE;         *pAttribs++ = 8;
        *pAttribs++ = GLX_BLUE_SIZE;        *pAttribs++ = 8;
        *pAttribs++ = GLX_GREEN_SIZE;       *pAttribs++ = 8;
        *pAttribs++ = GLX_ALPHA_SIZE;       *pAttribs++ = 8;
        *pAttribs++ = GLX_DEPTH_SIZE;       *pAttribs++ = 24;
        *pAttribs++ = GLX_STENCIL_SIZE;     *pAttribs++ = 8;

        if (samples > 1)
        {
            *pAttribs++ = GLX_SAMPLE_BUFFERS; *pAttribs++ = 1;
            *pAttribs++ = GLX_SAMPLES;        *pAttribs++ = samples;
        }

        *pAttribs++ = 0;

        // Tell X we are going to use the display
        m_dpy = XOpenDisplay(NULL);
        if (!m_dpy)
        {
            console::error("%s: XOpenDisplay() failed!\n", VOGL_FUNCTION_INFO_CSTR);
            return false;
        }

        // Get a new fb config that meets our attrib requirements

        m_pFB_configs = GL_ENTRYPOINT(glXChooseFBConfig)(m_dpy, DefaultScreen(m_dpy), fbAttribs, &m_num_fb_configs);
        if ((!m_pFB_configs) || (!m_num_fb_configs))
        {
            console::error("%s: glXChooseFBConfig() failed!\n", VOGL_FUNCTION_INFO_CSTR);
            return false;
        }

        XVisualInfo *pVisual_info = GL_ENTRYPOINT(glXGetVisualFromFBConfig)(m_dpy, m_pFB_configs[0]);
        if (!pVisual_info)
        {
            console::error("%s: glXGetVisualFromFBConfig() failed!\n", VOGL_FUNCTION_INFO_CSTR);
            return false;
        }

        // Now create an X window
        XSetWindowAttributes winAttribs;
        winAttribs.event_mask = ExposureMask | VisibilityChangeMask |
                                KeyPressMask | PointerMotionMask |
                                StructureNotifyMask;

        winAttribs.border_pixel = 0;
        winAttribs.bit_gravity = StaticGravity;
        winAttribs.colormap = XCreateColormap(m_dpy,
                                              RootWindow(m_dpy, pVisual_info->screen),
                                              pVisual_info->visual, AllocNone);
        GLint winmask = CWBorderPixel | CWBitGravity | CWEventMask | CWColormap;

        m_win = XCreateWindow(m_dpy, DefaultRootWindow(m_dpy), 20, 20,
                              width, height, 0,
                              pVisual_info->depth, InputOutput,
                              pVisual_info->visual, winmask, &winAttribs);

        const char *pWindow_name = (sizeof(void *) == sizeof(uint32)) ? "voglreplay 32-bit" : "voglreplay 64-bit";
        XStoreName(m_dpy, m_win, pWindow_name);
        XSetIconName(m_dpy, m_win, pWindow_name);

        XSizeHints sh;
        utils::zero_object(sh);
        sh.x = 0; // slam position up so when/if we resize the window glReadPixels still works as expected (this may be a bug in the NV driver, I dunno yet)
        sh.y = 0;
        sh.width = sh.min_width = sh.max_width = sh.base_width = width;
        sh.height = sh.min_height = sh.max_height = sh.base_height = height;
        sh.flags = PSize | PMinSize | PMaxSize | PBaseSize | PPosition;
        XSetWMNormalHints(m_dpy, m_win, &sh);

        XResizeWindow(m_dpy, m_win, width, height);

        XMapWindow(m_dpy, m_win);

        //glXWaitX();

        m_width = width;
        m_height = height;

        uint actual_width = 0, actual_height = 0;
        vogl_replay_window::get_actual_dimensions(actual_width, actual_height);
        vogl_debug_printf("%s: Created window, requested dimensions %ux%u, actual dimensions %ux%u\n", VOGL_FUNCTION_INFO_CSTR, m_width, m_height, actual_width, actual_height);

        return true;
    #else
        VOGL_ASSERT(!"impl");
        return false;
    #endif
}
bool vogl_default_framebuffer_state::restore(const vogl_context_info &context_info, bool restore_front_buffer) const
{
    VOGL_NOTE_UNUSED(context_info);

    if (!m_valid)
        return false;

    // TODO: Test multisampled default framebuffers
    // TODO: Check to ensure the stored fb is compatible with the current framebuffer
    const GLenum tex_target = (m_fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;

    vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);

    vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);

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

    for (uint i = 0; i < cDefFramebufferTotal; i++)
    {
        if ((!restore_front_buffer) && ((i == cDefFramebufferFrontLeft) || (i == cDefFramebufferFrontRight)))
            continue;

        if (!m_textures[i].is_valid())
            continue;

        GL_ENTRYPOINT(glDrawBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : g_def_framebuffer_enums[i]);
        if (vogl_check_gl_error_internal(true))
            continue;

        GLuint64 tex_handle64 = 0;

        vogl_handle_remapper def_handle_remapper;
        if (!m_textures[i].restore(context_info, def_handle_remapper, tex_handle64))
        {
            vogl_error_printf("%s: Failed restoring texture %u\n", VOGL_METHOD_NAME, i);
            continue;
        }

        GLuint tex_handle = static_cast<GLuint>(tex_handle64);

        // Create FBO
        GLuint fbo_handle = 0;
        GL_ENTRYPOINT(glGenFramebuffers)(1, &fbo_handle);
        VOGL_CHECK_GL_ERROR;

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

        GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glReadBuffer)((i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0);
        VOGL_CHECK_GL_ERROR;

        GLenum cur_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
        VOGL_CHECK_GL_ERROR;

        bool status = true;

        if (cur_status == GL_FRAMEBUFFER_COMPLETE)
        {
            GL_ENTRYPOINT(glBlitFramebuffer)(
                0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height,
                0, 0, m_fb_attribs.m_width, m_fb_attribs.m_height,
                (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT,
                GL_NEAREST);

            if (vogl_check_gl_error_internal())
            {
                status = false;
            }
        }

        if (!status)
        {
            vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i);
        }

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

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

        GL_ENTRYPOINT(glReadBuffer)(GL_FRONT_LEFT);
        VOGL_CHECK_GL_ERROR;

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

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

    return true;
}
Exemplo n.º 15
0
// Multiple sources, one multisampled destination. Caller creates destination.
bool vogl_msaa_texture_splitter::combine(GLuint src_texture, uint32_t dest_sample_index, GLenum dest_target, GLuint dest_texture)
{
    if (!m_valid)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    m_write_color_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
    m_write_color_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
    m_write_depth_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));
    m_write_depth_array_program.set_uniform("sample_mask", static_cast<int>(1U << dest_sample_index));

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

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

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

    const int mip_level = 0;

    GLenum internal_fmt = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(src_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));

    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))
        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;

    // This method disables sRGB reads and writes (we can do this because the source is non-multisampled and the dest is a multisampled render target.)
    GLint orig_srgb_decode = 0;
    if (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
    {
        GL_ENTRYPOINT(glGetTexParameteriv)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, &orig_srgb_decode);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
        VOGL_CHECK_GL_ERROR;
    }

    for (int layer = 0; layer < mip_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_MULTISAMPLE_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)
        {
            // Render quad to FBO
            GL_ENTRYPOINT(glViewport)(0, 0, mip_width, mip_height);
            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_ARRAY) ? m_write_color_array_program.get_handle() : m_write_color_program.get_handle());
                VOGL_CHECK_GL_ERROR;
            }
            else
            {
                GL_ENTRYPOINT(glUseProgram)((src_target == GL_TEXTURE_2D_ARRAY) ? m_write_depth_array_program.get_handle() : m_write_depth_program.get_handle());
                VOGL_CHECK_GL_ERROR;
            }

            GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
            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

    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 (m_context_info.supports_extension("GL_EXT_texture_sRGB_decode"))
    {
        GL_ENTRYPOINT(glTexParameteri)(src_target, GL_TEXTURE_SRGB_DECODE_EXT, orig_srgb_decode);
        VOGL_CHECK_GL_ERROR;
    }

    return false;
}
Exemplo n.º 16
0
void vogl_msaa_texture_splitter::deinit()
{
    if (!m_work_context)
        return;

    // We're switching contexts so serialize here (not sure if this is necessary, best to be safe).
    GL_ENTRYPOINT(glFinish)();
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindVertexArray)(0);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glUseProgram)(0);
    VOGL_CHECK_GL_ERROR;

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

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

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

    GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, 0);
    VOGL_CHECK_GL_ERROR;

    if (m_vao_handle)
    {
        GL_ENTRYPOINT(glDeleteVertexArrays)(1, &m_vao_handle);
        VOGL_CHECK_GL_ERROR;

        m_vao_handle = 0;
    }

    if (m_vertex_buffer)
    {
        GL_ENTRYPOINT(glDeleteBuffers)(1, &m_vertex_buffer);
        VOGL_CHECK_GL_ERROR;

        m_vertex_buffer = 0;
    }

    m_read_color_program.deinit();
    m_read_color_array_program.deinit();
    m_read_depth_program.deinit();
    m_read_depth_array_program.deinit();

    m_write_color_program.deinit();
    m_write_color_array_program.deinit();
    m_write_depth_program.deinit();
    m_write_depth_array_program.deinit();

    m_const_color_program.deinit();

    m_write_stencil_program.deinit();
    m_write_stencil_array_program.deinit();

    vogl_make_current(m_cur_display, m_cur_drawable, m_orig_context);

    vogl_destroy_context(m_cur_display, m_work_context);
    m_work_context = 0;

    m_orig_context = 0;
    m_cur_display = 0;
    m_cur_fb_config = 0;
    m_cur_drawable = 0;

    m_valid = false;
}
Exemplo n.º 17
0
// Copies MSAA color samples from an MSAA 2D to 2D_ARRAY texture to the stencil buffer of a MSAA 2D or 2D_ARRAY depth/stencil texture.
// Source is NOT multisampled, dest is multisampled.
bool vogl_msaa_texture_splitter::copy_color_sample_to_stencil(
        GLuint src_texture, uint32_t dest_sample_index, GLenum dest_target, GLuint dest_texture)
{
    bool exit_status = false;

    if (!m_valid)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    if ((dest_target != GL_TEXTURE_2D_MULTISAMPLE) && (dest_target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

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

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

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

    const int mip_level = 0;

    GLenum internal_fmt = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));

    int width = 0, height = 0, depth = 0, samples = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_WIDTH, &width);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_HEIGHT, &height);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_DEPTH, &depth);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(dest_target, mip_level, GL_TEXTURE_SAMPLES, &samples);

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

    if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (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;

    if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil])
        return false;

    GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT;
    if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
        fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;

    vogl_simple_gl_program &program = (dest_target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ? m_write_stencil_array_program : m_write_stencil_program;
    GL_ENTRYPOINT(glUseProgram)(program.get_handle());
    VOGL_CHECK_GL_ERROR;

    program.set_uniform("sample_mask", static_cast<int>(1 << dest_sample_index));

    GL_ENTRYPOINT(glColorMask)(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glStencilMask)(255);
    VOGL_CHECK_GL_ERROR;

    for (int layer = 0; layer < 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_MULTISAMPLE_ARRAY)
        {
            GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_texture, mip_level, layer);
            VOGL_CHECK_GL_ERROR;
        }
        else
        {
            GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, dest_target, dest_texture, mip_level);
            VOGL_CHECK_GL_ERROR;
        }

        GLenum draw_bufs[1] = { GL_NONE };
        GL_ENTRYPOINT(glDrawBuffers)(1, draw_bufs);
        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)
        {
            // Render quad to FBO
            GL_ENTRYPOINT(glViewport)(0, 0, width, height);
            VOGL_CHECK_GL_ERROR;

            if (!dest_sample_index)
            {
                GL_ENTRYPOINT(glClearStencil)(0);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glClear)(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] *= width;
                quad_tri_verts[i].m_uv0[1] *= 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;

            GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE);
            VOGL_CHECK_GL_ERROR;

            for (uint32_t stencil_val = 0; stencil_val <= 255; stencil_val++)
            {
                program.set_uniform("stencil_comp_val", stencil_val / 255.0f);

                GL_ENTRYPOINT(glStencilFunc)(GL_ALWAYS, stencil_val, 0xFF);
                VOGL_CHECK_GL_ERROR;

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

            } // stencil_val

            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

    exit_status = true;

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

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

    GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glStencilMask)(0);
    VOGL_CHECK_GL_ERROR;

    return exit_status;
}
Exemplo n.º 18
0
bool vogl_matrix_state::save_matrix_stack(const vogl_context_info &context_info, GLenum matrix, uint32_t index, GLenum depth_get, GLenum matrix_get)
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(context_info);

    GL_ENTRYPOINT(glMatrixMode)(matrix);
    if (vogl_check_gl_error())
        return false;

    GLint depth = 0;
    GL_ENTRYPOINT(glGetIntegerv)(depth_get, &depth);
    if (vogl_check_gl_error())
    {
        // This *should* work on AMD because it supports the ARB_imaging subset on compat contexts, and it supports the GL_COLOR matrix and the max stack depth is reported as 10.
        if (depth_get == GL_COLOR_MATRIX_STACK_DEPTH)
        {
            vogl_warning_printf("Using GL_COLOR_MATRIX_STACK_DEPTH workaround for AMD drivers - this will purposely force a stack underflow!\n");

            vogl::vector<matrix44D> matrices;
            for (;;)
            {
                matrix44D mat;
                GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr());
                if (vogl_check_gl_error())
                    return false;

                matrices.push_back(mat);

                GL_ENTRYPOINT(glPopMatrix)();
                bool failed_popping = vogl_check_gl_error();

                GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr());
                // AMD fails with a stack underflow on the get, not the pop - at least during tracing?
                if (vogl_check_gl_error())
                    failed_popping = true;

                if (failed_popping)
                    break;
            }

            for (int i = matrices.size() - 1; i >= 0; i--)
            {
                if (i != static_cast<int>(matrices.size()) - 1)
                {
                    GL_ENTRYPOINT(glPushMatrix)();
                    if (vogl_check_gl_error())
                        return false;
                }

                GL_ENTRYPOINT(glLoadMatrixd)(matrices[i].get_ptr());
                if (vogl_check_gl_error())
                    return false;
            }

            depth = matrices.size();
        }
        else
        {
            return false;
        }
    }

    if (depth < 1)
        return false;

    matrix_vec &vec = m_matrices[matrix_key(matrix, index)];
    vec.resize(depth);

    // deepest .. current
    // 0       1   2

    for (int i = 0; i < depth; i++)
    {
        matrix44D mat;
        GL_ENTRYPOINT(glGetDoublev)(matrix_get, mat.get_ptr());
        if (vogl_check_gl_error())
            return false;

        vec[depth - 1 - i] = mat;

        if (i != (depth - 1))
        {
            GL_ENTRYPOINT(glPopMatrix)();
            if (vogl_check_gl_error())
                return false;
        }
    }

    for (int i = 1; i < depth; i++)
    {
        GL_ENTRYPOINT(glPushMatrix)();
        if (vogl_check_gl_error())
            return false;

        GL_ENTRYPOINT(glLoadMatrixd)(vec[i].get_ptr());
        if (vogl_check_gl_error())
            return false;
    }

    return true;
}
Exemplo n.º 19
0
bool vogl_msaa_texture_splitter::init()
{
    deinit();

    // Create work context
    m_orig_context = vogl_get_current_context();
    m_cur_display = vogl_get_current_display();
    m_cur_fb_config = vogl_get_current_fb_config();
    m_cur_drawable = vogl_get_current_drawable();

    vogl_context_desc context_desc;
    m_work_context = vogl_create_context(m_cur_display, m_cur_fb_config, m_orig_context, 3, 2, eCHCDebugContextFlag | cCHCCoreProfileFlag, &context_desc);
    if (!m_work_context)
    {
        vogl_error_printf("Failed creating temporary context!\n");
        return false;
    }

    vogl_make_current(m_cur_display, m_cur_drawable, m_work_context);

    vogl_enable_generic_context_debug_messages();

    m_context_info.init(context_desc);

    GL_ENTRYPOINT(glGenVertexArrays)(1, &m_vao_handle);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindVertexArray)(m_vao_handle);
    VOGL_CHECK_GL_ERROR;

    // Create programs

    // Reading from MSAA
    if (!m_read_color_program.init(g_passthrough_vert_shader, g_read_color_frag_shader))
        return false;
    m_read_color_program.set_uniform("tex", 0);

    if (!m_read_color_array_program.init(g_passthrough_vert_shader, g_read_color_array_frag_shader))
        return false;
    m_read_color_array_program.set_uniform("tex", 0);

    if (!m_read_depth_program.init(g_passthrough_vert_shader, g_read_depth_frag_shader))
        return false;
    m_read_depth_program.set_uniform("tex", 0);

    if (!m_read_depth_array_program.init(g_passthrough_vert_shader, g_read_depth_array_frag_shader))
        return false;
    m_read_depth_array_program.set_uniform("tex", 0);

    // Writing to MSAA
    if (!m_write_color_program.init(g_passthrough_vert_shader, g_write_color_frag_shader))
        return false;
    m_write_color_program.set_uniform("tex", 0);

    if (!m_write_color_array_program.init(g_passthrough_vert_shader, g_write_color_array_frag_shader))
        return false;
    m_write_color_array_program.set_uniform("tex", 0);

    if (!m_write_depth_program.init(g_passthrough_vert_shader, g_write_depth_frag_shader))
        return false;
    m_write_depth_program.set_uniform("tex", 0);

    if (!m_write_depth_array_program.init(g_passthrough_vert_shader, g_write_depth_array_frag_shader))
        return false;
    m_write_depth_array_program.set_uniform("tex", 0);

    // Copying stencil to color
    if (!m_const_color_program.init(g_passthrough_vert_shader, g_const_color_frag_shader))
        return false;

    // Copying color to stencil
    if (!m_write_stencil_program.init(g_passthrough_vert_shader, g_write_stencil_frag_shader))
        return false;
    m_write_stencil_program.set_uniform("tex", 0);

    if (!m_write_stencil_array_program.init(g_passthrough_vert_shader, g_write_stencil_array_frag_shader))
        return false;
    m_write_stencil_array_program.set_uniform("tex", 0);

    // Create vertex buffer and bind it
    GL_ENTRYPOINT(glGenBuffers)(1, &m_vertex_buffer);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindBuffer)(GL_ARRAY_BUFFER, m_vertex_buffer);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glVertexAttribPointer)(0, 4, GL_FLOAT, GL_FALSE, sizeof(vogl_quad_vertex), (const GLvoid *)(uint64_t)VOGL_OFFSETOF(vogl_quad_vertex, m_pos));
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glVertexAttribPointer)(1, 3, GL_FLOAT, GL_FALSE, sizeof(vogl_quad_vertex), (const GLvoid *)(uint64_t)VOGL_OFFSETOF(vogl_quad_vertex, m_uv0));
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glEnableVertexAttribArray)(0);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glEnableVertexAttribArray)(1);
    VOGL_CHECK_GL_ERROR;

    vogl_reset_pixel_store_states();

    // Set state (some of this is probably not necessary)
    GL_ENTRYPOINT(glDisable)(GL_BLEND);
    GL_ENTRYPOINT(glDisable)(GL_CULL_FACE);
    GL_ENTRYPOINT(glDisable)(GL_DEPTH_TEST);
    GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
    GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
    GL_ENTRYPOINT(glStencilMask)(0);
    GL_ENTRYPOINT(glActiveTexture)(GL_TEXTURE0);
    VOGL_CHECK_GL_ERROR;

    m_valid = true;

    return true;
}
Exemplo n.º 20
0
bool vogl_renderbuffer_state::snapshot(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 handle, GLenum target)
{
    VOGL_FUNC_TRACER

    VOGL_NOTE_UNUSED(remapper);
    VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);
    VOGL_CHECK_GL_ERROR;
    VOGL_NOTE_UNUSED(target);

    clear();

    VOGL_ASSERT(handle <= cUINT32_MAX);

    m_snapshot_handle = static_cast<GLuint>(handle);

    vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);

    GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, m_snapshot_handle);
    VOGL_CHECK_GL_ERROR;

    if (!m_desc.snapshot(context_info))
        return false;

    if ((!m_desc.m_width) || (!m_desc.m_height) || (!m_desc.m_internal_format))
    {
        // Renderbuffer was only genned - no need to spit out warning
        //vogl_warning_printf("%s: Unable to retrieve description renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
    }
    else
    {
        vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);
        vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);

        const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;

        bool capture_status = false;

        GLenum internal_fmt = m_desc.m_internal_format;
        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))
        {
            // Create texture
            GLuint tex_handle = 0;
            GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
            VOGL_CHECK_GL_ERROR;

            if (m_desc.m_samples > 1)
            {
                GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
                    m_desc.m_samples,
                    internal_fmt,
                    m_desc.m_width,
                    m_desc.m_height,
                    GL_TRUE);
            }
            else
            {
                GL_ENTRYPOINT(glTexImage2D)(tex_target,
                    0,
                    internal_fmt,
                    m_desc.m_width,
                    m_desc.m_height,
                    0,
                    pInternal_tex_fmt->m_optimum_get_image_fmt,
                    pInternal_tex_fmt->m_optimum_get_image_type,
                    NULL);
            }

            if (!vogl_check_gl_error_internal())
            {
                GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
                VOGL_CHECK_GL_ERROR;

                GLenum attachment = GL_COLOR_ATTACHMENT0;
                GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
                GLenum blit_type = GL_COLOR_BUFFER_BIT;

                if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
                {
                    attachment = GL_DEPTH_STENCIL_ATTACHMENT;
                    draw_and_read_buf = GL_NONE;
                    blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
                }
                else if (m_desc.m_depth_size)
                {
                    attachment = GL_DEPTH_ATTACHMENT;
                    draw_and_read_buf = GL_NONE;
                    blit_type = GL_DEPTH_BUFFER_BIT;
                }
                else if (m_desc.m_stencil_size)
                {
                    attachment = GL_STENCIL_ATTACHMENT;
                    draw_and_read_buf = GL_NONE;
                    blit_type = GL_STENCIL_BUFFER_BIT;
                }

                GLuint src_fbo_handle = 0, dst_fbo_handle = 0;

                // Source FBO
                GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_READ_FRAMEBUFFER, attachment, GL_RENDERBUFFER, m_snapshot_handle);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
                VOGL_CHECK_GL_ERROR;

                // Dest FBO
                GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
                VOGL_CHECK_GL_ERROR;

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

                GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
                VOGL_CHECK_GL_ERROR;

                GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
                VOGL_CHECK_GL_ERROR;

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

                if ((read_status == GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
                {
                    GL_ENTRYPOINT(glBlitFramebuffer)(
                        0, 0, m_desc.m_width, m_desc.m_height,
                        0, 0, m_desc.m_width, m_desc.m_height,
                        blit_type,
                        GL_NEAREST);

                    if (!vogl_check_gl_error_internal())
                    {
                        vogl_handle_remapper def_handle_remapper;
                        if (m_texture.snapshot(context_info, def_handle_remapper, tex_handle, tex_target))
                            capture_status = true;
                    }
                }

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

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

                GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glDeleteFramebuffers)(1, &src_fbo_handle);
                VOGL_CHECK_GL_ERROR;
            }

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

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

        if (!capture_status)
        {
            vogl_error_printf("%s: Failed blitting renderbuffer data to texture for renderbuffer %" PRIu64 "\n", VOGL_METHOD_NAME, static_cast<uint64_t>(handle));
        }
    }

    m_is_valid = true;

    return true;
}
Exemplo n.º 21
0
// 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;
}
Exemplo n.º 22
0
bool vogl_renderbuffer_state::restore(const vogl_context_info &context_info, vogl_handle_remapper &remapper, GLuint64 &handle) const
{
    VOGL_FUNC_TRACER

    VOGL_ASSERT(context_info.get_version() >= VOGL_GL_VERSION_3_0);

    if (!m_is_valid)
        return false;

    vogl_scoped_binding_state orig_renderbuffer(GL_RENDERBUFFER);

    bool created_handle = false;

    if (!handle)
    {
        GLuint handle32 = 0;
        GL_ENTRYPOINT(glGenRenderbuffers)(1, &handle32);
        if ((vogl_check_gl_error()) || (!handle32))
            return false;
        handle = handle32;

        remapper.declare_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle, GL_NONE);
        VOGL_ASSERT(remapper.remap_handle(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle) == handle);

        created_handle = true;
    }

    GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, static_cast<GLuint>(handle));
    if (vogl_check_gl_error())
        goto handle_error;

    if ((m_desc.m_width) && (m_desc.m_height) && (m_desc.m_internal_format))
    {
        if (!m_desc.restore(context_info))
            goto handle_error;

        if (m_texture.is_valid())
        {
            GLenum attachment = GL_COLOR_ATTACHMENT0;
            GLenum draw_and_read_buf = GL_COLOR_ATTACHMENT0;
            GLenum blit_type = GL_COLOR_BUFFER_BIT;

            if ((m_desc.m_depth_size) && (m_desc.m_stencil_size))
            {
                attachment = GL_DEPTH_STENCIL_ATTACHMENT;
                draw_and_read_buf = GL_NONE;
                blit_type = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
            }
            else if (m_desc.m_depth_size)
            {
                attachment = GL_DEPTH_ATTACHMENT;
                draw_and_read_buf = GL_NONE;
                blit_type = GL_DEPTH_BUFFER_BIT;
            }
            else if (m_desc.m_stencil_size)
            {
                attachment = GL_STENCIL_ATTACHMENT;
                draw_and_read_buf = GL_NONE;
                blit_type = GL_STENCIL_BUFFER_BIT;
            }

            bool restore_status = false;

            GLuint64 tex_handle64 = 0;
            vogl_handle_remapper def_handle_remapper;
            if (m_texture.restore(context_info, def_handle_remapper, tex_handle64))
            {
                GLuint tex_handle = static_cast<GLuint>(tex_handle64);

                const GLenum tex_target = (m_desc.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;

                GLuint src_fbo_handle = 0, dst_fbo_handle = 0;

                // Source FBO
                GL_ENTRYPOINT(glGenFramebuffers)(1, &src_fbo_handle);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, src_fbo_handle);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glFramebufferTexture2D)(GL_READ_FRAMEBUFFER, attachment, tex_target, tex_handle, 0);
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glReadBuffer)(draw_and_read_buf);
                VOGL_CHECK_GL_ERROR;

                // Dest FBO
                GL_ENTRYPOINT(glGenFramebuffers)(1, &dst_fbo_handle);
                VOGL_CHECK_GL_ERROR;

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

                GL_ENTRYPOINT(glFramebufferRenderbuffer)(GL_DRAW_FRAMEBUFFER, attachment, GL_RENDERBUFFER, static_cast<GLuint>(handle));
                VOGL_CHECK_GL_ERROR;

                GL_ENTRYPOINT(glDrawBuffers)(1, &draw_and_read_buf);
                VOGL_CHECK_GL_ERROR;

                GLenum read_status = GL_ENTRYPOINT(glCheckFramebufferStatus)(GL_READ_FRAMEBUFFER);
                VOGL_CHECK_GL_ERROR;

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

                if ((read_status = GL_FRAMEBUFFER_COMPLETE) && (draw_status == GL_FRAMEBUFFER_COMPLETE))
                {
    #if 0
                    // HACK HACK HACK
                    if (m_texture.get_num_samples() > 1)
                    {
                        uint base_level = m_texture.get_params().get_value<GLenum>(GL_TEXTURE_BASE_LEVEL);

                        if (base_level < m_texture.get_num_levels())
                        {
                            const vogl_state_vector &state_vec = m_texture.get_level_params(0, base_level);

                            uint clear_mask = 0;
                            if (state_vec.get_value<GLenum>(GL_TEXTURE_DEPTH_SIZE))
                            {
                                clear_mask |= GL_DEPTH_BUFFER_BIT;
                            }
                            if (state_vec.get_value<GLenum>(GL_TEXTURE_STENCIL_SIZE))
                            {
                                clear_mask |= GL_STENCIL_BUFFER_BIT;
                            }
                            if (state_vec.get_value<GLenum>(GL_TEXTURE_RED_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_GREEN_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_BLUE_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_ALPHA_SIZE) +
                                state_vec.get_value<GLenum>(GL_TEXTURE_INTENSITY_SIZE) + state_vec.get_value<GLenum>(GL_TEXTURE_LUMINANCE_SIZE))
                            {
                                clear_mask |= GL_COLOR_BUFFER_BIT;
                            }

                            GL_ENTRYPOINT(glClearColor)(1.0f, 0.0f, 1.0f, 1.0f);
                            GL_ENTRYPOINT(glClearDepth)(.5f);
                            GL_ENTRYPOINT(glClearStencil)(128);
                            GL_ENTRYPOINT(glClear)(clear_mask);

                            VOGL_CHECK_GL_ERROR;
                        }
                    }
                    else
    #endif
                    {
                        GL_ENTRYPOINT(glBlitFramebuffer)(
                            0, 0, m_desc.m_width, m_desc.m_height,
                            0, 0, m_desc.m_width, m_desc.m_height,
                            blit_type,
                            GL_NEAREST);

                        if (!vogl_check_gl_error_internal())
                        {
                            restore_status = true;
                        }
                    }
                }

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

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

                GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
                VOGL_CHECK_GL_ERROR;

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

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

            if (!restore_status)
            {
                vogl_error_printf("%s: Failed restoring contents of renderbuffer %u\n", VOGL_METHOD_NAME, static_cast<GLuint>(handle));
            }
        }
    }

    return true;

handle_error:
    if (created_handle)
    {
        GL_ENTRYPOINT(glBindRenderbuffer)(GL_RENDERBUFFER, 0);
        VOGL_CHECK_GL_ERROR;

        remapper.delete_handle_and_object(VOGL_NAMESPACE_RENDER_BUFFERS, m_snapshot_handle, handle);

        //GLuint handle32 = static_cast<GLuint>(handle);
        //GL_ENTRYPOINT(glDeleteRenderbuffers)(1, &handle32);
        //VOGL_CHECK_GL_ERROR;

        handle = 0;
    }

    return false;
}
Exemplo n.º 23
0
bool vogl_msaa_texture_splitter::copy_stencil_samples_to_color(GLenum target, GLuint src_texture, GLuint &dest_texture)
{
    dest_texture = 0;

    if (!m_valid)
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

    if ((target != GL_TEXTURE_2D_MULTISAMPLE) && (target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY))
    {
        VOGL_ASSERT_ALWAYS;
        return false;
    }

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

    const int mip_level = 0;

    GLenum internal_fmt = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_INTERNAL_FORMAT, reinterpret_cast<GLint *>(&internal_fmt));

    int width = 0, height = 0, depth = 0, samples = 0;
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_WIDTH, &width);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_HEIGHT, &height);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_DEPTH, &depth);
    GL_ENTRYPOINT(glGetTexLevelParameteriv)(target, mip_level, GL_TEXTURE_SAMPLES, &samples);

    if ((vogl_check_gl_error()) || (width < 1) || (height < 1) || (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;

    if (!pInternal_tex_fmt->m_comp_sizes[cTCStencil])
        return false;

    GLenum fbo_attachment_target = GL_STENCIL_ATTACHMENT;
    if (pInternal_tex_fmt->m_comp_sizes[cTCDepth])
        fbo_attachment_target = GL_DEPTH_STENCIL_ATTACHMENT;

    GL_ENTRYPOINT(glGenTextures)(1, &dest_texture);
    VOGL_CHECK_GL_ERROR;

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

    const GLenum dest_internal_fmt = GL_RGBA;
    const GLboolean fixed_sample_locations = GL_TRUE;

    if (target == GL_TEXTURE_2D_MULTISAMPLE)
    {
        GL_ENTRYPOINT(glTexImage2DMultisample)(target, samples, dest_internal_fmt, width, height, fixed_sample_locations);
        VOGL_CHECK_GL_ERROR;
    }
    else
    {
        GL_ENTRYPOINT(glTexImage3DMultisample)(target, samples, dest_internal_fmt, width, height, depth, fixed_sample_locations);
        VOGL_CHECK_GL_ERROR;
    }

    GL_ENTRYPOINT(glUseProgram)(m_const_color_program.get_handle());
    VOGL_CHECK_GL_ERROR;

    for (int layer = 0; layer < depth; layer++)
    {
        GLuint temp_fbo = 0;
        GL_ENTRYPOINT(glGenFramebuffers)(1, &temp_fbo);
        VOGL_CHECK_GL_ERROR;

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

        if (target == GL_TEXTURE_2D_MULTISAMPLE)
        {
            GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, dest_texture, mip_level);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, target, src_texture, mip_level);
            VOGL_CHECK_GL_ERROR;
        }
        else
        {
            GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_texture, mip_level, layer);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glFramebufferTextureLayer)(GL_DRAW_FRAMEBUFFER, fbo_attachment_target, src_texture, mip_level, layer);
            VOGL_CHECK_GL_ERROR;
        }

        GLenum draw_buf = GL_COLOR_ATTACHMENT0;
        GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
        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)
        {
            GL_ENTRYPOINT(glDisable)(GL_FRAMEBUFFER_SRGB);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glViewport)(0, 0, width, height);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glClearColor)(0, 0, 0, 0);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glClear)(GL_COLOR_BUFFER_BIT);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glColorMask)(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glEnable)(GL_DEPTH_TEST);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDepthMask)(GL_FALSE);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glDepthFunc)(GL_ALWAYS);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glEnable)(GL_STENCIL_TEST);
            VOGL_CHECK_GL_ERROR;

            GL_ENTRYPOINT(glStencilOp)(GL_KEEP, GL_KEEP, GL_REPLACE);
            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] *= width;
                quad_tri_verts[i].m_uv0[1] *= 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;

            for (uint32_t stencil_val = 0; stencil_val <= 255; stencil_val++)
            {
                m_const_color_program.set_uniform("color", vec4F(stencil_val * (1.0f / 255.0f)));

                GL_ENTRYPOINT(glStencilFunc)(GL_EQUAL, stencil_val, 0xFF);
                VOGL_CHECK_GL_ERROR;

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

            } // stencil_val

            status = true;
        } // fbo_status

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

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

        temp_fbo = 0;

        if (!status)
            goto failure;

    } // layer

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

    GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
    VOGL_CHECK_GL_ERROR;
    return true;

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

    if (dest_texture)
    {
        GL_ENTRYPOINT(glDeleteTextures)(1, &dest_texture);
        VOGL_CHECK_GL_ERROR;

        dest_texture = 0;
    }

    GL_ENTRYPOINT(glDisable)(GL_STENCIL_TEST);
    VOGL_CHECK_GL_ERROR;

    return false;
}
bool vogl_default_framebuffer_state::snapshot(const vogl_context_info &context_info, const vogl_default_framebuffer_attribs &fb_attribs)
{
    VOGL_NOTE_UNUSED(context_info);

    clear();

    m_fb_attribs = fb_attribs;

    // Create compatible GL texture
    // Attach this texture to an FBO
    // Blit default framebuffer to this FBO
    // Capture this texture's state

    vogl_scoped_state_saver framebuffer_state_saver(cGSTReadBuffer, cGSTDrawBuffer);

    vogl_scoped_binding_state orig_framebuffers(GL_DRAW_FRAMEBUFFER, GL_READ_FRAMEBUFFER, GL_TEXTURE_2D, GL_TEXTURE_2D_MULTISAMPLE);

    GL_ENTRYPOINT(glBindFramebuffer)(GL_READ_FRAMEBUFFER, 0);
    VOGL_CHECK_GL_ERROR;

    vogl_scoped_binding_state orig_bindings(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER);

    GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_PACK_BUFFER, 0);
    VOGL_CHECK_GL_ERROR;

    GL_ENTRYPOINT(glBindBuffer)(GL_PIXEL_UNPACK_BUFFER, 0);
    VOGL_CHECK_GL_ERROR;

    vogl_scoped_state_saver pixelstore_state_saver(cGSTPixelStore);

    vogl_scoped_state_saver pixeltransfer_state_saver;
    if (!context_info.is_core_profile())
        pixeltransfer_state_saver.save(cGSTPixelTransfer);

    vogl_reset_pixel_store_states();
    if (!context_info.is_core_profile())
        vogl_reset_pixel_transfer_states();

    // TODO: Test multisampled default framebuffers
    const GLenum tex_target = (fb_attribs.m_samples > 1) ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;

    for (uint i = 0; i < cDefFramebufferTotal; i++)
    {
        GLenum internal_fmt, pixel_fmt, pixel_type;

        // TODO: This uses fixed pixel formats, and assumes there's always a depth/stencil buffer.
        if (i == cDefFramebufferDepthStencil)
        {
            if ((fb_attribs.m_depth_size + fb_attribs.m_stencil_size) == 0)
                continue;

            GL_ENTRYPOINT(glReadBuffer)(fb_attribs.m_double_buffered ? GL_BACK_LEFT : GL_FRONT_LEFT);

            internal_fmt = GL_DEPTH_STENCIL;
            pixel_fmt = GL_DEPTH_STENCIL;
            pixel_type = GL_UNSIGNED_INT_24_8;
        }
        else
        {
            if ((fb_attribs.m_r_size + fb_attribs.m_g_size + fb_attribs.m_b_size + fb_attribs.m_a_size) == 0)
                continue;

            GL_ENTRYPOINT(glReadBuffer)(g_def_framebuffer_enums[i]);

            internal_fmt = GL_RGBA;
            pixel_fmt = GL_RGBA;
            pixel_type = GL_UNSIGNED_INT_8_8_8_8_REV;
        }

        if (vogl_check_gl_error_internal(true))
            continue;

        // Create texture
        GLuint tex_handle = 0;
        GL_ENTRYPOINT(glGenTextures)(1, &tex_handle);
        VOGL_CHECK_GL_ERROR;

        GL_ENTRYPOINT(glBindTexture)(tex_target, tex_handle);
        VOGL_CHECK_GL_ERROR;

        if (fb_attribs.m_samples > 1)
        {
            GL_ENTRYPOINT(glTexImage2DMultisample)(tex_target,
                fb_attribs.m_samples,
                internal_fmt,
                fb_attribs.m_width,
                fb_attribs.m_height,
                GL_TRUE);
        }
        else
        {
            GL_ENTRYPOINT(glTexImage2D)(tex_target,
                0,
                internal_fmt,
                fb_attribs.m_width,
                fb_attribs.m_height,
                0,
                pixel_fmt,
                pixel_type,
                NULL);
        }

        if (vogl_check_gl_error_internal())
        {
            GL_ENTRYPOINT(glBindTexture)(tex_target, 0);
            VOGL_CHECK_GL_ERROR;

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

            continue;
        }

        GL_ENTRYPOINT(glTexParameteri)(tex_target, GL_TEXTURE_MAX_LEVEL, 0);
        VOGL_CHECK_GL_ERROR;

        // 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;

        GL_ENTRYPOINT(glFramebufferTexture2D)(GL_DRAW_FRAMEBUFFER, (i == cDefFramebufferDepthStencil) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_COLOR_ATTACHMENT0, tex_target, tex_handle, 0);
        VOGL_CHECK_GL_ERROR;

        GLenum draw_buf = (i == cDefFramebufferDepthStencil) ? GL_NONE : GL_COLOR_ATTACHMENT0;
        GL_ENTRYPOINT(glDrawBuffers)(1, &draw_buf);
        VOGL_CHECK_GL_ERROR;

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

        bool status = true;

        if (cur_status == GL_FRAMEBUFFER_COMPLETE)
        {
            GL_ENTRYPOINT(glBlitFramebuffer)(
                0, 0, fb_attribs.m_width, fb_attribs.m_height,
                0, 0, fb_attribs.m_width, fb_attribs.m_height,
                (i == cDefFramebufferDepthStencil) ? (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT) : GL_COLOR_BUFFER_BIT,
                GL_NEAREST);

            if (vogl_check_gl_error_internal())
            {
                status = false;
            }
        }

        if (status)
        {
            vogl_handle_remapper def_handle_remapper;
            status = m_textures[i].snapshot(context_info, def_handle_remapper, tex_handle, tex_target);

            if (!status)
            {
                vogl_error_printf("%s: Failed snapshotting texture for default framebuffer %s\n", VOGL_METHOD_NAME, g_gl_enums.find_gl_name(g_def_framebuffer_enums[i]));
            }
        }
        else
        {
            vogl_warning_printf("%s: Failed blitting framebuffer %u\n", VOGL_METHOD_NAME, i);
        }

        // 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;

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

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

    m_valid = true;

    return true;
}