]> git.cworth.org Git - apitrace/blob - retrace/glstate_shaders.cpp
Don't attempt to dump built-in uniforms.
[apitrace] / retrace / glstate_shaders.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <string.h>
28
29 #include <algorithm>
30 #include <iostream>
31 #include <map>
32 #include <sstream>
33
34 #include "json.hpp"
35 #include "glproc.hpp"
36 #include "glsize.hpp"
37 #include "glstate.hpp"
38 #include "glstate_internal.hpp"
39
40
41 namespace glstate {
42
43
44 // Mapping from shader type to shader source, used to accumulated the sources
45 // of different shaders with same type.
46 typedef std::map<std::string, std::string> ShaderMap;
47
48
49 static void
50 getShaderSource(ShaderMap &shaderMap, GLuint shader)
51 {
52     if (!shader) {
53         return;
54     }
55
56     GLint shader_type = 0;
57     glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
58     if (!shader_type) {
59         return;
60     }
61
62     GLint source_length = 0;
63     glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
64     if (!source_length) {
65         return;
66     }
67
68     GLchar *source = new GLchar[source_length];
69     GLsizei length = 0;
70     source[0] = 0;
71     glGetShaderSource(shader, source_length, &length, source);
72
73     shaderMap[enumToString(shader_type)] += source;
74
75     delete [] source;
76 }
77
78
79 static void
80 getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
81 {
82     if (!shaderObj) {
83         return;
84     }
85
86     GLint object_type = 0;
87     glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &object_type);
88     if (object_type != GL_SHADER_OBJECT_ARB) {
89         return;
90     }
91
92     GLint shader_type = 0;
93     glGetObjectParameterivARB(shaderObj, GL_OBJECT_SUBTYPE_ARB, &shader_type);
94     if (!shader_type) {
95         return;
96     }
97
98     GLint source_length = 0;
99     glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
100     if (!source_length) {
101         return;
102     }
103
104     GLcharARB *source = new GLcharARB[source_length];
105     GLsizei length = 0;
106     source[0] = 0;
107     glGetShaderSource(shaderObj, source_length, &length, source);
108
109     shaderMap[enumToString(shader_type)] += source;
110
111     delete [] source;
112 }
113
114
115 static inline void
116 dumpProgram(JSONWriter &json, GLint program)
117 {
118     GLint attached_shaders = 0;
119     glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
120     if (!attached_shaders) {
121         return;
122     }
123
124     ShaderMap shaderMap;
125
126     GLuint *shaders = new GLuint[attached_shaders];
127     GLsizei count = 0;
128     glGetAttachedShaders(program, attached_shaders, &count, shaders);
129     std::sort(shaders, shaders + count);
130     for (GLsizei i = 0; i < count; ++ i) {
131        getShaderSource(shaderMap, shaders[i]);
132     }
133     delete [] shaders;
134
135     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
136         json.beginMember(it->first);
137         json.writeString(it->second);
138         json.endMember();
139     }
140 }
141
142
143 static inline void
144 dumpProgramObj(JSONWriter &json, GLhandleARB programObj)
145 {
146     GLint attached_shaders = 0;
147     glGetObjectParameterivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
148     if (!attached_shaders) {
149         return;
150     }
151
152     ShaderMap shaderMap;
153
154     GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
155     GLsizei count = 0;
156     glGetAttachedObjectsARB(programObj, attached_shaders, &count, shaderObjs);
157     std::sort(shaderObjs, shaderObjs + count);
158     for (GLsizei i = 0; i < count; ++ i) {
159        getShaderObjSource(shaderMap, shaderObjs[i]);
160     }
161     delete [] shaderObjs;
162
163     for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
164         json.beginMember(it->first);
165         json.writeString(it->second);
166         json.endMember();
167     }
168 }
169
170 /**
171  * Built-in uniforms can't be queried through glGetUniform*.
172  */
173 static inline bool
174 isBuiltinUniform(const GLchar *name)
175 {
176     return name[0] == 'g' && name[1] == 'l' && name[2] == '_';
177 }
178
179 /*
180  * When fetching the uniform name of an array we usually get name[0]
181  * so we need to cut the trailing "[0]" in order to properly construct
182  * array names later. Otherwise we endup with stuff like
183  * uniformArray[0][0],
184  * uniformArray[0][1],
185  * instead of
186  * uniformArray[0],
187  * uniformArray[1].
188  */
189 static std::string
190 resolveUniformName(const GLchar *name,  GLint size)
191 {
192     std::string qualifiedName(name);
193     if (size > 1) {
194         std::string::size_type nameLength = qualifiedName.length();
195         static const char * const arrayStart = "[0]";
196         static const int arrayStartLen = 3;
197         if (qualifiedName.rfind(arrayStart) == (nameLength - arrayStartLen)) {
198             qualifiedName = qualifiedName.substr(0, nameLength - 3);
199         }
200     }
201     return qualifiedName;
202 }
203
204 static void
205 dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
206     GLenum elemType;
207     GLint numElems;
208     _gl_uniform_size(type, elemType, numElems);
209     if (elemType == GL_NONE) {
210         return;
211     }
212
213     GLfloat fvalues[4*4];
214     GLdouble dvalues[4*4];
215     GLint ivalues[4*4];
216     GLuint uivalues[4*4];
217
218     GLint i, j;
219
220     std::string qualifiedName = resolveUniformName(name, size);
221
222     for (i = 0; i < size; ++i) {
223         std::stringstream ss;
224         ss << qualifiedName;
225
226         if (size > 1) {
227             ss << '[' << i << ']';
228         }
229
230         std::string elemName = ss.str();
231
232         json.beginMember(elemName);
233
234         GLint location = glGetUniformLocation(program, elemName.c_str());
235         if (location >= 0) {
236             if (numElems > 1) {
237                 json.beginArray();
238             }
239
240             switch (elemType) {
241             case GL_FLOAT:
242                 glGetUniformfv(program, location, fvalues);
243                 for (j = 0; j < numElems; ++j) {
244                     json.writeNumber(fvalues[j]);
245                 }
246                 break;
247             case GL_DOUBLE:
248                 glGetUniformdv(program, location, dvalues);
249                 for (j = 0; j < numElems; ++j) {
250                     json.writeNumber(dvalues[j]);
251                 }
252                 break;
253             case GL_INT:
254                 glGetUniformiv(program, location, ivalues);
255                 for (j = 0; j < numElems; ++j) {
256                     json.writeNumber(ivalues[j]);
257                 }
258                 break;
259             case GL_UNSIGNED_INT:
260                 glGetUniformuiv(program, location, uivalues);
261                 for (j = 0; j < numElems; ++j) {
262                     json.writeNumber(uivalues[j]);
263                 }
264                 break;
265             case GL_BOOL:
266                 glGetUniformiv(program, location, ivalues);
267                 for (j = 0; j < numElems; ++j) {
268                     json.writeBool(ivalues[j]);
269                 }
270                 break;
271             default:
272                 assert(0);
273                 for (j = 0; j < numElems; ++j) {
274                     json.writeNull();
275                 }
276                 break;
277             }
278
279             if (numElems > 1) {
280                 json.endArray();
281             }
282         } else {
283             json.writeNull();
284         }
285
286         json.endMember();
287     }
288 }
289
290
291 static void
292 dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
293
294     GLenum elemType;
295     GLint numElems;
296     _gl_uniform_size(type, elemType, numElems);
297     if (elemType == GL_NONE) {
298         return;
299     }
300
301     GLfloat fvalues[4*4];
302     GLint ivalues[4*4];
303
304     GLint i, j;
305
306     std::string qualifiedName = resolveUniformName(name, size);
307
308     for (i = 0; i < size; ++i) {
309         std::stringstream ss;
310         ss << qualifiedName;
311
312         if (size > 1) {
313             ss << '[' << i << ']';
314         }
315
316         std::string elemName = ss.str();
317
318         json.beginMember(elemName);
319
320         GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
321         if (location >= 0) {
322             if (numElems > 1) {
323                 json.beginArray();
324             }
325
326             switch (elemType) {
327             case GL_DOUBLE:
328                 // glGetUniformdvARB does not exists
329             case GL_FLOAT:
330                 glGetUniformfvARB(programObj, location, fvalues);
331                 for (j = 0; j < numElems; ++j) {
332                     json.writeNumber(fvalues[j]);
333                 }
334                 break;
335             case GL_UNSIGNED_INT:
336                 // glGetUniformuivARB does not exists
337             case GL_INT:
338                 glGetUniformivARB(programObj, location, ivalues);
339                 for (j = 0; j < numElems; ++j) {
340                     json.writeNumber(ivalues[j]);
341                 }
342                 break;
343             case GL_BOOL:
344                 glGetUniformivARB(programObj, location, ivalues);
345                 for (j = 0; j < numElems; ++j) {
346                     json.writeBool(ivalues[j]);
347                 }
348                 break;
349             default:
350                 assert(0);
351                 for (j = 0; j < numElems; ++j) {
352                     json.writeNull();
353                 }
354                 break;
355             }
356
357             if (numElems > 1) {
358                 json.endArray();
359             }
360         } else {
361             json.writeNull();
362         }
363
364         json.endMember();
365     }
366 }
367
368
369 static inline void
370 dumpProgramUniforms(JSONWriter &json, GLint program)
371 {
372     GLint active_uniforms = 0;
373     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
374     if (!active_uniforms) {
375         return;
376     }
377
378     GLint active_uniform_max_length = 0;
379     glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
380     GLchar *name = new GLchar[active_uniform_max_length];
381     if (!name) {
382         return;
383     }
384
385     for (GLint index = 0; index < active_uniforms; ++index) {
386         GLsizei length = 0;
387         GLint size = 0;
388         GLenum type = GL_NONE;
389         glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
390
391         if (!isBuiltinUniform(name)) {
392             dumpUniform(json, program, size, type, name);
393         }
394     }
395
396     delete [] name;
397 }
398
399
400 static inline void
401 dumpProgramObjUniforms(JSONWriter &json, GLhandleARB programObj)
402 {
403     GLint active_uniforms = 0;
404     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
405     if (!active_uniforms) {
406         return;
407     }
408
409     GLint active_uniform_max_length = 0;
410     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
411     GLchar *name = new GLchar[active_uniform_max_length];
412     if (!name) {
413         return;
414     }
415
416     for (GLint index = 0; index < active_uniforms; ++index) {
417         GLsizei length = 0;
418         GLint size = 0;
419         GLenum type = GL_NONE;
420         glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
421
422         if (!isBuiltinUniform(name)) {
423             dumpUniformARB(json, programObj, size, type, name);
424         }
425     }
426
427     delete [] name;
428 }
429
430
431 static inline void
432 dumpArbProgram(JSONWriter &json, GLenum target)
433 {
434     if (!glIsEnabled(target)) {
435         return;
436     }
437
438     GLint program_length = 0;
439     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
440     if (!program_length) {
441         return;
442     }
443
444     GLchar *source = new GLchar[program_length + 1];
445     source[0] = 0;
446     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
447     source[program_length] = 0;
448
449     json.beginMember(enumToString(target));
450     json.writeString(source);
451     json.endMember();
452
453     delete [] source;
454 }
455
456
457 static inline void
458 dumpArbProgramUniforms(JSONWriter &json, GLenum target, const char *prefix)
459 {
460     if (!glIsEnabled(target)) {
461         return;
462     }
463
464     GLint program_parameters = 0;
465     glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
466     if (!program_parameters) {
467         return;
468     }
469
470     GLint max_program_local_parameters = 0;
471     glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
472     for (GLint index = 0; index < max_program_local_parameters; ++index) {
473         GLdouble params[4] = {0, 0, 0, 0};
474         glGetProgramLocalParameterdvARB(target, index, params);
475
476         if (!params[0] && !params[1] && !params[2] && !params[3]) {
477             continue;
478         }
479
480         char name[256];
481         snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index);
482
483         json.beginMember(name);
484         json.beginArray();
485         json.writeNumber(params[0]);
486         json.writeNumber(params[1]);
487         json.writeNumber(params[2]);
488         json.writeNumber(params[3]);
489         json.endArray();
490         json.endMember();
491     }
492
493     GLint max_program_env_parameters = 0;
494     glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
495     for (GLint index = 0; index < max_program_env_parameters; ++index) {
496         GLdouble params[4] = {0, 0, 0, 0};
497         glGetProgramEnvParameterdvARB(target, index, params);
498
499         if (!params[0] && !params[1] && !params[2] && !params[3]) {
500             continue;
501         }
502
503         char name[256];
504         snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index);
505
506         json.beginMember(name);
507         json.beginArray();
508         json.writeNumber(params[0]);
509         json.writeNumber(params[1]);
510         json.writeNumber(params[2]);
511         json.writeNumber(params[3]);
512         json.endArray();
513         json.endMember();
514     }
515 }
516
517
518 void
519 dumpShadersUniforms(JSONWriter &json, Context &context)
520 {
521     GLint program = 0;
522     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
523
524     GLhandleARB programObj = 0;
525     if (!context.ES && !program) {
526         programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
527     }
528
529     json.beginMember("shaders");
530     json.beginObject();
531     if (program) {
532         dumpProgram(json, program);
533     } else if (programObj) {
534         dumpProgramObj(json, programObj);
535     } else {
536         dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
537         dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
538     }
539     json.endObject();
540     json.endMember(); // shaders
541
542     json.beginMember("uniforms");
543     json.beginObject();
544     if (program) {
545         dumpProgramUniforms(json, program);
546     } else if (programObj) {
547         dumpProgramObjUniforms(json, programObj);
548     } else {
549         dumpArbProgramUniforms(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
550         dumpArbProgramUniforms(json, GL_VERTEX_PROGRAM_ARB, "vp.");
551     }
552     json.endObject();
553     json.endMember(); // uniforms
554 }
555
556
557 } /* namespace glstate */