]> git.cworth.org Git - apitrace/blob - retrace/glstate_shaders.cpp
Don't abuse double-underscore prefix.
[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  * When fetching the uniform name of an array we usually get name[0]
172  * so we need to cut the trailing "[0]" in order to properly construct
173  * array names later. Otherwise we endup with stuff like
174  * uniformArray[0][0],
175  * uniformArray[0][1],
176  * instead of
177  * uniformArray[0],
178  * uniformArray[1].
179  */
180 static std::string
181 resolveUniformName(const GLchar *name,  GLint size)
182 {
183     std::string qualifiedName(name);
184     if (size > 1) {
185         std::string::size_type nameLength = qualifiedName.length();
186         static const char * const arrayStart = "[0]";
187         static const int arrayStartLen = 3;
188         if (qualifiedName.rfind(arrayStart) == (nameLength - arrayStartLen)) {
189             qualifiedName = qualifiedName.substr(0, nameLength - 3);
190         }
191     }
192     return qualifiedName;
193 }
194
195 static void
196 dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
197     GLenum elemType;
198     GLint numElems;
199     _gl_uniform_size(type, elemType, numElems);
200     if (elemType == GL_NONE) {
201         return;
202     }
203
204     GLfloat fvalues[4*4];
205     GLdouble dvalues[4*4];
206     GLint ivalues[4*4];
207     GLuint uivalues[4*4];
208
209     GLint i, j;
210
211     std::string qualifiedName = resolveUniformName(name, size);
212
213     for (i = 0; i < size; ++i) {
214         std::stringstream ss;
215         ss << qualifiedName;
216
217         if (size > 1) {
218             ss << '[' << i << ']';
219         }
220
221         std::string elemName = ss.str();
222
223         json.beginMember(elemName);
224
225         GLint location = glGetUniformLocation(program, elemName.c_str());
226
227         if (numElems > 1) {
228             json.beginArray();
229         }
230
231         switch (elemType) {
232         case GL_FLOAT:
233             glGetUniformfv(program, location, fvalues);
234             for (j = 0; j < numElems; ++j) {
235                 json.writeNumber(fvalues[j]);
236             }
237             break;
238         case GL_DOUBLE:
239             glGetUniformdv(program, location, dvalues);
240             for (j = 0; j < numElems; ++j) {
241                 json.writeNumber(dvalues[j]);
242             }
243             break;
244         case GL_INT:
245             glGetUniformiv(program, location, ivalues);
246             for (j = 0; j < numElems; ++j) {
247                 json.writeNumber(ivalues[j]);
248             }
249             break;
250         case GL_UNSIGNED_INT:
251             glGetUniformuiv(program, location, uivalues);
252             for (j = 0; j < numElems; ++j) {
253                 json.writeNumber(uivalues[j]);
254             }
255             break;
256         case GL_BOOL:
257             glGetUniformiv(program, location, ivalues);
258             for (j = 0; j < numElems; ++j) {
259                 json.writeBool(ivalues[j]);
260             }
261             break;
262         default:
263             assert(0);
264             break;
265         }
266
267         if (numElems > 1) {
268             json.endArray();
269         }
270
271         json.endMember();
272     }
273 }
274
275
276 static void
277 dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
278
279     GLenum elemType;
280     GLint numElems;
281     _gl_uniform_size(type, elemType, numElems);
282     if (elemType == GL_NONE) {
283         return;
284     }
285
286     GLfloat fvalues[4*4];
287     GLint ivalues[4*4];
288
289     GLint i, j;
290
291     std::string qualifiedName = resolveUniformName(name, size);
292
293     for (i = 0; i < size; ++i) {
294         std::stringstream ss;
295         ss << qualifiedName;
296
297         if (size > 1) {
298             ss << '[' << i << ']';
299         }
300
301         std::string elemName = ss.str();
302
303         json.beginMember(elemName);
304
305         GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
306
307         if (numElems > 1) {
308             json.beginArray();
309         }
310
311         switch (elemType) {
312         case GL_DOUBLE:
313             // glGetUniformdvARB does not exists
314         case GL_FLOAT:
315             glGetUniformfvARB(programObj, location, fvalues);
316             for (j = 0; j < numElems; ++j) {
317                 json.writeNumber(fvalues[j]);
318             }
319             break;
320         case GL_UNSIGNED_INT:
321             // glGetUniformuivARB does not exists
322         case GL_INT:
323             glGetUniformivARB(programObj, location, ivalues);
324             for (j = 0; j < numElems; ++j) {
325                 json.writeNumber(ivalues[j]);
326             }
327             break;
328         case GL_BOOL:
329             glGetUniformivARB(programObj, location, ivalues);
330             for (j = 0; j < numElems; ++j) {
331                 json.writeBool(ivalues[j]);
332             }
333             break;
334         default:
335             assert(0);
336             break;
337         }
338
339         if (numElems > 1) {
340             json.endArray();
341         }
342
343         json.endMember();
344     }
345 }
346
347
348 static inline void
349 dumpProgramUniforms(JSONWriter &json, GLint program)
350 {
351     GLint active_uniforms = 0;
352     glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
353     if (!active_uniforms) {
354         return;
355     }
356
357     GLint active_uniform_max_length = 0;
358     glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
359     GLchar *name = new GLchar[active_uniform_max_length];
360     if (!name) {
361         return;
362     }
363
364     for (GLint index = 0; index < active_uniforms; ++index) {
365         GLsizei length = 0;
366         GLint size = 0;
367         GLenum type = GL_NONE;
368         glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
369
370         dumpUniform(json, program, size, type, name);
371     }
372
373     delete [] name;
374 }
375
376
377 static inline void
378 dumpProgramObjUniforms(JSONWriter &json, GLhandleARB programObj)
379 {
380     GLint active_uniforms = 0;
381     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
382     if (!active_uniforms) {
383         return;
384     }
385
386     GLint active_uniform_max_length = 0;
387     glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
388     GLchar *name = new GLchar[active_uniform_max_length];
389     if (!name) {
390         return;
391     }
392
393     for (GLint index = 0; index < active_uniforms; ++index) {
394         GLsizei length = 0;
395         GLint size = 0;
396         GLenum type = GL_NONE;
397         glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
398
399         dumpUniformARB(json, programObj, size, type, name);
400     }
401
402     delete [] name;
403 }
404
405
406 static inline void
407 dumpArbProgram(JSONWriter &json, GLenum target)
408 {
409     if (!glIsEnabled(target)) {
410         return;
411     }
412
413     GLint program_length = 0;
414     glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
415     if (!program_length) {
416         return;
417     }
418
419     GLchar *source = new GLchar[program_length + 1];
420     source[0] = 0;
421     glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
422     source[program_length] = 0;
423
424     json.beginMember(enumToString(target));
425     json.writeString(source);
426     json.endMember();
427
428     delete [] source;
429 }
430
431
432 static inline void
433 dumpArbProgramUniforms(JSONWriter &json, GLenum target, const char *prefix)
434 {
435     if (!glIsEnabled(target)) {
436         return;
437     }
438
439     GLint program_parameters = 0;
440     glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
441     if (!program_parameters) {
442         return;
443     }
444
445     GLint max_program_local_parameters = 0;
446     glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
447     for (GLint index = 0; index < max_program_local_parameters; ++index) {
448         GLdouble params[4] = {0, 0, 0, 0};
449         glGetProgramLocalParameterdvARB(target, index, params);
450
451         if (!params[0] && !params[1] && !params[2] && !params[3]) {
452             continue;
453         }
454
455         char name[256];
456         snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index);
457
458         json.beginMember(name);
459         json.beginArray();
460         json.writeNumber(params[0]);
461         json.writeNumber(params[1]);
462         json.writeNumber(params[2]);
463         json.writeNumber(params[3]);
464         json.endArray();
465         json.endMember();
466     }
467
468     GLint max_program_env_parameters = 0;
469     glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
470     for (GLint index = 0; index < max_program_env_parameters; ++index) {
471         GLdouble params[4] = {0, 0, 0, 0};
472         glGetProgramEnvParameterdvARB(target, index, params);
473
474         if (!params[0] && !params[1] && !params[2] && !params[3]) {
475             continue;
476         }
477
478         char name[256];
479         snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index);
480
481         json.beginMember(name);
482         json.beginArray();
483         json.writeNumber(params[0]);
484         json.writeNumber(params[1]);
485         json.writeNumber(params[2]);
486         json.writeNumber(params[3]);
487         json.endArray();
488         json.endMember();
489     }
490 }
491
492
493 void
494 dumpShadersUniforms(JSONWriter &json, Context &context)
495 {
496     GLint program = 0;
497     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
498
499     GLhandleARB programObj = 0;
500     if (!context.ES && !program) {
501         programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
502     }
503
504     json.beginMember("shaders");
505     json.beginObject();
506     if (program) {
507         dumpProgram(json, program);
508     } else if (programObj) {
509         dumpProgramObj(json, programObj);
510     } else {
511         dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
512         dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
513     }
514     json.endObject();
515     json.endMember(); // shaders
516
517     json.beginMember("uniforms");
518     json.beginObject();
519     if (program) {
520         dumpProgramUniforms(json, program);
521     } else if (programObj) {
522         dumpProgramObjUniforms(json, programObj);
523     } else {
524         dumpArbProgramUniforms(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
525         dumpArbProgramUniforms(json, GL_VERTEX_PROGRAM_ARB, "vp.");
526     }
527     json.endObject();
528     json.endMember(); // uniforms
529 }
530
531
532 } /* namespace glstate */