ShaderProgram.cc 7.22 KB
Newer Older
1 2 3 4 5
/***********************************************************************
 * Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
 * All rights reserved.                                                *
 * Distributed under the terms of the MIT License (see LICENSE.TXT).   *
 **********************************************************************/
Robert Menzel's avatar
Robert Menzel committed
6

Robert Menzel's avatar
Robert Menzel committed
7
#include <ACGL/OpenGL/Objects/ShaderProgram.hh>
8
#include <ACGL/OpenGL/Objects/VertexArrayObject.hh>
9
#include <ACGL/OpenGL/Objects/FrameBufferObject.hh>
Robert Menzel's avatar
Robert Menzel committed
10
#include <ACGL/OpenGL/Tools.hh>
Robert Menzel's avatar
Robert Menzel committed
11

Robert Menzel's avatar
Robert Menzel committed
12 13
using namespace ACGL::OpenGL;
using namespace ACGL::Base;
Robert Menzel's avatar
Robert Menzel committed
14 15
using namespace ACGL::Utils;

16
bool ShaderProgram::link() const
Robert Menzel's avatar
Robert Menzel committed
17
{
18 19 20
	// Clear uniform cache
	mUniformLocationCache.clear();

21
    glLinkProgram(mObjectName);
Robert Menzel's avatar
Robert Menzel committed
22

23 24
    // check for program link errors:
    GLint programError;
25
    glGetProgramiv(mObjectName, GL_LINK_STATUS, &programError);
Robert Menzel's avatar
Robert Menzel committed
26

27
    if (programError != GL_TRUE)
Robert Menzel's avatar
Robert Menzel committed
28 29
    {
        // yes, errors :-(
30 31 32 33
        error() << "Program could not get linked:" << std::endl;
    }

    GLsizei length = 0;
34
    glGetProgramiv(mObjectName, GL_INFO_LOG_LENGTH, &length);
35 36 37 38
    if (length > 1)
    {
        // error log or warnings:
        GLchar* pInfo = new char[length + 1];
39
        glGetProgramInfoLog(mObjectName,  length, &length, pInfo);
40 41 42
        warning() << "Linker log: " << std::string(pInfo) << std::endl;
        delete[] pInfo;
        return (programError == GL_TRUE); // if the log contains only warnings we return true
Robert Menzel's avatar
Robert Menzel committed
43 44 45
    }
    return true;
}
46

Robert Menzel's avatar
Robert Menzel committed
47
void ShaderProgram::setAttributeLocations(ConstSharedLocationMappings _locationMappings)
48
{
49 50
    if (!_locationMappings) return;

51 52
    bool needsRelink = false;

Robert Menzel's avatar
Robert Menzel committed
53 54
    // search through all attributes:
    LocationMappings::LocationMap locations = _locationMappings->getLocations();
55

Robert Menzel's avatar
Robert Menzel committed
56 57 58 59 60 61
    for(LocationMappings::LocationMap::iterator it = locations.begin();
        it != locations.end();
        ++it)
    {
        // find out whether a fragment data location with a matching name exists in this shader
        GLint attributeLocation = getAttributeLocation((*it).first);
62

63
        if ( attributeLocation  != -1 ) // attributeLocation with that name exists?
64
        {
65 66 67
            // NOTE: even if the attribute is currently bound correctly already, it might not have
            // been set by bindAttribLocation explititly so the linker might reassign another value
            // during relinking! So set it explititly!
Robert Menzel's avatar
Robert Menzel committed
68
            bindAttributeLocation((*it).first, (*it).second);
69 70 71 72 73 74
            needsRelink = true;
        }
    }

    // re-link the program only if necessary
    if(needsRelink)
75 76 77 78 79
    {
        link();
    }
}

80
#if (ACGL_OPENGL_VERSION >= 30)
Robert Menzel's avatar
Robert Menzel committed
81
void ShaderProgram::setFragmentDataLocations(ConstSharedLocationMappings _locationMappings)
82
{
83 84
    if (!_locationMappings) return;

85 86
    bool needsRelink = false;

Robert Menzel's avatar
Robert Menzel committed
87 88 89 90 91 92
    // search through all color attachments:
    LocationMappings::LocationMap locations = _locationMappings->getLocations();

    for(LocationMappings::LocationMap::iterator it = locations.begin();
        it != locations.end();
        ++it)
93 94
    {
        // find out whether a fragment data location with a matching name exists in this shader
Robert Menzel's avatar
Robert Menzel committed
95
        GLint fragmentDataLocation = getFragmentDataLocation((*it).first);
96

97
        if (fragmentDataLocation  != -1) // fragment data location with that name exists?
Robert Menzel's avatar
Robert Menzel committed
98 99
        {
            bindFragmentDataLocation((*it).first, (*it).second);
100 101 102 103 104 105 106
            needsRelink = true;
        }
    }

    // re-link the program only if necessary
    if(needsRelink)
    {
107
        link();
108 109
    }
}
110
#endif // (ACGL_OPENGL_VERSION >= 30)
111

