From: Mikko Rasa Date: Sat, 25 Aug 2012 11:23:26 +0000 (+0300) Subject: Basic tracking and inspection of shaders and programs X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=90368e53a94c6fa68cb678a1a03a9da7bf0c7dd8;p=gldbg.git Basic tracking and inspection of shaders and programs --- diff --git a/flavors/gl/source/glstate.cpp b/flavors/gl/source/glstate.cpp index 0163c2f..4f9eba5 100644 --- a/flavors/gl/source/glstate.cpp +++ b/flavors/gl/source/glstate.cpp @@ -136,6 +136,27 @@ GlState::GlState(): decoder->glDrawElements = glDrawElements; decoder->glDrawRangeElements = glDrawRangeElements; decoder->glDrawRangeElementsEXT = glDrawRangeElements; + + decoder->glCreateShader = glCreateShader; + decoder->glCreateShaderObjectARB = glCreateShader; + decoder->glShaderSource = glShaderSource; + decoder->glShaderSourceARB = glShaderSource; + decoder->glCompileShader = glCompileShader; + decoder->glCompileShaderARB = glCompileShader; + decoder->glGetShaderiv = glGetShaderiv; + decoder->glGetShaderInfoLog = glGetShaderInfoLog; + decoder->glDeleteShader = glDeleteShader; + decoder->glCreateProgram = glCreateProgram; + decoder->glCreateProgramObjectARB = glCreateProgram; + decoder->glAttachShader = glAttachShader; + decoder->glAttachObjectARB = glAttachShader; + decoder->glLinkProgram = glLinkProgram; + decoder->glLinkProgramARB = glLinkProgram; + decoder->glGetProgramiv = glGetProgramiv; + decoder->glGetProgramInfoLog = glGetProgramInfoLog; + decoder->glDeleteObjectARB = glDeleteObjectARB; + decoder->glGetObjectParameterivARB = glGetObjectParameterivARB; + decoder->glGetInfoLogARB = glGetInfoLogARB; } GlState::~GlState() @@ -200,6 +221,22 @@ const ArrayState &GlState::get_attrib_array(unsigned index) const throw runtime_error("Unknown attribute array"); } +const ShaderState &GlState::get_shader(unsigned id) const +{ + ShaderMap::const_iterator i = shaders.find(id); + if(i==shaders.end()) + throw runtime_error("Unknown shader"); + return i->second; +} + +const ProgramState &GlState::get_program(unsigned id) const +{ + ProgramMap::const_iterator i = programs.find(id); + if(i==programs.end()) + throw runtime_error("Unknown program"); + return i->second; +} + const BufferState *GlState::get_current_buffer(GLenum target) const { return const_cast(this)->get_current_buffer(target); @@ -297,6 +334,61 @@ ArrayState &GlState::get_attrib_array(unsigned index) return array; } +ShaderState *GlState::get_shader(unsigned id, bool create) +{ + ShaderMap::iterator i = shaders.find(id); + if(i==shaders.end() && create) + { + i = shaders.insert(ShaderMap::value_type(id, ShaderState())).first; + i->second.id = id; + } + return (i!=shaders.end() ? &i->second : 0); +} + +void GlState::delete_shader(unsigned id) +{ + ShaderMap::iterator i = shaders.find(id); + if(i==shaders.end()) + return; + + for(ProgramMap::const_iterator j=programs.begin(); j!=programs.end(); ++j) + { + const vector &prog_shaders = j->second.shaders; + for(vector::const_iterator k=prog_shaders.begin(); k!=prog_shaders.end(); ++k) + if(*k==&i->second) + { + i->second.pending_delete = true; + return; + } + } + + shaders.erase(i); +} + +void GlState::delete_program(unsigned id) +{ + ProgramMap::iterator i = programs.find(id); + if(i==programs.end()) + return; + + vector prog_shaders = i->second.shaders; + programs.erase(i); + for(vector::const_iterator j=prog_shaders.begin(); j!=prog_shaders.end(); ++j) + if((*j)->pending_delete) + delete_shader((*j)->id); +} + +ProgramState *GlState::get_program(unsigned id, bool create) +{ + ProgramMap::iterator i = programs.find(id); + if(i==programs.end() && create) + { + i = programs.insert(ProgramMap::value_type(id, ProgramState())).first; + i->second.id = id; + } + return (i!=programs.end() ? &i->second : 0); +} + // Boolean state void GlState::glEnableClientState(void *user_data, GLenum state) @@ -486,3 +578,119 @@ void GlState::glDrawRangeElements(void *user_data, GLenum, unsigned, unsigned, i if(BufferState *buf = reinterpret_cast(user_data)->element_buffer) buf->content.update_elements(type); } + +// Shaders + +void GlState::glCreateShader(void *user_data, unsigned id, GLenum type) +{ + if(ShaderState *shader = reinterpret_cast(user_data)->get_shader(id, true)) + shader->type = type; +} + +void GlState::glShaderSource(void *user_data, unsigned id, int count, const char **str, const int *length) +{ + if(ShaderState *shader = reinterpret_cast(user_data)->get_shader(id, false)) + { + shader->source.clear(); + for(int i=0; isource.push_back(str[i]); + else + shader->source.push_back(string(str[i], length[i])); + } + shader->source_changed = true; + } +} + +void GlState::glCompileShader(void *user_data, unsigned id) +{ + if(ShaderState *shader = reinterpret_cast(user_data)->get_shader(id, false)) + shader->source_changed = false; +} + +void GlState::glGetShaderiv(void *user_data, unsigned id, GLenum pname, int *param) +{ + if(ShaderState *shader = reinterpret_cast(user_data)->get_shader(id, false)) + { + if(pname==GL_COMPILE_STATUS) + shader->compile_status = *param; + } +} + +void GlState::glGetShaderInfoLog(void *user_data, unsigned id, int, int *, char *log) +{ + if(ShaderState *shader = reinterpret_cast(user_data)->get_shader(id, false)) + shader->info_log = log; +} + +void GlState::glDeleteShader(void *user_data, unsigned id) +{ + reinterpret_cast(user_data)->delete_shader(id); +} + +void GlState::glCreateProgram(void *user_data, unsigned id) +{ + reinterpret_cast(user_data)->get_program(id, true); +} + +void GlState::glAttachShader(void *user_data, unsigned prog_id, unsigned shader_id) +{ + GlState *self = reinterpret_cast(user_data); + if(ProgramState *prog = self->get_program(prog_id, false)) + if(ShaderState *shader = self->get_shader(shader_id, false)) + prog->shaders.push_back(shader); +} + +void GlState::glLinkProgram(void *user_data, unsigned id) +{ + if(ProgramState *program = reinterpret_cast(user_data)->get_program(id, false)) + program->shaders_changed = false; +} + +void GlState::glGetProgramiv(void *user_data, unsigned id, GLenum pname, int *param) +{ + if(ProgramState *program = reinterpret_cast(user_data)->get_program(id, false)) + { + if(pname==GL_LINK_STATUS) + program->link_status = *param; + } +} + +void GlState::glGetProgramInfoLog(void *user_data, unsigned id, int, int *, char *log) +{ + if(ProgramState *program = reinterpret_cast(user_data)->get_program(id, false)) + program->info_log = log; +} + +void GlState::glDeleteProgram(void *user_data, unsigned id) +{ + reinterpret_cast(user_data)->delete_program(id); +} + +void GlState::glDeleteObjectARB(void *user_data, unsigned id) +{ + GlState *self = reinterpret_cast(user_data); + if(self->shaders.count(id)) + self->delete_shader(id); + else if(self->programs.count(id)) + self->delete_program(id); +} + +void GlState::glGetObjectParameterivARB(void *user_data, unsigned id, GLenum pname, int *param) +{ + GlState *self = reinterpret_cast(user_data); + if(self->shaders.count(id)) + glGetShaderiv(user_data, id, pname, param); + else if(self->programs.count(id)) + glGetProgramiv(user_data, id, pname, param); +} + +void GlState::glGetInfoLogARB(void *user_data, unsigned id, int bufsize, int *length, char *log) +{ + GlState *self = reinterpret_cast(user_data); + if(self->shaders.count(id)) + glGetShaderInfoLog(user_data, id, bufsize, length, log); + else if(self->programs.count(id)) + glGetProgramInfoLog(user_data, id, bufsize, length, log); +} diff --git a/flavors/gl/source/glstate.h b/flavors/gl/source/glstate.h index e6a3d98..e829103 100644 --- a/flavors/gl/source/glstate.h +++ b/flavors/gl/source/glstate.h @@ -6,6 +6,7 @@ #include "arraystate.h" #include "bufferstate.h" #include "gldecoder.h" +#include "programstate.h" #include "texturestate.h" struct Vector3 @@ -37,6 +38,8 @@ class GlState public: typedef std::map TextureMap; typedef std::map BufferMap; + typedef std::map ShaderMap; + typedef std::map ProgramMap; private: GlDecoder *decoder; @@ -57,6 +60,8 @@ private: ArrayState color_array; ArrayState texcoord_arrays[8]; std::map attrib_arrays; + ShaderMap shaders; + ProgramMap programs; public: GlState(); @@ -76,6 +81,10 @@ public: const ArrayState &get_array(GLenum) const; const ArrayState &get_texture_coord_array(unsigned) const; const ArrayState &get_attrib_array(unsigned) const; + const ShaderMap &get_shaders() const { return shaders; } + const ShaderState &get_shader(unsigned) const; + const ProgramMap &get_programs() const { return programs; } + const ProgramState &get_program(unsigned) const; private: bool &get_boolean_state(GLenum); TextureState *get_current_texture(GLenum); @@ -85,6 +94,10 @@ private: void set_current_texture(GLenum, unsigned); void set_current_buffer(GLenum, unsigned); ArrayState &get_attrib_array(unsigned); + ShaderState *get_shader(unsigned, bool); + void delete_shader(unsigned); + ProgramState *get_program(unsigned, bool); + void delete_program(unsigned); static void glEnableClientState(void *, GLenum); static void glDisableClientState(void *, GLenum); @@ -123,6 +136,22 @@ private: static void glDrawElements(void *, GLenum, int, GLenum, const void *); static void glDrawRangeElements(void *, GLenum, unsigned, unsigned, int, GLenum, const void *); + + static void glCreateShader(void *, unsigned, GLenum); + static void glShaderSource(void *, unsigned, int, const char **, const int *); + static void glCompileShader(void *, unsigned); + static void glGetShaderiv(void *, unsigned, GLenum, int *); + static void glGetShaderInfoLog(void *, unsigned, int, int *, char *); + static void glDeleteShader(void *, unsigned); + static void glCreateProgram(void *, unsigned); + static void glAttachShader(void *, unsigned, unsigned); + static void glLinkProgram(void *, unsigned); + static void glGetProgramiv(void *, unsigned, GLenum, int *); + static void glGetProgramInfoLog(void *, unsigned, int, int *, char *); + static void glDeleteProgram(void *, unsigned); + static void glDeleteObjectARB(void *, unsigned); + static void glGetObjectParameterivARB(void *, unsigned, GLenum, int *); + static void glGetInfoLogARB(void *, unsigned, int, int *, char *); }; #endif diff --git a/flavors/gl/source/inspector.cpp b/flavors/gl/source/inspector.cpp index 150457e..f7d90f8 100644 --- a/flavors/gl/source/inspector.cpp +++ b/flavors/gl/source/inspector.cpp @@ -32,6 +32,20 @@ Inspector::Inspector(GlDbg &dbg) " Lists buffer objects\n\n" "buffer ID\n" " Print information about a buffer object\n"); + + cmd_interp.register_command("shader", this, &Inspector::cmd_shader) + .set_help("Inspect shader object state", + "shader\n" + " List shader objects\n\n" + "shader ID\n" + " Print information about a shader object\n"); + + cmd_interp.register_command("program", this, &Inspector::cmd_program) + .set_help("Inspect program object state", + "program\n" + " List program objects\n\n" + "program ID\n" + " Print information about a program object\n"); } void Inspector::decode(const char *data, unsigned len) @@ -39,6 +53,22 @@ void Inspector::decode(const char *data, unsigned len) state.decode(data, len); } +void Inspector::print_indented(const string &str, unsigned indent) +{ + string spaces(indent, ' '); + string::size_type start = 0; + while(1) + { + string::size_type newline = str.find('\n', start); + string line = str.substr(start, newline-start); + if(newline!=string::npos || !line.empty()) + printf("%s%s\n", spaces.c_str(), line.c_str()); + if(newline==string::npos) + break; + start = newline+1; + } +} + void Inspector::cmd_state(const string &args) { const GlState &glstate = state; @@ -266,3 +296,86 @@ void Inspector::cmd_buffer(const string &args) } } } + +void Inspector::cmd_shader(const string &args) +{ + if(args.empty()) + { + const GlState::ShaderMap &shaders = state.get_shaders(); + printf("%d shader objects:\n", shaders.size()); + for(GlState::ShaderMap::const_iterator i=shaders.begin(); i!=shaders.end(); ++i) + { + string descr = i->second.describe(); + printf(" %d: %s\n", i->first, descr.c_str()); + } + } + else + { + char *end = 0; + unsigned id = strtoul(args.c_str(), &end, 0); + if(end && *end) + throw runtime_error("Invalid shader id"); + + const ShaderState &shader = state.get_shader(id); + printf("Shader %d:\n", shader.id); + printf(" Type: %s\n", describe_enum(shader.type, "")); + unsigned n = 0; + for(vector::const_iterator i=shader.source.begin(); i!=shader.source.end(); ++i, ++n) + { + printf(" Source string %d:\n", n); + print_indented(*i, 4); + } + if(shader.source_changed) + printf(" Source changed since last compile\n"); + printf(" Compile status: %d\n", shader.compile_status); + if(shader.info_log.empty()) + printf(" Info log is empty\n"); + else + { + printf(" Info log:\n"); + print_indented(shader.info_log, 4); + } + if(shader.pending_delete) + printf(" Pending deletion\n"); + } +} + +void Inspector::cmd_program(const std::string &args) +{ + if(args.empty()) + { + const GlState::ProgramMap &programs = state.get_programs(); + printf("%d program objects:\n", programs.size()); + for(GlState::ProgramMap::const_iterator i=programs.begin(); i!=programs.end(); ++i) + { + string descr = i->second.describe(); + printf(" %d: %s\n", i->first, descr.c_str()); + } + } + else + { + char *end = 0; + unsigned id = strtoul(args.c_str(), &end, 0); + if(end && *end) + throw runtime_error("Invalid program id"); + + const ProgramState &program = state.get_program(id); + printf("Program %d:\n", program.id); + printf(" Attached shaders:\n"); + for(vector::const_iterator i=program.shaders.begin(); i!=program.shaders.end(); ++i) + { + string descr = (*i)->describe(); + printf(" %d: %s\n", (*i)->id, descr.c_str()); + } + if(program.shaders_changed) + printf(" Shaders changed since last compile\n"); + printf(" Link status: %d\n", program.link_status); + if(program.info_log.empty()) + printf(" Info log is empty\n"); + else + { + printf(" Info log:\n"); + print_indented(program.info_log, 4); + } + } +} diff --git a/flavors/gl/source/inspector.h b/flavors/gl/source/inspector.h index 562cdcf..c4d3d06 100644 --- a/flavors/gl/source/inspector.h +++ b/flavors/gl/source/inspector.h @@ -14,9 +14,13 @@ public: virtual void decode(const char *, unsigned); private: + void print_indented(const std::string &, unsigned); + void cmd_state(const std::string &); void cmd_texture(const std::string &); void cmd_buffer(const std::string &); + void cmd_shader(const std::string &); + void cmd_program(const std::string &); }; #endif diff --git a/flavors/gl/source/programstate.cpp b/flavors/gl/source/programstate.cpp new file mode 100644 index 0000000..f0614c4 --- /dev/null +++ b/flavors/gl/source/programstate.cpp @@ -0,0 +1,29 @@ +#include "enums.h" +#include "programstate.h" +#include "strformat.h" + +using namespace std; + +ShaderState::ShaderState(): + id(0), + source_changed(false), + compile_status(false), + pending_delete(false) +{ } + +string ShaderState::describe() const +{ + return describe_enum(type, ""); +} + + +ProgramState::ProgramState(): + id(0), + shaders_changed(false), + link_status(false) +{ } + +string ProgramState::describe() const +{ + return strformat("%d shaders", shaders.size()); +} diff --git a/flavors/gl/source/programstate.h b/flavors/gl/source/programstate.h new file mode 100644 index 0000000..b255291 --- /dev/null +++ b/flavors/gl/source/programstate.h @@ -0,0 +1,36 @@ +#ifndef PROGRAMSTATE_H_ +#define PROGRAMSTATE_H_ + +#include +#include +#include "opengl.h" + +struct ShaderState +{ + unsigned id; + GLenum type; + std::vector source; + bool source_changed; + bool compile_status; + std::string info_log; + bool pending_delete; + + ShaderState(); + + std::string describe() const; +}; + +struct ProgramState +{ + unsigned id; + std::vector shaders; + bool shaders_changed; + bool link_status; + std::string info_log; + + ProgramState(); + + std::string describe() const; +}; + +#endif