Cocos2d-x与program相关的类有:
- GLProgram:包含Shader Compile,Uniform Cache,Attrib Cache
- GLProgramState:每一个GLProgram对象都有一个与之对应的GLProgramState用于Cache所有的State,包括:Uniform和Attrib 。当前版本没有完善此类,因此所有的Cache都还在GLProgram中实现,而且glVertexAttribPointer这种东西还在Render类中,因此Attrib Cache现在没有太大的实质性的用处,另外并没有使用VAO和static draw VBO(每次Render的draw之前都会重新上传顶点属性数据)
- GLProgramCache:单实例类,Cache all default GLProgram,init()函数会加载所有的Shader Code然后生成GLProgram保存到Cache中
- GLProgramStateCache:单实例类,Cache all GLProgramState,init()函数会创建或获取已有GLProgramState,新创建的会加入到Cache
使用方法:用GLProgramStateCache中的接口获取GLProgramState,GLProgramState初始化时获取GLProgramCache单实例,GLProgramCache获取实例时创建所有的默认GLProgram。
待完善:当下,GLProgramState没有什么作用,其大部分功能还没有从GLProgram中分离出来,所以相关的apply()函数还是调用的GLProgram中的setUniform类函数。另外,Render类中draw函数没有将glVertexAttribPointer这种设置分离到GLProgramState中去。
GLProgram
1.包含的数据
/**VertexAttrib is a structure to encapsulate data got from glGetActiveAttrib.*/
struct VertexAttrib
{
/**Index of attribute, start from 0.*/
GLuint index;
/**Number of Data type in the attribute, could range from 0-4.*/
GLint size;
/**Data type of the attribute, could be GL_FLOAT, GL_UNSIGNED_BYTE etc.*/
GLenum type;
/**The string name in vertex shader.*/
std::string name;
};
/**Uniform is a structure to encapsulate data got from glGetActiveUniform and glGetUniformLocation.*/
struct Uniform
{
/**The place where the uniform placed, starts from 0.*/
GLint location;
/**Number of data type in attribute.*/
GLint size;
/**Data type of the attribute.*/
GLenum type;
/**String of the uniform name.*/
std::string name;
};
/**OpenGL handle for program.*/
GLuint _program;
/**OpenGL handle for vertex shader.*/
GLuint _vertShader;
/**OpenGL handle for fragment shader.*/
GLuint _fragShader;
/**Built in uniforms.*/
GLint _builtInUniforms[UNIFORM_MAX];
/**Indicate whether it has a offline shader compiler or not.*/
bool _hasShaderCompiler;
/**User defined Uniforms.*/
std::unordered_map<std::string, Uniform> _userUniforms;
/**User defined vertex attributes.*/
std::unordered_map<std::string, VertexAttrib> _vertexAttribs;
/**Hash value of uniforms for quick access.*/
std::unordered_map<GLint, std::pair<GLvoid*, unsigned int>> _hashForUniforms;
//cached director pointer for calling
Director* _director;
/*needed uniforms*/
UniformFlags _flags;
VertexAttrib:保存VertexAttrib的location,name,size(if vec2 = 2, vec3 = 3),type(like GLfoat)
Uniform:保存Uniform的location,name,size,type
_builtInUniforms:用于保存共用的Uniform的location的数组,name是已知的不用保存
_userUniforms:用于保存Userdefine的Uniform的location和name的map
_hashForUniforms:用于Cache所有的Uniform的location,data,data length的map,这个功能将来会迁移到GLProgramState
_flags:用于标志相同类型的Uniform是否在Program中定义
2.操作流程
1)create
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();
ret->updateUniforms();
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
2)init
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 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;
}
init包含了compile,attach两个过程,其中需要特别注意Compile过程,如下:
static const char * COCOS2D_SHADER_UNIFORMS =
"uniform mat4 CC_PMatrix;\n"
"uniform mat4 CC_MVMatrix;\n"
"uniform mat4 CC_MVPMatrix;\n"
"uniform mat3 CC_NormalMatrix;\n"
"uniform vec4 CC_Time;\n"
"uniform vec4 CC_SinTime;\n"
"uniform vec4 CC_CosTime;\n"
"uniform vec4 CC_Random01;\n"
"uniform sampler2D CC_Texture0;\n"
"uniform sampler2D CC_Texture1;\n"
"uniform sampler2D CC_Texture2;\n"
"uniform