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()
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<GlState *>(this)->get_current_buffer(target);
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<ShaderState *> &prog_shaders = j->second.shaders;
+ for(vector<ShaderState *>::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<ShaderState *> prog_shaders = i->second.shaders;
+ programs.erase(i);
+ for(vector<ShaderState *>::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)
if(BufferState *buf = reinterpret_cast<GlState *>(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<GlState *>(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<GlState *>(user_data)->get_shader(id, false))
+ {
+ shader->source.clear();
+ for(int i=0; i<count; ++i)
+ {
+ if(!length || length[i]<0)
+ shader->source.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<GlState *>(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<GlState *>(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<GlState *>(user_data)->get_shader(id, false))
+ shader->info_log = log;
+}
+
+void GlState::glDeleteShader(void *user_data, unsigned id)
+{
+ reinterpret_cast<GlState *>(user_data)->delete_shader(id);
+}
+
+void GlState::glCreateProgram(void *user_data, unsigned id)
+{
+ reinterpret_cast<GlState *>(user_data)->get_program(id, true);
+}
+
+void GlState::glAttachShader(void *user_data, unsigned prog_id, unsigned shader_id)
+{
+ GlState *self = reinterpret_cast<GlState *>(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<GlState *>(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<GlState *>(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<GlState *>(user_data)->get_program(id, false))
+ program->info_log = log;
+}
+
+void GlState::glDeleteProgram(void *user_data, unsigned id)
+{
+ reinterpret_cast<GlState *>(user_data)->delete_program(id);
+}
+
+void GlState::glDeleteObjectARB(void *user_data, unsigned id)
+{
+ GlState *self = reinterpret_cast<GlState *>(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<GlState *>(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<GlState *>(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);
+}
#include "arraystate.h"
#include "bufferstate.h"
#include "gldecoder.h"
+#include "programstate.h"
#include "texturestate.h"
struct Vector3
public:
typedef std::map<unsigned, TextureState> TextureMap;
typedef std::map<unsigned, BufferState> BufferMap;
+ typedef std::map<unsigned, ShaderState> ShaderMap;
+ typedef std::map<unsigned, ProgramState> ProgramMap;
private:
GlDecoder *decoder;
ArrayState color_array;
ArrayState texcoord_arrays[8];
std::map<unsigned, ArrayState> attrib_arrays;
+ ShaderMap shaders;
+ ProgramMap programs;
public:
GlState();
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);
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);
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
" 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)
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;
}
}
}
+
+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<string>::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<ShaderState *>::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);
+ }
+ }
+}
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
--- /dev/null
+#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());
+}
--- /dev/null
+#ifndef PROGRAMSTATE_H_
+#define PROGRAMSTATE_H_
+
+#include <string>
+#include <vector>
+#include "opengl.h"
+
+struct ShaderState
+{
+ unsigned id;
+ GLenum type;
+ std::vector<std::string> 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<ShaderState *> shaders;
+ bool shaders_changed;
+ bool link_status;
+ std::string info_log;
+
+ ProgramState();
+
+ std::string describe() const;
+};
+
+#endif