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 *****************************************************************************/
PVRTShaderLoadSourceFromMemory(const char * pszShaderCode,const GLenum Type,GLuint * const pObject,CPVRTString * const pReturnError,const char * const * aszDefineArray,GLuint uiDefArraySize)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 *****************************************************************************/
PVRTShaderLoadBinaryFromMemory(const void * const ShaderData,const size_t Size,const GLenum Type,const GLenum Format,GLuint * const pObject,CPVRTString * const pReturnError)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 *****************************************************************************/
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)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 *****************************************************************************/
PVRTCreateProgram(GLuint * const pProgramObject,const GLuint VertexShader,const GLuint FragmentShader,const char ** const pszAttribs,const int i32NumAttribs,CPVRTString * const pReturnError)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