Esempio n. 1
0
/*-------------------------------------
 * Setup a shader's attributes
-------------------------------------*/
bool ShaderProgramAssembly::setup_program_attribs(ShaderProgram& outProg) const noexcept {
    outProg.uniforms = draw::get_shader_attribs(outProg, vertex_attrib_t::UNIFORM_ATTRIB);
    outProg.vertAttribs = get_linked_shader_attribs(outProg, shader_stage_t::SHADER_STAGE_VERTEX);
    outProg.fragAttribs = get_linked_shader_attribs(outProg, shader_stage_t::SHADER_STAGE_FRAGMENT);
    // not bothering to support geometry shader attributes.

    // Shader stages all need attributes
    if (!outProg.get_vertex_attribs().get_num_attribs()) {
        LS_LOG_ERR("\tFailed to introspect the vertex shader of ", outProg.gpu_id(), ".\n");
        LS_DEBUG_ASSERT(false);
        return false;
    }

    if (!outProg.get_fragment_attribs().get_num_attribs()) {
        LS_LOG_ERR("\tFailed to introspect the fragment shader of ", outProg.gpu_id(), ".\n");
        LS_DEBUG_ASSERT(false);
        return false;
    }
    
    const GLuint shaderId = outProg.gpu_id();
    GLint totalUniformBlocks = 0;
    
    glGetProgramiv(shaderId, GL_ACTIVE_UNIFORM_BLOCKS, &totalUniformBlocks);
    LS_LOG_GL_ERR();
    
    LS_LOG_MSG("\tLocated ", totalUniformBlocks, " uniform blocks in shader ", shaderId, '.');
    outProg.uniformBlocks.reset(new(std::nothrow) ShaderBlockAttrib[totalUniformBlocks]);
    
    if (!outProg.uniformBlocks) {
        LS_LOG_ERR("\tFailed to allocate space for ", totalUniformBlocks, " uniform blocks!");
        LS_DEBUG_ASSERT(false);
        return false;
    }
    
    for (int i = 0; i < totalUniformBlocks; ++i) {
        const bool isIntrospected = outProg.uniformBlocks[i].run_block_introspection(shaderId, i);
        
        if (!isIntrospected) {
            LS_LOG_ERR("\tFailed to introspect uniform block ", i, '.');
            outProg.uniformBlocks.reset();
            LS_DEBUG_ASSERT(false);
            return false;
        }
    }
    
    outProg.numUniformBlocks = totalUniformBlocks;
    
    return true;
}
Esempio n. 2
0
/*-------------------------------------
 * Set the vertex layout locations for an unlinked shader program
-------------------------------------*/
bool ShaderProgramAssembly::assign_shader_layouts(
    const ShaderProgram& prog,
    const ShaderObject& shdr
) const noexcept {

    if (prog.get_attached_shader_id(shdr.get_shader_type()) != shdr.gpu_id()) {
        return false;
    }

    // fragment shaders in OpenGLES 3.0 can't have their location manually
    // specified as glBindFragDataLocation is unavailable. Geometry shaders on
    // desktop GL versions should not have attribs as it increases the amount
    // of required maintenance for a feature with limited support.
    if (shdr.get_shader_type() != shader_stage_t::SHADER_STAGE_VERTEX) {
        return true;
    }

    // Manually assign layout locations so OpenGL doesn't optimize out
    // perfectly valid locations of variables.
    const ShaderAttribArray& attribs = shdr.get_attribs();
    
    for (unsigned i = 0; i < attribs.get_num_attribs(); ++i) {
        const ShaderAttrib& attrib = attribs.get_attrib(i);
        glBindAttribLocation(prog.gpu_id(), attrib.get_location(), attrib.get_name().get());
        LS_LOG_GL_ERR();
    }

    return true;
}
Esempio n. 3
0
/*-------------------------------------
 * Attach shader objects to a program
-------------------------------------*/
bool ShaderProgramAssembly::assemble(ShaderProgram& outProg, bool runLinker) noexcept {
    LS_LOG_MSG("Attempting to assemble a Shader Program.");

    if (!is_assembly_valid()) {
        LS_LOG_ERR("\tFailed to assemble a Shader Program. Invalid inputs shader detected.\n");
        return false;
    }

    if (outProg.gpu_id() != 0) {
        LS_LOG_ERR("\tAttempted to assemble a preexisting program object.\n");
        return false;
    }
    else {
        const GLuint progId = glCreateProgram();

        LS_LOG_GL_ERR();

        if (progId == 0) {
            LS_LOG_ERR("\tUnable to create a handle to an OpenGL Shader Program.\n");
            return false;
        }

        outProg.gpuId = progId;
    }

    glAttachShader(outProg.gpu_id(), pVertShader->gpu_id());
    LS_LOG_GL_ERR();

    glAttachShader(outProg.gpu_id(), pFragShader->gpu_id());
    LS_LOG_GL_ERR();
    
    #ifdef LS_DRAW_BACKEND_GL
        if (pGeomShader && pGeomShader->is_valid()) {
            glAttachShader(outProg.gpu_id(), pGeomShader->gpu_id());
            LS_LOG_GL_ERR();
        }
    #endif

    // Ensure all shaders attached to the program correctly
    if (!assign_shader_layouts(outProg, *pVertShader)
    || !assign_shader_layouts(outProg, *pFragShader)
    ) {
        LS_LOG_ERR(
            "\tAn Error occurred while attaching a shader to the shader program ",
            outProg.gpu_id(), " during assembly. The shader program will be destroyed.\n"
        );
        outProg.terminate();
        return false;
    }

    LS_LOG_MSG("\tSuccessfully assembled the Shader Program ", outProg.gpu_id(), ".\n");

    if (runLinker) {
        return link(outProg);
    }

    return true;
}
Esempio n. 4
0
/*-------------------------------------
-------------------------------------*/
bool ShaderProgramAssembly::link(ShaderProgram& outProg) const noexcept {
    LS_LOG_MSG("Attempting to link the shader ", outProg.gpu_id(), '.');

    GLint linkResult = 0;

    glLinkProgram(outProg.gpu_id());
    LS_LOG_GL_ERR();

    glGetProgramiv(outProg.gpu_id(), GL_LINK_STATUS, &linkResult);
    LS_LOG_GL_ERR();

    GLint logLength = 0;

    glGetProgramiv(outProg.gpu_id(), GL_INFO_LOG_LENGTH, &logLength);
    LS_LOG_GL_ERR();

    utils::Pointer <GLchar[]> logData {new GLchar[logLength + 1]};
    logData[logLength] = '\0';

    glGetProgramInfoLog(outProg.gpu_id(), logLength, nullptr, logData.get());
    LS_LOG_GL_ERR();
    LS_LOG_MSG("\tProgram linker log:\n", logData.get(), '\n');

    if (linkResult != GL_TRUE) {
        LS_DEBUG_ASSERT(false);
        return false;
    }

    LS_LOG_MSG("\tSuccessfully linked shader ", outProg.gpu_id(), ". Now running introspection\n");
    if (!setup_program_attribs(outProg)) {
        LS_LOG_ERR("\tIntrospection of shader", outProg.gpu_id(), "failed during post-link setup.\n");
        return false;
    }

    LS_LOG_MSG(
        "\tDone. Successfully assembled and linked shader ", outProg.gpu_id(), ":",
        "\n\t\tUniforms:            ", outProg.uniforms.get_num_attribs(),
        "\n\t\tVertex Attribs:      ", outProg.vertAttribs.get_num_attribs(),
        "\n\t\tFragment Attribs:    ", outProg.fragAttribs.get_num_attribs(),
        '\n'
    );

    return true;
}