Home | History | Annotate | Download | only in OGLES2
      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