diff options
author | Jacek Antonelli | 2008-09-06 18:24:57 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-09-06 18:25:07 -0500 |
commit | 798d367d54a6c6379ad355bd8345fa40e31e7fe9 (patch) | |
tree | 1921f1708cd0240648c97bc02df2c2ab5f2fc41e /linden/indra/llrender/llshadermgr.cpp | |
parent | Second Life viewer sources 1.20.15 (diff) | |
download | meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.zip meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.gz meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.bz2 meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.xz |
Second Life viewer sources 1.21.0-RC
Diffstat (limited to 'linden/indra/llrender/llshadermgr.cpp')
-rw-r--r-- | linden/indra/llrender/llshadermgr.cpp | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/linden/indra/llrender/llshadermgr.cpp b/linden/indra/llrender/llshadermgr.cpp new file mode 100644 index 0000000..4416775 --- /dev/null +++ b/linden/indra/llrender/llshadermgr.cpp | |||
@@ -0,0 +1,513 @@ | |||
1 | /** | ||
2 | * @file llshadermgr.cpp | ||
3 | * @brief Shader manager implementation. | ||
4 | * | ||
5 | * $LicenseInfo:firstyear=2005&license=viewergpl$ | ||
6 | * | ||
7 | * Copyright (c) 2005-2008, Linden Research, Inc. | ||
8 | * | ||
9 | * Second Life Viewer Source Code | ||
10 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
11 | * to you under the terms of the GNU General Public License, version 2.0 | ||
12 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
13 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
14 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
15 | * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 | ||
16 | * | ||
17 | * There are special exceptions to the terms and conditions of the GPL as | ||
18 | * it is applied to this Source Code. View the full text of the exception | ||
19 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
20 | * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception | ||
21 | * | ||
22 | * By copying, modifying or distributing this software, you acknowledge | ||
23 | * that you have read and understood your obligations described above, | ||
24 | * and agree to abide by those obligations. | ||
25 | * | ||
26 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
27 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
28 | * COMPLETENESS OR PERFORMANCE. | ||
29 | * $/LicenseInfo$ | ||
30 | */ | ||
31 | |||
32 | #include "linden_common.h" | ||
33 | |||
34 | #include "llshadermgr.h" | ||
35 | |||
36 | #include "llfile.h" | ||
37 | #include "llrender.h" | ||
38 | |||
39 | #if LL_DARWIN | ||
40 | #include "OpenGL/OpenGL.h" | ||
41 | #endif | ||
42 | |||
43 | #ifdef LL_RELEASE_FOR_DOWNLOAD | ||
44 | #define UNIFORM_ERRS LL_WARNS_ONCE("Shader") | ||
45 | #else | ||
46 | #define UNIFORM_ERRS LL_ERRS("Shader") | ||
47 | #endif | ||
48 | |||
49 | // Lots of STL stuff in here, using namespace std to keep things more readable | ||
50 | using std::vector; | ||
51 | using std::pair; | ||
52 | using std::make_pair; | ||
53 | using std::string; | ||
54 | |||
55 | LLShaderMgr * LLShaderMgr::sInstance = NULL; | ||
56 | |||
57 | LLShaderMgr::LLShaderMgr() | ||
58 | { | ||
59 | } | ||
60 | |||
61 | |||
62 | LLShaderMgr::~LLShaderMgr() | ||
63 | { | ||
64 | } | ||
65 | |||
66 | // static | ||
67 | LLShaderMgr * LLShaderMgr::instance() | ||
68 | { | ||
69 | if(NULL == sInstance) | ||
70 | { | ||
71 | LL_ERRS("Shaders") << "LLShaderMgr should already have been instantiated by the application!" << LL_ENDL; | ||
72 | } | ||
73 | |||
74 | return sInstance; | ||
75 | } | ||
76 | |||
77 | BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) | ||
78 | { | ||
79 | llassert_always(shader != NULL); | ||
80 | LLShaderFeatures *features = & shader->mFeatures; | ||
81 | |||
82 | ////////////////////////////////////// | ||
83 | // Attach Vertex Shader Features First | ||
84 | ////////////////////////////////////// | ||
85 | |||
86 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
87 | if (features->calculatesAtmospherics) | ||
88 | { | ||
89 | if (!shader->attachObject("windlight/atmosphericsVarsV.glsl")) | ||
90 | { | ||
91 | return FALSE; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | if (features->calculatesLighting) | ||
96 | { | ||
97 | if (!shader->attachObject("windlight/atmosphericsHelpersV.glsl")) | ||
98 | { | ||
99 | return FALSE; | ||
100 | } | ||
101 | |||
102 | if (features->isSpecular) | ||
103 | { | ||
104 | if (!shader->attachObject("lighting/lightFuncSpecularV.glsl")) | ||
105 | { | ||
106 | return FALSE; | ||
107 | } | ||
108 | |||
109 | if (!shader->attachObject("lighting/sumLightsSpecularV.glsl")) | ||
110 | { | ||
111 | return FALSE; | ||
112 | } | ||
113 | |||
114 | if (!shader->attachObject("lighting/lightSpecularV.glsl")) | ||
115 | { | ||
116 | return FALSE; | ||
117 | } | ||
118 | } | ||
119 | else | ||
120 | { | ||
121 | if (!shader->attachObject("lighting/lightFuncV.glsl")) | ||
122 | { | ||
123 | return FALSE; | ||
124 | } | ||
125 | |||
126 | if (!shader->attachObject("lighting/sumLightsV.glsl")) | ||
127 | { | ||
128 | return FALSE; | ||
129 | } | ||
130 | |||
131 | if (!shader->attachObject("lighting/lightV.glsl")) | ||
132 | { | ||
133 | return FALSE; | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
139 | if (features->calculatesAtmospherics) | ||
140 | { | ||
141 | if (!shader->attachObject("windlight/atmosphericsV.glsl")) | ||
142 | { | ||
143 | return FALSE; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | if (features->hasSkinning) | ||
148 | { | ||
149 | if (!shader->attachObject("avatar/avatarSkinV.glsl")) | ||
150 | { | ||
151 | return FALSE; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | /////////////////////////////////////// | ||
156 | // Attach Fragment Shader Features Next | ||
157 | /////////////////////////////////////// | ||
158 | |||
159 | if(features->calculatesAtmospherics) | ||
160 | { | ||
161 | if (!shader->attachObject("windlight/atmosphericsVarsF.glsl")) | ||
162 | { | ||
163 | return FALSE; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
168 | if (features->hasGamma) | ||
169 | { | ||
170 | if (!shader->attachObject("windlight/gammaF.glsl")) | ||
171 | { | ||
172 | return FALSE; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | if (features->hasAtmospherics) | ||
177 | { | ||
178 | if (!shader->attachObject("windlight/atmosphericsF.glsl")) | ||
179 | { | ||
180 | return FALSE; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | if (features->hasTransport) | ||
185 | { | ||
186 | if (!shader->attachObject("windlight/transportF.glsl")) | ||
187 | { | ||
188 | return FALSE; | ||
189 | } | ||
190 | |||
191 | // Test hasFullbright and hasShiny and attach fullbright and | ||
192 | // fullbright shiny atmos transport if we split them out. | ||
193 | } | ||
194 | |||
195 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
196 | if (features->hasWaterFog) | ||
197 | { | ||
198 | if (!shader->attachObject("environment/waterFogF.glsl")) | ||
199 | { | ||
200 | return FALSE; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | if (features->hasLighting) | ||
205 | { | ||
206 | |||
207 | if (features->hasWaterFog) | ||
208 | { | ||
209 | if (!shader->attachObject("lighting/lightWaterF.glsl")) | ||
210 | { | ||
211 | return FALSE; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | else | ||
216 | { | ||
217 | if (!shader->attachObject("lighting/lightF.glsl")) | ||
218 | { | ||
219 | return FALSE; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
225 | else if (features->isFullbright) | ||
226 | { | ||
227 | |||
228 | if (features->hasWaterFog) | ||
229 | { | ||
230 | if (!shader->attachObject("lighting/lightFullbrightWaterF.glsl")) | ||
231 | { | ||
232 | return FALSE; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | else if (features->isShiny) | ||
237 | { | ||
238 | if (!shader->attachObject("lighting/lightFullbrightShinyF.glsl")) | ||
239 | { | ||
240 | return FALSE; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | else | ||
245 | { | ||
246 | if (!shader->attachObject("lighting/lightFullbrightF.glsl")) | ||
247 | { | ||
248 | return FALSE; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | // NOTE order of shader object attaching is VERY IMPORTANT!!! | ||
254 | else if (features->isShiny) | ||
255 | { | ||
256 | |||
257 | if (features->hasWaterFog) | ||
258 | { | ||
259 | if (!shader->attachObject("lighting/lightShinyWaterF.glsl")) | ||
260 | { | ||
261 | return FALSE; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | else | ||
266 | { | ||
267 | if (!shader->attachObject("lighting/lightShinyF.glsl")) | ||
268 | { | ||
269 | return FALSE; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | return TRUE; | ||
274 | } | ||
275 | |||
276 | //============================================================================ | ||
277 | // Load Shader | ||
278 | |||
279 | static std::string get_object_log(GLhandleARB ret) | ||
280 | { | ||
281 | std::string res; | ||
282 | |||
283 | //get log length | ||
284 | GLint length; | ||
285 | glGetObjectParameterivARB(ret, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); | ||
286 | if (length > 0) | ||
287 | { | ||
288 | //the log could be any size, so allocate appropriately | ||
289 | GLcharARB* log = new GLcharARB[length]; | ||
290 | glGetInfoLogARB(ret, length, &length, log); | ||
291 | res = std::string((char *)log); | ||
292 | delete[] log; | ||
293 | } | ||
294 | return res; | ||
295 | } | ||
296 | |||
297 | void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns) | ||
298 | { | ||
299 | std::string log = get_object_log(ret); | ||
300 | if ( log.length() > 0 ) | ||
301 | { | ||
302 | if (warns) | ||
303 | { | ||
304 | LL_WARNS("ShaderLoading") << log << LL_ENDL; | ||
305 | } | ||
306 | else | ||
307 | { | ||
308 | LL_DEBUGS("ShaderLoading") << log << LL_ENDL; | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | |||
313 | GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type) | ||
314 | { | ||
315 | GLenum error; | ||
316 | error = glGetError(); | ||
317 | if (error != GL_NO_ERROR) | ||
318 | { | ||
319 | LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL; | ||
320 | } | ||
321 | |||
322 | LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL; | ||
323 | |||
324 | if (filename.empty()) | ||
325 | { | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | |||
330 | //read in from file | ||
331 | LLFILE* file = NULL; | ||
332 | |||
333 | S32 try_gpu_class = shader_level; | ||
334 | S32 gpu_class; | ||
335 | |||
336 | //find the most relevant file | ||
337 | for (gpu_class = try_gpu_class; gpu_class > 0; gpu_class--) | ||
338 | { //search from the current gpu class down to class 1 to find the most relevant shader | ||
339 | std::stringstream fname; | ||
340 | fname << getShaderDirPrefix(); | ||
341 | fname << gpu_class << "/" << filename; | ||
342 | |||
343 | LL_DEBUGS("ShaderLoading") << "Looking in " << fname.str() << LL_ENDL; | ||
344 | file = LLFile::fopen(fname.str(), "r"); /* Flawfinder: ignore */ | ||
345 | if (file) | ||
346 | { | ||
347 | LL_INFOS("ShaderLoading") << "Loading file: shaders/class" << gpu_class << "/" << filename << " (Want class " << gpu_class << ")" << LL_ENDL; | ||
348 | break; // done | ||
349 | } | ||
350 | } | ||
351 | |||
352 | if (file == NULL) | ||
353 | { | ||
354 | LL_WARNS("ShaderLoading") << "GLSL Shader file not found: " << filename << LL_ENDL; | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | //we can't have any lines longer than 1024 characters | ||
359 | //or any shaders longer than 1024 lines... deal - DaveP | ||
360 | GLcharARB buff[1024]; | ||
361 | GLcharARB* text[1024]; | ||
362 | GLuint count = 0; | ||
363 | |||
364 | |||
365 | //copy file into memory | ||
366 | while(fgets((char *)buff, 1024, file) != NULL && count < (sizeof(buff)/sizeof(buff[0]))) | ||
367 | { | ||
368 | text[count++] = (GLcharARB *)strdup((char *)buff); | ||
369 | } | ||
370 | fclose(file); | ||
371 | |||
372 | //create shader object | ||
373 | GLhandleARB ret = glCreateShaderObjectARB(type); | ||
374 | error = glGetError(); | ||
375 | if (error != GL_NO_ERROR) | ||
376 | { | ||
377 | LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL; | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | //load source | ||
382 | glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL); | ||
383 | error = glGetError(); | ||
384 | if (error != GL_NO_ERROR) | ||
385 | { | ||
386 | LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL; | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | //compile source | ||
391 | glCompileShaderARB(ret); | ||
392 | error = glGetError(); | ||
393 | if (error != GL_NO_ERROR) | ||
394 | { | ||
395 | LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL; | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | //free memory | ||
400 | for (GLuint i = 0; i < count; i++) | ||
401 | { | ||
402 | free(text[i]); | ||
403 | } | ||
404 | if (error == GL_NO_ERROR) | ||
405 | { | ||
406 | //check for errors | ||
407 | GLint success = GL_TRUE; | ||
408 | glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success); | ||
409 | error = glGetError(); | ||
410 | if (error != GL_NO_ERROR || success == GL_FALSE) | ||
411 | { | ||
412 | //an error occured, print log | ||
413 | LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL; | ||
414 | dumpObjectLog(ret); | ||
415 | ret = 0; | ||
416 | } | ||
417 | } | ||
418 | else | ||
419 | { | ||
420 | ret = 0; | ||
421 | } | ||
422 | stop_glerror(); | ||
423 | |||
424 | //successfully loaded, save results | ||
425 | if (ret) | ||
426 | { | ||
427 | // Add shader file to map | ||
428 | mShaderObjects[filename] = ret; | ||
429 | shader_level = try_gpu_class; | ||
430 | } | ||
431 | else | ||
432 | { | ||
433 | if (shader_level > 1) | ||
434 | { | ||
435 | shader_level--; | ||
436 | return loadShaderFile(filename,shader_level,type); | ||
437 | } | ||
438 | LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL; | ||
439 | } | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) | ||
444 | { | ||
445 | //check for errors | ||
446 | glLinkProgramARB(obj); | ||
447 | GLint success = GL_TRUE; | ||
448 | glGetObjectParameterivARB(obj, GL_OBJECT_LINK_STATUS_ARB, &success); | ||
449 | if (!suppress_errors && success == GL_FALSE) | ||
450 | { | ||
451 | //an error occured, print log | ||
452 | LL_WARNS("ShaderLoading") << "GLSL Linker Error:" << LL_ENDL; | ||
453 | } | ||
454 | |||
455 | // NOTE: Removing LL_DARWIN block as it doesn't seem to actually give the correct answer, | ||
456 | // but want it for reference once I move it. | ||
457 | #if 0 | ||
458 | // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software | ||
459 | // per Apple's suggestion | ||
460 | glBegin(gGL.mMode); | ||
461 | glEnd(); | ||
462 | |||
463 | // Query whether the shader can or cannot run in hardware | ||
464 | // http://developer.apple.com/qa/qa2007/qa1502.html | ||
465 | long vertexGPUProcessing; | ||
466 | CGLContextObj ctx = CGLGetCurrentContext(); | ||
467 | CGLGetParameter (ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing); | ||
468 | long fragmentGPUProcessing; | ||
469 | CGLGetParameter (ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing); | ||
470 | if (!fragmentGPUProcessing || !vertexGPUProcessing) | ||
471 | { | ||
472 | LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; | ||
473 | success = GL_FALSE; | ||
474 | suppress_errors = FALSE; | ||
475 | } | ||
476 | |||
477 | #else | ||
478 | std::string log = get_object_log(obj); | ||
479 | LLStringUtil::toLower(log); | ||
480 | if (log.find("software") != std::string::npos) | ||
481 | { | ||
482 | LL_WARNS("ShaderLoading") << "GLSL Linker: Running in Software:" << LL_ENDL; | ||
483 | success = GL_FALSE; | ||
484 | suppress_errors = FALSE; | ||
485 | } | ||
486 | #endif | ||
487 | if (!suppress_errors) | ||
488 | { | ||
489 | dumpObjectLog(obj, !success); | ||
490 | } | ||
491 | |||
492 | return success; | ||
493 | } | ||
494 | |||
495 | BOOL LLShaderMgr::validateProgramObject(GLhandleARB obj) | ||
496 | { | ||
497 | //check program validity against current GL | ||
498 | glValidateProgramARB(obj); | ||
499 | GLint success = GL_TRUE; | ||
500 | glGetObjectParameterivARB(obj, GL_OBJECT_VALIDATE_STATUS_ARB, &success); | ||
501 | if (success == GL_FALSE) | ||
502 | { | ||
503 | LL_WARNS("ShaderLoading") << "GLSL program not valid: " << LL_ENDL; | ||
504 | dumpObjectLog(obj); | ||
505 | } | ||
506 | else | ||
507 | { | ||
508 | dumpObjectLog(obj, FALSE); | ||
509 | } | ||
510 | |||
511 | return success; | ||
512 | } | ||
513 | |||