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-2014 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 "OgreGLSLProgram.h"
30 #include "OgreGLSLShader.h"
31 #include "OgreGpuProgramManager.h"
32 #include "OgreGLSLShader.h"
33 #include "OgreRoot.h"
34 #include "OgreGLSLExtSupport.h"
35 
36 namespace Ogre {
37 
GLSLProgram(GLSLShader * vertexShader,GLSLShader * hullShader,GLSLShader * domainShader,GLSLShader * geometryShader,GLSLShader * fragmentShader,GLSLShader * computeShader)38     GLSLProgram::GLSLProgram(GLSLShader* vertexShader,
39                              GLSLShader* hullShader,
40                              GLSLShader* domainShader,
41                              GLSLShader* geometryShader,
42                              GLSLShader* fragmentShader,
43                              GLSLShader* computeShader)
44         : GLSLProgramCommon(vertexShader)
45         , mHullShader(hullShader)
46         , mDomainShader(domainShader)
47         , mGeometryShader(geometryShader)
48         , mFragmentShader(fragmentShader)
49         , mComputeShader(computeShader)
50     {
51     }
52 
getCombinedName()53     Ogre::String GLSLProgram::getCombinedName()
54     {
55         String name;
56         if (mVertexShader)
57         {
58             name += "Vertex Shader: ";
59             name += mVertexShader->getName();
60             name += "\n";
61         }
62         if (mHullShader)
63         {
64             name += "Tessellation Control Shader: ";
65             name += mHullShader->getName();
66             name += "\n";
67         }
68         if (mDomainShader)
69         {
70             name += "Tessellation Evaluation Shader: ";
71             name += mDomainShader->getName();
72             name += "\n";
73         }
74         if (mGeometryShader)
75         {
76             name += "Geometry Shader: ";
77             name += mGeometryShader->getName();
78             name += "\n";
79         }
80         if (mFragmentShader)
81         {
82             name += "Fragment Shader: ";
83             name += mFragmentShader->getName();
84             name += "\n";
85         }
86         if (mComputeShader)
87         {
88             name += "Compute Shader: ";
89             name += mComputeShader->getName();
90             name += "\n";
91         }
92 
93         return name;
94     }
95 
bindFixedAttributes(GLuint program)96     void GLSLProgram::bindFixedAttributes(GLuint program)
97     {
98         GLint maxAttribs = Root::getSingleton().getRenderSystem()->getCapabilities()->getNumVertexAttributes();
99 
100         size_t numAttribs = sizeof(msCustomAttributes) / sizeof(CustomAttribute);
101         for (size_t i = 0; i < numAttribs; ++i)
102         {
103             const CustomAttribute& a = msCustomAttributes[i];
104             if (a.attrib < maxAttribs)
105             {
106 
107                 OGRE_CHECK_GL_ERROR(glBindAttribLocation(program, a.attrib, a.name));
108             }
109         }
110     }
111 
getCombinedHash()112     uint32 GLSLProgram::getCombinedHash()
113     {
114         uint32 hash = 0;
115         GpuProgram* progs[] = {mVertexShader, mFragmentShader, mGeometryShader,
116                                mHullShader,   mDomainShader,   mComputeShader};
117         for (auto p : progs)
118         {
119             if(!p) continue;
120             hash = p->_getHash(hash);
121         }
122         return hash;
123     }
124 
setTransformFeedbackVaryings(const std::vector<String> & nameStrings)125     void GLSLProgram::setTransformFeedbackVaryings(const std::vector<String>& nameStrings)
126     {
127         // Get program object ID.
128         GLuint programId;
129         if (Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_SEPARATE_SHADER_OBJECTS))
130         {
131             //TODO include tessellation stages
132             GLSLShader* glslGpuProgram = getGeometryShader();
133             if (!glslGpuProgram)
134                 glslGpuProgram = getVertexShader();
135 
136             programId = glslGpuProgram->getGLProgramHandle();
137 
138             // force re-link
139             GpuProgramManager::getSingleton().removeMicrocodeFromCache(glslGpuProgram->_getHash());
140             glslGpuProgram->setLinked(false);
141         }
142         else
143         {
144             programId = getGLProgramHandle();
145 
146             // force re-link
147             GpuProgramManager::getSingleton().removeMicrocodeFromCache(getCombinedHash());
148         }
149         mLinked = false;
150 
151         // Convert to const char * for GL
152         std::vector<const char*> names;
153         for (uint e = 0; e < nameStrings.size(); e++)
154         {
155             names.push_back(nameStrings[e].c_str());
156         }
157 
158         // TODO replace glTransformFeedbackVaryings with in-shader specification (GL 4.4)
159         OGRE_CHECK_GL_ERROR(glTransformFeedbackVaryings(programId, nameStrings.size(), &names[0],
160                                                         GL_INTERLEAVED_ATTRIBS));
161 
162 #if OGRE_DEBUG_MODE
163         activate();
164         // Check if varyings were successfully set.
165         GLchar Name[64];
166         GLsizei Length(0);
167         GLsizei Size(0);
168         GLenum Type(0);
169         // bool Validated = false;
170         for (size_t i = 0; i < nameStrings.size(); i++)
171         {
172             OGRE_CHECK_GL_ERROR(
173                 glGetTransformFeedbackVarying(programId, i, 64, &Length, &Size, &Type, Name));
174             LogManager::getSingleton().stream() << "Varying " << i << ": " << Name << " " << Length
175                                                 << " " << Size << " " << Type;
176             // Validated = (Size == 1) && (Type == GL_FLOAT_VEC3);
177             // std::cout << Validated << " " << GL_FLOAT_VEC3 << std::endl;
178         }
179 #endif
180     }
181 
getMicrocodeFromCache(uint32 id)182     void GLSLProgram::getMicrocodeFromCache(uint32 id)
183     {
184         GpuProgramManager::Microcode cacheMicrocode =
185             GpuProgramManager::getSingleton().getMicrocodeFromCache(id);
186 
187         cacheMicrocode->seek(0);
188 
189         // Turns out we need this param when loading.
190         GLenum binaryFormat = 0;
191         cacheMicrocode->read(&binaryFormat, sizeof(GLenum));
192 
193         // Get size of binary.
194         GLint binaryLength = static_cast<GLint>(cacheMicrocode->size() - sizeof(GLenum));
195 
196         // Load binary.
197         OGRE_CHECK_GL_ERROR(glProgramBinary(mGLProgramHandle,
198                                             binaryFormat,
199                                             cacheMicrocode->getCurrentPtr(),
200                                             binaryLength));
201 
202         GLint success = 0;
203         OGRE_CHECK_GL_ERROR(glGetProgramiv(mGLProgramHandle, GL_LINK_STATUS, &success));
204 
205         if(success)
206         {
207             mLinked = true;
208             return;
209         }
210 
211         logObjectInfo("could not load from cache "+getCombinedName(), mGLProgramHandle);
212         // Something must have changed since the program binaries
213         // were cached away. Fallback to source shader loading path,
214         // and then retrieve and cache new program binaries once again.
215         compileAndLink();
216     }
217 
218 } // namespace Ogre
219