# $Id$
-CFLAGS = -Igensrc -ggdb -Wall -Wextra -Werror
-CXXFLAGS = -Igensrc -ggdb -Wall -Wextra -Werror
+CFLAGS = -Igensrc -ggdb -Wall -Wextra
+CXXFLAGS = -Igensrc -ggdb -Wall -Wextra
PACKAGES_gldbg = mspcore mspstrings mspio mspfs
CXXFLAGS_gldbg = $(shell pkg-config --cflags $(PACKAGES_gldbg))
gldump: source/gldecoder.o source/gldump.o source/glprint.o source/enums.o source/arraysize.o source/tmpalloc.o
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
-gldbg: source/gldbg.o source/gldecoder.o source/glprint.o source/commandinterpreter.o source/tracer.o source/process.o source/enums.o source/arraysize.o source/tmpalloc.o source/glstate.o source/texturestate.o source/bufferstate.o
+gldbg: source/gldbg.o source/gldecoder.o source/glprint.o source/commandinterpreter.o source/tracer.o source/process.o source/enums.o source/arraysize.o source/tmpalloc.o source/glstate.o source/texturestate.o source/bufferstate.o source/profiler.o
$(CXX) -o $@ $^ $(LIBS_gldbg) $(LIBS) $(LDFLAGS)
source/glwrap.o: source/functions.h gensrc/functions.enum gensrc/glwrap.funcs
source/gldump.o: source/gldecoder.h gensrc/gldecoder.struct source/glprint.h
source/glprint.o: source/arraysize.h gensrc/glprint.funcs gensrc/gldecoder.struct
source/enums.o: gensrc/enums.table
-source/gldbg.o: source/gldbg.h source/gldecoder.h source/tracer.h source/commandinterpreter.h source/glstate.h
+source/gldbg.o: source/gldbg.h source/gldecoder.h source/tracer.h source/commandinterpreter.h source/glstate.h source/profiler.h
source/tracer.o: source/gldecoder.h source/glprint.h
source/commandinterpreter.o: source/gldbg.h source/glstate.h
source/process.o: source/process.h
"trace end\n"
" Terminate trace, closing the file.\n");
+ commands["profile"] = Command(&CommandInterpreter::cmd_profile,
+ "Profiles GL usage and performance",
+ "profile {on|off}\n"
+ " Enables or disables profiling\n");
+
commands["state"] = Command(&CommandInterpreter::cmd_state,
"Inspects general GL state",
"state vertex\n"
}
}
+void CommandInterpreter::cmd_profile(const string &args)
+{
+ Profiler &profiler = gldbg.get_profiler();
+ if(args.empty() || args=="on")
+ profiler.enable();
+ else if(args=="off")
+ profiler.disable();
+ else
+ throw InvalidParameterValue("Invalid argument");
+}
+
void CommandInterpreter::cmd_state(const string &args)
{
const GlState &glstate = gldbg.get_glstate();
void cmd_kill(const std::string &);
void cmd_exit(const std::string &);
void cmd_trace(const std::string &);
+ void cmd_profile(const std::string &);
void cmd_state(const std::string &);
void cmd_texture(const std::string &);
void cmd_buffer(const std::string &);
break;
tracer.decode(data, len);
glstate.decode(data, len);
+ profiler.decode(data, len);
buf_offset += size;
}
if(buf_offset>8192)
#include "commandinterpreter.h"
#include "glstate.h"
#include "process.h"
+#include "profiler.h"
#include "tracer.h"
class GlDbg: public Msp::Application
bool flushing;
Tracer tracer;
GlState glstate;
+ Profiler profiler;
bool got_sigchld;
static RegApp<GlDbg> reg;
int main();
Tracer &get_tracer() { return tracer; }
GlState &get_glstate() { return glstate; }
+ Profiler &get_profiler() { return profiler; }
Process &get_process() { return process; }
void launch();
void quit(bool);
static void *libgl = NULL;
if(!libgl)
{
- libgl = dlopen("libGL.so", RTLD_NOW);
+ const char *libgl_name = getenv("GLWRAP_LIBGL");
+ if(!libgl_name)
+ libgl_name = "libGL.so";
+ libgl = dlopen(libgl_name, RTLD_NOW);
if(!libgl)
{
- fprintf(stderr, "Could not open libGL: %s\n", dlerror());
+ fprintf(stderr, "Could not open %s: %s\n", libgl_name, dlerror());
abort();
}
}
void (*glXGetProcAddress(const GLubyte *procname))(void)
{
- void *handle = dlopen(NULL, RTLD_LAZY);
- void (*ret)() = dlsym(handle, (const char *)procname);
+ void *handle = 0;
+ void (*ret)() = 0;
+
+ if(glsym((const char *)procname))
+ {
+ handle = dlopen(NULL, RTLD_LAZY);
+ ret = dlsym(handle, (const char *)procname);
+ }
+
begin_packet(FUNC_GLXGETPROCADDRESS);
write_pointer(ret);
- write_string(procname);
+ write_string((const char *)procname);
send_packet();
+
return ret;
}
--- /dev/null
+#include <msp/io/print.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#include "profiler.h"
+
+using namespace Msp;
+
+Profiler::Profiler():
+ decoder(gldecoder_new(this, 0)),
+ enabled(false)
+{
+ decoder->glDrawArrays = glDrawArrays;
+ decoder->glDrawElements = glDrawElements;
+ decoder->glDrawRangeElements = glDrawRangeElements;
+ decoder->glXSwapBuffers = glXSwapBuffers;
+}
+
+void Profiler::enable()
+{
+ enabled = true;
+ frames = 0;
+ draw_calls = 0;
+ vertices = 0;
+ triangles = 0;
+ start = Msp::Time::now();
+}
+
+void Profiler::disable()
+{
+ enabled = false;
+}
+
+int Profiler::decode(const char *data, unsigned len)
+{
+ if(enabled)
+ return gldecoder_decode(decoder, data, len);
+ else
+ return 0;
+}
+
+void Profiler::glDrawArrays(void *user_data, GLenum mode, int, int count)
+{
+ glDrawElements(user_data, mode, count, 0, 0);
+}
+
+void Profiler::glDrawElements(void *user_data, GLenum mode, int count, GLenum, const void *)
+{
+ Profiler *self = reinterpret_cast<Profiler *>(user_data);
+
+ ++self->draw_calls;
+ self->vertices += count;
+
+ switch(mode)
+ {
+ case GL_TRIANGLES:
+ self->triangles += count/3;
+ break;
+ case GL_TRIANGLE_STRIP:
+ case GL_TRIANGLE_FAN:
+ if(count>2)
+ self->triangles += count-2;
+ break;
+ case GL_QUADS:
+ self->triangles += count/4;
+ break;
+ case GL_QUAD_STRIP:
+ if(count>3)
+ self->triangles += count/2-1;
+ break;
+ }
+}
+
+void Profiler::glDrawRangeElements(void *user_data, GLenum mode, unsigned, unsigned, int count, GLenum type, const void *data)
+{
+ glDrawElements(user_data, mode, count, type, data);
+}
+
+void Profiler::glXSwapBuffers(void *user_data, Display *, GLXDrawable)
+{
+ Profiler *self = reinterpret_cast<Profiler *>(user_data);
+
+ IO::print("%d draw calls, %d vertices, %d triangles\n", self->draw_calls, self->vertices, self->triangles);
+ self->draw_calls = 0;
+ self->vertices = 0;
+ self->triangles = 0;
+
+ ++self->frames;
+ Msp::Time::TimeStamp t = Msp::Time::now();
+ Msp::Time::TimeDelta dt = t-self->start;
+ if(dt>Msp::Time::sec)
+ {
+ Msp::IO::print("%d frames in %s seconds\n", self->frames, dt);
+ self->start = t;
+ self->frames = 0;
+ }
+}
--- /dev/null
+#ifndef PROFILER_H_
+#define PROFILER_H_
+
+#include <msp/time/timestamp.h>
+#include "gldecoder.h"
+
+class Profiler
+{
+private:
+ GlDecoder *decoder;
+ bool enabled;
+ Msp::Time::TimeStamp start;
+ unsigned frames;
+ unsigned draw_calls;
+ unsigned vertices;
+ unsigned triangles;
+
+public:
+ Profiler();
+
+ void enable();
+ void disable();
+ int decode(const char *, unsigned);
+private:
+ static void glDrawArrays(void *, GLenum, int, int);
+ static void glDrawElements(void *, GLenum, int, GLenum, const void *);
+ static void glDrawRangeElements(void *, GLenum, unsigned, unsigned, int, GLenum, const void *);
+ static void glXSwapBuffers(void *, Display *, GLXDrawable);
+};
+
+#endif