cocos2dx 원본 분석:shader의 생성 과정

19554 단어 cocos2d-x
cocos2dx의 shader는 GL Program에서 만듭니다. 모두 3단계입니다.정점 및 픽셀 셰이더 초기화 2.음영처리 프로그램 연결 3.uniform 변수 정보 업데이트
GLProgram* GLProgram::createWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
{
    auto ret = new (std::nothrow) GLProgram();
    /*              */
    if(ret && ret->initWithByteArrays(vShaderByteArray, fShaderByteArray, compileTimeDefines)) {
        /*      */
        ret->link();
        /*  uniform   ,      uniform*/
        ret->updateUniforms();
        ret->autorelease();
        return ret;
    }

    CC_SAFE_DELETE(ret);
    return nullptr;
}

/정점 착색기 및 픽셀 착색기 컴파일하기/
bool GLProgram::initWithByteArrays(const GLchar* vShaderByteArray, const GLchar* fShaderByteArray, const std::string& compileTimeDefines)
{
    /*      ,                           */
    _program = glCreateProgram();
    CHECK_GL_ERROR_DEBUG();

    // convert defines here. If we do it in "compileShader" we will do it it twice.
    // a cache for the defines could be useful, but seems like overkill at this point
    std::string replacedDefines = "";
    replaceDefines(compileTimeDefines, replacedDefines);

    _vertShader = _fragShader = 0;
    /*       */
    if (vShaderByteArray)
    {
        if (!compileShader(&_vertShader, GL_VERTEX_SHADER, vShaderByteArray, replacedDefines))
        {
            CCLOG("cocos2d: ERROR: Failed to compile vertex shader");
            return false;
       }
    }
    /*       */
    // Create and compile fragment shader
    if (fShaderByteArray)
    {
        if (!compileShader(&_fragShader, GL_FRAGMENT_SHADER, fShaderByteArray, replacedDefines))
        {
            CCLOG("cocos2d: ERROR: Failed to compile fragment shader");
            return false;
        }
    }
    /*        */
    if (_vertShader)
    {
        glAttachShader(_program, _vertShader);
    }
    CHECK_GL_ERROR_DEBUG();

    if (_fragShader)
    {
        glAttachShader(_program, _fragShader);
    }

    _hashForUniforms.clear();

    CHECK_GL_ERROR_DEBUG();

    return true;
}

정점 착색기와 픽셀 착색기는 모두 이 함수를 사용하여 컴파일을 완성해야 한다
bool GLProgram::compileShader(GLuint* shader, GLenum type, const GLchar* source, const std::string& convertedDefines)
{
    GLint status;
    if (!source)
    {
        return false;
    }
    /* shander       ,      ,  cocos2dx uniform     ,   shader   uniform              。
    static const char * COCOS2D_SHADER_UNIFORMS =
        "uniform mat4 CC_PMatrix;
"
"uniform mat4 CC_MVMatrix;
"
"uniform mat4 CC_MVPMatrix;
"
"uniform mat3 CC_NormalMatrix;
"
"uniform vec4 CC_Time;
"
"uniform vec4 CC_SinTime;
"
"uniform vec4 CC_CosTime;
"
"uniform vec4 CC_Random01;
"
"uniform sampler2D CC_Texture0;
"
"uniform sampler2D CC_Texture1;
"
"uniform sampler2D CC_Texture2;
"
"uniform sampler2D CC_Texture3;
"
"//CC INCLUDES END

"
; */ const GLchar *sources[] = { #if CC_TARGET_PLATFORM == CC_PLATFORM_WINRT (type == GL_VERTEX_SHADER ? "precision mediump float;
precision mediump int;
"
: "precision mediump float;
precision mediump int;
"
), #elif (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32 && CC_TARGET_PLATFORM != CC_PLATFORM_LINUX && CC_TARGET_PLATFORM != CC_PLATFORM_MAC) (type == GL_VERTEX_SHADER ? "precision highp float;
precision highp int;
"
: "precision mediump float;
precision mediump int;
"
), #endif COCOS2D_SHADER_UNIFORMS, convertedDefines.c_str(), source}; /* shader */ *shader = glCreateShader(type); glShaderSource(*shader, sizeof(sources)/sizeof(*sources), sources, nullptr); glCompileShader(*shader); /* */ glGetShaderiv(*shader, GL_COMPILE_STATUS, &status); if (! status) { /* */ GLsizei length; glGetShaderiv(*shader, GL_SHADER_SOURCE_LENGTH, &length); GLchar* src = (GLchar *)malloc(sizeof(GLchar) * length); glGetShaderSource(*shader, length, nullptr, src); CCLOG("cocos2d: ERROR: Failed to compile shader:
%s"
, src); if (type == GL_VERTEX_SHADER) { CCLOG("cocos2d: %s", getVertexShaderLog().c_str()); } else { CCLOG("cocos2d: %s", getFragmentShaderLog().c_str()); } free(src); return false;; } return (status == GL_TRUE); }

