diff options
Diffstat (limited to 'progs/tests/debugger.c')
-rw-r--r-- | progs/tests/debugger.c | 733 |
1 files changed, 733 insertions, 0 deletions
diff --git a/progs/tests/debugger.c b/progs/tests/debugger.c new file mode 100644 index 00000000000..4c6955bcfc6 --- /dev/null +++ b/progs/tests/debugger.c @@ -0,0 +1,733 @@ +/* + * Test the GL_MESA_program_debug extension + */ + + +#include <assert.h> +#include <ctype.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#define GL_GLEXT_PROTOTYPES +#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) +{ + const GLubyte *lineStart = string; + const GLubyte *p = string; + GLubyte *s; + int len; + + *line = 1; + + while (p != pos) { + if (*p == (GLubyte) '\n') { + (*line)++; + lineStart = p + 1; + } + p++; + } + + *col = (pos - lineStart) + 1; + + /* return copy of this line */ + while (*p != 0 && *p != '\n') + p++; + len = p - lineStart; + s = (GLubyte *) malloc(len + 1); + memcpy(s, lineStart, len); + s[len] = 0; + + return s; +} + + +#define ARB_VERTEX_PROGRAM 1 +#define ARB_FRAGMENT_PROGRAM 2 +#define NV_VERTEX_PROGRAM 3 +#define NV_FRAGMENT_PROGRAM 4 + + +struct breakpoint { + enum {PIXEL, LINE} type; + int x, y; + int line; + GLboolean enabled; +}; + +#define MAX_BREAKPOINTS 100 +static struct breakpoint Breakpoints[MAX_BREAKPOINTS]; +static int NumBreakpoints = 0; + + + +/* + * Interactive debugger + */ +static void Debugger2(GLenum target, GLvoid *data) +{ + static GLuint skipCount = 0; + const GLubyte *ln; + GLint pos, line, column; + GLint id; + int progType; + GLint len; + GLubyte *program; + GLboolean stop; + int i; + + /* 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; + + /* Until we hit zero, continue rendering */ + if (skipCount > 0) { + skipCount--; + 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); + + /* test breakpoints */ + if (NumBreakpoints > 0) + stop = GL_FALSE; + else + stop = GL_TRUE; + for (i = 0; i < NumBreakpoints; i++) { + if (Breakpoints[i].enabled) { + switch (Breakpoints[i].type) { + case PIXEL: + if (progType == ARB_FRAGMENT_PROGRAM) { + + } + else if (progType == NV_FRAGMENT_PROGRAM) { + GLfloat pos[4]; + int px, py; + glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV, + 6, (GLubyte *) "f[WPOS]", pos); + px = (int) pos[0]; + py = (int) pos[1]; + printf("%d, %d\n", px, py); + if (px == Breakpoints[i].x && + py == Breakpoints[i].y) { + printf("Break at pixel (%d, %d)\n", px, py); + stop = GL_TRUE; + } + } + break; + case LINE: + if (line == Breakpoints[i].line) { + /* hit a breakpoint! */ + printf("Break at line %d\n", line); + stop = GL_TRUE; + } + break; + } + } + } + if (!stop) { + free(program); + return; + } + + 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': + /* skip N instructions */ + i = atoi(cmd + 2); + skipCount = i; + printf("Skipping %d instructions\n", i); + return; + case 'n': + /* next */ + return; + case 'c': + 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': + if (cmd[1] == ' ' && isdigit(cmd[2])) { + char *comma = strchr(cmd, ','); + if (comma) { + /* break at pixel */ + int x = atoi(cmd + 2); + int y = atoi(comma + 1); + if (NumBreakpoints < MAX_BREAKPOINTS) { + Breakpoints[NumBreakpoints].type = PIXEL; + Breakpoints[NumBreakpoints].x = x; + Breakpoints[NumBreakpoints].y = y; + Breakpoints[NumBreakpoints].enabled = GL_TRUE; + NumBreakpoints++; + printf("Breakpoint %d: break at pixel (%d, %d)\n", + NumBreakpoints, x, y); + } + } + else { + /* break at line */ + int l = atoi(cmd + 2); + if (l && NumBreakpoints < MAX_BREAKPOINTS) { + Breakpoints[NumBreakpoints].type = LINE; + Breakpoints[NumBreakpoints].line = l; + Breakpoints[NumBreakpoints].enabled = GL_TRUE; + NumBreakpoints++; + printf("Breakpoint %d: break at line %d\n", + NumBreakpoints, l); + } + } + } + else { + /* list breakpoints */ + printf("Breakpoints:\n"); + for (i = 0; i < NumBreakpoints; i++) { + switch (Breakpoints[i].type) { + case LINE: + printf(" %d: break at line %d\n", + i + 1, Breakpoints[i].line); + break; + case PIXEL: + printf(" %d: break at pixel (%d, %d)\n", + i + 1, Breakpoints[i].x, Breakpoints[i].y); + break; + } + } + } + break; + case 'h': + /* help */ + printf("Debugger commands:\n"); + printf(" b list breakpoints\n"); + printf(" b N break at line N\n"); + printf(" b x,y break at pixel x,y\n"); + printf(" c continue execution\n"); + printf(" d display register values\n"); + printf(" h help\n"); + printf(" l list program\n"); + printf(" n next instruction\n"); + printf(" p V print value V\n"); + printf(" s N skip N instructions\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; + const GLubyte *ln; + GLint line, column; + GLfloat v[4]; + + assert(target == GL_FRAGMENT_PROGRAM_NV); + + glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA, &pos); + + ln = find_line_column((const GLubyte *) data, (const GLubyte *) data + pos, + &line, &column); + printf("%d:%d: %s\n", line, column, (char *) ln); + + glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV, + 2, (const GLubyte *) "R0", v); + printf(" R0 = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]); + glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV, + 7, (const GLubyte *) "f[WPOS]", v); + printf(" o[WPOS] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]); + glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV, + 7, (const GLubyte *) "o[COLR]", v); + printf(" o[COLR] = %g, %g, %g, %g\n", v[0], v[1], v[2], v[3]); + + free((void *) ln); +} + + + + +/**********************************************************************/ + +static GLfloat Diffuse[4] = { 0.5, 0.5, 1.0, 1.0 }; +static GLfloat Specular[4] = { 0.8, 0.8, 0.8, 1.0 }; +static GLfloat LightPos[4] = { 0.0, 10.0, 20.0, 1.0 }; +static GLfloat Delta = 1.0; + +static GLuint FragProg; +static GLuint VertProg; +static GLboolean Anim = GL_TRUE; +static GLboolean Wire = GL_FALSE; +static GLboolean PixelLight = GL_TRUE; + +static GLfloat Xrot = 0, Yrot = 0; + + +#define NAMED_PARAMETER4FV(prog, name, v) \ + glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v) + + +static void Display( void ) +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + if (PixelLight) { + NAMED_PARAMETER4FV(FragProg, "LightPos", LightPos); + glEnable(GL_FRAGMENT_PROGRAM_NV); + glEnable(GL_VERTEX_PROGRAM_NV); + glDisable(GL_LIGHTING); + } + else { + glLightfv(GL_LIGHT0, GL_POSITION, LightPos); + glDisable(GL_FRAGMENT_PROGRAM_NV); + glDisable(GL_VERTEX_PROGRAM_NV); + glEnable(GL_LIGHTING); + } + + glPushMatrix(); + glRotatef(Xrot, 1, 0, 0); + glRotatef(Yrot, 0, 1, 0); + +#if 1 + glutSolidSphere(2.0, 10, 5); +#else + { + GLUquadricObj *q = gluNewQuadric(); + gluQuadricNormals(q, GL_SMOOTH); + gluQuadricTexture(q, GL_TRUE); + glRotatef(90, 1, 0, 0); + glTranslatef(0, 0, -1); + gluCylinder(q, 1.0, 1.0, 2.0, 24, 1); + gluDeleteQuadric(q); + } +#endif + + glPopMatrix(); + + glutSwapBuffers(); +} + + +static void Idle(void) +{ + LightPos[0] += Delta; + if (LightPos[0] > 25.0) + Delta = -1.0; + else if (LightPos[0] <- 25.0) + Delta = 1.0; + glutPostRedisplay(); +} + + +static void Reshape( int width, int height ) +{ + glViewport( 0, 0, width, height ); + glMatrixMode( GL_PROJECTION ); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 ); + /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/ + glMatrixMode( GL_MODELVIEW ); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -15.0 ); +} + + +static void Key( unsigned char key, int x, int y ) +{ + (void) x; + (void) y; + switch (key) { + case ' ': + Anim = !Anim; + if (Anim) + glutIdleFunc(Idle); + else + glutIdleFunc(NULL); + break; + case 'x': + LightPos[0] -= 1.0; + break; + case 'X': + LightPos[0] += 1.0; + break; + case 'w': + Wire = !Wire; + if (Wire) + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + else + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + break; + case 'p': + PixelLight = !PixelLight; + if (PixelLight) { + printf("Per-pixel lighting\n"); + } + else { + printf("Conventional lighting\n"); + } + break; + case 27: + exit(0); + break; + } + glutPostRedisplay(); +} + +static void SpecialKey( int key, int x, int y ) +{ + const GLfloat step = 3.0; + (void) x; + (void) y; + switch (key) { + case GLUT_KEY_UP: + Xrot -= step; + break; + case GLUT_KEY_DOWN: + Xrot += step; + break; + case GLUT_KEY_LEFT: + Yrot -= step; + break; + case GLUT_KEY_RIGHT: + Yrot += step; + break; + } + glutPostRedisplay(); +} + + +static void Init( int argc, char *argv[] ) +{ + static const char *fragProgramText = + "!!FP1.0\n" + "DECLARE Diffuse; \n" + "DECLARE Specular; \n" + "DECLARE LightPos; \n" + + "# Compute normalized LightPos, put it in R0\n" + "DP3 R0.x, LightPos, LightPos;\n" + "RSQ R0.y, R0.x;\n" + "MUL R0, LightPos, R0.y;\n" + + "# Compute normalized normal, put it in R1\n" + "DP3 R1, f[TEX0], f[TEX0]; \n" + "RSQ R1.y, R1.x;\n" + "MUL R1, f[TEX0], R1.y;\n" + + "# Compute dot product of light direction and normal vector\n" + "DP3 R2, R0, R1;\n" + + "MUL R3, Diffuse, R2; # diffuse attenuation\n" + + "POW R4, R2.x, {20.0}.x; # specular exponent\n" + + "MUL R5, Specular, R4; # specular attenuation\n" + + "ADD o[COLR], R3, R5; # add diffuse and specular colors\n" + "END \n" + ; + + static const char *vertProgramText = + "!!VP1.0\n" + "# typical modelview/projection transform\n" + "DP4 o[HPOS].x, c[0], v[OPOS] ;\n" + "DP4 o[HPOS].y, c[1], v[OPOS] ;\n" + "DP4 o[HPOS].z, c[2], v[OPOS] ;\n" + "DP4 o[HPOS].w, c[3], v[OPOS] ;\n" + "# transform normal by inv transpose of modelview, put in tex0\n" + "DP4 o[TEX0].x, c[4], v[NRML] ;\n" + "DP4 o[TEX0].y, c[5], v[NRML] ;\n" + "DP4 o[TEX0].z, c[6], v[NRML] ;\n" + "DP4 o[TEX0].w, c[7], v[NRML] ;\n" + "END\n"; + ; + + if (!glutExtensionSupported("GL_NV_vertex_program")) { + printf("Sorry, this demo requires GL_NV_vertex_program\n"); + exit(1); + } + if (!glutExtensionSupported("GL_NV_fragment_program")) { + printf("Sorry, this demo requires GL_NV_fragment_program\n"); + exit(1); + } + + glGenProgramsNV(1, &FragProg); + assert(FragProg > 0); + glGenProgramsNV(1, &VertProg); + assert(VertProg > 0); + + /* + * Fragment program + */ + glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg, + strlen(fragProgramText), + (const GLubyte *) fragProgramText); + assert(glIsProgramNV(FragProg)); + glBindProgramNV(GL_FRAGMENT_PROGRAM_NV, FragProg); + + NAMED_PARAMETER4FV(FragProg, "Diffuse", Diffuse); + NAMED_PARAMETER4FV(FragProg, "Specular", Specular); + + /* + * Vertex program + */ + glLoadProgramNV(GL_VERTEX_PROGRAM_NV, VertProg, + strlen(vertProgramText), + (const GLubyte *) vertProgramText); + assert(glIsProgramNV(VertProg)); + glBindProgramNV(GL_VERTEX_PROGRAM_NV, VertProg); + glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 0, GL_MODELVIEW_PROJECTION_NV, GL_IDENTITY_NV); + glTrackMatrixNV(GL_VERTEX_PROGRAM_NV, 4, GL_MODELVIEW, GL_INVERSE_TRANSPOSE_NV); + + /* + * Misc init + */ + glClearColor(0.3, 0.3, 0.3, 0.0); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHT0); + glEnable(GL_LIGHTING); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Diffuse); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Specular); + glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.0); + + printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER)); + printf("Press p to toggle between per-pixel and per-vertex lighting\n"); + +#ifdef GL_MESA_program_debug + 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 +} + + +int main( int argc, char *argv[] ) +{ + glutInit( &argc, argv ); + glutInitWindowPosition( 0, 0 ); + glutInitWindowSize( 200, 200 ); + glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH ); + glutCreateWindow(argv[0]); + glutReshapeFunc( Reshape ); + glutKeyboardFunc( Key ); + glutSpecialFunc( SpecialKey ); + glutDisplayFunc( Display ); + if (Anim) + glutIdleFunc(Idle); + Init(argc, argv); + glutMainLoop(); + return 0; +} |