glsl: test loop unroll with uint overflow
[piglit.git] / generated_tests / gen_builtin_uniform_tests.py
blobc9275c4b099b4fa276632f0aef23e1a291bec8b4
1 # coding=utf-8
3 # Copyright © 2011 Intel Corporation
5 # Permission is hereby granted, free of charge, to any person obtaining a
6 # copy of this software and associated documentation files (the "Software"),
7 # to deal in the Software without restriction, including without limitation
8 # the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 # and/or sell copies of the Software, and to permit persons to whom the
10 # Software is furnished to do so, subject to the following conditions:
12 # The above copyright notice and this permission notice (including the next
13 # paragraph) shall be included in all copies or substantial portions of the
14 # Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 # DEALINGS IN THE SOFTWARE.
24 # Generate a set of shader_runner tests for every overloaded version
25 # of every built-in function, based on the test vectors computed by
26 # builtin_function.py.
28 # In each set of generated tests, one test exercises the built-in
29 # function in each type of shader (vertex, geometry, and fragment).
30 # In all cases, the inputs to the built-in function come from
31 # uniforms, so that the effectiveness of the test won't be
32 # circumvented by constant folding in the GLSL compiler.
34 # The tests operate by invoking the built-in function in the
35 # appropriate shader, applying a scale and offset so that the expected
36 # values are in the range [0.25, 0.75], and then outputting the result
37 # as a solid rgba color, which is then checked using shader_runner's
38 # "probe rgba" command.
40 # For built-in functions whose result type is a matrix, the test
41 # checks one column at a time.
43 # This program outputs, to stdout, the name of each file it generates.
44 # With the optional argument --names-only, it only outputs the names
45 # of the files; it doesn't generate them.
47 from builtin_function import *
48 import abc
49 import numpy
50 import optparse
51 import os
52 import os.path
54 from modules import utils
57 def compute_offset_and_scale(test_vectors):
58 """Compute scale and offset values such that for each result in
59 test_vectors, (result - offset) * scale is in the range [0.25,
60 0.75], and scale is less than or equal to 1.0. These values are
61 used to transform the test vectors so that their outputs can be
62 stored in gl_FragColor without overflow.
63 """
64 low = min(numpy.min(tv.result) for tv in test_vectors)
65 hi = max(numpy.max(tv.result) for tv in test_vectors)
66 span = hi - low
67 center = (hi + low)/2.0
68 span *= 2.0
69 if span < 1.0:
70 span = 1.0
71 offset = center - span/2.0
72 scale = 1.0/span
73 return offset, scale
76 def shader_runner_format(values):
77 """Format the given values for use in a shader_runner "uniform" or
78 "probe rgba" command. Bools are converted to 0's and 1's, and
79 values are separated by spaces.
80 """
81 transformed_values = []
82 for value in values:
83 if isinstance(value, (bool, np.bool_)):
84 transformed_values.append(int(value))
85 else:
86 transformed_values.append(value)
87 return ' '.join(repr(x) for x in transformed_values)
90 def shader_runner_type(glsl_type):
91 """Return the appropriate type name necessary for binding a
92 uniform of the given type using shader_runner's "uniform" command.
93 Boolean values and vectors are converted to ints, and square
94 matrices are written in "matNxN" form.
95 """
96 if glsl_type.base_type == glsl_bool:
97 if glsl_type.is_scalar:
98 return 'int'
99 else:
100 return 'ivec{0}'.format(glsl_type.num_rows)
101 elif glsl_type.is_matrix:
102 return 'mat{0}x{1}'.format(glsl_type.num_cols, glsl_type.num_rows)
103 else:
104 return str(glsl_type)
107 class Comparator(object):
108 """Base class which abstracts how we compare expected and actual
109 values.
111 __metaclass__ = abc.ABCMeta
113 def make_additional_declarations(self):
114 """Return additional declarations, if any, that are needed in
115 the shader program.
117 return ''
119 @abc.abstractmethod
120 def make_result_handler(self, invocation, output_var):
121 """Return the shader code that is needed to produce the result
122 and store it in output_var.
124 invocation is the GLSL code to compute the output of the
125 built-in function.
128 @abc.abstractmethod
129 def draw_test(self, test_vector, draw_command):
130 """Return the shader_runner test code that is needed to run a
131 single test vector.
134 @abc.abstractmethod
135 def result_vector(self, test_vector):
136 """Return the expected result color as a list of floats."""
138 def testname_suffix(self):
139 """Return a string to be used as a suffix on the test name to
140 distinguish it from tests using other comparators."""
141 return ''
144 class BoolComparator(Comparator):
145 """Comparator that tests functions returning bools and bvecs by
146 converting them to floats.
148 This comparator causes code to be generated in the following form:
150 rettype result = func(args);
151 output_var = vec4(result, 0.0, ...);
153 def __init__(self, signature):
154 assert not signature.rettype.is_matrix
155 self.__signature = signature
156 self.__padding = 4 - signature.rettype.num_rows
158 def make_result_handler(self, invocation, output_var):
159 statements = ' {0} result = {1};\n'.format(
160 self.__signature.rettype, invocation)
161 statements += ' {0} = vec4(result{1});\n'.format(
162 output_var, ', 0.0' * self.__padding)
163 return statements
165 def convert_to_float(self, value):
166 """Convert the given vector or scalar value to a list of
167 floats representing the expected color produced by the test.
169 value = value*1.0 # convert bools to floats
170 value = column_major_values(value)
171 value += [0.0] * self.__padding
172 return value
174 def draw_test(self, test_vector, draw_command):
175 return draw_command
177 def result_vector(self, test_vector):
178 return self.convert_to_float(test_vector.result)
181 class BoolIfComparator(Comparator):
182 """Comparator that tests functions returning bools by evaluating
183 them inside an if statement.
185 This comparator causes code to be generated in the following form:
187 if (func(args))
188 output_var = vec4(1.0, 1.0, 0.0, 1.0);
189 else
190 output_var = vecp(0.0, 0.0, 1.0, 1.0);
192 def __init__(self, signature):
193 assert signature.rettype == glsl_bool
194 self.__padding = 4 - signature.rettype.num_rows
196 def make_result_handler(self, invocation, output_var):
197 statements = ' if({0})\n'.format(invocation)
198 statements += ' {0} = vec4(1.0, 1.0, 0.0, 1.0);\n'.format(
199 output_var)
200 statements += ' else\n'
201 statements += ' {0} = vec4(0.0, 0.0, 1.0, 1.0);\n'.format(
202 output_var)
203 return statements
205 def convert_to_float(self, value):
206 """Convert the given vector or scalar value to a list of
207 floats representing the expected color produced by the test.
209 if value:
210 return [1.0, 1.0, 0.0, 1.0]
211 else:
212 return [0.0, 0.0, 1.0, 1.0]
214 def draw_test(self, test_vector, draw_command):
215 return draw_command
217 def result_vector(self, test_vector):
218 return self.convert_to_float(test_vector.result)
220 def testname_suffix(self):
221 return '-using-if'
224 class IntComparator(Comparator):
225 """Comparator that tests functions returning ints or ivecs using a
226 strict equality test.
228 This comparator causes code to be generated in the following form:
230 rettype result = func(args);
231 output_var = result == expected ? vec4(0.0, 1.0, 0.0, 1.0)
232 : vec4(1.0, 0.0, 0.0, 1.0);
234 def __init__(self, signature):
235 self.__signature = signature
237 def make_additional_declarations(self):
238 return 'uniform {0} expected;\n'.format(self.__signature.rettype)
240 def make_result_handler(self, invocation, output_var):
241 statements = ' {0} result = {1};\n'.format(
242 self.__signature.rettype, invocation)
243 statements += ' {v} = {cond} ? {green} : {red};\n'.format(
244 v=output_var, cond='result == expected',
245 green='vec4(0.0, 1.0, 0.0, 1.0)',
246 red='vec4(1.0, 0.0, 0.0, 1.0)')
247 return statements
249 def draw_test(self, test_vector, draw_command):
250 test = 'uniform {0} expected {1}\n'.format(
251 shader_runner_type(self.__signature.rettype),
252 shader_runner_format(column_major_values(test_vector.result)))
253 test += draw_command
254 return test
256 def result_vector(self, test_vector):
257 return [0.0, 1.0, 0.0, 1.0]
260 class FloatComparator(Comparator):
261 """Comparator that tests functions returning floats or vecs using a
262 strict equality test.
264 This comparator causes code to be generated in the following form:
266 rettype result = func(args);
267 output_var = distance(result, expected) <= tolerance
268 ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);
270 def __init__(self, signature):
271 self.__signature = signature
273 def make_additional_declarations(self):
274 decls = 'uniform float tolerance;\n'
275 decls += 'uniform {0} expected;\n'.format(self.__signature.rettype)
276 return decls
278 def make_indexers(self):
279 """Build a list of strings which index into every possible
280 value of the result. For example, if the result is a vec2,
281 then build the indexers ['[0]', '[1]'].
283 if self.__signature.rettype.num_cols == 1:
284 col_indexers = ['']
285 else:
286 col_indexers = ['[{0}]'.format(i)
287 for i in range(self.__signature.rettype.num_cols)]
288 if self.__signature.rettype.num_rows == 1:
289 row_indexers = ['']
290 else:
291 row_indexers = ['[{0}]'.format(i)
292 for i in range(self.__signature.rettype.num_rows)]
293 return [col_indexer + row_indexer
294 for col_indexer in col_indexers
295 for row_indexer in row_indexers]
297 def make_result_handler(self, invocation, output_var):
298 statements = ' {0} result = {1};\n'.format(
299 self.__signature.rettype, invocation)
300 # Can't use distance when testing itself, or when the rettype
301 # is a matrix.
302 if self.__signature.name == 'distance' or \
303 self.__signature.rettype.is_matrix:
304 statements += ' {0} residual = result - expected;\n'.format(
305 self.__signature.rettype)
306 statements += ' float error_sq = {0};\n'.format(
307 ' + '.join(
308 'residual{0} * residual{0}'.format(indexer)
309 for indexer in self.make_indexers()))
310 condition = 'error_sq <= tolerance * tolerance'
311 else:
312 condition = 'distance(result, expected) <= tolerance'
313 statements += ' {v} = {cond} ? {green} : {red};\n'.format(
314 v=output_var, cond=condition, green='vec4(0.0, 1.0, 0.0, 1.0)',
315 red='vec4(1.0, 0.0, 0.0, 1.0)')
316 return statements
318 def draw_test(self, test_vector, draw_command):
319 test = 'uniform {0} expected {1}\n'.format(
320 shader_runner_type(self.__signature.rettype),
321 shader_runner_format(column_major_values(test_vector.result)))
322 test += 'uniform float tolerance {0}\n'.format(
323 shader_runner_format([test_vector.tolerance]))
324 test += draw_command
325 return test
327 def result_vector(self, test_vector):
328 return [0.0, 1.0, 0.0, 1.0]
331 class ShaderTest(object):
332 """Class used to build a test of a single built-in. This is an
333 abstract base class--derived types should override test_prefix(),
334 make_vertex_shader(), make_fragment_shader(), and other functions
335 if necessary.
337 __metaclass__ = abc.ABCMeta
339 def __init__(self, signature, test_vectors, use_if):
340 """Prepare to build a test for a single built-in. signature
341 is the signature of the built-in (a key from the
342 builtin_function.test_suite dict), and test_vectors is the
343 list of test vectors for testing the given builtin (the
344 corresponding value from the builtin_function.test_suite
345 dict).
347 If use_if is True, then the generated test checks the result
348 by using it in an if statement--this only works for builtins
349 returning bool.
351 self._signature = signature
352 self._test_vectors = test_vectors
354 # Size of the rectangles drawn by the test.
355 self.rect_width = 4
356 self.rect_height = 4
357 # shader_runner currently defaults to a 250x250 window. We
358 # could reduce window size to cut test time, but there are
359 # platform-dependent limits we haven't really characterized
360 # (smaller on Linux than Windows, but still present in some
361 # window managers).
362 self.win_width = 250
363 self.win_height = 250
364 self.tests_per_row = (self.win_width // self.rect_width)
365 self.test_rows = (self.win_height // self.rect_height)
367 if use_if:
368 self._comparator = BoolIfComparator(signature)
369 elif signature.rettype.base_type == glsl_bool:
370 self._comparator = BoolComparator(signature)
371 elif signature.rettype.base_type == glsl_float:
372 self._comparator = FloatComparator(signature)
373 elif signature.rettype.base_type in (glsl_int, glsl_uint):
374 self._comparator = IntComparator(signature)
375 elif signature.rettype.base_type in (glsl_int64_t, glsl_uint64_t):
376 self._comparator = IntComparator(signature)
377 else:
378 raise Exception('Unexpected rettype {0}'.format(signature.rettype))
380 def glsl_version(self):
381 return self._signature.version_introduced
383 def draw_command(self, test_num):
384 x = (test_num % self.tests_per_row) * self.rect_width
385 y = (test_num // self.tests_per_row) * self.rect_height
386 assert(y + self.rect_height <= self.win_height)
387 return 'draw rect ortho {0} {1} {2} {3}\n'.format(x, y,
388 self.rect_width,
389 self.rect_height)
391 def probe_command(self, test_num, probe_vector):
392 return 'probe rect rgba ({0}, {1}, {2}, {3}) ({4}, {5}, {6}, {7})\n'.format(
393 (test_num % self.tests_per_row) * self.rect_width,
394 (test_num // self.tests_per_row) * self.rect_height,
395 self.rect_width,
396 self.rect_height,
397 probe_vector[0], probe_vector[1], probe_vector[2], probe_vector[3])
399 def extensions(self):
400 ext = []
401 if self._signature.extension:
402 ext.append(self._signature.extension)
403 return ext
405 def make_additional_requirements(self):
406 """Return a string that should be included in the test's
407 [require] section.
409 return ''
411 @abc.abstractmethod
412 def test_prefix(self):
413 """Return the prefix that should be used in the test file name
414 to identify the type of test, e.g. "vs" for a vertex shader
415 test.
418 def make_vertex_shader(self):
419 """Return the vertex shader for this test (or None if this
420 test doesn't require a vertex shader). No need to
421 reimplement this function in classes that don't use vertex
422 shaders.
424 return None
426 def make_tess_ctrl_shader(self):
427 """Return the tessellation control shader for this test
428 (or None if this test doesn't require a geometry shader).
429 No need to reimplement this function in classes that don't
430 use geometry shaders.
432 return None
434 def make_tess_eval_shader(self):
435 """Return the tessellation evaluation shader for this test
436 (or None if this test doesn't require a geometry shader).
437 No need to reimplement this function in classes that don't
438 use geometry shaders.
440 return None
442 def make_geometry_shader(self):
443 """Return the geometry shader for this test (or None if this
444 test doesn't require a geometry shader). No need to
445 reimplement this function in classes that don't use geometry
446 shaders.
448 return None
450 def make_geometry_layout(self):
451 """Return the geometry layout for this test (or None if this
452 test doesn't require a geometry layout section). No need to
453 reimplement this function in classes that don't use geometry
454 shaders.
456 return None
458 def make_fragment_shader(self):
459 """Return the fragment shader for this test (or None if this
460 test doesn't require a fragment shader). No need to
461 reimplement this function in classes that don't use fragment
462 shaders.
464 return None
466 def make_compute_shader(self):
467 """Return the compute shader for this test (or None if this test
468 doesn't require a compute shader). No need to reimplement
469 this function in classes that don't use compute shaders.
471 return None
473 def needs_probe_per_draw(self):
474 """Returns whether the test needs the probe to be immediately after each
476 draw call.
478 return False
480 def make_test_shader(self, additional_declarations, prefix_statements,
481 output_var, suffix_statements):
482 """Generate the shader code necessary to test the built-in.
483 additional_declarations is a string containing any
484 declarations that need to be before the main() function of the
485 shader. prefix_statements is a string containing any
486 additional statements than need to be inside the main()
487 function of the shader, before the built-in function is
488 called. output_var is the variable that the result of the
489 built-in function should be assigned to, after conversion to a
490 vec4. suffix_statements is a string containing any additional
491 statements that need to be inside the main() function of the
492 shader, after the built-in function is called.
494 shader = ''
495 for ext in self.extensions():
496 shader += '#extension GL_{0} : require\n'.format(ext)
497 shader += additional_declarations
498 for i in range(len(self._signature.argtypes)):
499 shader += 'uniform {0} arg{1};\n'.format(
500 self._signature.argtypes[i], i)
501 shader += self._comparator.make_additional_declarations()
502 shader += '\n'
503 shader += 'void main()\n'
504 shader += '{\n'
505 shader += prefix_statements
506 invocation = self._signature.template.format(
507 *['arg{0}'.format(i)
508 for i in range(len(self._signature.argtypes))])
509 shader += self._comparator.make_result_handler(invocation, output_var)
510 shader += suffix_statements
511 shader += '}\n'
512 return shader
514 def make_test_init(self):
515 """Generate initialization for the test.
517 return ''
519 def make_test(self):
520 """Make the complete shader_runner test file, and return it as
521 a string.
523 test = self.make_test_init()
524 for test_num, test_vector in enumerate(self._test_vectors):
525 for i in range(len(test_vector.arguments)):
526 test += 'uniform {0} arg{1} {2}\n'.format(
527 shader_runner_type(self._signature.argtypes[i]),
528 i, shader_runner_format(
529 column_major_values(test_vector.arguments[i])))
530 test += self._comparator.draw_test(test_vector,
531 self.draw_command(test_num))
532 if self.needs_probe_per_draw():
533 result_color = self._comparator.result_vector(test_vector)
534 test += self.probe_command(test_num, result_color)
536 if not self.needs_probe_per_draw():
537 for test_num, test_vector in enumerate(self._test_vectors):
538 result_color = self._comparator.result_vector(test_vector)
539 test += self.probe_command(test_num, result_color)
540 return test
542 def filename(self):
543 argtype_names = '-'.join(
544 str(argtype) for argtype in self._signature.argtypes)
545 if self.extensions():
546 subdir = self.extensions()[0].lower()
547 else:
548 subdir = 'glsl-{0:1.2f}'.format(float(self.glsl_version()) / 100)
549 return os.path.join(
550 'spec', subdir, 'execution', 'built-in-functions',
551 '{0}-{1}-{2}{3}.shader_test'.format(
552 self.test_prefix(), self._signature.name, argtype_names,
553 self._comparator.testname_suffix()))
555 def generate_shader_test(self):
556 """Generate the test and write it to the output file."""
557 shader_test = '[require]\n'
558 shader_test += 'GLSL >= {0:1.2f}\n'.format(
559 float(self.glsl_version()) / 100)
560 for extension in self.extensions():
561 shader_test += 'GL_{}\n'.format(extension)
562 shader_test += self.make_additional_requirements()
563 shader_test += '\n'
564 vs = self.make_vertex_shader()
565 if vs:
566 shader_test += '[vertex shader]\n'
567 shader_test += vs
568 shader_test += '\n'
569 tcs = self.make_tess_ctrl_shader()
570 if tcs:
571 shader_test += '[tessellation control shader]\n'
572 shader_test += tcs
573 shader_test += '\n'
574 tes = self.make_tess_eval_shader()
575 if tes:
576 shader_test += '[tessellation evaluation shader]\n'
577 shader_test += tes
578 shader_test += '\n'
579 gs = self.make_geometry_shader()
580 if gs:
581 shader_test += '[geometry shader]\n'
582 shader_test += gs
583 shader_test += '\n'
584 gl = self.make_geometry_layout()
585 if gl:
586 shader_test += '[geometry layout]\n'
587 shader_test += gl
588 shader_test += '\n'
589 fs = self.make_fragment_shader()
590 if fs:
591 shader_test += '[fragment shader]\n'
592 shader_test += fs
593 shader_test += '\n'
594 cs = self.make_compute_shader()
595 if cs:
596 shader_test += '[compute shader]\n'
597 shader_test += cs
598 shader_test += '\n'
599 shader_test += '[test]\n'
600 shader_test += 'clear color 0.0 0.0 1.0 0.0\n'
601 shader_test += 'clear\n'
602 shader_test += self.make_test()
603 filename = self.filename()
604 dirname = os.path.dirname(filename)
605 utils.safe_makedirs(dirname)
606 with open(filename, 'w') as f:
607 f.write(shader_test)
610 class VertexShaderTest(ShaderTest):
611 """Derived class for tests that exercise the built-in in a vertex
612 shader.
614 def test_prefix(self):
615 return 'vs'
617 def make_vertex_shader(self):
618 if self.glsl_version() >= 140:
619 return self.make_test_shader(
620 'in vec4 piglit_vertex;\n' +
621 'out vec4 color;\n',
622 ' gl_Position = piglit_vertex;\n',
623 'color', '')
624 else:
625 return self.make_test_shader(
626 'varying vec4 color;\n',
627 ' gl_Position = gl_Vertex;\n',
628 'color', '')
630 def make_fragment_shader(self):
631 shader = '''varying vec4 color;
633 void main()
635 gl_FragColor = color;
638 return shader
641 class TessellationShaderTest(ShaderTest):
642 """Abstract class for tests that exercise the built-in in
643 tessellation shaders.
646 def glsl_version(self):
647 return max(150, ShaderTest.glsl_version(self))
649 def make_additional_requirements(self):
650 return 'GL_ARB_tessellation_shader'
652 def extensions(self):
653 ext = []
654 if self._signature.extension:
655 ext.append(self._signature.extension)
656 ext.append("ARB_tessellation_shader")
657 return ext
659 def draw_command(self, test_num):
660 x = (test_num % self.tests_per_row) * self.rect_width
661 y = (test_num // self.tests_per_row) * self.rect_height
662 assert(y + self.rect_height <= self.win_height)
663 return 'draw rect ortho patch {0} {1} {2} {3}\n'.format(x, y,
664 self.rect_width,
665 self.rect_height)
667 def make_vertex_shader(self):
668 shader = \
669 """in vec4 piglit_vertex;
670 out vec4 vertex_to_tcs;
672 void main()
674 vertex_to_tcs = piglit_vertex;
677 return shader
679 def make_fragment_shader(self):
680 shader = \
681 """in vec4 color_to_fs;
683 void main()
685 gl_FragColor = color_to_fs;
688 return shader
691 class TessCtrlShaderTest(TessellationShaderTest):
692 """Derived class for tests that exercise the built-in in a
693 tessellation control shader.
696 def test_prefix(self):
697 return 'tcs'
699 def make_tess_ctrl_shader(self):
700 additional_declarations = \
701 """layout(vertices = 4) out;
702 in vec4 vertex_to_tcs[];
703 out vec4 vertex_to_tes[];
704 patch out vec4 color_to_tes;
706 body = \
707 """ vertex_to_tes[gl_InvocationID] = vertex_to_tcs[gl_InvocationID];
708 color_to_tes = tmp_color;
709 gl_TessLevelOuter = float[4](1.0, 1.0, 1.0, 1.0);
710 gl_TessLevelInner = float[2](1.0, 1.0);
712 shader = self.make_test_shader(
713 additional_declarations,
714 ' vec4 tmp_color;\n',
715 'tmp_color',
716 body)
717 return shader
719 def make_tess_eval_shader(self):
720 shader = \
721 """#extension GL_ARB_tessellation_shader : require
722 layout(quads) in;
724 in vec4 vertex_to_tes[];
725 patch in vec4 color_to_tes;
726 out vec4 color_to_fs;
727 void main() {
728 gl_Position = mix(mix(vertex_to_tes[0], vertex_to_tes[1], gl_TessCoord.x),
729 mix(vertex_to_tes[2], vertex_to_tes[3], gl_TessCoord.x),
730 gl_TessCoord.y);
731 color_to_fs = color_to_tes;
734 return shader
737 class GeometryShaderTest(ShaderTest):
738 """Derived class for tests that exercise the built-in in a
739 geometry shader.
741 def test_prefix(self):
742 return 'gs'
744 def glsl_version(self):
745 return max(150, ShaderTest.glsl_version(self))
747 def make_vertex_shader(self):
748 shader = ''
749 shader += "in vec4 piglit_vertex;\n"
750 shader += "out vec4 vertex_to_gs;\n"
752 shader += "void main()\n"
753 shader += "{\n"
754 shader += " vertex_to_gs = piglit_vertex;\n"
755 shader += "}\n"
757 return shader
759 def make_geometry_shader(self):
760 additional_declarations = ''
761 additional_declarations += 'layout(triangles) in;\n'
762 additional_declarations \
763 += 'layout(triangle_strip, max_vertices = 3) out;\n'
764 additional_declarations += 'in vec4 vertex_to_gs[3];\n'
765 additional_declarations += 'out vec4 color;\n'
766 return self.make_test_shader(
767 additional_declarations,
768 ' vec4 tmp_color;\n',
769 'tmp_color',
770 ' for (int i = 0; i < 3; i++) {\n'
771 ' gl_Position = vertex_to_gs[i];\n'
772 ' color = tmp_color;\n'
773 ' EmitVertex();\n'
774 ' }\n')
776 def make_fragment_shader(self):
777 shader = '''varying vec4 color;
779 void main()
781 gl_FragColor = color;
784 return shader
787 class FragmentShaderTest(ShaderTest):
788 """Derived class for tests that exercise the built-in in a
789 fragment shader.
791 def test_prefix(self):
792 return 'fs'
794 def make_vertex_shader(self):
795 shader = ""
796 if self.glsl_version() >= 140:
797 shader += "in vec4 piglit_vertex;\n"
799 shader += "void main()\n"
800 shader += "{\n"
801 if self.glsl_version() >= 140:
802 shader += " gl_Position = piglit_vertex;\n"
803 else:
804 shader += " gl_Position = gl_Vertex;\n"
805 shader += "}\n"
807 return shader
809 def make_fragment_shader(self):
810 return self.make_test_shader('', '', 'gl_FragColor', '')
813 class ComputeShaderTest(ShaderTest):
814 """Derived class for tests that exercise the built-in in a
815 compute shader.
817 def test_prefix(self):
818 return 'cs'
820 def glsl_version(self):
821 return max(430, ShaderTest.glsl_version(self))
823 def make_compute_shader(self):
824 additional_declarations = 'writeonly uniform image2D tex;\n'
825 num_tests = len(self._test_vectors)
826 layout_tmpl = 'layout(local_size_x = {0}) in;\n'
827 additional_declarations += layout_tmpl.format(num_tests)
828 return self.make_test_shader(
829 additional_declarations,
830 ' vec4 tmp_color;\n',
831 'tmp_color',
832 ' ivec2 coord = ivec2(gl_GlobalInvocationID.xy);\n'
833 ' imageStore(tex, coord, tmp_color);\n')
835 def make_test_init(self):
836 return '''uniform int tex 0
837 texture rgbw 0 ({0}, 1) GL_RGBA8
838 image texture 0 GL_RGBA8
839 fb tex 2d 0
840 '''.format(len(self._test_vectors))
843 def draw_command(self, test_num):
844 return 'compute 1 1 1\n'
846 def probe_command(self, test_num, probe_vector):
847 # Note: shader_runner uses a 250x250 window so we must
848 # ensure that test_num <= 250.
849 return 'probe rgb {0} 0 {1} {2} {3} {4}\n'.format(test_num % 250,
850 probe_vector[0],
851 probe_vector[1],
852 probe_vector[2],
853 probe_vector[3])
854 def needs_probe_per_draw(self):
855 return True
857 def all_tests():
858 for use_if in [False, True]:
859 for signature, test_vectors in sorted(test_suite.items()):
860 if use_if and signature.rettype != glsl_bool:
861 continue
862 yield VertexShaderTest(signature, test_vectors, use_if)
863 yield TessCtrlShaderTest(signature, test_vectors, use_if)
864 yield GeometryShaderTest(signature, test_vectors, use_if)
865 yield FragmentShaderTest(signature, test_vectors, use_if)
866 yield ComputeShaderTest(signature, test_vectors, use_if)
869 def main():
870 desc = 'Generate shader tests that test built-in functions using uniforms'
871 usage = 'usage: %prog [-h] [--names-only]'
872 parser = optparse.OptionParser(description=desc, usage=usage)
873 parser.add_option(
874 '--names-only',
875 dest='names_only',
876 action='store_true',
877 help="Don't output files, just generate a list of filenames to stdout")
878 options, args = parser.parse_args()
879 for test in all_tests():
880 if not options.names_only:
881 test.generate_shader_test()
882 print(test.filename())
885 if __name__ == '__main__':
886 main()