1 /****************************************************************************** 2 3 @File OGLES2/PVRTShader.cpp 4 5 @Title OGLES2/PVRTShader 6 7 @Version 8 9 @Copyright Copyright (c) Imagination Technologies Limited. 10 11 @Platform ANSI compatible 12 13 @Description Shader handling for OpenGL ES 2.0 14 15 ******************************************************************************/ 16 17 #include "PVRTString.h" 18 #include "PVRTShader.h" 19 #include "PVRTResourceFile.h" 20 #include "PVRTGlobal.h" 21 #include <ctype.h> 22 #include <string.h> 23 24 /*!*************************************************************************** 25 @Function PVRTShaderLoadSourceFromMemory 26 @Input pszShaderCode shader source code 27 @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 28 @Output pObject the resulting shader object 29 @Output pReturnError the error message if it failed 30 @Input aszDefineArray Array of defines to be pre-appended to shader string 31 @Input uiDefArraySize Size of the define array 32 @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills the str string) 33 @Description Loads a shader source code into memory and compiles it. 34 It also pre-appends the array of defines that have been passed in 35 to the source code before compilation. 36 *****************************************************************************/ 37 EPVRTError PVRTShaderLoadSourceFromMemory( const char* pszShaderCode, 38 const GLenum Type, 39 GLuint* const pObject, 40 CPVRTString* const pReturnError, 41 const char* const* aszDefineArray, GLuint uiDefArraySize) 42 { 43 // Append define's here if there are any 44 CPVRTString pszShaderString; 45 46 if(uiDefArraySize > 0) 47 { 48 while(isspace(*pszShaderCode)) 49 ++pszShaderCode; 50 51 if(*pszShaderCode == '#') 52 { 53 const char* tmp = pszShaderCode + 1; 54 55 while(isspace(*tmp)) 56 ++tmp; 57 58 if(strncmp(tmp, "version", 7) == 0) 59 { 60 const char* c = strchr(pszShaderCode, '\n'); 61 62 if(c) 63 { 64 size_t length = c - pszShaderCode + 1; 65 pszShaderString = CPVRTString(pszShaderCode, length); 66 pszShaderCode += length; 67 } 68 else 69 { 70 pszShaderString = CPVRTString(pszShaderCode) + "\n"; 71 pszShaderCode = '\0'; 72 } 73 } 74 } 75 76 for(GLuint i = 0 ; i < uiDefArraySize; ++i) 77 { 78 pszShaderString += "#define "; 79 pszShaderString += aszDefineArray[i]; 80 pszShaderString += "\n"; 81 } 82 } 83 84 // Append the shader code to the string 85 pszShaderString += pszShaderCode; 86 87 /* Create and compile the shader object */ 88 *pObject = glCreateShader(Type); 89 const char* pszString(pszShaderString.c_str()); 90 glShaderSource(*pObject, 1, &pszString, NULL); 91 glCompileShader(*pObject); 92 93 /* Test if compilation succeeded */ 94 GLint ShaderCompiled; 95 glGetShaderiv(*pObject, GL_COMPILE_STATUS, &ShaderCompiled); 96 if (!ShaderCompiled) 97 { 98 int i32InfoLogLength, i32CharsWritten; 99 glGetShaderiv(*pObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength); 100 char* pszInfoLog = new char[i32InfoLogLength]; 101 glGetShaderInfoLog(*pObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog); 102 *pReturnError = CPVRTString("Failed to compile shader: ") + pszInfoLog + "\n"; 103 delete [] pszInfoLog; 104 glDeleteShader(*pObject); 105 return PVR_FAIL; 106 } 107 108 return PVR_SUCCESS; 109 } 110 111 /*!*************************************************************************** 112 @Function PVRTShaderLoadBinaryFromMemory 113 @Input ShaderData shader compiled binary data 114 @Input Size size of shader binary data in bytes 115 @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 116 @Input Format shader binary format 117 @Output pObject the resulting shader object 118 @Output pReturnError the error message if it failed 119 @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills the str string) 120 @Description Takes a shader binary from memory and passes it to the GL. 121 *****************************************************************************/ 122 EPVRTError PVRTShaderLoadBinaryFromMemory( const void* const ShaderData, 123 const size_t Size, 124 const GLenum Type, 125 const GLenum Format, 126 GLuint* const pObject, 127 CPVRTString* const pReturnError) 128 { 129 /* Create and compile the shader object */ 130 *pObject = glCreateShader(Type); 131 132 // Get the list of supported binary formats 133 // and if (more then 0) find given Format among them 134 GLint numFormats = 0; 135 GLint *listFormats; 136 int i; 137 glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS,&numFormats); 138 if(numFormats != 0) { 139 listFormats = new GLint[numFormats]; 140 for(i=0;i<numFormats;++i) 141 listFormats[i] = 0; 142 glGetIntegerv(GL_SHADER_BINARY_FORMATS,listFormats); 143 for(i=0;i<numFormats;++i) { 144 if(listFormats[i] == (int) Format) { 145 glShaderBinary(1, pObject, Format, ShaderData, (GLint)Size); 146 if (glGetError() != GL_NO_ERROR) 147 { 148 *pReturnError = CPVRTString("Failed to load binary shader\n"); 149 glDeleteShader(*pObject); 150 return PVR_FAIL; 151 } 152 return PVR_SUCCESS; 153 } 154 } 155 delete [] listFormats; 156 } 157 *pReturnError = CPVRTString("Failed to load binary shader\n"); 158 glDeleteShader(*pObject); 159 return PVR_FAIL; 160 } 161 162 /*!*************************************************************************** 163 @Function PVRTShaderLoadFromFile 164 @Input pszBinFile binary shader filename 165 @Input pszSrcFile source shader filename 166 @Input Type type of shader (GL_VERTEX_SHADER or GL_FRAGMENT_SHADER) 167 @Input Format shader binary format, or 0 for source shader 168 @Output pObject the resulting shader object 169 @Output pReturnError the error message if it failed 170 @Input pContext Context 171 @Input aszDefineArray Array of defines to be pre-appended to shader string 172 @Input uiDefArraySize Size of the define array 173 @Return PVR_SUCCESS on success and PVR_FAIL on failure (also fills pReturnError) 174 @Description Loads a shader file into memory and passes it to the GL. 175 It also passes defines that need to be pre-appended to the shader before compilation. 176 *****************************************************************************/ 177 EPVRTError PVRTShaderLoadFromFile( const char* const pszBinFile, 178 const char* const pszSrcFile, 179 const GLenum Type, 180 const GLenum Format, 181 GLuint* const pObject, 182 CPVRTString* const pReturnError, 183 const SPVRTContext* const pContext, 184 const char* const* aszDefineArray, GLuint uiDefArraySize) 185 { 186 PVRT_UNREFERENCED_PARAMETER(pContext); 187 188 *pReturnError = ""; 189 190 /* 191 Prepending defines relies on altering the source file that is loaded. 192 For this reason, the function calls the source loader instead of the binary loader if defines have 193 been passed in. 194 */ 195 if(Format && pszBinFile && uiDefArraySize == 0) 196 { 197 CPVRTResourceFile ShaderFile(pszBinFile); 198 if (ShaderFile.IsOpen()) 199 { 200 if(PVRTShaderLoadBinaryFromMemory(ShaderFile.DataPtr(), ShaderFile.Size(), Type, Format, pObject, pReturnError) == PVR_SUCCESS) 201 return PVR_SUCCESS; 202 } 203 204 *pReturnError += CPVRTString("Failed to open shader ") + pszBinFile + "\n"; 205 } 206 207 CPVRTResourceFile ShaderFile(pszSrcFile); 208 if (!ShaderFile.IsOpen()) 209 { 210 *pReturnError += CPVRTString("Failed to open shader ") + pszSrcFile + "\n"; 211 return PVR_FAIL; 212 } 213 214 CPVRTString ShaderFileString; 215 const char* pShaderData = (const char*) ShaderFile.DataPtr(); 216 217 // Is our shader resource file data null terminated? 218 if(pShaderData[ShaderFile.Size()-1] != '\0') 219 { 220 // If not create a temporary null-terminated string 221 ShaderFileString.assign(pShaderData, ShaderFile.Size()); 222 pShaderData = ShaderFileString.c_str(); 223 } 224 225 return PVRTShaderLoadSourceFromMemory(pShaderData, Type, pObject, pReturnError, aszDefineArray, uiDefArraySize); 226 } 227 228 /*!*************************************************************************** 229 @Function PVRTCreateProgram 230 @Output pProgramObject the created program object 231 @Input VertexShader the vertex shader to link 232 @Input FragmentShader the fragment shader to link 233 @Input pszAttribs an array of attribute names 234 @Input i32NumAttribs the number of attributes to bind 235 @Output pReturnError the error message if it failed 236 @Returns PVR_SUCCESS on success, PVR_FAIL if failure 237 @Description Links a shader program. 238 *****************************************************************************/ 239 EPVRTError PVRTCreateProgram( GLuint* const pProgramObject, 240 const GLuint VertexShader, 241 const GLuint FragmentShader, 242 const char** const pszAttribs, 243 const int i32NumAttribs, 244 CPVRTString* const pReturnError) 245 { 246 *pProgramObject = glCreateProgram(); 247 248 glAttachShader(*pProgramObject, FragmentShader); 249 glAttachShader(*pProgramObject, VertexShader); 250 251 for (int i = 0; i < i32NumAttribs; ++i) 252 { 253 glBindAttribLocation(*pProgramObject, i, pszAttribs[i]); 254 } 255 256 // Link the program object 257 glLinkProgram(*pProgramObject); 258 GLint Linked; 259 glGetProgramiv(*pProgramObject, GL_LINK_STATUS, &Linked); 260 if (!Linked) 261 { 262 int i32InfoLogLength, i32CharsWritten; 263 glGetProgramiv(*pProgramObject, GL_INFO_LOG_LENGTH, &i32InfoLogLength); 264 char* pszInfoLog = new char[i32InfoLogLength]; 265 glGetProgramInfoLog(*pProgramObject, i32InfoLogLength, &i32CharsWritten, pszInfoLog); 266 *pReturnError = CPVRTString("Failed to link: ") + pszInfoLog + "\n"; 267 delete [] pszInfoLog; 268 return PVR_FAIL; 269 } 270 271 glUseProgram(*pProgramObject); 272 273 return PVR_SUCCESS; 274 } 275 276 /***************************************************************************** 277 End of file (PVRTShader.cpp) 278 *****************************************************************************/ 279 280