| /****************************************************************************** | |
| @File OGLES2/PVRTShader.cpp | |
| @Title OGLES2/PVRTShader | |
| @Version | |
| @Copyright Copyright (c) Imagination Technologies Limited. | |
| @Platform ANSI compatible | |
| @Description Shader handling for OpenGL ES 2.0 | |
| ******************************************************************************/ | |
| #include "PVRTString.h" | |
| #include "PVRTShader.h" | |
| #include "PVRTResourceFile.h" | |
| #include "PVRTGlobal.h" | |
| #include <ctype.h> | |
| #include <string.h> | |
| /*!*************************************************************************** | |
| @Function PVRTShaderLoadSourceFromMemory | |
| @Input pszShaderCode shader source code | |
| @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) | |
| @Output pObject the resulting shader object | |
| @Output pReturnError the error message if it failed | |
| @Input aszDefineArray Array of defines to be pre-appended to shader string | |
| @Input uiDefArraySize Size of the define array | |
| @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills the str string) | |
| @Description Loads a shader source code into memory and compiles it. | |
| It also pre-appends the array of defines that have been passed in | |
| to the source code before compilation. | |
| *****************************************************************************/ | |
| EPVRTError PVRTShaderLoadSourceFromMemory( const char* pszShaderCode, | |
| const GLenum Type, | |
| GLuint* const pObject, | |
| CPVRTString* const pReturnError, | |
| const char* const* aszDefineArray, GLuint uiDefArraySize) | |
| { | |
| // Append define's here if there are any | |
| CPVRTString pszShaderString; | |
| if(uiDefArraySize > 0) | |
| { | |
| while(isspace(*pszShaderCode)) | |
| ++pszShaderCode; | |
| if(*pszShaderCode == '#') | |
| { | |
| const char* tmp = pszShaderCode + 1; | |
| while(isspace(*tmp)) | |
| ++tmp; | |
| if(strncmp(tmp, "version", 7) == 0) | |
| { | |
| const char* c = strchr(pszShaderCode, '\n'); | |
| if(c) | |
| { | |
| size_t length = c - pszShaderCode + 1; | |
| pszShaderString = CPVRTString(pszShaderCode, length); | |
| pszShaderCode += length; | |
| } | |
| else | |
| { | |
| pszShaderString = CPVRTString(pszShaderCode) + "\n"; | |
| pszShaderCode = '\0'; | |
| } | |
| } | |
| } | |
| for(GLuint i = 0 ; i < uiDefArraySize; ++i) | |
| { | |
| pszShaderString += "#define "; | |
| pszShaderString += aszDefineArray[i]; | |
| pszShaderString += "\n"; | |
| } | |
| } | |
| // Append the shader code to the string | |
| pszShaderString += pszShaderCode; | |
| /* Create and compile the shader object */ | |
| *pObject = glCreateShader(Type); | |
| const char* pszString(pszShaderString.c_str()); | |
| glShaderSource(*pObject, 1, &pszString, NULL); | |
| glCompileShader(*pObject); | |
| /* Test if compilation succeeded */ | |
| GLint ShaderCompiled; | |
| glGetShaderiv(*pObject, GL_COMPILE_STATUS, &ShaderCompiled); | |
| if (!ShaderCompiled) | |
| { | |
| int i32InfoLogLength, i32CharsWritten; | |
| glGetShaderiv(*pObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength); | |
| char* pszInfoLog = new char[i32InfoLogLength]; | |
| glGetShaderInfoLog(*pObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog); | |
| *pReturnError = CPVRTString("Failed to compile shader: ") + pszInfoLog + "\n"; | |
| delete [] pszInfoLog; | |
| glDeleteShader(*pObject); | |
| return PVR_FAIL; | |
| } | |
| return PVR_SUCCESS; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTShaderLoadBinaryFromMemory | |
| @Input ShaderData shader compiled binary data | |
| @Input Size size of shader binary data in bytes | |
| @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) | |
| @Input Format shader binary format | |
| @Output pObject the resulting shader object | |
| @Output pReturnError the error message if it failed | |
| @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills the str string) | |
| @Description Takes a shader binary from memory and passes it to the GL. | |
| *****************************************************************************/ | |
| EPVRTError PVRTShaderLoadBinaryFromMemory( const void* const ShaderData, | |
| const size_t Size, | |
| const GLenum Type, | |
| const GLenum Format, | |
| GLuint* const pObject, | |
| CPVRTString* const pReturnError) | |
| { | |
| /* Create and compile the shader object */ | |
| *pObject = glCreateShader(Type); | |
| // Get the list of supported binary formats | |
| // and if (more then 0) find given Format among them | |
| GLint numFormats = 0; | |
| GLint *listFormats; | |
| int i; | |
| glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS,&numFormats); | |
| if(numFormats != 0) { | |
| listFormats = new GLint[numFormats]; | |
| for(i=0;i<numFormats;++i) | |
| listFormats[i] = 0; | |
| glGetIntegerv(GL_SHADER_BINARY_FORMATS,listFormats); | |
| for(i=0;i<numFormats;++i) { | |
| if(listFormats[i] == (int) Format) { | |
| glShaderBinary(1, pObject, Format, ShaderData, (GLint)Size); | |
| if (glGetError() != GL_NO_ERROR) | |
| { | |
| *pReturnError = CPVRTString("Failed to load binary shader\n"); | |
| glDeleteShader(*pObject); | |
| return PVR_FAIL; | |
| } | |
| return PVR_SUCCESS; | |
| } | |
| } | |
| delete [] listFormats; | |
| } | |
| *pReturnError = CPVRTString("Failed to load binary shader\n"); | |
| glDeleteShader(*pObject); | |
| return PVR_FAIL; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTShaderLoadFromFile | |
| @Input pszBinFile binary shader filename | |
| @Input pszSrcFile source shader filename | |
| @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) | |
| @Input Format shader binary format, or 0 for source shader | |
| @Output pObject the resulting shader object | |
| @Output pReturnError the error message if it failed | |
| @Input pContext Context | |
| @Input aszDefineArray Array of defines to be pre-appended to shader string | |
| @Input uiDefArraySize Size of the define array | |
| @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills pReturnError) | |
| @Description Loads a shader file into memory and passes it to the GL. | |
| It also passes defines that need to be pre-appended to the shader before compilation. | |
| *****************************************************************************/ | |
| EPVRTError PVRTShaderLoadFromFile( const char* const pszBinFile, | |
| const char* const pszSrcFile, | |
| const GLenum Type, | |
| const GLenum Format, | |
| GLuint* const pObject, | |
| CPVRTString* const pReturnError, | |
| const SPVRTContext* const pContext, | |
| const char* const* aszDefineArray, GLuint uiDefArraySize) | |
| { | |
| PVRT_UNREFERENCED_PARAMETER(pContext); | |
| *pReturnError = ""; | |
| /* | |
| Prepending defines relies on altering the source file that is loaded. | |
| For this reason, the function calls the source loader instead of the binary loader if defines have | |
| been passed in. | |
| */ | |
| if(Format && pszBinFile && uiDefArraySize == 0) | |
| { | |
| CPVRTResourceFile ShaderFile(pszBinFile); | |
| if (ShaderFile.IsOpen()) | |
| { | |
| if(PVRTShaderLoadBinaryFromMemory(ShaderFile.DataPtr(), ShaderFile.Size(), Type, Format, pObject, pReturnError) == PVR_SUCCESS) | |
| return PVR_SUCCESS; | |
| } | |
| *pReturnError += CPVRTString("Failed to open shader ") + pszBinFile + "\n"; | |
| } | |
| CPVRTResourceFile ShaderFile(pszSrcFile); | |
| if (!ShaderFile.IsOpen()) | |
| { | |
| *pReturnError += CPVRTString("Failed to open shader ") + pszSrcFile + "\n"; | |
| return PVR_FAIL; | |
| } | |
| CPVRTString ShaderFileString; | |
| const char* pShaderData = (const char*) ShaderFile.DataPtr(); | |
| // Is our shader resource file data null terminated? | |
| if(pShaderData[ShaderFile.Size()-1] != '\0') | |
| { | |
| // If not create a temporary null-terminated string | |
| ShaderFileString.assign(pShaderData, ShaderFile.Size()); | |
| pShaderData = ShaderFileString.c_str(); | |
| } | |
| return PVRTShaderLoadSourceFromMemory(pShaderData, Type, pObject, pReturnError, aszDefineArray, uiDefArraySize); | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTCreateProgram | |
| @Output pProgramObject the created program object | |
| @Input VertexShader the vertex shader to link | |
| @Input FragmentShader the fragment shader to link | |
| @Input pszAttribs an array of attribute names | |
| @Input i32NumAttribs the number of attributes to bind | |
| @Output pReturnError the error message if it failed | |
| @Returns PVR_SUCCESS on success, PVR_FAIL if failure | |
| @Description Links a shader program. | |
| *****************************************************************************/ | |
| EPVRTError PVRTCreateProgram( GLuint* const pProgramObject, | |
| const GLuint VertexShader, | |
| const GLuint FragmentShader, | |
| const char** const pszAttribs, | |
| const int i32NumAttribs, | |
| CPVRTString* const pReturnError) | |
| { | |
| *pProgramObject = glCreateProgram(); | |
| glAttachShader(*pProgramObject, FragmentShader); | |
| glAttachShader(*pProgramObject, VertexShader); | |
| for (int i = 0; i < i32NumAttribs; ++i) | |
| { | |
| glBindAttribLocation(*pProgramObject, i, pszAttribs[i]); | |
| } | |
| // Link the program object | |
| glLinkProgram(*pProgramObject); | |
| GLint Linked; | |
| glGetProgramiv(*pProgramObject, GL_LINK_STATUS, &Linked); | |
| if (!Linked) | |
| { | |
| int i32InfoLogLength, i32CharsWritten; | |
| glGetProgramiv(*pProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength); | |
| char* pszInfoLog = new char[i32InfoLogLength]; | |
| glGetProgramInfoLog(*pProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog); | |
| *pReturnError = CPVRTString("Failed to link: ") + pszInfoLog + "\n"; | |
| delete [] pszInfoLog; | |
| return PVR_FAIL; | |
| } | |
| glUseProgram(*pProgramObject); | |
| return PVR_SUCCESS; | |
| } | |
| /***************************************************************************** | |
| End of file (PVRTShader.cpp) | |
| *****************************************************************************/ | |