aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llrender/llshadermgr.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-09-06 18:24:57 -0500
committerJacek Antonelli2008-09-06 18:25:07 -0500
commit798d367d54a6c6379ad355bd8345fa40e31e7fe9 (patch)
tree1921f1708cd0240648c97bc02df2c2ab5f2fc41e /linden/indra/llrender/llshadermgr.cpp
parentSecond Life viewer sources 1.20.15 (diff)
downloadmeta-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.cpp513
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
50using std::vector;
51using std::pair;
52using std::make_pair;
53using std::string;
54
55LLShaderMgr * LLShaderMgr::sInstance = NULL;
56
57LLShaderMgr::LLShaderMgr()
58{
59}
60
61
62LLShaderMgr::~LLShaderMgr()
63{
64}
65
66// static
67LLShaderMgr * 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
77BOOL 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
279static 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
297void 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
313GLhandleARB 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
443BOOL 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
495BOOL 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