2 * Test the GL_MESA_program_debug extension
12 #define GL_GLEXT_PROTOTYPES
17 * Print the string with line numbers
19 static void list_program(const GLubyte
*string
, GLsizei len
)
21 const char *c
= (const char *) string
;
22 int i
, line
= 1, printNumber
= 1;
24 for (i
= 0; i
< len
; i
++) {
41 * Return the line number and column number that corresponds to the
42 * given program position. Also return a null-terminated copy of that
43 * line of the program string.
45 static const GLubyte
*
46 find_line_column(const GLubyte
*string
, const GLubyte
*pos
,
47 GLint
*line
, GLint
*col
)
49 const GLubyte
*lineStart
= string
;
50 const GLubyte
*p
= string
;
57 if (*p
== (GLubyte
) '\n') {
64 *col
= (pos
- lineStart
) + 1;
66 /* return copy of this line */
67 while (*p
!= 0 && *p
!= '\n')
70 s
= (GLubyte
*) malloc(len
+ 1);
71 memcpy(s
, lineStart
, len
);
78 #define ARB_VERTEX_PROGRAM 1
79 #define ARB_FRAGMENT_PROGRAM 2
80 #define NV_VERTEX_PROGRAM 3
81 #define NV_FRAGMENT_PROGRAM 4
85 enum {PIXEL
, LINE
} type
;
91 #define MAX_BREAKPOINTS 100
92 static struct breakpoint Breakpoints
[MAX_BREAKPOINTS
];
93 static int NumBreakpoints
= 0;
98 * Interactive debugger
100 static void Debugger2(GLenum target
, GLvoid
*data
)
102 static GLuint skipCount
= 0;
104 GLint pos
, line
, column
;
112 /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
113 * hard to distinguish between them.
115 if (target
== GL_FRAGMENT_PROGRAM_ARB
)
116 progType
= ARB_FRAGMENT_PROGRAM
;
117 else if (target
== GL_FRAGMENT_PROGRAM_NV
)
118 progType
= NV_FRAGMENT_PROGRAM
;
120 progType
= NV_VERTEX_PROGRAM
;
122 /* Until we hit zero, continue rendering */
128 /* Get id of the program and current position */
130 case ARB_FRAGMENT_PROGRAM
:
131 glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_BINDING_ARB
, &id
);
132 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
134 case NV_FRAGMENT_PROGRAM
:
135 glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV
, &id
);
136 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
138 case ARB_VERTEX_PROGRAM
:
139 glGetProgramivARB(GL_VERTEX_PROGRAM_ARB
, GL_PROGRAM_BINDING_ARB
, &id
);
140 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA
, &pos
);
142 case NV_VERTEX_PROGRAM
:
143 glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV
, &id
);
144 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA
, &pos
);
150 /* get program string */
151 if (progType
== ARB_VERTEX_PROGRAM
||
152 progType
== ARB_FRAGMENT_PROGRAM
)
153 glGetProgramivARB(target
, GL_PROGRAM_LENGTH_ARB
, &len
);
155 glGetProgramivNV(id
, GL_PROGRAM_LENGTH_NV
, &len
);
156 program
= malloc(len
+ 1);
157 if (progType
== ARB_VERTEX_PROGRAM
||
158 progType
== ARB_FRAGMENT_PROGRAM
)
159 glGetProgramStringARB(target
, GL_PROGRAM_STRING_ARB
, program
);
161 glGetProgramStringNV(id
, GL_PROGRAM_STRING_NV
, program
);
164 /* Get current line number, column, line string */
165 ln
= find_line_column(program
, program
+ pos
, &line
, &column
);
167 /* test breakpoints */
168 if (NumBreakpoints
> 0)
172 for (i
= 0; i
< NumBreakpoints
; i
++) {
173 if (Breakpoints
[i
].enabled
) {
174 switch (Breakpoints
[i
].type
) {
176 if (progType
== ARB_FRAGMENT_PROGRAM
) {
179 else if (progType
== NV_FRAGMENT_PROGRAM
) {
182 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
183 6, (GLubyte
*) "f[WPOS]", pos
);
186 printf("%d, %d\n", px
, py
);
187 if (px
== Breakpoints
[i
].x
&&
188 py
== Breakpoints
[i
].y
) {
189 printf("Break at pixel (%d, %d)\n", px
, py
);
195 if (line
== Breakpoints
[i
].line
) {
196 /* hit a breakpoint! */
197 printf("Break at line %d\n", line
);
209 printf("%d: %s\n", line
, ln
);
211 /* get commands from stdin */
213 char command
[1000], *cmd
;
215 /* print prompt and get command */
216 printf("(%s %d) ", (target
== GL_VERTEX_PROGRAM_ARB
? "vert" : "frag"),
218 fgets(command
, 999, stdin
);
220 /* skip leading whitespace */
221 for (cmd
= command
; cmd
[0] == ' '; cmd
++)
225 /* nothing (repeat the previous cmd?) */
230 /* skip N instructions */
233 printf("Skipping %d instructions\n", i
);
241 /* dump machine state */
242 if (progType
== NV_FRAGMENT_PROGRAM
) {
243 static const char *inRegs
[] = {
244 "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
245 "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
248 static const char *outRegs
[] = {
249 "o[COLR]", "o[COLH]", "o[DEPR]", NULL
253 printf("Fragment input attributes:\n");
254 for (i
= 0; inRegs
[i
]; i
++) {
255 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
257 (const GLubyte
*) inRegs
[i
], v
);
258 printf(" %s: %g, %g, %g, %g\n", inRegs
[i
],
259 v
[0], v
[1], v
[2], v
[3]);
261 printf("Fragment output attributes:\n");
262 for (i
= 0; outRegs
[i
]; i
++) {
263 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
265 (const GLubyte
*) outRegs
[i
], v
);
266 printf(" %s: %g, %g, %g, %g\n", outRegs
[i
],
267 v
[0], v
[1], v
[2], v
[3]);
269 printf("Temporaries:\n");
270 for (i
= 0; i
< 4; i
++) {
273 sprintf(temp
, "R%d", i
);
274 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
276 (const GLubyte
*) temp
, v
);
277 printf(" %s: %g, %g, %g, %g\n", temp
, v
[0],v
[1],v
[2],v
[3]);
280 else if (progType
== NV_VERTEX_PROGRAM
) {
283 static const char *inRegs
[] = {
284 "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
285 "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
286 "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
287 "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
290 static const char *outRegs
[] = {
291 "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
292 "o[BFC1]", "o[FOGC]", "o[PSIZ]",
293 "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
294 "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
297 printf("Vertex input attributes:\n");
298 for (i
= 0; inRegs
[i
]; i
++) {
299 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
301 (const GLubyte
*) inRegs
[i
], v
);
302 printf(" %s: %g, %g, %g, %g\n", inRegs
[i
],
303 v
[0], v
[1], v
[2], v
[3]);
305 printf("Vertex output attributes:\n");
306 for (i
= 0; outRegs
[i
]; i
++) {
307 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
309 (const GLubyte
*) outRegs
[i
], v
);
310 printf(" %s: %g, %g, %g, %g\n", outRegs
[i
],
311 v
[0], v
[1], v
[2], v
[3]);
313 printf("Temporaries:\n");
314 for (i
= 0; i
< 4; i
++) {
317 sprintf(temp
, "R%d", i
);
318 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
320 (const GLubyte
*) temp
, v
);
321 printf(" %s: %g, %g, %g, %g\n", temp
, v
[0],v
[1],v
[2],v
[3]);
327 list_program(program
, len
);
339 if (*c
== '\n' || *c
== '\r')
344 glGetProgramRegisterfvMESA(target
, strlen(cmd
),
345 (const GLubyte
*) cmd
, v
);
346 if (glGetError() == GL_NO_ERROR
)
347 printf("%s = %g, %g, %g, %g\n", cmd
, v
[0], v
[1], v
[2], v
[3]);
349 printf("Invalid expression\n");
353 if (cmd
[1] == ' ' && isdigit(cmd
[2])) {
354 char *comma
= strchr(cmd
, ',');
357 int x
= atoi(cmd
+ 2);
358 int y
= atoi(comma
+ 1);
359 if (NumBreakpoints
< MAX_BREAKPOINTS
) {
360 Breakpoints
[NumBreakpoints
].type
= PIXEL
;
361 Breakpoints
[NumBreakpoints
].x
= x
;
362 Breakpoints
[NumBreakpoints
].y
= y
;
363 Breakpoints
[NumBreakpoints
].enabled
= GL_TRUE
;
365 printf("Breakpoint %d: break at pixel (%d, %d)\n",
366 NumBreakpoints
, x
, y
);
371 int l
= atoi(cmd
+ 2);
372 if (l
&& NumBreakpoints
< MAX_BREAKPOINTS
) {
373 Breakpoints
[NumBreakpoints
].type
= LINE
;
374 Breakpoints
[NumBreakpoints
].line
= l
;
375 Breakpoints
[NumBreakpoints
].enabled
= GL_TRUE
;
377 printf("Breakpoint %d: break at line %d\n",
383 /* list breakpoints */
384 printf("Breakpoints:\n");
385 for (i
= 0; i
< NumBreakpoints
; i
++) {
386 switch (Breakpoints
[i
].type
) {
388 printf(" %d: break at line %d\n",
389 i
+ 1, Breakpoints
[i
].line
);
392 printf(" %d: break at pixel (%d, %d)\n",
393 i
+ 1, Breakpoints
[i
].x
, Breakpoints
[i
].y
);
401 printf("Debugger commands:\n");
402 printf(" b list breakpoints\n");
403 printf(" b N break at line N\n");
404 printf(" b x,y break at pixel x,y\n");
405 printf(" c continue execution\n");
406 printf(" d display register values\n");
408 printf(" l list program\n");
409 printf(" n next instruction\n");
410 printf(" p V print value V\n");
411 printf(" s N skip N instructions\n");
414 printf("Unknown command: %c\n", cmd
[0]);
421 * Print current line, some registers, and continue.
423 static void Debugger(GLenum target
, GLvoid
*data
)
430 assert(target
== GL_FRAGMENT_PROGRAM_NV
);
432 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
434 ln
= find_line_column((const GLubyte
*) data
, (const GLubyte
*) data
+ pos
,
436 printf("%d:%d: %s\n", line
, column
, (char *) ln
);
438 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
439 2, (const GLubyte
*) "R0", v
);
440 printf(" R0 = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
441 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
442 7, (const GLubyte
*) "f[WPOS]", v
);
443 printf(" o[WPOS] = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
444 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
445 7, (const GLubyte
*) "o[COLR]", v
);
446 printf(" o[COLR] = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
454 /**********************************************************************/
456 static GLfloat Diffuse
[4] = { 0.5, 0.5, 1.0, 1.0 };
457 static GLfloat Specular
[4] = { 0.8, 0.8, 0.8, 1.0 };
458 static GLfloat LightPos
[4] = { 0.0, 10.0, 20.0, 1.0 };
459 static GLfloat Delta
= 1.0;
461 static GLuint FragProg
;
462 static GLuint VertProg
;
463 static GLboolean Anim
= GL_TRUE
;
464 static GLboolean Wire
= GL_FALSE
;
465 static GLboolean PixelLight
= GL_TRUE
;
467 static GLfloat Xrot
= 0, Yrot
= 0;
470 #define NAMED_PARAMETER4FV(prog, name, v) \
471 glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
474 static void Display( void )
476 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
479 NAMED_PARAMETER4FV(FragProg
, "LightPos", LightPos
);
480 glEnable(GL_FRAGMENT_PROGRAM_NV
);
481 glEnable(GL_VERTEX_PROGRAM_NV
);
482 glDisable(GL_LIGHTING
);
485 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
486 glDisable(GL_FRAGMENT_PROGRAM_NV
);
487 glDisable(GL_VERTEX_PROGRAM_NV
);
488 glEnable(GL_LIGHTING
);
492 glRotatef(Xrot
, 1, 0, 0);
493 glRotatef(Yrot
, 0, 1, 0);
496 glutSolidSphere(2.0, 10, 5);
499 GLUquadricObj
*q
= gluNewQuadric();
500 gluQuadricNormals(q
, GL_SMOOTH
);
501 gluQuadricTexture(q
, GL_TRUE
);
502 glRotatef(90, 1, 0, 0);
503 glTranslatef(0, 0, -1);
504 gluCylinder(q
, 1.0, 1.0, 2.0, 24, 1);
515 static void Idle(void)
517 LightPos
[0] += Delta
;
518 if (LightPos
[0] > 25.0)
520 else if (LightPos
[0] <- 25.0)
526 static void Reshape( int width
, int height
)
528 glViewport( 0, 0, width
, height
);
529 glMatrixMode( GL_PROJECTION
);
531 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
532 /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
533 glMatrixMode( GL_MODELVIEW
);
535 glTranslatef( 0.0, 0.0, -15.0 );
539 static void Key( unsigned char key
, int x
, int y
)
560 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
562 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
565 PixelLight
= !PixelLight
;
567 printf("Per-pixel lighting\n");
570 printf("Conventional lighting\n");
580 static void SpecialKey( int key
, int x
, int y
)
582 const GLfloat step
= 3.0;
603 static void Init( int argc
, char *argv
[] )
605 static const char *fragProgramText
=
607 "DECLARE Diffuse; \n"
608 "DECLARE Specular; \n"
609 "DECLARE LightPos; \n"
611 "# Compute normalized LightPos, put it in R0\n"
612 "DP3 R0.x, LightPos, LightPos;\n"
614 "MUL R0, LightPos, R0.y;\n"
616 "# Compute normalized normal, put it in R1\n"
617 "DP3 R1, f[TEX0], f[TEX0]; \n"
619 "MUL R1, f[TEX0], R1.y;\n"
621 "# Compute dot product of light direction and normal vector\n"
624 "MUL R3, Diffuse, R2; # diffuse attenuation\n"
626 "POW R4, R2.x, {20.0}.x; # specular exponent\n"
628 "MUL R5, Specular, R4; # specular attenuation\n"
630 "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
634 static const char *vertProgramText
=
636 "# typical modelview/projection transform\n"
637 "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
638 "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
639 "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
640 "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
641 "# transform normal by inv transpose of modelview, put in tex0\n"
642 "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
643 "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
644 "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
645 "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
649 if (!glutExtensionSupported("GL_NV_vertex_program")) {
650 printf("Sorry, this demo requires GL_NV_vertex_program\n");
653 if (!glutExtensionSupported("GL_NV_fragment_program")) {
654 printf("Sorry, this demo requires GL_NV_fragment_program\n");
658 glGenProgramsNV(1, &FragProg
);
659 assert(FragProg
> 0);
660 glGenProgramsNV(1, &VertProg
);
661 assert(VertProg
> 0);
666 glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV
, FragProg
,
667 strlen(fragProgramText
),
668 (const GLubyte
*) fragProgramText
);
669 assert(glIsProgramNV(FragProg
));
670 glBindProgramNV(GL_FRAGMENT_PROGRAM_NV
, FragProg
);
672 NAMED_PARAMETER4FV(FragProg
, "Diffuse", Diffuse
);
673 NAMED_PARAMETER4FV(FragProg
, "Specular", Specular
);
678 glLoadProgramNV(GL_VERTEX_PROGRAM_NV
, VertProg
,
679 strlen(vertProgramText
),
680 (const GLubyte
*) vertProgramText
);
681 assert(glIsProgramNV(VertProg
));
682 glBindProgramNV(GL_VERTEX_PROGRAM_NV
, VertProg
);
683 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV
, 0, GL_MODELVIEW_PROJECTION_NV
, GL_IDENTITY_NV
);
684 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV
, 4, GL_MODELVIEW
, GL_INVERSE_TRANSPOSE_NV
);
689 glClearColor(0.3, 0.3, 0.3, 0.0);
690 glEnable(GL_DEPTH_TEST
);
692 glEnable(GL_LIGHTING
);
693 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, Diffuse
);
694 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, Specular
);
695 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, 20.0);
697 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
698 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
700 #ifdef GL_MESA_program_debug
701 if (argc
> 1 && strcmp(argv
[1], "fragment") == 0) {
702 printf(">> Debugging fragment program\n");
703 glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB
, Debugger2
,
704 (GLvoid
*) fragProgramText
);
705 glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA
);
708 printf(">> Debugging vertex program\n");
709 glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB
, Debugger2
,
710 (GLvoid
*) fragProgramText
);
711 glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA
);
717 int main( int argc
, char *argv
[] )
719 glutInit( &argc
, argv
);
720 glutInitWindowPosition( 0, 0 );
721 glutInitWindowSize( 200, 200 );
722 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
723 glutCreateWindow(argv
[0]);
724 glutReshapeFunc( Reshape
);
725 glutKeyboardFunc( Key
);
726 glutSpecialFunc( SpecialKey
);
727 glutDisplayFunc( Display
);