1 /**************************************************************************
3 * Copyright 2011 Jose Fonseca
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 **************************************************************************/
37 #include "glstate.hpp"
38 #include "glstate_internal.hpp"
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;
50 getShaderSource(ShaderMap &shaderMap, GLuint shader)
56 GLint shader_type = 0;
57 glGetShaderiv(shader, GL_SHADER_TYPE, &shader_type);
62 GLint source_length = 0;
63 glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &source_length);
68 GLchar *source = new GLchar[source_length];
71 glGetShaderSource(shader, source_length, &length, source);
73 shaderMap[enumToString(shader_type)] += source;
80 getShaderObjSource(ShaderMap &shaderMap, GLhandleARB shaderObj)
86 GLint object_type = 0;
87 glGetObjectParameterivARB(shaderObj, GL_OBJECT_TYPE_ARB, &object_type);
88 if (object_type != GL_SHADER_OBJECT_ARB) {
92 GLint shader_type = 0;
93 glGetObjectParameterivARB(shaderObj, GL_OBJECT_SUBTYPE_ARB, &shader_type);
98 GLint source_length = 0;
99 glGetObjectParameterivARB(shaderObj, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &source_length);
100 if (!source_length) {
104 GLcharARB *source = new GLcharARB[source_length];
107 glGetShaderSource(shaderObj, source_length, &length, source);
109 shaderMap[enumToString(shader_type)] += source;
116 dumpProgram(JSONWriter &json, GLint program)
118 GLint attached_shaders = 0;
119 glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
120 if (!attached_shaders) {
126 GLuint *shaders = new GLuint[attached_shaders];
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]);
135 for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
136 json.beginMember(it->first);
137 json.writeString(it->second);
144 dumpProgramObj(JSONWriter &json, GLhandleARB programObj)
146 GLint attached_shaders = 0;
147 glGetObjectParameterivARB(programObj, GL_OBJECT_ATTACHED_OBJECTS_ARB, &attached_shaders);
148 if (!attached_shaders) {
154 GLhandleARB *shaderObjs = new GLhandleARB[attached_shaders];
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]);
161 delete [] shaderObjs;
163 for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
164 json.beginMember(it->first);
165 json.writeString(it->second);
171 * Built-in uniforms can't be queried through glGetUniform*.
174 isBuiltinUniform(const GLchar *name)
176 return name[0] == 'g' && name[1] == 'l' && name[2] == '_';
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],
190 resolveUniformName(const GLchar *name, GLint size)
192 std::string qualifiedName(name);
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);
201 return qualifiedName;
206 dumpUniformValues(JSONWriter &json, GLenum type, const void *values, GLint matrix_stride = 0, GLboolean is_row_major = GL_FALSE) {
208 GLint numCols, numRows;
209 _gl_uniform_size(type, elemType, numCols, numRows);
210 if (!numCols || !numRows) {
214 size_t elemSize = _gl_type_size(elemType);
216 GLint row_stride = 0;
217 GLint col_stride = 0;
219 row_stride = elemSize;
220 col_stride = matrix_stride ? matrix_stride : numRows * elemSize;
222 col_stride = elemSize;
223 row_stride = matrix_stride ? matrix_stride : numCols * elemSize;
230 for (GLint row = 0; row < numRows; ++row) {
235 for (GLint col = 0; col < numCols; ++col) {
237 const GLbyte *rawvalue;
238 const GLfloat *fvalue;
239 const GLdouble *dvalue;
241 const GLuint *uivalue;
244 u.rawvalue = (const GLbyte *)values + row*row_stride + col*col_stride;
248 json.writeNumber(*u.fvalue);
251 json.writeNumber(*u.dvalue);
254 json.writeNumber(*u.ivalue);
256 case GL_UNSIGNED_INT:
257 json.writeNumber(*u.uivalue);
260 json.writeBool(*u.uivalue);
281 * Dump an uniform that belows to an uniform block.
284 dumpUniformBlock(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name, GLuint index, GLuint block_index) {
287 GLint array_stride = 0;
288 GLint matrix_stride = 0;
289 GLint is_row_major = GL_FALSE;
290 glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_OFFSET, &offset);
291 glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_ARRAY_STRIDE, &array_stride);
292 glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_MATRIX_STRIDE, &matrix_stride);
293 glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_IS_ROW_MAJOR, &is_row_major);
296 glGetActiveUniformBlockiv(program, block_index, GL_UNIFORM_BLOCK_BINDING, &slot);
302 GLint active_uniform_block_max_name_length = 0;
303 glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &active_uniform_block_max_name_length);
305 GLchar* block_name = new GLchar[active_uniform_block_max_name_length];
307 GLint block_data_size = 0;
308 glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_DATA_SIZE, &block_data_size);
311 glGetActiveUniformBlockName(program, index, active_uniform_block_max_name_length, &length, block_name);
314 << "uniform `" << name << "`, size " << size << ", type " << enumToString(type) << "\n"
315 << " block " << block_index << ", name `" << block_name << "`, size " << block_data_size << "; binding " << slot << "; \n"
316 << " offset " << offset << ", array stride " << array_stride << ", matrix stride " << matrix_stride << ", row_major " << is_row_major << "\n"
323 glGetIntegeri_v(GL_UNIFORM_BUFFER_BINDING, slot, &ubo);
325 GLint previous_ubo = 0;
326 glGetIntegerv(GL_UNIFORM_BUFFER_BINDING, &previous_ubo);
328 glBindBuffer(GL_UNIFORM_BUFFER, ubo);
330 const GLbyte *raw_data = (const GLbyte *)glMapBuffer(GL_UNIFORM_BUFFER, GL_READ_ONLY);
332 std::string qualifiedName = resolveUniformName(name, size);
334 for (GLint i = 0; i < size; ++i) {
335 std::stringstream ss;
339 ss << '[' << i << ']';
342 std::string elemName = ss.str();
344 json.beginMember(elemName);
346 const GLbyte *row = raw_data + offset + array_stride*i;
348 dumpUniformValues(json, type, row, matrix_stride, is_row_major);
353 glUnmapBuffer(GL_UNIFORM_BUFFER);
356 glBindBuffer(GL_UNIFORM_BUFFER, previous_ubo);
361 dumpUniform(JSONWriter &json, GLint program, GLint size, GLenum type, const GLchar *name) {
363 GLint numCols, numRows;
364 _gl_uniform_size(type, elemType, numCols, numRows);
365 if (elemType == GL_NONE) {
370 GLfloat fvalues[4*4];
371 GLdouble dvalues[4*4];
373 GLuint uivalues[4*4];
378 std::string qualifiedName = resolveUniformName(name, size);
380 for (i = 0; i < size; ++i) {
381 std::stringstream ss;
385 ss << '[' << i << ']';
388 std::string elemName = ss.str();
390 GLint location = glGetUniformLocation(program, elemName.c_str());
391 assert(location != -1);
392 if (location == -1) {
396 json.beginMember(elemName);
400 glGetUniformfv(program, location, u.fvalues);
403 glGetUniformdv(program, location, u.dvalues);
406 glGetUniformiv(program, location, u.ivalues);
408 case GL_UNSIGNED_INT:
409 glGetUniformuiv(program, location, u.uivalues);
412 glGetUniformiv(program, location, u.ivalues);
419 dumpUniformValues(json, type, &u);
427 dumpUniformARB(JSONWriter &json, GLhandleARB programObj, GLint size, GLenum type, const GLchar *name) {
429 GLint numCols, numRows;
430 _gl_uniform_size(type, elemType, numCols, numRows);
431 GLint numElems = numCols * numRows;
432 if (elemType == GL_NONE) {
436 GLfloat fvalues[4*4];
438 GLdouble dvalues[4*4];
439 GLfloat fvalues[4*4];
445 std::string qualifiedName = resolveUniformName(name, size);
447 for (i = 0; i < size; ++i) {
448 std::stringstream ss;
452 ss << '[' << i << ']';
455 std::string elemName = ss.str();
457 json.beginMember(elemName);
459 GLint location = glGetUniformLocationARB(programObj, elemName.c_str());
460 if (location == -1) {
466 // glGetUniformdvARB does not exists
467 glGetUniformfvARB(programObj, location, fvalues);
468 for (j = 0; j < numElems; ++j) {
469 u.dvalues[j] = fvalues[j];
473 glGetUniformfvARB(programObj, location, fvalues);
475 case GL_UNSIGNED_INT:
476 // glGetUniformuivARB does not exists
478 glGetUniformivARB(programObj, location, u.ivalues);
481 glGetUniformivARB(programObj, location, u.ivalues);
488 dumpUniformValues(json, type, &u);
496 dumpProgramUniforms(JSONWriter &json, GLint program)
498 GLint active_uniforms = 0;
499 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniforms);
500 if (!active_uniforms) {
504 GLint active_uniform_max_length = 0;
505 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length);
506 GLchar *name = new GLchar[active_uniform_max_length];
511 for (GLuint index = 0; (GLint)index < active_uniforms; ++index) {
514 GLenum type = GL_NONE;
515 glGetActiveUniform(program, index, active_uniform_max_length, &length, &size, &type, name);
517 if (isBuiltinUniform(name)) {
521 GLint location = glGetUniformLocation(program, name);
522 if (location != -1) {
523 dumpUniform(json, program, size, type, name);
527 GLint block_index = -1;
528 glGetActiveUniformsiv(program, 1, &index, GL_UNIFORM_BLOCK_INDEX, &block_index);
529 if (block_index != -1) {
530 dumpUniformBlock(json, program, size, type, name, index, block_index);
542 dumpProgramObjUniforms(JSONWriter &json, GLhandleARB programObj)
544 GLint active_uniforms = 0;
545 glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORMS_ARB, &active_uniforms);
546 if (!active_uniforms) {
550 GLint active_uniform_max_length = 0;
551 glGetObjectParameterivARB(programObj, GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB, &active_uniform_max_length);
552 GLchar *name = new GLchar[active_uniform_max_length];
557 for (GLint index = 0; index < active_uniforms; ++index) {
560 GLenum type = GL_NONE;
561 glGetActiveUniformARB(programObj, index, active_uniform_max_length, &length, &size, &type, name);
563 if (isBuiltinUniform(name)) {
567 dumpUniformARB(json, programObj, size, type, name);
575 dumpArbProgram(JSONWriter &json, GLenum target)
577 if (!glIsEnabled(target)) {
581 GLint program_length = 0;
582 glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &program_length);
583 if (!program_length) {
587 GLchar *source = new GLchar[program_length + 1];
589 glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, source);
590 source[program_length] = 0;
592 json.beginMember(enumToString(target));
593 json.writeString(source);
601 dumpArbProgramUniforms(JSONWriter &json, GLenum target, const char *prefix)
603 if (!glIsEnabled(target)) {
607 GLint program_parameters = 0;
608 glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters);
609 if (!program_parameters) {
613 GLint max_program_local_parameters = 0;
614 glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters);
615 for (GLint index = 0; index < max_program_local_parameters; ++index) {
616 GLdouble params[4] = {0, 0, 0, 0};
617 glGetProgramLocalParameterdvARB(target, index, params);
619 if (!params[0] && !params[1] && !params[2] && !params[3]) {
624 snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index);
626 json.beginMember(name);
628 json.writeNumber(params[0]);
629 json.writeNumber(params[1]);
630 json.writeNumber(params[2]);
631 json.writeNumber(params[3]);
636 GLint max_program_env_parameters = 0;
637 glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters);
638 for (GLint index = 0; index < max_program_env_parameters; ++index) {
639 GLdouble params[4] = {0, 0, 0, 0};
640 glGetProgramEnvParameterdvARB(target, index, params);
642 if (!params[0] && !params[1] && !params[2] && !params[3]) {
647 snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index);
649 json.beginMember(name);
651 json.writeNumber(params[0]);
652 json.writeNumber(params[1]);
653 json.writeNumber(params[2]);
654 json.writeNumber(params[3]);
661 dumpProgramUniformsStage(JSONWriter &json, GLint program, const char *stage)
664 json.beginMember(stage);
666 dumpProgramUniforms(json, program);
673 dumpShadersUniforms(JSONWriter &json, Context &context)
676 GLint vertex_program = 0;
677 GLint fragment_program = 0;
678 GLint geometry_program = 0;
679 GLint tess_control_program = 0;
680 GLint tess_evaluation_program = 0;
683 glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &pipeline);
685 glGetProgramPipelineiv(pipeline, GL_VERTEX_SHADER, &vertex_program);
686 glGetProgramPipelineiv(pipeline, GL_FRAGMENT_SHADER, &fragment_program);
687 glGetProgramPipelineiv(pipeline, GL_GEOMETRY_SHADER, &geometry_program);
688 glGetProgramPipelineiv(pipeline, GL_TESS_CONTROL_SHADER, &tess_control_program);
689 glGetProgramPipelineiv(pipeline, GL_TESS_EVALUATION_SHADER, &tess_evaluation_program);
694 GLhandleARB programObj = 0;
696 glGetIntegerv(GL_CURRENT_PROGRAM, &program);
697 if (!context.ES && !program) {
698 programObj = glGetHandleARB(GL_PROGRAM_OBJECT_ARB);
702 json.beginMember("shaders");
705 dumpProgram(json, vertex_program);
706 dumpProgram(json, fragment_program);
707 dumpProgram(json, geometry_program);
708 dumpProgram(json, tess_control_program);
709 dumpProgram(json, tess_evaluation_program);
710 } else if (program) {
711 dumpProgram(json, program);
712 } else if (programObj) {
713 dumpProgramObj(json, programObj);
715 dumpArbProgram(json, GL_FRAGMENT_PROGRAM_ARB);
716 dumpArbProgram(json, GL_VERTEX_PROGRAM_ARB);
719 json.endMember(); // shaders
721 json.beginMember("uniforms");
724 dumpProgramUniformsStage(json, vertex_program, "GL_VERTEX_SHADER");
725 dumpProgramUniformsStage(json, fragment_program, "GL_FRAGMENT_SHADER");
726 dumpProgramUniformsStage(json, geometry_program, "GL_GEOMETRY_SHADER");
727 dumpProgramUniformsStage(json, tess_control_program, "GL_TESS_CONTROL_SHADER");
728 dumpProgramUniformsStage(json, tess_evaluation_program, "GL_TESS_EVALUATION_SHADER");
729 } else if (program) {
730 dumpProgramUniforms(json, program);
731 } else if (programObj) {
732 dumpProgramObjUniforms(json, programObj);
734 dumpArbProgramUniforms(json, GL_FRAGMENT_PROGRAM_ARB, "fp.");
735 dumpArbProgramUniforms(json, GL_VERTEX_PROGRAM_ARB, "vp.");
738 json.endMember(); // uniforms
742 } /* namespace glstate */