GlState::GlState():
decoder(gldecoder_new(this, NULL)),
+ texcoord(1),
active_tex(0),
client_active_tex(0),
+ texunits(1),
array_buffer(0),
element_buffer(0),
uniform_buffer(0),
- uniform_bind_points(64)
+ texcoord_arrays(1)
{
vertex_array.kind = GL_VERTEX_ARRAY;
normal_array.kind = GL_NORMAL_ARRAY;
color_array.kind = GL_COLOR_ARRAY;
- for(unsigned i=0; i<8; ++i)
- {
- texcoord_arrays[i].kind = GL_TEXTURE_COORD_ARRAY;
- texcoord_arrays[i].index = i;
- }
+ texcoord_arrays[0].kind = GL_TEXTURE_COORD_ARRAY;
+ texcoord_arrays[0].index = 0;
+
+ decoder->glGetIntegerv = glGetIntegerv;
decoder->glEnableClientState = glEnableClientState;
decoder->glDisableClientState = glDisableClientState;
return gldecoder_decode(decoder, data, len);
}
+void GlState::glGetIntegerv(void *user_data, GLenum pname, int *param)
+{
+ GlState *self = reinterpret_cast<GlState *>(user_data);
+ if(pname==GL_MAX_TEXTURE_UNITS)
+ {
+ self->texcoord.resize(*param);
+ self->texunits.resize(*param);
+ self->texcoord_arrays.resize(*param);
+ for(unsigned i=0; i<self->texcoord_arrays.size(); ++i)
+ {
+ self->texcoord_arrays[i].kind = GL_TEXTURE_COORD_ARRAY;
+ self->texcoord_arrays[i].index = i;
+ }
+ }
+ else if(pname==GL_MAX_VERTEX_ATTRIBS)
+ {
+ self->attrib_arrays.resize(*param);
+ for(unsigned i=0; i<self->attrib_arrays.size(); ++i)
+ self->attrib_arrays[i].index = i;
+ }
+ else if(pname==GL_MAX_UNIFORM_BUFFER_BINDINGS)
+ self->uniform_bind_points.resize(*param);
+}
+
// Boolean state
bool &GlState::get_boolean_state(GLenum state)
// Vertex arrays
-ArrayState &GlState::get_attrib_array(unsigned index)
-{
- map<unsigned, ArrayState>::iterator i = attrib_arrays.find(index);
- if(i!=attrib_arrays.end())
- return i->second;
-
- ArrayState &array = attrib_arrays[index];
- array.index = index;
-
- return array;
-}
-
void GlState::glVertexPointer(void *user_data, int size, GLenum type, int stride, const void *data)
{
GlState *self = reinterpret_cast<GlState *>(user_data);
void GlState::glVertexAttribPointer(void *user_data, unsigned index, int size, GLenum type, unsigned char norm, int stride, const void *data)
{
GlState *self = reinterpret_cast<GlState *>(user_data);
- self->get_attrib_array(index).set(size, type, norm, stride, self->array_buffer, reinterpret_cast<long>(data));
+ self->attrib_arrays[index].set(size, type, norm, stride, self->array_buffer, reinterpret_cast<long>(data));
}
const ArrayState &GlState::get_array(GLenum array) const
const ArrayState &GlState::get_attrib_array(unsigned index) const
{
- map<unsigned, ArrayState>::const_iterator i = attrib_arrays.find(index);
- if(i!=attrib_arrays.end())
- return i->second;
-
- // XXX Return a dummy?
- throw runtime_error("Unknown attribute array");
+ return attrib_arrays[index];
}
// Array draw commands
/**
Tracks OpenGL state based on the command stream. This class is essentially a
(partial) OpenGL implementation in itself.
-
-XXX Should determine the number of texture units the target implementation
-actually supports.
*/
class GlState
{
private:
GlDecoder *decoder;
Vector4 color;
- Vector4 texcoord[8];
+ std::vector<Vector4> texcoord;
Vector3 normal;
unsigned active_tex;
unsigned client_active_tex;
TextureMap textures;
- TexUnitState texunits[8];
+ std::vector<TexUnitState> texunits;
BufferMap buffers;
BufferState *array_buffer;
BufferState *element_buffer;
ArrayState vertex_array;
ArrayState normal_array;
ArrayState color_array;
- ArrayState texcoord_arrays[8];
- std::map<unsigned, ArrayState> attrib_arrays;
+ std::vector<ArrayState> texcoord_arrays;
+ std::vector<ArrayState> attrib_arrays;
ShaderMap shaders;
ProgramMap programs;
int decode(const char *, unsigned);
+private:
+ static void glGetIntegerv(void *, GLenum, int *);
+
+public:
+ unsigned get_max_texture_units() const { return texunits.size(); }
+ unsigned get_max_vertex_attribs() const { return attrib_arrays.size(); }
+ unsigned get_max_uniform_buffer_bindings() const { return uniform_bind_points.size(); }
+
private:
bool &get_boolean_state(GLenum);
static void glEnableClientState(void *, GLenum);
const Vector3 &get_normal() const { return normal; }
private:
- ArrayState &get_attrib_array(unsigned);
-
static void glVertexPointer(void *, int, GLenum, int, const void *);
static void glNormalPointer(void *, GLenum, int, const void *);
static void glColorPointer(void *, int, GLenum, int, const void *);
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
+#include "breakpoint.h"
#include "enums.h"
+#include "functions.h"
#include "gldbg.h"
#include "inspector.h"
#include "strformat.h"
using namespace std;
-Inspector::Inspector(GlDbg &dbg)
+Inspector::Inspector(GlDbg &d):
+ gldbg(d),
+ decoder(gldecoder_new(this, NULL)),
+ query_state(0)
{
- CommandInterpreter &cmd_interp = dbg.get_command_interpreter();
+ CommandInterpreter &cmd_interp = gldbg.get_command_interpreter();
cmd_interp.register_command("state", this, &Inspector::cmd_state)
.set_help("Inspects general GL state",
" List program objects\n\n"
"program ID\n"
" Print information about a program object\n");
+
+ decoder->gldBreak = gldBreak;
}
void Inspector::decode(const char *data, unsigned len)
{
+ if(query_state)
+ gldecoder_decode(decoder, data, len);
state.decode(data, len);
}
+void Inspector::process_started()
+{
+ gldbg.set_breakpoint(FUNC_GLXMAKECURRENT, BREAK_RETURN, this);
+ query_state = 1;
+}
+
+void Inspector::process_stopped(int reason)
+{
+ if((reason>>8)==3 && query_state==2)
+ {
+ GlPacket *pkt = packet_begin(FUNC_GLDQUERYLIMITS);
+ gldbg.send(pkt);
+ query_state = 0;
+ gldbg.resume_from_break(this);
+ }
+}
+
+void Inspector::gldBreak(void *user_data, unsigned short func, unsigned char flag)
+{
+ if(func==FUNC_GLXMAKECURRENT && flag==BREAK_RETURN)
+ ++reinterpret_cast<Inspector *>(user_data)->query_state;
+}
+
void Inspector::print_indented(const string &str, unsigned indent)
{
string spaces(indent, ' ');
printf("Current vertex attributes:\n");
const Vector4 &color = glstate.get_color();
printf(" Color: [%05.3f, %05.3f, %05.3f, %05.3f]\n", color.r, color.g, color.b, color.a);
- for(unsigned i=0; i<8; ++i)
+ unsigned count = glstate.get_max_texture_units();
+ for(unsigned i=0; i<count; ++i)
{
const Vector4 &texcoord = glstate.get_texcoord(i);
printf(" TexCoord%d: [%05.3f, %05.3f, %05.3f, %05.3f]\n", i, texcoord.s, texcoord.t, texcoord.p, texcoord.q);
else if(args=="bind")
{
printf("Current bindings:\n");
- for(unsigned i=0; i<8; ++i)
+ unsigned count = glstate.get_max_texture_units();
+ for(unsigned i=0; i<count; ++i)
{
printf(" Texture unit %d:\n", i);
const TexUnitState &unit = glstate.get_texture_unit(i);
printf(" GL_ELEMENT_ARRAY_BUFFER: %d\n", (buf ? buf->id : 0));
buf = glstate.get_current_buffer(GL_UNIFORM_BUFFER);
printf(" GL_UNIFORM_BUFFER: %d\n", (buf ? buf->id : 0));
- for(unsigned i=0; i<64; ++i)
+ count = glstate.get_max_uniform_buffer_bindings();
+ for(unsigned i=0; i<count; ++i)
{
const BufferBindingState &binding = glstate.get_buffer_binding(GL_UNIFORM_BUFFER, i);
if(binding.buffer)
class Inspector: public RegisteredTool<Inspector>
{
private:
+ GlDbg &gldbg;
GlState state;
+ GlDecoder *decoder;
+ int query_state;
public:
Inspector(GlDbg &);
virtual void decode(const char *, unsigned);
+ virtual void process_started();
+ virtual void process_stopped(int);
+
private:
+ static void gldBreak(void *, unsigned short, unsigned char);
+
void print_indented(const std::string &, unsigned);
void cmd_state(const std::string &);
: FUNC_GLDBREAK,
: FUNC_GLDHOLD,
: FUNC_GLDQUERYVIEWPORT,
-: FUNC_GLDREADPIXELS
+: FUNC_GLDREADPIXELS,
+: FUNC_GLDQUERYLIMITS
:};
free(data);
}
+static void receive_gldQueryLimits(GlPacket *pkt UNUSED)
+{
+ int value;
+
+ no_break = 1;
+ value = 0;
+ glGetIntegerv(GL_MAX_TEXTURE_UNITS, &value);
+ value = 0;
+ glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value);
+ value = 0;
+ glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &value);
+ no_break = 0;
+}
+
static void receive(void)
{
GlPacket *pkt;
case FUNC_GLDHOLD: receive_gldHold(pkt); break;
case FUNC_GLDQUERYVIEWPORT: receive_gldQueryViewport(pkt); break;
case FUNC_GLDREADPIXELS: receive_gldReadPixels(pkt); break;
+ case FUNC_GLDQUERYLIMITS: receive_gldQueryLimits(pkt); break;
default:;
}
}