112
SharedLocationMappings ShaderProgram::getAttributeLocations() const
Robert Menzel's avatar
Robert Menzel committed
113 114 115 116 117 118 119 120 121 122 123
{
    SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() );

    // query the number of _active_ attributes:
    GLint attributeCount;
    glGetProgramiv( mObjectName, GL_ACTIVE_ATTRIBUTES, &attributeCount );
    if (attributeCount == 0) return locationMap;

    // reserve a string long enought for the longest name:
    GLint longestAttributeName;
    glGetProgramiv( mObjectName, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,  &longestAttributeName );
124 125 126

    if (longestAttributeName == 0) return locationMap; // work around an old nvidia bug.

Robert Menzel's avatar
Robert Menzel committed
127 128 129 130 131 132 133 134
    char *name = new char[longestAttributeName+1];

    // get the name and location of each active attribute:
    for (int i = 0; i < attributeCount; ++i) {
        GLenum  type;
        GLint   size;
        GLsizei length;
        glGetActiveAttrib( mObjectName, i, longestAttributeName, &length, &size, &type, name );
Robert Menzel's avatar
Robert Menzel committed
135
        name[ length+1 ] = 0; // null terminate string
Robert Menzel's avatar
Robert Menzel committed
136 137 138

        GLint attribLocation = glGetAttribLocation( mObjectName, name );

139 140 141 142
        // if the attribute name starts with "gl_", i.e. is a reserved attribute name, ignore it
        if(length >= 3 && strncmp(name, "gl_", 3) == 0)
            continue;

Robert Menzel's avatar
Robert Menzel committed
143 144 145
        locationMap->setLocation( std::string(name), (GLuint) attribLocation );
    }

Robert Menzel's avatar
Robert Menzel committed
146
    delete[] name;
Robert Menzel's avatar
Robert Menzel committed
147 148 149
    return locationMap;
}

150
#if (ACGL_OPENGL_VERSION >= 30)
Robert Menzel's avatar
Robert Menzel committed
151 152 153 154 155 156 157 158
SharedLocationMappings ShaderProgram::getFragmentDataLocations()
{
    SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() );

    ACGL::Utils::error() << " ShaderProgram::getFragmentDataLocations is not implemented -> missing OpenGL API" << std::endl;

    return locationMap;
}
159
#endif //(ACGL_OPENGL_VERSION >= 30)
Robert Menzel's avatar
Robert Menzel committed
160

161
#if (ACGL_OPENGL_VERSION >= 31)
162
SharedLocationMappings ShaderProgram::getUniformOffsetsOfBlock( GLuint _blockIndex ) const
Robert Menzel's avatar
Robert Menzel committed
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
{
    SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() );

    if (_blockIndex == GL_INVALID_INDEX) return locationMap; // block does not exist

    // query the number of _active_ uniforms:
    GLint uniformCount;
    glGetProgramiv( mObjectName, GL_ACTIVE_UNIFORMS, &uniformCount );
    if (uniformCount == 0) return locationMap;

    // reserve a string long enought for the longest name:
    GLint longestUniformName;
    glGetProgramiv( mObjectName, GL_ACTIVE_UNIFORM_MAX_LENGTH,  &longestUniformName );
    char *name = new char[longestUniformName+1];

    // get the name and location of each active attribute:
    for (int i = 0; i < uniformCount; ++i) {
        GLsizei length;
        glGetActiveUniformName( mObjectName, i, longestUniformName, &length, name );

        name[ length+1 ] = 0; // null terminate string

        GLuint idx = i;
        GLint uniformBlockIndex;
        glGetActiveUniformsiv( mObjectName, 1, &idx, GL_UNIFORM_BLOCK_INDEX, &uniformBlockIndex );

        if (uniformBlockIndex != -1) {
            if ((GLuint)uniformBlockIndex == _blockIndex) {
                GLint offset;
                glGetActiveUniformsiv( mObjectName, 1, &idx, GL_UNIFORM_OFFSET, &offset );
                //ACGL::Utils::message() << "uniform " << i << " is " << name << " block: " << uniformBlockIndex << " offset: " << offset << std::endl;
                locationMap->setLocation( std::string(name), (GLuint) offset );
            }
        }
    }

    delete[] name;
    return locationMap;
}

203
GLsizeiptr ShaderProgram::getUniformBlockSize( GLuint _blockIndex ) const
Robert Menzel's avatar
Robert Menzel committed
204 205 206 207 208 209 210 211
{
    if (_blockIndex == GL_INVALID_INDEX) return 0; // block does not exist

    GLint uniformBlockSize;
    glGetActiveUniformBlockiv( mObjectName, _blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlockSize);

    return (GLsizeiptr) uniformBlockSize;
}
212
#endif // OpenGL 3.1