Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
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;
}