New interactive debugging code - vertex or fragment program.
This commit is contained in:
@@ -12,7 +12,35 @@
|
||||
#include <GL/glut.h>
|
||||
|
||||
|
||||
/*
|
||||
* Print the string with line numbers
|
||||
*/
|
||||
static void list_program(const GLubyte *string, GLsizei len)
|
||||
{
|
||||
const char *c = (const char *) string;
|
||||
int i, line = 1, printNumber = 1;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (printNumber) {
|
||||
printf("%3d ", line);
|
||||
printNumber = 0;
|
||||
}
|
||||
if (*c == '\n') {
|
||||
line++;
|
||||
printNumber = 1;
|
||||
}
|
||||
putchar(*c);
|
||||
c++;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the line number and column number that corresponds to the
|
||||
* given program position. Also return a null-terminated copy of that
|
||||
* line of the program string.
|
||||
*/
|
||||
static const GLubyte *
|
||||
find_line_column(const GLubyte *string, const GLubyte *pos,
|
||||
GLint *line, GLint *col)
|
||||
@@ -46,6 +74,241 @@ find_line_column(const GLubyte *string, const GLubyte *pos,
|
||||
}
|
||||
|
||||
|
||||
#define ARB_VERTEX_PROGRAM 1
|
||||
#define ARB_FRAGMENT_PROGRAM 2
|
||||
#define NV_VERTEX_PROGRAM 3
|
||||
#define NV_FRAGMENT_PROGRAM 4
|
||||
|
||||
|
||||
/*
|
||||
* Interactive debugger
|
||||
*/
|
||||
static void Debugger2(GLenum target, GLvoid *data)
|
||||
{
|
||||
static GLboolean continueFlag = GL_FALSE;
|
||||
const GLubyte *ln;
|
||||
GLint pos, line, column;
|
||||
GLint id;
|
||||
int progType;
|
||||
GLint len;
|
||||
GLubyte *program;
|
||||
|
||||
/* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
|
||||
* hard to distinguish between them.
|
||||
*/
|
||||
if (target == GL_FRAGMENT_PROGRAM_ARB)
|
||||
progType = ARB_FRAGMENT_PROGRAM;
|
||||
else if (target == GL_FRAGMENT_PROGRAM_NV)
|
||||
progType = NV_FRAGMENT_PROGRAM;
|
||||
else
|
||||
progType = NV_VERTEX_PROGRAM;
|
||||
|
||||
|
||||
if (continueFlag)
|
||||
return;
|
||||
|
||||
/* Get id of the program and current position */
|
||||
switch (progType) {
|
||||
case ARB_FRAGMENT_PROGRAM:
|
||||
glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
|
||||
glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
|
||||
break;
|
||||
case NV_FRAGMENT_PROGRAM:
|
||||
glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV, &id);
|
||||
glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos);
|
||||
break;
|
||||
case ARB_VERTEX_PROGRAM:
|
||||
glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &id);
|
||||
glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
|
||||
break;
|
||||
case NV_VERTEX_PROGRAM:
|
||||
glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &id);
|
||||
glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA, &pos);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
/* get program string */
|
||||
if (progType == ARB_VERTEX_PROGRAM ||
|
||||
progType == ARB_FRAGMENT_PROGRAM)
|
||||
glGetProgramivARB(target, GL_PROGRAM_LENGTH_ARB, &len);
|
||||
else
|
||||
glGetProgramivNV(id, GL_PROGRAM_LENGTH_NV, &len);
|
||||
program = malloc(len + 1);
|
||||
if (progType == ARB_VERTEX_PROGRAM ||
|
||||
progType == ARB_FRAGMENT_PROGRAM)
|
||||
glGetProgramStringARB(target, GL_PROGRAM_STRING_ARB, program);
|
||||
else
|
||||
glGetProgramStringNV(id, GL_PROGRAM_STRING_NV, program);
|
||||
|
||||
|
||||
/* Get current line number, column, line string */
|
||||
ln = find_line_column(program, program + pos, &line, &column);
|
||||
|
||||
printf("%d: %s\n", line, ln);
|
||||
|
||||
/* get commands from stdin */
|
||||
while (1) {
|
||||
char command[1000], *cmd;
|
||||
|
||||
/* print prompt and get command */
|
||||
printf("(%s %d) ", (target == GL_VERTEX_PROGRAM_ARB ? "vert" : "frag"),
|
||||
line);
|
||||
fgets(command, 999, stdin);
|
||||
|
||||
/* skip leading whitespace */
|
||||
for (cmd = command; cmd[0] == ' '; cmd++)
|
||||
;
|
||||
|
||||
if (!cmd[0])
|
||||
/* nothing (repeat the previous cmd?) */
|
||||
continue;
|
||||
|
||||
switch (cmd[0]) {
|
||||
case 's':
|
||||
case 'n':
|
||||
/* step / next */
|
||||
return;
|
||||
case 'c':
|
||||
continueFlag = GL_TRUE;
|
||||
return;
|
||||
case 'd':
|
||||
/* dump machine state */
|
||||
if (progType == NV_FRAGMENT_PROGRAM) {
|
||||
static const char *inRegs[] = {
|
||||
"f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
|
||||
"f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
|
||||
NULL
|
||||
};
|
||||
static const char *outRegs[] = {
|
||||
"o[COLR]", "o[COLH]", "o[DEPR]", NULL
|
||||
};
|
||||
GLfloat v[4];
|
||||
int i;
|
||||
printf("Fragment input attributes:\n");
|
||||
for (i = 0; inRegs[i]; i++) {
|
||||
glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
|
||||
strlen(inRegs[i]),
|
||||
(const GLubyte *) inRegs[i], v);
|
||||
printf(" %s: %g, %g, %g, %g\n", inRegs[i],
|
||||
v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
printf("Fragment output attributes:\n");
|
||||
for (i = 0; outRegs[i]; i++) {
|
||||
glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
|
||||
strlen(outRegs[i]),
|
||||
(const GLubyte *) outRegs[i], v);
|
||||
printf(" %s: %g, %g, %g, %g\n", outRegs[i],
|
||||
v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
printf("Temporaries:\n");
|
||||
for (i = 0; i < 4; i++) {
|
||||
char temp[100];
|
||||
GLfloat v[4];
|
||||
sprintf(temp, "R%d", i);
|
||||
glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV,
|
||||
strlen(temp),
|
||||
(const GLubyte *) temp, v);
|
||||
printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
|
||||
}
|
||||
}
|
||||
else if (progType == NV_VERTEX_PROGRAM) {
|
||||
GLfloat v[4];
|
||||
int i;
|
||||
static const char *inRegs[] = {
|
||||
"v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
|
||||
"v[COL1]", "v[FOGC]", "v[6]", "v[7]",
|
||||
"v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
|
||||
"v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
|
||||
NULL
|
||||
};
|
||||
static const char *outRegs[] = {
|
||||
"o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
|
||||
"o[BFC1]", "o[FOGC]", "o[PSIZ]",
|
||||
"o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
|
||||
"o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
|
||||
NULL
|
||||
};
|
||||
printf("Vertex input attributes:\n");
|
||||
for (i = 0; inRegs[i]; i++) {
|
||||
glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
|
||||
strlen(inRegs[i]),
|
||||
(const GLubyte *) inRegs[i], v);
|
||||
printf(" %s: %g, %g, %g, %g\n", inRegs[i],
|
||||
v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
printf("Vertex output attributes:\n");
|
||||
for (i = 0; outRegs[i]; i++) {
|
||||
glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
|
||||
strlen(outRegs[i]),
|
||||
(const GLubyte *) outRegs[i], v);
|
||||
printf(" %s: %g, %g, %g, %g\n", outRegs[i],
|
||||
v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
printf("Temporaries:\n");
|
||||
for (i = 0; i < 4; i++) {
|
||||
char temp[100];
|
||||
GLfloat v[4];
|
||||
sprintf(temp, "R%d", i);
|
||||
glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV,
|
||||
strlen(temp),
|
||||
(const GLubyte *) temp, v);
|
||||
printf(" %s: %g, %g, %g, %g\n", temp, v[0],v[1],v[2],v[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
/* list */
|
||||
list_program(program, len);
|
||||
break;
|
||||
case 'p':
|
||||
/* print */
|
||||
{
|
||||
GLfloat v[4];
|
||||
char *c;
|
||||
cmd++;
|
||||
while (*cmd == ' ')
|
||||
cmd++;
|
||||
c = cmd;
|
||||
while (*c) {
|
||||
if (*c == '\n' || *c == '\r')
|
||||
*c = 0;
|
||||
else
|
||||
c++;
|
||||
}
|
||||
glGetProgramRegisterfvMESA(target, strlen(cmd),
|
||||
(const GLubyte *) cmd, v);
|
||||
if (glGetError() == GL_NO_ERROR)
|
||||
printf("%s = %g, %g, %g, %g\n", cmd, v[0], v[1], v[2], v[3]);
|
||||
else
|
||||
printf("Invalid expression\n");
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
/* break */
|
||||
/* break at line number */
|
||||
/* break at screen pixel (x,y) */
|
||||
/* break if condition is true */
|
||||
printf("Breakpoints not implemented yet.\n");
|
||||
break;
|
||||
case 'h':
|
||||
/* help */
|
||||
printf("Debugger commands:\n");
|
||||
printf(" s step n next c continue\n");
|
||||
printf(" d dump regs h help l list\n");
|
||||
printf(" b break p print\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown command: %c\n", cmd[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print current line, some registers, and continue.
|
||||
*/
|
||||
static void Debugger(GLenum target, GLvoid *data)
|
||||
{
|
||||
GLint pos;
|
||||
@@ -226,7 +489,7 @@ static void SpecialKey( int key, int x, int y )
|
||||
}
|
||||
|
||||
|
||||
static void Init( void )
|
||||
static void Init( int argc, char *argv[] )
|
||||
{
|
||||
static const char *fragProgramText =
|
||||
"!!FP1.0\n"
|
||||
@@ -324,9 +587,18 @@ static void Init( void )
|
||||
printf("Press p to toggle between per-pixel and per-vertex lighting\n");
|
||||
|
||||
#ifdef GL_MESA_program_debug
|
||||
glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger,
|
||||
(GLvoid *) fragProgramText);
|
||||
glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
|
||||
if (argc > 1 && strcmp(argv[1], "fragment") == 0) {
|
||||
printf(">> Debugging fragment program\n");
|
||||
glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB, Debugger2,
|
||||
(GLvoid *) fragProgramText);
|
||||
glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA);
|
||||
}
|
||||
else {
|
||||
printf(">> Debugging vertex program\n");
|
||||
glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB, Debugger2,
|
||||
(GLvoid *) fragProgramText);
|
||||
glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -344,7 +616,7 @@ int main( int argc, char *argv[] )
|
||||
glutDisplayFunc( Display );
|
||||
if (Anim)
|
||||
glutIdleFunc(Idle);
|
||||
Init();
|
||||
Init(argc, argv);
|
||||
glutMainLoop();
|
||||
return 0;
|
||||
}
|
||||
|
Reference in New Issue
Block a user