]> git.tdb.fi Git - gldbg.git/commitdiff
Basic tracking and inspection of shaders and programs
authorMikko Rasa <tdb@tdb.fi>
Sat, 25 Aug 2012 11:23:26 +0000 (14:23 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 25 Aug 2012 11:53:57 +0000 (14:53 +0300)
flavors/gl/source/glstate.cpp
flavors/gl/source/glstate.h
flavors/gl/source/inspector.cpp
flavors/gl/source/inspector.h
flavors/gl/source/programstate.cpp [new file with mode: 0644]
flavors/gl/source/programstate.h [new file with mode: 0644]

index 0163c2f884605603170f60303ad9d856e611ea28..4f9eba5b9d2bd11d499e7b0920403ee00de19e5f 100644 (file)
@@ -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<GlState *>(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<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)
@@ -486,3 +578,119 @@ void GlState::glDrawRangeElements(void *user_data, GLenum, unsigned, unsigned, i
        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);
+}
index e6a3d9812f556f6b351799da28625e8978620402..e829103c7556884344bf2d80d9b6e0c99492c309 100644 (file)
@@ -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<unsigned, TextureState> TextureMap;
        typedef std::map<unsigned, BufferState> BufferMap;
+       typedef std::map<unsigned, ShaderState> ShaderMap;
+       typedef std::map<unsigned, ProgramState> ProgramMap;
 
 private:
        GlDecoder *decoder;
@@ -57,6 +60,8 @@ private:
        ArrayState color_array;
        ArrayState texcoord_arrays[8];
        std::map<unsigned, ArrayState> 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
index 150457eb8a87ff4750d1f3be6243242c3ac4ec35..f7d90f846802c72f97e63b1b6198d53127b70fd9 100644 (file)
@@ -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<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);
+               }
+       }
+}
index 562cdcf9d0c53d02aebb2aa5f813362a7c04ed1d..c4d3d06b56ce7773f35c208d26be0aecf8d90c43 100644 (file)
@@ -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 (file)
index 0000000..f0614c4
--- /dev/null
@@ -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 (file)
index 0000000..b255291
--- /dev/null
@@ -0,0 +1,36 @@
+#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