픽셀 착색기와 정점 착색기를 컴파일하여 착색 프로그램에 연결한 후 링크로 링크 완료
bool GLProgram::link()
{
    CCASSERT(_program != 0, "Cannot link invalid program");

    GLint status = GL_TRUE;
    /*  cocos2dx            */
    bindPredefinedVertexAttribs();
    /*      */
    glLinkProgram(_program);
    /*        ,                   _vertexAttribs */
    parseVertexAttribs();
    /* cocos2dx     uniform    _userUniforms */
    parseUniforms();
    /*           */
    clearShader();

#if DEBUG || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
    glGetProgramiv(_program, GL_LINK_STATUS, &status);

    if (status == GL_FALSE)
    {
        CCLOG("cocos2d: ERROR: Failed to link program: %i", _program);
        GL::deleteProgram(_program);
        _program = 0;
    }
#endif

    return (status == GL_TRUE);
}

코코스2dx의 정점 속성을 고정된 인덱스에 귀속합니다
void GLProgram::bindPredefinedVertexAttribs()
{
    /*cocos2dx       */
    static const struct {
        const char *attributeName;
        int location;
    } attribute_locations[] =
    {
        {GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION},
        {GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR},
        {GLProgram::ATTRIBUTE_NAME_TEX_COORD, GLProgram::VERTEX_ATTRIB_TEX_COORD},
        {GLProgram::ATTRIBUTE_NAME_TEX_COORD1, GLProgram::VERTEX_ATTRIB_TEX_COORD1},
        {GLProgram::ATTRIBUTE_NAME_TEX_COORD2, GLProgram::VERTEX_ATTRIB_TEX_COORD2},
        {GLProgram::ATTRIBUTE_NAME_TEX_COORD3, GLProgram::VERTEX_ATTRIB_TEX_COORD3},
        {GLProgram::ATTRIBUTE_NAME_NORMAL, GLProgram::VERTEX_ATTRIB_NORMAL},
    };

    const int size = sizeof(attribute_locations) / sizeof(attribute_locations[0]);
    /*            */
    for(int i=0; i<size;i++) {
        glBindAttribLocation(_program, attribute_locations[i].location, attribute_locations[i].attributeName);
    }
}

uniform의 위치를 기록하고 어떤 uniform을 사용했는지 기록합니다
void GLProgram::updateUniforms()
{
    /*  uniformuniform   ,        */
    _builtInUniforms[UNIFORM_AMBIENT_COLOR] = glGetUniformLocation(_program, UNIFORM_NAME_AMBIENT_COLOR);
    _builtInUniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);
    _builtInUniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);
    _builtInUniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);
    _builtInUniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_NORMAL_MATRIX);

    _builtInUniforms[UNIFORM_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_TIME);
    _builtInUniforms[UNIFORM_SIN_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_SIN_TIME);
    _builtInUniforms[UNIFORM_COS_TIME] = glGetUniformLocation(_program, UNIFORM_NAME_COS_TIME);

    _builtInUniforms[UNIFORM_RANDOM01] = glGetUniformLocation(_program, UNIFORM_NAME_RANDOM01);

    _builtInUniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);
    _builtInUniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);
    _builtInUniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);
    _builtInUniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);
    /*           uniform,         */
    _flags.usesP = _builtInUniforms[UNIFORM_P_MATRIX] != -1;
    _flags.usesMV = _builtInUniforms[UNIFORM_MV_MATRIX] != -1;
    _flags.usesMVP = _builtInUniforms[UNIFORM_MVP_MATRIX] != -1;
    _flags.usesNormal = _builtInUniforms[UNIFORM_NORMAL_MATRIX] != -1;
    _flags.usesTime = (
                       _builtInUniforms[UNIFORM_TIME] != -1 ||
                       _builtInUniforms[UNIFORM_SIN_TIME] != -1 ||
                       _builtInUniforms[UNIFORM_COS_TIME] != -1
                       );
    _flags.usesRandom = _builtInUniforms[UNIFORM_RANDOM01] != -1;

    this->use();
    /*      */
    // Since sample most probably won't change, set it to 0,1,2,3 now.
    if(_builtInUniforms[UNIFORM_SAMPLER0] != -1)
       setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER0], 0);
    if(_builtInUniforms[UNIFORM_SAMPLER1] != -1)
        setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER1], 1);
    if(_builtInUniforms[UNIFORM_SAMPLER2] != -1)
        setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER2], 2);
    if(_builtInUniforms[UNIFORM_SAMPLER3] != -1)
        setUniformLocationWith1i(_builtInUniforms[UNIFORM_SAMPLER3], 3);
}

좋은 웹페이지 즐겨찾기