diff options
author | Francisco Jerez <currojerez@riseup.net> | 2014-12-04 12:11:24 +0200 |
---|---|---|
committer | Francisco Jerez <currojerez@riseup.net> | 2014-12-04 12:11:24 +0200 |
commit | 1b4d73b2052b5cc2f3d5fd6e463b0eff7f742afb (patch) | |
tree | 8a285d85aacaacb3533ff873f209cb9f9c755711 /generated_tests | |
parent | 358781d859bc43c969d66a0066b3baf355a738e2 (diff) |
arb_shader_image_load_store: Import GLSL parser test generator script.
Reviewed-by: Dylan Baker <dylanx.c.baker@intel.com>
Diffstat (limited to 'generated_tests')
-rw-r--r-- | generated_tests/CMakeLists.txt | 4 | ||||
-rw-r--r-- | generated_tests/gen_shader_image_load_store_tests.py | 822 |
2 files changed, 826 insertions, 0 deletions
diff --git a/generated_tests/CMakeLists.txt b/generated_tests/CMakeLists.txt index 848e233c4..6c8eaf941 100644 --- a/generated_tests/CMakeLists.txt +++ b/generated_tests/CMakeLists.txt @@ -110,6 +110,9 @@ piglit_make_generated_tests( constant_array_size_tests_fp64.list gen_constant_array_size_tests_fp64.py builtin_function_fp64.py) +piglit_make_generated_tests( + shader_image_load_store_tests.list + gen_shader_image_load_store_tests.py) # OpenCL Test generators piglit_make_generated_tests( @@ -146,6 +149,7 @@ add_custom_target(gen-gl-tests interpolation-qualifier-built-in-variable.list builtin_uniform_tests_fp64.list constant_array_size_tests_fp64.list + shader_image_load_store_tests.list ) # Create a custom target for generating OpenCL tests diff --git a/generated_tests/gen_shader_image_load_store_tests.py b/generated_tests/gen_shader_image_load_store_tests.py new file mode 100644 index 000000000..b2928098a --- /dev/null +++ b/generated_tests/gen_shader_image_load_store_tests.py @@ -0,0 +1,822 @@ +# coding=utf-8 +# +# Copyright (C) 2014 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +from __future__ import print_function +import os.path +from mako.template import Template +from textwrap import dedent + + +def gen_header(status): + """ + Generate a GLSL program header. + + Generate header code for ARB_shader_image_load_store GLSL parser + tests that are expected to give status as result. + """ + return dedent("""\ + /* + * [config] + * expect_result: {0} + * glsl_version: 1.50 + * require_extensions: GL_ARB_shader_image_load_store + * [end config] + */ + #version 150 + #extension GL_ARB_shader_image_load_store: require + """.format(status)) + + +def gen_vector_type(scalar, dim): + """ + Generate a GLSL vector type name. + + Generate a GLSL vector type based on the given scalar type with the + specified number of dimensions. + """ + vector_types = { + 'int': 'ivec', + 'uint': 'uvec', + 'float': 'vec', + } + + return ('{0}{1}'.format(vector_types[scalar], dim) if dim > 1 + else scalar) + + +def gen_scalar_args(arity): + """ + Generate image builtin scalar arguments. + + Returns a generator of well-formed scalar arguments for an image + built-in of the given arity having t as argument type. + """ + return lambda t: ', {0}(0)'.format(t) * arity + + +def gen_vector_args(arity): + """ + Generate image builtin vector arguments. + + Returns a generator of well-formed arguments for an image built-in + of the given arity having a 4-component vector of t as argument + type. + """ + return lambda t: ', {0}(0)'.format(gen_vector_type(t, 4)) * arity + + +def gen_address_args(dim): + """ + Generate image address arguments. + + Returns a generator for the coordinate argument of an image + built-in expecting an address of the given dimensionality. If + fail is True the generated argument will have an arbitrary + incorrect dimensionality. + """ + return (lambda fail = False: ', {0}(0)'.format( + gen_vector_type('int', dim if not fail else dim % 3 + 1))) + + +def gen_address_args_ms(dim): + """Generate multisample image address arguments.""" + return (lambda fail = False: + gen_address_args(dim)() + (', 0' if not fail else '')) + + +def product(ps, *qss): + """ + Generate the cartesian product of a number of lists of dictionaries. + + Each generated element will be the union of some combination of + elements from the iterable arguments. The resulting value of each + 'name' item will be the concatenation of names of the respective + element combination separated with dashes. + """ + for q in (product(*qss) if qss else [{}]): + for p in ps: + r = dict(p, **q) + r['name'] = '-'.join(s['name'] for s in (p, q) if s.get('name')) + yield r + + +def gen(name, src, tests): + """ + Expand a source template for the provided list of test definitions. + + Generate a GLSL parser test for each of the elements of the + 'tests' iterable, each of them should be a dictionary of + definitions that will be used as environment to render the source + template. + + The file name of each test will be the concatenation of the 'name' + argument with the 'name' item from the respective test dictionary. + """ + template = Template(dedent(src)) + + for t in product([{'name': name}], tests): + filename = os.path.join('spec', + 'ARB_shader_image_load_store', + 'compiler', + '{0}.{1}'.format(t['name'], + t['shader_stage'])) + print(filename) + + dirname = os.path.dirname(filename) + if not os.path.exists(dirname): + os.makedirs(dirname) + + with open(filename, 'w') as f: + f.write(template.render(header = gen_header, **t)) + + +shader_stages = [ + {'shader_stage': 'frag'}, + {'shader_stage': 'vert'} +] + + +image_atomic_builtins = [ + { + 'name': 'atomic-add', + 'image_builtin': 'imageAtomicAdd', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-min', + 'image_builtin': 'imageAtomicMin', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-max', + 'image_builtin': 'imageAtomicMax', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-and', + 'image_builtin': 'imageAtomicAnd', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-or', + 'image_builtin': 'imageAtomicOr', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-xor', + 'image_builtin': 'imageAtomicXor', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-exchange', + 'image_builtin': 'imageAtomicExchange', + 'image_args': gen_scalar_args(1) + }, + { + 'name': 'atomic-comp-swap', + 'image_builtin': 'imageAtomicCompSwap', + 'image_args': gen_scalar_args(2) + } +] + + +image_load_builtin = [ + { + 'name': 'load', + 'image_builtin': 'imageLoad', + 'image_args': gen_vector_args(0) + } +] + + +image_store_builtin = [ + { + 'name': 'store', + 'image_builtin': 'imageStore', + 'image_args': gen_vector_args(1) + } +] + + +image_types = [ + { + 'name': '1d', + 'image_type': 'image1D', + 'image_addr': gen_address_args(1) + }, + { + 'name': '2d', + 'image_type': 'image2D', + 'image_addr': gen_address_args(2) + }, + { + 'name': '3d', + 'image_type': 'image3D', + 'image_addr': gen_address_args(3) + }, + { + 'name': '2d-rect', + 'image_type': 'image2DRect', + 'image_addr': gen_address_args(2) + }, + { + 'name': 'cube', + 'image_type': 'imageCube', + 'image_addr': gen_address_args(3) + }, + { + 'name': 'buffer', + 'image_type': 'imageBuffer', + 'image_addr': gen_address_args(1) + }, + { + 'name': '1d-array', + 'image_type': 'image1DArray', + 'image_addr': gen_address_args(2) + }, + { + 'name': '2d-array', + 'image_type': 'image2DArray', + 'image_addr': gen_address_args(3) + }, + { + 'name': 'cube-array', + 'image_type': 'imageCubeArray', + 'image_addr': gen_address_args(3) + }, + { + 'name': '2d-ms', + 'image_type': 'image2DMS', + 'image_addr': gen_address_args_ms(2) + }, + { + 'name': '2d-ms-array', + 'image_type': 'image2DMSArray', + 'image_addr': gen_address_args_ms(3) + } +] + + +# +# Test the preprocessor defines. +# +gen('preprocessor', """\ + ${header('pass')} + + #if !defined GL_ARB_shader_image_load_store + # error GL_ARB_shader_image_load_store is not defined + #elif GL_ARB_shader_image_load_store != 1 + # error GL_ARB_shader_image_load_store is not equal to 1 + #endif + + void main() + { + } +""", shader_stages) + +# +# Test the early_fragment_tests layout qualifier. +# +gen('early-fragment-tests', """\ + ${header('pass' if shader_stage == 'frag' and hunk == 'in' else 'fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Fragment shaders also allow the following layout qualifier on 'in' + * only (not with variable declarations): + * + * layout-qualifier-id + * early_fragment_tests" + */ + layout(early_fragment_tests) ${hunk}; + + void main() + { + } +""", product(shader_stages, [ + {'name': 'in', 'hunk': 'in'}, + {'name': 'out', 'hunk': 'out'}, + {'name': 'uniform', 'hunk': 'uniform uint u'}, + {'name': 'in-var', 'hunk': 'in float f'}, + {'name': 'uniform-buffer', 'hunk': 'uniform b { image2D img; }'} +])) + +# +# Test image declarations. +# +gen('declaration-allowed', """\ + ${header('pass')} + /* + * From the ARB_shader_image_load_store spec: + * + * "[Images] can only be declared as function parameters or uniform + * variables." + */ + layout(rgba32f) uniform ${image_type} img; + layout(rgba32ui) uniform u${image_type} uimg; + layout(rgba32i) uniform i${image_type} iimg; + + void f(${image_type} arg, + u${image_type} uarg, + i${image_type} iarg) + { + } + + void main() + { + } +""", product(image_types, shader_stages)) + +gen('declaration-global', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "[Images] can only be declared as function parameters or uniform + * variables." + */ + layout(rgba32f) ${qualifier} image2D img; + + void main() + { + } +""", product(shader_stages, [ + {'name': 'const', 'qualifier': 'const'}, + {'name': 'in', 'qualifier': 'in'}, + {'name': 'out', 'qualifier': 'out'} +])) + +gen('declaration-local', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "[Images] can only be declared as function parameters or uniform + * variables." + */ + void main() + { + layout(rgba32f) image2D img; + } +""", shader_stages) + +gen('declaration-uniform-block', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Sets of uniforms, except for samplers and images, can be grouped + * into uniform blocks." + */ + uniform b { + layout(rgba32f) image2D img; + }; + + void main() + { + } +""", shader_stages) + +gen('declaration-argument', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Images cannot be treated as l-values; hence, they cannot be used + * as out or inout function parameters, nor can they be assigned + * into." + */ + void f(${qualifier} image2D y) + { + } + + void main() + { + } +""", product(shader_stages, [ + {'name': 'inout', 'qualifier': 'inout'}, + {'name': 'out', 'qualifier': 'out'} +])) + +gen('declaration-initializer', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "[Images] cannot be declared with an initializer in a shader." + */ + layout(rgba32f) uniform image2D img = 0; + + void main() + { + } +""", shader_stages) + +gen('declaration-format-qualifier', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "It is an error to declare an image variable where the format + * qualifier does not match the image variable type." + */ + layout(${format}) uniform ${prefix}${image_type} img; + + void main() + { + } +""", product(image_types, shader_stages, [ + {'name': 'float', + 'format': 'rgba32f', + 'prefix': 'i'}, + {'name': 'int', + 'format': 'rgba32i', + 'prefix': 'u'}, + {'name': 'uint', + 'format': 'rgba32ui', + 'prefix': ''} +])) + +gen('declaration-format-qualifier-duplicate', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Only one format qualifier may be specified for any image variable + * declaration." + */ + layout(rgba32f) layout(rgba32f) uniform image2D img; + + void main() + { + } +""", shader_stages) + +gen('declaration-format-qualifier-missing', """\ + ${header(status)} + /* + * From the ARB_shader_image_load_store spec: + * + * "Uniforms not qualified with "writeonly" must have a format + * layout qualifier." + */ + ${qualifier} uniform image2D img; + + void main() + { + } +""", product(shader_stages, [ + {'name': 'writeonly', + 'qualifier': 'writeonly', + 'status': 'pass'}, + {'name': 'readonly', + 'qualifier': 'readonly', + 'status': 'fail'}, + {'name': 'readwrite', + 'qualifier': '', + 'status': 'fail'} +])) + +gen('declaration-memory-qualifier-sampler', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Only variables declared as image types [...] can be qualified + * with a memory qualifier. " + */ + ${qualifier} uniform sampler2D s; + + void main() + { + } +""", product(shader_stages, [ + {'name': 'readonly', 'qualifier': 'readonly'}, + {'name': 'writeonly', 'qualifier': 'writeonly'}, + {'name': 'coherent', 'qualifier': 'coherent'}, + {'name': 'volatile', 'qualifier': 'volatile'}, + {'name': 'restrict', 'qualifier': 'restrict'} +])) + +# +# Test expressions involving images. +# +gen('expression-allowed', """\ + ${header('pass')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Except for array indexing, structure field selection, and + * parentheses, images are not allowed to be operands in + * expressions." + */ + layout(rgba32f) uniform ${image_type} imgs[2]; + uniform vec4 y; + + out vec4 color; + + void main() + { + color = y + imageLoad((imgs[1]) ${image_addr()}); + } +""", product(image_types[:1], shader_stages)) + +gen('expression', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Except for array indexing, structure field selection, and + * parentheses, images are not allowed to be operands in + * expressions." + */ + layout(rgba32f) uniform image2D img; + + void main() + { + ${expression}; + } +""", product(shader_stages, [ + {'name': 'arithmetic-1', 'expression': '-img'}, + {'name': 'arithmetic-2', 'expression': 'img + img'}, + {'name': 'arithmetic-3', 'expression': 'img - img'}, + {'name': 'arithmetic-4', 'expression': 'img * img'}, + {'name': 'arithmetic-5', 'expression': 'img / img'}, + {'name': 'arithmetic-6', 'expression': '++img'}, + {'name': 'arithmetic-7', 'expression': '--img'}, + {'name': 'arithmetic-8', 'expression': 'img++'}, + {'name': 'arithmetic-9', 'expression': 'img--'}, + {'name': 'assignment-1', 'expression': 'img ^= img'}, + {'name': 'assignment-2', 'expression': 'img |= img'}, + {'name': 'assignment-3', 'expression': 'img = img'}, + {'name': 'assignment-4', 'expression': 'img += img'}, + {'name': 'assignment-5', 'expression': 'img -= img'}, + {'name': 'assignment-6', 'expression': 'img *= img'}, + {'name': 'assignment-7', 'expression': 'img /= img'}, + {'name': 'assignment-8', 'expression': 'img %= img'}, + {'name': 'assignment-9', 'expression': 'img <<= img'}, + {'name': 'assignment-10', 'expression': 'img >>= img'}, + {'name': 'assignment-11', 'expression': 'img &= img'}, + {'name': 'binary-1', 'expression': '~img'}, + {'name': 'binary-2', 'expression': 'img << img'}, + {'name': 'binary-3', 'expression': 'img >> img'}, + {'name': 'binary-4', 'expression': 'img & img'}, + {'name': 'binary-5', 'expression': 'img | img'}, + {'name': 'binary-6', 'expression': 'img ^ img'}, + {'name': 'conversion-1', 'expression': 'float(img)'}, + {'name': 'conversion-2', 'expression': 'uint(img)'}, + {'name': 'conversion-3', 'expression': 'bool(img)'}, + {'name': 'conversion-4', 'expression': 'image1D(img)'}, + {'name': 'field-selection', 'expression': 'img.x'}, + {'name': 'function-call', 'expression': 'img()'}, + {'name': 'logical-1', 'expression': '!img'}, + {'name': 'logical-2', 'expression': 'img && img'}, + {'name': 'logical-3', 'expression': 'img || img'}, + {'name': 'logical-4', 'expression': 'img ^^ img'}, + {'name': 'relational-1', 'expression': 'img == img'}, + {'name': 'relational-2', 'expression': 'img != img'}, + {'name': 'relational-3', 'expression': 'img < img'}, + {'name': 'relational-4', 'expression': 'img > img'}, + {'name': 'relational-5', 'expression': 'img <= img'}, + {'name': 'relational-6', 'expression': 'img >= img'}, + {'name': 'selection', 'expression': 'true ? img : img'}, + {'name': 'subscript', 'expression': 'img[0]'} +])) + +# +# Test passing of image variables in function calls. +# +gen('call-argument-qualifiers', """\ + ${header(status)} + /* + * From the ARB_shader_image_load_store spec: + * + * "The values of image variables qualified with 'coherent', + * 'volatile', 'restrict', 'readonly', or 'writeonly' may not be + * passed to functions whose formal parameters lack such + * qualifiers. [...] It is legal to have additional qualifiers on a + * formal parameter, but not to have fewer." + */ + layout(rgba32f) ${actual_qualifier} uniform image2D x; + + void f(${formal_qualifier} image2D y) + { + } + + void main() + { + f(x); + } +""", product(shader_stages, [ + {'name': 'allowed-volatile', + 'actual_qualifier': 'volatile', + 'formal_qualifier': 'volatile coherent', + 'status': 'pass'}, + {'name': 'allowed-coherent', + 'actual_qualifier': 'coherent', + 'formal_qualifier': 'volatile coherent', + 'status': 'pass'}, + {'name': 'allowed-restrict', + 'actual_qualifier': 'restrict', + 'formal_qualifier': 'volatile restrict', + 'status': 'pass'}, + {'name': 'allowed-readonly', + 'actual_qualifier': 'readonly', + 'formal_qualifier': 'restrict readonly', + 'status': 'pass'}, + {'name': 'allowed-writeonly', + 'actual_qualifier': 'writeonly', + 'formal_qualifier': 'volatile writeonly', + 'status': 'pass'}, + {'name': 'disallowed-volatile', + 'actual_qualifier': 'volatile', + 'formal_qualifier': '', + 'status': 'fail'}, + {'name': 'disallowed-coherent', + 'actual_qualifier': 'coherent', + 'formal_qualifier': 'restrict', + 'status': 'fail'}, + {'name': 'disallowed-restrict', + 'actual_qualifier': 'restrict', + 'formal_qualifier': '', + 'status': 'fail'}, + {'name': 'disallowed-readonly', + 'actual_qualifier': 'readonly', + 'formal_qualifier': 'restrict writeonly', + 'status': 'fail'}, + {'name': 'disallowed-writeonly', + 'actual_qualifier': 'writeonly', + 'formal_qualifier': 'volatile readonly', + 'status': 'fail'} +])) + +gen('call-argument-type', """\ + ${header('pass' if image_type == 'image2D' else 'fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "As function parameters, images may only be passed to [arguments] + * of matching type." + */ + layout(rgba32f) uniform image2D x; + + void f(${image_type} y) + { + } + + void main() + { + f(x); + } +""", product(image_types, shader_stages)) + +# +# Test the language built-in constants and functions. +# +gen('builtin-constants', """\ + ${header('pass')} + /* + * Check that the builtin constants defined by the extension + * are present. + */ + out ivec4 color; + + void main() + { + color.x = gl_MaxImageUnits + + gl_MaxCombinedImageUnitsAndFragmentOutputs + + gl_MaxImageSamples + + gl_MaxVertexImageUniforms + + gl_MaxTessControlImageUniforms + + gl_MaxTessEvaluationImageUniforms + + gl_MaxGeometryImageUniforms + + gl_MaxFragmentImageUniforms + + gl_MaxCombinedImageUniforms; + } +""", shader_stages) + +gen('builtin-image-argument-mismatch', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "Atomic memory operations are supported on only [...]: an image + * variable with signed integer components (iimage*) format qualifier + * of 'r32i', or an image variable with unsigned integer components + * (uimage*) and format qualifier of 'r32ui'." + * + * Call an atomic built-in with a floating point image data type. + */ + layout(r32f) uniform ${image_type} img; + + void main() + { + ${image_builtin}(img ${image_addr()} ${image_args('float')}); + } +""", product(image_atomic_builtins, image_types[:1], shader_stages)) + +gen('builtin-data-argument-mismatch', """\ + ${header('fail')} + /* + * Call a signed integer atomic built-in with a mismatching + * argument data type. + */ + layout(r32i) uniform i${image_type} img; + + void main() + { + ${image_builtin}(img ${image_addr()} ${image_args('uint')}); + } +""", product(image_store_builtin + image_atomic_builtins, + image_types[:1], shader_stages)) + +gen('builtin-address-argument-mismatch', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "The 'IMAGE_INFO' placeholder is replaced by one of the following + * parameter lists: + * gimage1D image, int coord + * gimage2D image, ivec2 coord + * gimage3D image, ivec3 coord + * gimage2DRect image, ivec2 coord + * gimageCube image, ivec3 coord + * gimageBuffer image, int coord + * gimage1DArray image, ivec2 coord + * gimage2DArray image, ivec3 coord + * gimageCubeArray image, ivec3 coord + * gimage2DMS image, ivec2 coord, int sample + * gimage2DMSArray image, ivec3 coord, int sample" + * + * Pass an argument as address coordinate that doesn't match the + * dimensionality of the specified image. + */ + layout(r32i) uniform i${image_type} img; + + void main() + { + ${image_builtin}(img ${image_addr(fail = True)} ${image_args('int')}); + } +""", product(image_load_builtin + image_store_builtin + image_atomic_builtins, + image_types, shader_stages)) + +gen('builtin-qualifier-mismatch-readonly', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "It is an error to pass an image variable qualified with 'readonly' + * to imageStore() or other built-in functions that modify image + * memory." + * + * Call a built-in function on a readonly qualified image. + */ + layout(r32i) readonly uniform i${image_type} img; + + void main() + { + ${image_builtin}(img ${image_addr()} ${image_args('int')}); + } +""", product(image_store_builtin + image_atomic_builtins, + image_types[:1], shader_stages)) + +gen('builtin-qualifier-mismatch-writeonly', """\ + ${header('fail')} + /* + * From the ARB_shader_image_load_store spec: + * + * "It is an error to pass an image variable qualified with 'writeonly' + * to imageLoad() or other built-in functions that read image + * memory." + * + * Call a built-in function on a writeonly qualified image. + */ + layout(r32i) writeonly uniform i${image_type} img; + + void main() + { + ${image_builtin}(img ${image_addr()} ${image_args('int')}); + } +""", product(image_load_builtin + image_atomic_builtins, + image_types[:1], shader_stages)) |