1 // BEGIN_COPYRIGHT -*- glean -*-
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
5 // Permission is hereby granted, free of charge, to any person
6 // obtaining a copy of this software and associated documentation
7 // files (the "Software"), to deal in the Software without
8 // restriction, including without limitation the rights to use,
9 // copy, modify, merge, publish, distribute, sublicense, and/or
10 // sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
29 // tfragprog.cpp: Test GL_ARB_fragment_program extension.
30 // Brian Paul 22 October 2005
32 // This is pretty simple. Specific fragment programs are run, we read back
33 // the framebuffer color and compare the color to the expected result.
34 // Pretty much any fragment program can be tested in the manner.
35 // Ideally, an additional fragment program test should be developed which
36 // exhaustively tests instruction combinations with all the various swizzle
37 // and masking options, etc.
38 // But this test is good for regression testing to be sure that particular or
39 // unique programs work correctly.
46 #include "tfragprog1.h"
52 static PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB_func
;
53 static PFNGLGENPROGRAMSARBPROC glGenProgramsARB_func
;
54 static PFNGLPROGRAMSTRINGARBPROC glProgramStringARB_func
;
55 static PFNGLBINDPROGRAMARBPROC glBindProgramARB_func
;
56 static PFNGLISPROGRAMARBPROC glIsProgramARB_func
;
57 static PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB_func
;
58 static PFNGLGETPROGRAMIVARBPROC glGetProgramivARB_func
;
59 static PFNGLFOGCOORDFPROC glFogCoordf_func
;
63 #define CLAMP01( X ) ( (X)<(0.0) ? (0.0) : ((X)>(1.0) ? (1.0) : (X)) )
65 #define ABS(X) ( (X) < 0.0 ? -(X) : (X) )
67 #define MAX( A, B ) ( (A) > (B) ? (A) : (B) )
69 #define MIN( A, B ) ( (A) < (B) ? (A) : (B) )
70 // Duplicate value four times
71 #define SMEAR(X) (X), (X), (X), (X)
73 #define DONT_CARE_Z -1.0
74 #define DONT_CARE_COLOR -1.0
76 #define FRAGCOLOR { 0.25, 0.75, 0.5, 0.25 }
77 #define PARAM0 { 0.0, 0.0, 0.0, 0.0 }
78 #define PARAM1 { 0.5, 0.25, 1.0, 0.5 }
79 #define PARAM2 { -1.0, 0.0, 0.25, -0.5 }
80 static const GLfloat FragColor
[4] = FRAGCOLOR
;
81 static const GLfloat Param0
[4] = PARAM0
;
82 static const GLfloat Param1
[4] = PARAM1
;
83 static const GLfloat Param2
[4] = PARAM2
;
84 static GLfloat InfNan
[4];
85 static GLfloat FogColor
[4] = {1.0, 1.0, 0.0, 0.0};
86 static GLfloat FogStart
= 10.0;
87 static GLfloat FogEnd
= 100.0;
88 static GLfloat FogDensity
= 0.03;
89 static GLfloat FogCoord
= 50.0; /* Between FogStart and FogEnd */
92 // These are the specific fragment programs which we'll test
93 // Alphabetical order, please
94 static const FragmentProgram Programs
[] = {
98 "PARAM p = program.local[2]; \n"
99 "ABS result.color, p; \n"
111 "PARAM p = program.local[1]; \n"
112 "ADD result.color, fragment.color, p; \n"
114 { CLAMP01(FragColor
[0] + Param1
[0]),
115 CLAMP01(FragColor
[1] + Param1
[1]),
116 CLAMP01(FragColor
[2] + Param1
[2]),
117 CLAMP01(FragColor
[3] + Param1
[3])
122 "ADD with saturation",
124 "PARAM p = program.local[1]; \n"
127 "ADD_SAT result.color, t, p; \n"
129 { CLAMP01(Param1
[0] + Param1
[0] + Param1
[0]),
130 CLAMP01(Param1
[1] + Param1
[1] + Param1
[1]),
131 CLAMP01(Param1
[2] + Param1
[2] + Param1
[2]),
132 CLAMP01(Param1
[3] + Param1
[3] + Param1
[3]),
139 "PARAM zero = program.local[0]; \n"
140 "PARAM p1 = program.local[1]; \n"
141 "PARAM p2 = program.local[2]; \n"
142 "CMP result.color, p2, zero, p1; \n"
144 { Param0
[0], Param1
[1], Param1
[2], Param0
[3] },
150 "PARAM values = { 0.0, 3.14159, 0.5, 1.0 }; \n"
151 "COS result.color.x, values.x; \n"
152 "COS result.color.y, values.y; \n"
153 "COS result.color.z, values.z; \n"
154 "COS result.color.w, values.w; \n"
166 "PARAM values = { 6.78318, 7.28318, 6.28318, -5.78318 }; \n"
167 "COS result.color.x, values.x; \n"
168 "COS result.color.y, values.y; \n"
169 "COS result.color.z, values.z; \n"
170 "COS result.color.w, values.w; \n"
182 "PARAM p1 = program.local[1]; \n"
183 "DP3 result.color, p1, fragment.color; \n"
185 { SMEAR(CLAMP01(Param1
[0] * FragColor
[0] +
186 Param1
[1] * FragColor
[1] +
187 Param1
[2] * FragColor
[2]))
194 "PARAM p1 = program.local[1]; \n"
195 "DP4 result.color, p1, fragment.color; \n"
197 { SMEAR(CLAMP01(Param1
[0] * FragColor
[0] +
198 Param1
[1] * FragColor
[1] +
199 Param1
[2] * FragColor
[2] +
200 Param1
[3] * FragColor
[3]))
207 "PARAM p1 = program.local[1]; \n"
208 "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
210 "DPH t, p1, fragment.color; \n"
211 "MUL result.color, t, scale; \n"
213 { SMEAR(CLAMP01((Param1
[0] * FragColor
[0] +
214 Param1
[1] * FragColor
[1] +
215 Param1
[2] * FragColor
[2] +
216 FragColor
[3]) * 0.1))
224 "PARAM v1 = {9.9, 0.16, 0.16, 9.9}; \n"
225 "PARAM v2 = {9.9, 2.5, 9.9, 2.5}; \n"
226 "DST result.color, v1, v2; \n"
238 "PARAM scale = {0.01, 0.01, 0.01, 0.01}; \n"
239 "PARAM values = {0.0, 1.0, 4.0, -2.0 }; \n"
241 "EX2 t.x, values.x; \n"
242 "EX2 t.y, values.y; \n"
243 "EX2 t.z, values.z; \n"
244 "EX2 t.w, values.w; \n"
245 "MUL result.color, t, scale; \n"
256 "PARAM values = {4.8, 0.3, -0.2, 1.2}; \n"
257 "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
260 "MUL result.color, t, scale; \n"
272 "PARAM values = {-1.1, 0.1, -2.2, 2.4 }; \n"
273 "FRC result.color, values; \n"
275 { 0.9, 0.1, 0.8, 0.4 },
281 "PARAM values = {64.0, 1, 30, 4}; \n"
282 "PARAM scale = {0.1, 0.1, 0.1, 0.1}; \n"
284 "LG2 t.x, values.x; \n"
285 "LG2 t.y, values.y; \n"
286 "LG2 t.z, values.z; \n"
287 "LG2 t.w, values.w; \n"
288 "MUL result.color, t, scale; \n"
300 "PARAM values = {0.65, 0.9, 0.0, 8.0}; \n"
301 "LIT result.color, values; \n"
305 0.433, // roughly Pow(values.y, values.w)
311 "LIT test 2 (degenerate case: 0 ^ 0 -> 1)",
313 "PARAM values = {0.65, 0.0, 0.0, 0.0}; \n"
314 "LIT result.color, values; \n"
324 "LIT test 3 (case x < 0)",
326 "PARAM values = {-0.5, 0.0, 0.0, 0.0}; \n"
327 "LIT result.color, values; \n"
330 CLAMP01(-0.5), // values.x
339 "PARAM p1 = program.local[1]; \n"
340 "PARAM t = {0.2, 0.5, 1.0, 0.0}; \n"
341 "LRP result.color, t, fragment.color, p1; \n"
343 { 0.2 * FragColor
[0] + (1.0 - 0.2) * Param1
[0],
344 0.5 * FragColor
[1] + (1.0 - 0.5) * Param1
[1],
345 1.0 * FragColor
[2] + (1.0 - 1.0) * Param1
[2],
346 0.0 * FragColor
[3] + (1.0 - 0.0) * Param1
[3]
353 "PARAM p1 = program.local[1]; \n"
354 "PARAM p2 = program.local[2]; \n"
355 "MAD result.color, fragment.color, p1, p2; \n"
357 { CLAMP01(FragColor
[0] * Param1
[0] + Param2
[0]),
358 CLAMP01(FragColor
[1] * Param1
[1] + Param2
[1]),
359 CLAMP01(FragColor
[2] * Param1
[2] + Param2
[2]),
360 CLAMP01(FragColor
[3] * Param1
[3] + Param2
[3])
367 "PARAM p1 = program.local[1]; \n"
368 "PARAM p2 = program.local[2]; \n"
369 "MAX result.color, p1, p2; \n"
371 { MAX(Param1
[0], Param2
[0]),
372 MAX(Param1
[1], Param2
[1]),
373 MAX(Param1
[2], Param2
[2]),
374 MAX(Param1
[3], Param2
[3]),
381 "PARAM p1 = program.local[1]; \n"
382 "MIN result.color, p1, fragment.color; \n"
384 { MIN(Param1
[0], FragColor
[0]),
385 MIN(Param1
[1], FragColor
[1]),
386 MIN(Param1
[2], FragColor
[2]),
387 MIN(Param1
[3], FragColor
[3]),
394 "MOV result.color, fragment.color; \n"
402 "PARAM p = program.local[1]; \n"
403 "MUL result.color, fragment.color, p; \n"
405 { CLAMP01(FragColor
[0] * Param1
[0]),
406 CLAMP01(FragColor
[1] * Param1
[1]),
407 CLAMP01(FragColor
[2] * Param1
[2]),
408 CLAMP01(FragColor
[3] * Param1
[3])
415 "PARAM zero = program.local[0]; \n"
416 "PARAM p = program.local[1]; \n"
417 "MOV result.color, zero; \n"
418 "MUL result.color.xy, fragment.color, p; \n"
420 { CLAMP01(FragColor
[0] * Param1
[0]),
421 CLAMP01(FragColor
[1] * Param1
[1]),
428 "POW test (exponentiation)",
430 "PARAM values = {0.5, 2, 3, 4}; \n"
431 "POW result.color.x, values.x, values.y; \n"
432 "POW result.color.y, values.x, values.z; \n"
433 "POW result.color.z, values.x, values.w; \n"
434 "POW result.color.w, values.w, values.x; \n"
438 0.5 * 0.5 * 0.5 * 0.5,
443 "RCP test (reciprocal)",
445 "PARAM values = {8, -10, 1, 12 }; \n"
446 "RCP result.color.x, values.x; \n"
447 "RCP result.color.y, values.y; \n"
448 "RCP result.color.z, values.z; \n"
449 "RCP result.color.w, values.w; \n"
451 { 1.0 / 8.0, CLAMP01(1.0 / -10.0), 1, 1.0 / 12.0 },
455 /* check that RCP result is replicated across XYZW */
456 "RCP test 2 (reciprocal)",
458 "PARAM values = {8, -10, 1, 12 }; \n"
459 "MOV result.color, values; \n"
460 "RCP result.color, values.x; \n"
462 { 1.0 / 8.0, 1.0 / 8.0, 1.0 / 8.0, 1.0 / 8.0 },
466 "RSQ test 1 (reciprocal square root)",
468 "PARAM values = {1, 4, 9, 100 }; \n"
469 "RSQ result.color.x, values.x; \n"
470 "RSQ result.color.y, values.y; \n"
471 "RSQ result.color.z, values.z; \n"
472 "RSQ result.color.w, values.w; \n"
474 { 1.0, 0.5, 0.3333, 0.1 },
478 "RSQ test 2 (reciprocal square root of negative value)",
480 "PARAM values = {0, -100, -5, -1}; \n"
481 "RSQ result.color.x, values.x; \n"
482 "RSQ result.color.y, values.y; \n"
483 "RSQ result.color.z, values.z; \n"
484 "RSQ result.color.w, values.w; \n"
496 "PARAM values = { 0.5, 0.5, 0.0, 0.0 }; \n"
497 "SCS result.color.x, values.x; \n"
498 "SCS result.color.y, values.y; \n"
510 "PARAM p0 = program.local[0]; \n"
511 "PARAM p2 = program.local[2]; \n"
512 "SGE result.color, p2, p0; \n"
514 { Param2
[0] >= Param0
[0] ? 1.0 : 0.0,
515 Param2
[1] >= Param0
[1] ? 1.0 : 0.0,
516 Param2
[2] >= Param0
[2] ? 1.0 : 0.0,
517 Param2
[3] >= Param0
[3] ? 1.0 : 0.0,
524 "PARAM values = { 1.57079, -1.57079, 0.5, 1.0 }; \n"
525 "SIN result.color.x, values.x; \n"
526 "SIN result.color.y, values.y; \n"
527 "SIN result.color.z, values.z; \n"
528 "SIN result.color.w, values.w; \n"
540 "PARAM values = { 3.14159, -3.14159, 6.78319, -5.78319 }; \n"
541 "SIN result.color.x, values.x; \n"
542 "SIN result.color.y, values.y; \n"
543 "SIN result.color.z, values.z; \n"
544 "SIN result.color.w, values.w; \n"
556 "PARAM p1 = program.local[1]; \n"
557 "SLT result.color, fragment.color, p1; \n"
559 { FragColor
[0] < Param1
[0] ? 1.0 : 0.0,
560 FragColor
[1] < Param1
[1] ? 1.0 : 0.0,
561 FragColor
[2] < Param1
[2] ? 1.0 : 0.0,
562 FragColor
[3] < Param1
[3] ? 1.0 : 0.0,
567 "SUB test (with swizzle)",
569 "PARAM p1 = program.local[1]; \n"
570 "SUB result.color, p1.yxwz, fragment.color.yxwz; \n"
572 { CLAMP01(Param1
[1] - FragColor
[1]),
573 CLAMP01(Param1
[0] - FragColor
[0]),
574 CLAMP01(Param1
[3] - FragColor
[3]),
575 CLAMP01(Param1
[2] - FragColor
[2])
580 "SUB with saturation",
582 "PARAM p1 = program.local[1]; \n"
583 "PARAM bias = {0.1, 0.1, 0.1, 0.1}; \n"
585 "SUB_SAT t, fragment.color, p1; \n"
586 "ADD result.color, t, bias; \n"
588 { CLAMP01(FragColor
[0] - Param1
[1]) + 0.1,
589 CLAMP01(FragColor
[1] - Param1
[1]) + 0.1,
590 CLAMP01(FragColor
[2] - Param1
[2]) + 0.1,
591 CLAMP01(FragColor
[3] - Param1
[3]) + 0.1
598 "PARAM p = program.local[1]; \n"
599 "SWZ result.color, p, -1,-y,z,0; \n"
609 // this test checks that SOA execution is handled correctly
610 "swizzled move test",
613 "PARAM p = program.local[1]; \n"
615 "MOV t, t.yxwz; \n" // "in-place" swizzle
616 "MOV result.color, t; \n"
618 { Param1
[1], Param1
[0], Param1
[3], Param1
[2] },
622 // this test checks that SOA execution is handled correctly
626 "PARAM p = program.local[1]; \n"
628 "ADD t, t, t.yxwz; \n" // "in-place" swizzled add
629 "MOV result.color, t; \n"
631 { CLAMP01(Param1
[0] + Param1
[1]),
632 CLAMP01(Param1
[1] + Param1
[0]),
633 CLAMP01(Param1
[2] + Param1
[3]),
634 CLAMP01(Param1
[3] + Param1
[2]) },
640 "PARAM p1 = program.local[1]; \n"
641 "PARAM p2 = program.local[2]; \n"
642 "XPD result.color, p1, p2; \n"
644 { CLAMP01(Param1
[1] * Param2
[2] - Param1
[2] * Param2
[1]),
645 CLAMP01(Param1
[2] * Param2
[0] - Param1
[0] * Param2
[2]),
646 CLAMP01(Param1
[0] * Param2
[1] - Param1
[1] * Param2
[0]),
654 "PARAM p = program.local[1]; \n"
655 "MOV result.color, p; \n"
656 "MOV result.depth.z, p.y; \n"
666 // ============= Numeric stress tests =================================
667 // Basically just check that we don't crash when we do divides by
670 "Divide by zero test",
672 "PARAM zero = program.local[0]; \n"
673 "RCP result.color.x, zero.x; \n"
674 "RCP result.color.y, zero.y; \n"
675 "RCP result.color.z, zero.z; \n"
676 "RCP result.color.w, zero.w; \n"
686 "Infinity and nan test",
688 "PARAM zero = program.local[0]; \n"
689 "PARAM infNan = program.local[9]; \n"
690 "ADD result.color, infNan, zero; \n"
700 // ============= Fog tests ============================================
702 #define FOG_FACT ((FogEnd - FogCoord) / (FogEnd - FogStart))
704 "ARB_fog_linear test",
706 "OPTION ARB_fog_linear; \n"
707 "MOV result.color, fragment.color; \n"
709 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
710 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
711 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
717 "Computed fog linear test",
719 "# fogParams.x = density \n"
720 "# fogParams.y = start \n"
721 "# fogParams.z = end \n"
722 "# fogParams.w = 1/(end-start) \n"
723 "PARAM fogParams = state.fog.params; \n"
724 "ATTRIB fogCoord = fragment.fogcoord; \n"
725 "PARAM fogColor = state.fog.color; \n"
726 "TEMP numerator, f; \n"
727 "# f = (end - coord) / (end - start) \n"
728 "SUB numerator, fogParams.z, fogCoord.x; \n"
729 "MUL_SAT f, numerator, fogParams.w; \n"
730 "LRP result.color.rgb, f, fragment.color, fogColor; \n"
731 "MOV result.color.a, fragment.color.a; \n"
733 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
734 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
735 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
743 #define FOG_FACT 0.2231 // = exp(-Density * Coord)
747 "OPTION ARB_fog_exp; \n"
748 "MOV result.color, fragment.color; \n"
750 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
751 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
752 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
758 #define FOG_FACT 0.3535 // = ex2(-Density * Coord)
760 // NOTE: we could also do this with the POW instruction
761 "Computed fog exp test",
763 "# fogParams.x = density \n"
764 "# fogParams.y = start \n"
765 "# fogParams.z = end \n"
766 "# fogParams.w = 1/(end-start) \n"
767 "PARAM fogParams = state.fog.params; \n"
768 "ATTRIB fogCoord = fragment.fogcoord; \n"
769 "PARAM fogColor = state.fog.color; \n"
771 "# f = exp(-density * coord) \n"
772 "MUL dc.x, fogParams.x, fogCoord.x; \n"
773 "EX2_SAT f, -dc.x; \n"
774 "LRP result.color.rgb, f, fragment.color, fogColor; \n"
775 "MOV result.color.a, fragment.color.a; \n"
777 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
778 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
779 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
787 #define FOG_FACT 0.1054 // = exp(-(Density * Coord)^2)
791 "OPTION ARB_fog_exp2; \n"
792 "MOV result.color, fragment.color; \n"
794 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
795 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
796 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
802 #define FOG_FACT 0.2102 // = ex2(-(Density * Coord)^2)
804 // NOTE: we could also do this with the POW instruction
805 "Computed fog exp2 test",
807 "# fogParams.x = density \n"
808 "# fogParams.y = start \n"
809 "# fogParams.z = end \n"
810 "# fogParams.w = 1/(end-start) \n"
811 "PARAM fogParams = state.fog.params; \n"
812 "ATTRIB fogCoord = fragment.fogcoord; \n"
813 "PARAM fogColor = state.fog.color; \n"
815 "# f = exp(-(density * coord)^2) \n"
816 "MUL dc.x, fogParams.x, fogCoord.x; \n"
817 "MUL dc.x, dc.x, dc.x; \n"
818 "EX2_SAT f, -dc.x; \n"
819 "LRP result.color.rgb, f, fragment.color, fogColor; \n"
820 "MOV result.color.a, fragment.color.a; \n"
822 { FragColor
[0] * FOG_FACT
+ FogColor
[0] * (1.0 - FOG_FACT
),
823 FragColor
[1] * FOG_FACT
+ FogColor
[1] * (1.0 - FOG_FACT
),
824 FragColor
[2] * FOG_FACT
+ FogColor
[2] * (1.0 - FOG_FACT
),
831 // XXX add lots more tests here!
832 { NULL
, NULL
, {0,0,0,0}, 0 } // end of list sentinal
838 FragmentProgramTest::setup(void)
840 // setup Infinity, Nan values
844 nan
= (0xff << 23) | (1 << 0);
845 nanPtr
= (float *) &nan
;
846 InfNan
[0] = HUGE_VAL
;
847 InfNan
[1] = -HUGE_VAL
;
848 InfNan
[2] = (float) (*nanPtr
);
849 InfNan
[3] = 1.0 / HUGE_VAL
;
851 // get function pointers
852 glProgramLocalParameter4fvARB_func
= (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC
) GLUtils::getProcAddress("glProgramLocalParameter4fvARB");
853 assert(glProgramLocalParameter4fvARB_func
);
855 glGenProgramsARB_func
= (PFNGLGENPROGRAMSARBPROC
) GLUtils::getProcAddress("glGenProgramsARB");
856 assert(glGenProgramsARB_func
);
858 glProgramStringARB_func
= (PFNGLPROGRAMSTRINGARBPROC
) GLUtils::getProcAddress("glProgramStringARB");
859 assert(glProgramStringARB_func
);
861 glBindProgramARB_func
= (PFNGLBINDPROGRAMARBPROC
) GLUtils::getProcAddress("glBindProgramARB");
862 assert(glBindProgramARB_func
);
864 glIsProgramARB_func
= (PFNGLISPROGRAMARBPROC
) GLUtils::getProcAddress("glIsProgramARB");
865 assert(glIsProgramARB_func
);
867 glDeleteProgramsARB_func
= (PFNGLDELETEPROGRAMSARBPROC
) GLUtils::getProcAddress("glDeleteProgramsARB");
868 assert(glDeleteProgramsARB_func
);
870 glGetProgramivARB_func
= (PFNGLGETPROGRAMIVARBPROC
) GLUtils::getProcAddress("glGetProgramivARB");
871 assert(glGetProgramivARB_func
);
873 glFogCoordf_func
= (PFNGLFOGCOORDFPROC
) GLUtils::getProcAddress("glFogCoordf");
874 assert(glFogCoordf_func
);
877 glGenProgramsARB_func(1, &progID
);
878 glBindProgramARB_func(GL_FRAGMENT_PROGRAM_ARB
, progID
);
879 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
881 // load program inputs
882 glColor4fv(FragColor
);
883 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB
, 0, Param0
);
884 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB
, 1, Param1
);
885 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB
, 2, Param2
);
886 glProgramLocalParameter4fvARB_func(GL_FRAGMENT_PROGRAM_ARB
, 9, InfNan
);
888 GLenum err
= glGetError();
889 assert(!err
); // should be OK
891 // setup vertex transform (we'll draw a quad in middle of window)
892 glMatrixMode(GL_PROJECTION
);
895 glOrtho(-1.0, 1.0, -1.0, 1.0, 0.0, 1.0);
897 glOrtho(-4.0, 4.0, -4.0, 4.0, 0.0, 1.0);
899 glMatrixMode(GL_MODELVIEW
);
901 glDrawBuffer(GL_FRONT
);
902 glReadBuffer(GL_FRONT
);
905 glFogf(GL_FOG_START
, FogStart
);
906 glFogf(GL_FOG_END
, FogEnd
);
907 glFogf(GL_FOG_DENSITY
, FogDensity
);
908 glFogfv(GL_FOG_COLOR
, FogColor
);
909 glFogi(GL_FOG_COORDINATE_SOURCE_EXT
, GL_FOG_COORDINATE_EXT
);
910 glFogCoordf_func(FogCoord
);
912 // compute error tolerances (may need fine-tuning)
914 glGetIntegerv(GL_RED_BITS
, &bufferBits
[0]);
915 glGetIntegerv(GL_GREEN_BITS
, &bufferBits
[1]);
916 glGetIntegerv(GL_BLUE_BITS
, &bufferBits
[2]);
917 glGetIntegerv(GL_ALPHA_BITS
, &bufferBits
[3]);
918 glGetIntegerv(GL_DEPTH_BITS
, &bufferBits
[4]);
920 tolerance
[0] = 2.0 / (1 << bufferBits
[0]);
921 tolerance
[1] = 2.0 / (1 << bufferBits
[1]);
922 tolerance
[2] = 2.0 / (1 << bufferBits
[2]);
924 tolerance
[3] = 2.0 / (1 << bufferBits
[3]);
928 tolerance
[4] = 16.0 / (1 << bufferBits
[4]);
935 FragmentProgramTest::reportFailure(const char *programName
,
936 const GLfloat expectedColor
[4],
937 const GLfloat actualColor
[4] ) const
939 env
->log
<< "FAILURE:\n";
940 env
->log
<< " Program: " << programName
<< "\n";
941 env
->log
<< " Expected color: ";
942 env
->log
<< expectedColor
[0] << ", ";
943 env
->log
<< expectedColor
[1] << ", ";
944 env
->log
<< expectedColor
[2] << ", ";
945 env
->log
<< expectedColor
[3] << "\n";
946 env
->log
<< " Observed color: ";
947 env
->log
<< actualColor
[0] << ", ";
948 env
->log
<< actualColor
[1] << ", ";
949 env
->log
<< actualColor
[2] << ", ";
950 env
->log
<< actualColor
[3] << "\n";
955 FragmentProgramTest::reportZFailure(const char *programName
,
956 GLfloat expectedZ
, GLfloat actualZ
) const
958 env
->log
<< "FAILURE:\n";
959 env
->log
<< " Program: " << programName
<< "\n";
960 env
->log
<< " Expected Z: " << expectedZ
<< "\n";
961 env
->log
<< " Observed Z: " << actualZ
<< "\n";
965 // Compare actual and expected colors
967 FragmentProgramTest::equalColors(const GLfloat act
[4], const GLfloat exp
[4]) const
969 if (fabsf(act
[0] - exp
[0]) > tolerance
[0] && exp
[0] != DONT_CARE_COLOR
)
971 if (fabsf(act
[1] - exp
[1]) > tolerance
[1] && exp
[1] != DONT_CARE_COLOR
)
973 if (fabsf(act
[2] - exp
[2]) > tolerance
[2] && exp
[2] != DONT_CARE_COLOR
)
975 if (fabsf(act
[3] - exp
[3]) > tolerance
[3] && exp
[3] != DONT_CARE_COLOR
)
982 FragmentProgramTest::equalDepth(GLfloat z0
, GLfloat z1
) const
984 if (fabsf(z0
- z1
) > tolerance
[4])
992 FragmentProgramTest::testProgram(const FragmentProgram
&p
)
994 glProgramStringARB_func(GL_FRAGMENT_PROGRAM_ARB
,
995 GL_PROGRAM_FORMAT_ASCII_ARB
,
996 strlen(p
.progString
),
997 (const GLubyte
*) p
.progString
);
999 GLenum err
= glGetError();
1001 env
->log
<< "OpenGL error " << (int) err
<< "\n";
1002 env
->log
<< "Invalid Fragment Program:\n";
1003 env
->log
<< p
.progString
;
1004 env
->log
<< glGetString(GL_PROGRAM_ERROR_STRING_ARB
) << "\n";
1008 // to avoid potential issue with undefined result.depth.z
1009 if (p
.expectedZ
== DONT_CARE_Z
)
1010 glDisable(GL_DEPTH_TEST
);
1012 glEnable(GL_DEPTH_TEST
);
1015 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1017 glBegin(GL_POLYGON
);
1026 glReadPixels(windowWidth
/ 2, windowHeight
/ 2, 1, 1,
1027 GL_RGBA
, GL_FLOAT
, pixel
);
1030 printf("%s: Expect: %.3f %.3f %.3f %.3f found: %.3f %.3f %.3f %.3f\n",
1032 p
.expectedColor
[0], p
.expectedColor
[1],
1033 p
.expectedColor
[2], p
.expectedColor
[3],
1034 pixel
[0], pixel
[1], pixel
[2], pixel
[3]);
1036 if (!equalColors(pixel
, p
.expectedColor
)) {
1037 reportFailure(p
.name
, p
.expectedColor
, pixel
);
1041 if (p
.expectedZ
!= DONT_CARE_Z
) {
1043 glReadPixels(windowWidth
/ 2, windowHeight
/ 2, 1, 1,
1044 GL_DEPTH_COMPONENT
, GL_FLOAT
, &z
);
1045 if (!equalDepth(z
, p
.expectedZ
)) {
1046 reportZFailure(p
.name
, p
.expectedZ
, z
);
1055 FragmentProgramTest::runOne(MultiTestResult
&r
, Window
&w
)
1057 // to test a single sub-test, set the name here:
1058 const char *single
= getenv("PIGLIT_TEST");
1064 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
1066 for (int i
= 0; Programs
[i
].name
; i
++) {
1068 if (!single
|| strcmp(single
, Programs
[i
].name
) == 0) {
1071 glViewport(0, i
* 20, windowWidth
, 20);
1073 if (!testProgram(Programs
[i
])) {
1086 r
.pass
= (r
.numFailed
== 0);
1090 // The test object itself:
1091 FragmentProgramTest
fragmentProgramTest("fragProg1", "window, rgb, z",
1092 "GL_ARB_fragment_program",
1093 "Fragment Program test 1: test a specific set of fragment programs.\n");
1097 } // namespace GLEAN