2 * Test the GL_MESA_program_debug extension
12 #include <glad/glad.h>
13 #include "glut_wrap.h"
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
86 enum {PIXEL
, LINE
} type
;
92 #define MAX_BREAKPOINTS 100
93 static struct breakpoint Breakpoints
[MAX_BREAKPOINTS
];
94 static int NumBreakpoints
= 0;
99 * Interactive debugger
101 static void Debugger2(GLenum target
, GLvoid
*data
)
103 static GLuint skipCount
= 0;
105 GLint pos
= 0, line
, column
;
113 /* Sigh, GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV so it's a bit
114 * hard to distinguish between them.
116 if (target
== GL_FRAGMENT_PROGRAM_ARB
)
117 progType
= ARB_FRAGMENT_PROGRAM
;
118 else if (target
== GL_FRAGMENT_PROGRAM_NV
)
119 progType
= NV_FRAGMENT_PROGRAM
;
121 progType
= NV_VERTEX_PROGRAM
;
123 /* Until we hit zero, continue rendering */
129 /* Get id of the program and current position */
131 case ARB_FRAGMENT_PROGRAM
:
132 glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_BINDING_ARB
, &id
);
133 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
135 case NV_FRAGMENT_PROGRAM
:
136 glGetIntegerv(GL_FRAGMENT_PROGRAM_BINDING_NV
, &id
);
137 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
139 case ARB_VERTEX_PROGRAM
:
140 glGetProgramivARB(GL_VERTEX_PROGRAM_ARB
, GL_PROGRAM_BINDING_ARB
, &id
);
141 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA
, &pos
);
143 case NV_VERTEX_PROGRAM
:
144 glGetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV
, &id
);
145 glGetIntegerv(GL_VERTEX_PROGRAM_POSITION_MESA
, &pos
);
151 /* get program string */
152 if (progType
== ARB_VERTEX_PROGRAM
||
153 progType
== ARB_FRAGMENT_PROGRAM
)
154 glGetProgramivARB(target
, GL_PROGRAM_LENGTH_ARB
, &len
);
156 glGetProgramivNV(id
, GL_PROGRAM_LENGTH_NV
, &len
);
157 program
= malloc(len
+ 1);
158 if (progType
== ARB_VERTEX_PROGRAM
||
159 progType
== ARB_FRAGMENT_PROGRAM
)
160 glGetProgramStringARB(target
, GL_PROGRAM_STRING_ARB
, program
);
162 glGetProgramStringNV(id
, GL_PROGRAM_STRING_NV
, program
);
165 /* Get current line number, column, line string */
166 ln
= find_line_column(program
, program
+ pos
, &line
, &column
);
168 /* test breakpoints */
169 if (NumBreakpoints
> 0)
173 for (i
= 0; i
< NumBreakpoints
; i
++) {
174 if (Breakpoints
[i
].enabled
) {
175 switch (Breakpoints
[i
].type
) {
177 if (progType
== ARB_FRAGMENT_PROGRAM
) {
180 else if (progType
== NV_FRAGMENT_PROGRAM
) {
183 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
184 6, (GLubyte
*) "f[WPOS]", pos
);
187 printf("%d, %d\n", px
, py
);
188 if (px
== Breakpoints
[i
].x
&&
189 py
== Breakpoints
[i
].y
) {
190 printf("Break at pixel (%d, %d)\n", px
, py
);
196 if (line
== Breakpoints
[i
].line
) {
197 /* hit a breakpoint! */
198 printf("Break at line %d\n", line
);
210 printf("%d: %s\n", line
, ln
);
212 /* get commands from stdin */
214 char command
[1000], *cmd
;
216 /* print prompt and get command */
217 printf("(%s %d) ", (target
== GL_VERTEX_PROGRAM_ARB
? "vert" : "frag"),
219 fgets(command
, 999, stdin
);
221 /* skip leading whitespace */
222 for (cmd
= command
; cmd
[0] == ' '; cmd
++)
226 /* nothing (repeat the previous cmd?) */
231 /* skip N instructions */
234 printf("Skipping %d instructions\n", i
);
242 /* dump machine state */
243 if (progType
== NV_FRAGMENT_PROGRAM
) {
244 static const char *inRegs
[] = {
245 "f[WPOS]", "f[COL0]", "f[COL1]", "f[FOGC]",
246 "f[TEX0]", "f[TEX1]", "f[TEX2]", "f[TEX3]",
249 static const char *outRegs
[] = {
250 "o[COLR]", "o[COLH]", "o[DEPR]", NULL
254 printf("Fragment input attributes:\n");
255 for (i
= 0; inRegs
[i
]; i
++) {
256 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
258 (const GLubyte
*) inRegs
[i
], v
);
259 printf(" %s: %g, %g, %g, %g\n", inRegs
[i
],
260 v
[0], v
[1], v
[2], v
[3]);
262 printf("Fragment output attributes:\n");
263 for (i
= 0; outRegs
[i
]; i
++) {
264 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
266 (const GLubyte
*) outRegs
[i
], v
);
267 printf(" %s: %g, %g, %g, %g\n", outRegs
[i
],
268 v
[0], v
[1], v
[2], v
[3]);
270 printf("Temporaries:\n");
271 for (i
= 0; i
< 4; i
++) {
274 sprintf(temp
, "R%d", i
);
275 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
277 (const GLubyte
*) temp
, v
);
278 printf(" %s: %g, %g, %g, %g\n", temp
, v
[0],v
[1],v
[2],v
[3]);
281 else if (progType
== NV_VERTEX_PROGRAM
) {
284 static const char *inRegs
[] = {
285 "v[OPOS]", "v[WGHT]", "v[NRML]", "v[COL0]",
286 "v[COL1]", "v[FOGC]", "v[6]", "v[7]",
287 "v[TEX0]", "v[TEX1]", "v[TEX2]", "v[TEX3]",
288 "v[TEX4]", "v[TEX5]", "v[TEX6]", "v[TEX7]",
291 static const char *outRegs
[] = {
292 "o[HPOS]", "o[COL0]", "o[COL1]", "o[BFC0]",
293 "o[BFC1]", "o[FOGC]", "o[PSIZ]",
294 "o[TEX0]", "o[TEX1]", "o[TEX2]", "o[TEX3]",
295 "o[TEX4]", "o[TEX5]", "o[TEX6]", "o[TEX7]",
298 printf("Vertex input attributes:\n");
299 for (i
= 0; inRegs
[i
]; i
++) {
300 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
302 (const GLubyte
*) inRegs
[i
], v
);
303 printf(" %s: %g, %g, %g, %g\n", inRegs
[i
],
304 v
[0], v
[1], v
[2], v
[3]);
306 printf("Vertex output attributes:\n");
307 for (i
= 0; outRegs
[i
]; i
++) {
308 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
310 (const GLubyte
*) outRegs
[i
], v
);
311 printf(" %s: %g, %g, %g, %g\n", outRegs
[i
],
312 v
[0], v
[1], v
[2], v
[3]);
314 printf("Temporaries:\n");
315 for (i
= 0; i
< 4; i
++) {
318 sprintf(temp
, "R%d", i
);
319 glGetProgramRegisterfvMESA(GL_VERTEX_PROGRAM_NV
,
321 (const GLubyte
*) temp
, v
);
322 printf(" %s: %g, %g, %g, %g\n", temp
, v
[0],v
[1],v
[2],v
[3]);
328 list_program(program
, len
);
340 if (*c
== '\n' || *c
== '\r')
345 glGetProgramRegisterfvMESA(target
, strlen(cmd
),
346 (const GLubyte
*) cmd
, v
);
347 if (glGetError() == GL_NO_ERROR
)
348 printf("%s = %g, %g, %g, %g\n", cmd
, v
[0], v
[1], v
[2], v
[3]);
350 printf("Invalid expression\n");
354 if (cmd
[1] == ' ' && isdigit(cmd
[2])) {
355 char *comma
= strchr(cmd
, ',');
358 int x
= atoi(cmd
+ 2);
359 int y
= atoi(comma
+ 1);
360 if (NumBreakpoints
< MAX_BREAKPOINTS
) {
361 Breakpoints
[NumBreakpoints
].type
= PIXEL
;
362 Breakpoints
[NumBreakpoints
].x
= x
;
363 Breakpoints
[NumBreakpoints
].y
= y
;
364 Breakpoints
[NumBreakpoints
].enabled
= GL_TRUE
;
366 printf("Breakpoint %d: break at pixel (%d, %d)\n",
367 NumBreakpoints
, x
, y
);
372 int l
= atoi(cmd
+ 2);
373 if (l
&& NumBreakpoints
< MAX_BREAKPOINTS
) {
374 Breakpoints
[NumBreakpoints
].type
= LINE
;
375 Breakpoints
[NumBreakpoints
].line
= l
;
376 Breakpoints
[NumBreakpoints
].enabled
= GL_TRUE
;
378 printf("Breakpoint %d: break at line %d\n",
384 /* list breakpoints */
385 printf("Breakpoints:\n");
386 for (i
= 0; i
< NumBreakpoints
; i
++) {
387 switch (Breakpoints
[i
].type
) {
389 printf(" %d: break at line %d\n",
390 i
+ 1, Breakpoints
[i
].line
);
393 printf(" %d: break at pixel (%d, %d)\n",
394 i
+ 1, Breakpoints
[i
].x
, Breakpoints
[i
].y
);
402 printf("Debugger commands:\n");
403 printf(" b list breakpoints\n");
404 printf(" b N break at line N\n");
405 printf(" b x,y break at pixel x,y\n");
406 printf(" c continue execution\n");
407 printf(" d display register values\n");
409 printf(" l list program\n");
410 printf(" n next instruction\n");
411 printf(" p V print value V\n");
412 printf(" s N skip N instructions\n");
415 printf("Unknown command: %c\n", cmd
[0]);
422 * Print current line, some registers, and continue.
424 static void Debugger(GLenum target
, GLvoid
*data
)
431 assert(target
== GL_FRAGMENT_PROGRAM_NV
);
433 glGetIntegerv(GL_FRAGMENT_PROGRAM_POSITION_MESA
, &pos
);
435 ln
= find_line_column((const GLubyte
*) data
, (const GLubyte
*) data
+ pos
,
437 printf("%d:%d: %s\n", line
, column
, (char *) ln
);
439 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
440 2, (const GLubyte
*) "R0", v
);
441 printf(" R0 = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
442 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
443 7, (const GLubyte
*) "f[WPOS]", v
);
444 printf(" o[WPOS] = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
445 glGetProgramRegisterfvMESA(GL_FRAGMENT_PROGRAM_NV
,
446 7, (const GLubyte
*) "o[COLR]", v
);
447 printf(" o[COLR] = %g, %g, %g, %g\n", v
[0], v
[1], v
[2], v
[3]);
455 /**********************************************************************/
457 static GLfloat Diffuse
[4] = { 0.5, 0.5, 1.0, 1.0 };
458 static GLfloat Specular
[4] = { 0.8, 0.8, 0.8, 1.0 };
459 static GLfloat LightPos
[4] = { 0.0, 10.0, 20.0, 1.0 };
460 static GLfloat Delta
= 1.0;
462 static GLuint FragProg
;
463 static GLuint VertProg
;
464 static GLboolean Anim
= GL_TRUE
;
465 static GLboolean Wire
= GL_FALSE
;
466 static GLboolean PixelLight
= GL_TRUE
;
468 static GLfloat Xrot
= 0, Yrot
= 0;
471 #define NAMED_PARAMETER4FV(prog, name, v) \
472 glProgramNamedParameter4fvNV(prog, strlen(name), (const GLubyte *) name, v)
475 static void Display( void )
477 glClear( GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
480 NAMED_PARAMETER4FV(FragProg
, "LightPos", LightPos
);
481 glEnable(GL_FRAGMENT_PROGRAM_NV
);
482 glEnable(GL_VERTEX_PROGRAM_NV
);
483 glDisable(GL_LIGHTING
);
486 glLightfv(GL_LIGHT0
, GL_POSITION
, LightPos
);
487 glDisable(GL_FRAGMENT_PROGRAM_NV
);
488 glDisable(GL_VERTEX_PROGRAM_NV
);
489 glEnable(GL_LIGHTING
);
493 glRotatef(Xrot
, 1, 0, 0);
494 glRotatef(Yrot
, 0, 1, 0);
497 glutSolidSphere(2.0, 10, 5);
500 GLUquadricObj
*q
= gluNewQuadric();
501 gluQuadricNormals(q
, GL_SMOOTH
);
502 gluQuadricTexture(q
, GL_TRUE
);
503 glRotatef(90, 1, 0, 0);
504 glTranslatef(0, 0, -1);
505 gluCylinder(q
, 1.0, 1.0, 2.0, 24, 1);
516 static void Idle(void)
518 LightPos
[0] += Delta
;
519 if (LightPos
[0] > 25.0)
521 else if (LightPos
[0] <- 25.0)
527 static void Reshape( int width
, int height
)
529 glViewport( 0, 0, width
, height
);
530 glMatrixMode( GL_PROJECTION
);
532 glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
533 /*glOrtho( -2.0, 2.0, -2.0, 2.0, 5.0, 25.0 );*/
534 glMatrixMode( GL_MODELVIEW
);
536 glTranslatef( 0.0, 0.0, -15.0 );
540 static void Key( unsigned char key
, int x
, int y
)
561 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
563 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
566 PixelLight
= !PixelLight
;
568 printf("Per-pixel lighting\n");
571 printf("Conventional lighting\n");
581 static void SpecialKey( int key
, int x
, int y
)
583 const GLfloat step
= 3.0;
604 static void Init( int argc
, char *argv
[] )
606 static const char *fragProgramText
=
608 "DECLARE Diffuse; \n"
609 "DECLARE Specular; \n"
610 "DECLARE LightPos; \n"
612 "# Compute normalized LightPos, put it in R0\n"
613 "DP3 R0.x, LightPos, LightPos;\n"
615 "MUL R0, LightPos, R0.y;\n"
617 "# Compute normalized normal, put it in R1\n"
618 "DP3 R1, f[TEX0], f[TEX0]; \n"
620 "MUL R1, f[TEX0], R1.y;\n"
622 "# Compute dot product of light direction and normal vector\n"
625 "MUL R3, Diffuse, R2; # diffuse attenuation\n"
627 "POW R4, R2.x, {20.0}.x; # specular exponent\n"
629 "MUL R5, Specular, R4; # specular attenuation\n"
631 "ADD o[COLR], R3, R5; # add diffuse and specular colors\n"
635 static const char *vertProgramText
=
637 "# typical modelview/projection transform\n"
638 "DP4 o[HPOS].x, c[0], v[OPOS] ;\n"
639 "DP4 o[HPOS].y, c[1], v[OPOS] ;\n"
640 "DP4 o[HPOS].z, c[2], v[OPOS] ;\n"
641 "DP4 o[HPOS].w, c[3], v[OPOS] ;\n"
642 "# transform normal by inv transpose of modelview, put in tex0\n"
643 "DP4 o[TEX0].x, c[4], v[NRML] ;\n"
644 "DP4 o[TEX0].y, c[5], v[NRML] ;\n"
645 "DP4 o[TEX0].z, c[6], v[NRML] ;\n"
646 "DP4 o[TEX0].w, c[7], v[NRML] ;\n"
650 if (!glutExtensionSupported("GL_NV_vertex_program")) {
651 printf("Sorry, this demo requires GL_NV_vertex_program\n");
654 if (!glutExtensionSupported("GL_NV_fragment_program")) {
655 printf("Sorry, this demo requires GL_NV_fragment_program\n");
659 glGenProgramsNV(1, &FragProg
);
660 assert(FragProg
> 0);
661 glGenProgramsNV(1, &VertProg
);
662 assert(VertProg
> 0);
667 glLoadProgramNV(GL_FRAGMENT_PROGRAM_NV
, FragProg
,
668 strlen(fragProgramText
),
669 (const GLubyte
*) fragProgramText
);
670 assert(glIsProgramNV(FragProg
));
671 glBindProgramNV(GL_FRAGMENT_PROGRAM_NV
, FragProg
);
673 NAMED_PARAMETER4FV(FragProg
, "Diffuse", Diffuse
);
674 NAMED_PARAMETER4FV(FragProg
, "Specular", Specular
);
679 glLoadProgramNV(GL_VERTEX_PROGRAM_NV
, VertProg
,
680 strlen(vertProgramText
),
681 (const GLubyte
*) vertProgramText
);
682 assert(glIsProgramNV(VertProg
));
683 glBindProgramNV(GL_VERTEX_PROGRAM_NV
, VertProg
);
684 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV
, 0, GL_MODELVIEW_PROJECTION_NV
, GL_IDENTITY_NV
);
685 glTrackMatrixNV(GL_VERTEX_PROGRAM_NV
, 4, GL_MODELVIEW
, GL_INVERSE_TRANSPOSE_NV
);
690 glClearColor(0.3, 0.3, 0.3, 0.0);
691 glEnable(GL_DEPTH_TEST
);
693 glEnable(GL_LIGHTING
);
694 glMaterialfv(GL_FRONT_AND_BACK
, GL_DIFFUSE
, Diffuse
);
695 glMaterialfv(GL_FRONT_AND_BACK
, GL_SPECULAR
, Specular
);
696 glMaterialf(GL_FRONT_AND_BACK
, GL_SHININESS
, 20.0);
698 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
699 printf("Press p to toggle between per-pixel and per-vertex lighting\n");
701 #ifdef GL_MESA_program_debug
702 if (argc
> 1 && strcmp(argv
[1], "fragment") == 0) {
703 printf(">> Debugging fragment program\n");
704 glProgramCallbackMESA(GL_FRAGMENT_PROGRAM_ARB
, Debugger2
,
705 (GLvoid
*) fragProgramText
);
706 glEnable(GL_FRAGMENT_PROGRAM_CALLBACK_MESA
);
709 printf(">> Debugging vertex program\n");
710 glProgramCallbackMESA(GL_VERTEX_PROGRAM_ARB
, Debugger2
,
711 (GLvoid
*) fragProgramText
);
712 glEnable(GL_VERTEX_PROGRAM_CALLBACK_MESA
);
718 int main( int argc
, char *argv
[] )
720 glutInit( &argc
, argv
);
721 glutInitWindowPosition( 0, 0 );
722 glutInitWindowSize( 200, 200 );
723 glutInitDisplayMode( GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
724 glutCreateWindow(argv
[0]);
726 glutReshapeFunc( Reshape
);
727 glutKeyboardFunc( Key
);
728 glutSpecialFunc( SpecialKey
);
729 glutDisplayFunc( Display
);