1 /*
2  -----------------------------------------------------------------------------
3  This source file is part of OGRE
4  (Object-oriented Graphics Rendering Engine)
5  For the latest info, see http://www.ogre3d.org/
6 
7  Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9  Permission is hereby granted, free of charge, to any person obtaining a copy
10  of this software and associated documentation files (the "Software"), to deal
11  in the Software without restriction, including without limitation the rights
12  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13  copies of the Software, and to permit persons to whom the Software is
14  furnished to do so, subject to the following conditions:
15 
16  The above copyright notice and this permission notice shall be included in
17  all copies or substantial portions of the Software.
18 
19  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25  THE SOFTWARE.
26  -----------------------------------------------------------------------------
27  */
28 
29 #include "OgreGLSLESProgramCommon.h"
30 #include "OgreGLSLESGpuProgram.h"
31 #include "OgreGpuProgramManager.h"
32 #include "OgreGLES2Util.h"
33 #include "OgreGLES2RenderSystem.h"
34 #include "OgreRoot.h"
35 
36 namespace Ogre {
37 
38 	//-----------------------------------------------------------------------
GLSLESProgramCommon(GLSLESGpuProgram * vertexProgram,GLSLESGpuProgram * fragmentProgram)39 	GLSLESProgramCommon::GLSLESProgramCommon(GLSLESGpuProgram* vertexProgram, GLSLESGpuProgram* fragmentProgram)
40     : mVertexProgram(vertexProgram)
41     , mFragmentProgram(fragmentProgram)
42     , mUniformRefsBuilt(false)
43     , mLinked(false)
44     , mTriedToLinkAndFailed(false)
45 	{
46 		// init mCustomAttributesIndexes
47 		for(size_t i = 0 ; i < VES_COUNT; i++)
48 			for(size_t j = 0 ; j < OGRE_MAX_TEXTURE_COORD_SETS; j++)
49             {
50                 mCustomAttributesIndexes[i][j] = NULL_CUSTOM_ATTRIBUTES_INDEX;
51             }
52 
53         // Initialize the attribute to semantic map
54         mSemanticTypeMap.insert(SemanticToStringMap::value_type("vertex", VES_POSITION));
55         mSemanticTypeMap.insert(SemanticToStringMap::value_type("blendWeights", VES_BLEND_WEIGHTS));
56         mSemanticTypeMap.insert(SemanticToStringMap::value_type("normal", VES_NORMAL));
57         mSemanticTypeMap.insert(SemanticToStringMap::value_type("colour", VES_DIFFUSE));
58         mSemanticTypeMap.insert(SemanticToStringMap::value_type("secondary_colour", VES_SPECULAR));
59         mSemanticTypeMap.insert(SemanticToStringMap::value_type("blendIndices", VES_BLEND_INDICES));
60         mSemanticTypeMap.insert(SemanticToStringMap::value_type("tangent", VES_TANGENT));
61         mSemanticTypeMap.insert(SemanticToStringMap::value_type("binormal", VES_BINORMAL));
62         mSemanticTypeMap.insert(SemanticToStringMap::value_type("uv", VES_TEXTURE_COORDINATES));
63 
64         if ((!mVertexProgram || !mFragmentProgram) &&
65             !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS))
66         {
67             OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
68                         "Attempted to create a shader program without both a vertex and fragment program.",
69                         "GLSLESProgramCommon::GLSLESProgramCommon");
70         }
71 
72         // Initialise uniform cache
73 		mUniformCache = new GLES2UniformCache();
74 	}
75 
76 	//-----------------------------------------------------------------------
~GLSLESProgramCommon(void)77 	GLSLESProgramCommon::~GLSLESProgramCommon(void)
78 	{
79 		OGRE_CHECK_GL_ERROR(glDeleteProgram(mGLProgramHandle));
80 
81         delete mUniformCache;
82         mUniformCache = 0;
83 	}
84 
85 	//-----------------------------------------------------------------------
getCombinedName()86 	Ogre::String GLSLESProgramCommon::getCombinedName()
87 	{
88 		String name;
89 		if (mVertexProgram)
90 		{
91 			name += "Vertex Program:" ;
92 			name += mVertexProgram->getName();
93 		}
94 		if (mFragmentProgram)
95 		{
96 			name += " Fragment Program:" ;
97 			name += mFragmentProgram->getName();
98 		}
99         name += "\n";
100 
101 		return name;
102 	}
103 
104 	//-----------------------------------------------------------------------
getAttributeSemanticEnum(String type)105     VertexElementSemantic GLSLESProgramCommon::getAttributeSemanticEnum(String type)
106     {
107         VertexElementSemantic semantic = mSemanticTypeMap[type];
108         if(semantic > 0)
109         {
110             return semantic;
111         }
112         else
113         {
114             assert(false && "Missing attribute!");
115             return (VertexElementSemantic)0;
116         }
117     }
118 
119 	//-----------------------------------------------------------------------
getAttributeSemanticString(VertexElementSemantic semantic)120 	const char * GLSLESProgramCommon::getAttributeSemanticString(VertexElementSemantic semantic)
121 	{
122         for (SemanticToStringMap::iterator i = mSemanticTypeMap.begin(); i != mSemanticTypeMap.end(); ++i)
123         {
124             if((*i).second == semantic)
125                 return (*i).first.c_str();
126         }
127 
128         assert(false && "Missing attribute!");
129         return 0;
130 	}
131 
132 	//-----------------------------------------------------------------------
getAttributeIndex(VertexElementSemantic semantic,uint index)133 	GLint GLSLESProgramCommon::getAttributeIndex(VertexElementSemantic semantic, uint index)
134 	{
135 		GLint res = mCustomAttributesIndexes[semantic-1][index];
136 		if (res == NULL_CUSTOM_ATTRIBUTES_INDEX)
137 		{
138 			const char * attString = getAttributeSemanticString(semantic);
139 			GLint attrib;
140             OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(mGLProgramHandle, attString));
141 
142 			// sadly position is a special case
143 			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX && semantic == VES_POSITION)
144 			{
145 				OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(mGLProgramHandle, "position"));
146 			}
147 
148 			// for uv and other case the index is a part of the name
149 			if (attrib == NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX)
150 			{
151 				String attStringWithSemantic = String(attString) + StringConverter::toString(index);
152 				OGRE_CHECK_GL_ERROR(attrib = glGetAttribLocation(mGLProgramHandle, attStringWithSemantic.c_str()));
153 			}
154 
155 			// update mCustomAttributesIndexes with the index we found (or didn't find)
156 			mCustomAttributesIndexes[semantic-1][index] = attrib;
157 			res = attrib;
158 		}
159 		return res;
160 	}
161 	//-----------------------------------------------------------------------
isAttributeValid(VertexElementSemantic semantic,uint index)162 	bool GLSLESProgramCommon::isAttributeValid(VertexElementSemantic semantic, uint index)
163 	{
164 		return getAttributeIndex(semantic, index) != NOT_FOUND_CUSTOM_ATTRIBUTES_INDEX;
165 	}
166     //-----------------------------------------------------------------------
getMicrocodeFromCache(void)167 	void GLSLESProgramCommon::getMicrocodeFromCache(void)
168 	{
169 		GpuProgramManager::Microcode cacheMicrocode =
170             GpuProgramManager::getSingleton().getMicrocodeFromCache(getCombinedName());
171 
172 		// add to the microcode to the cache
173 		String name;
174 		name = getCombinedName();
175 
176 		// turns out we need this param when loading
177 		GLenum binaryFormat = 0;
178 
179 		cacheMicrocode->seek(0);
180 
181 		// get size of binary
182 		cacheMicrocode->read(&binaryFormat, sizeof(GLenum));
183 
184         if(getGLES2SupportRef()->checkExtension("GL_OES_get_program_binary") || gleswIsSupported(3, 0))
185         {
186             GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum));
187 
188             // load binary
189             OGRE_CHECK_GL_ERROR(glProgramBinaryOES(mGLProgramHandle,
190                                binaryFormat,
191                                cacheMicrocode->getPtr(),
192                                binaryLength));
193         }
194 
195 		GLint success = 0;
196 		OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_LINK_STATUS, &success));
197 		if (!success)
198 		{
199 			//
200 			// Something must have changed since the program binaries
201 			// were cached away.  Fallback to source shader loading path,
202 			// and then retrieve and cache new program binaries once again.
203 			//
204 			compileAndLink();
205 		}
206 	}
207 
208 } // namespace Ogre
209