• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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