[Piglit] [PATCH 1/2] arb_shader_bit_encoding: Add test generator.

Matt Turner mattst88 at gmail.com
Wed Aug 7 17:52:13 PDT 2013


On Wed, Aug 7, 2013 at 5:36 PM, Ian Romanick <idr at freedesktop.org> wrote:
> On 08/06/2013 09:40 PM, Matt Turner wrote:
>>
>> Generates fragment and vertex shader execution tests for the built-in
>> functions floatBitsToInt(), floatBitsToUint(), intBitsToFloat(), and
>> uintBitsToFloat().
>>
>> Functions are tested under
>>         GLSL 1.30 + ARB_shader_bit_encoding
>>         GLSL 1.50 + ARB_gpu_shader5
>>         GLSL 4.00
>
>
> Both ARB_shader_bit_encoding and ARB_gpu_shader5 add the same functions.
> ARB_gpu_shader5 requires GLSL 1.50 (so sayeth the spec), and
> ARB_shader_bit_encoding has no requirement (but it uses uint, so it must
> need at least GLSL 1.30).  Right?

Yes, exactly. Worth me documenting in the commit message?

> And, of course, ARB_gpu_shader5 is part of GLSL 4.00.
>
>
>> ---
>>   generated_tests/CMakeLists.txt                   |   4 +
>>   generated_tests/gen_shader_bit_encoding_tests.py | 234
>> +++++++++++++++++++++++
>>   2 files changed, 238 insertions(+)
>>   create mode 100644 generated_tests/gen_shader_bit_encoding_tests.py
>>
>> diff --git a/generated_tests/CMakeLists.txt
>> b/generated_tests/CMakeLists.txt
>> index db3734f..8c0bc02 100644
>> --- a/generated_tests/CMakeLists.txt
>> +++ b/generated_tests/CMakeLists.txt
>> @@ -40,6 +40,9 @@ piglit_make_generated_tests(
>>         texture_query_lod_tests.list
>>         gen_texture_query_lod_tests.py)
>>   piglit_make_generated_tests(
>> +       shader_bit_encoding_tests.list
>> +       gen_shader_bit_encoding_tests.py)
>> +piglit_make_generated_tests(
>>         uniform-initializer_tests.list
>>         gen_uniform_initializer_tests.py
>>         uniform-initializer-templates/fs-initializer.template
>> @@ -65,4 +68,5 @@ add_custom_target(gen-tests ALL
>>                 interpolation_tests.list
>>                 non-lvalue_tests.list
>>                 texture_query_lod_tests.list
>> +               shader_bit_encoding_tests.list
>>                 uniform-initializer_tests.list)
>> diff --git a/generated_tests/gen_shader_bit_encoding_tests.py
>> b/generated_tests/gen_shader_bit_encoding_tests.py
>> new file mode 100644
>> index 0000000..a6ff674
>> --- /dev/null
>> +++ b/generated_tests/gen_shader_bit_encoding_tests.py
>> @@ -0,0 +1,234 @@
>> +#!/usr/bin/env python2
>> +# coding=utf-8
>> +#
>> +# Copyright © 2013 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.
>> +
>> +import struct
>> +import os
>> +import os.path
>> +from mako.template import Template
>> +from textwrap import dedent
>> +
>> +def floatBitsToInt(f):
>> +    return struct.unpack('i', struct.pack('f', f))[0]
>> +
>> +def floatBitsToUint(f):
>> +    return struct.unpack('I', struct.pack('f', f))[0]
>> +
>> +def intBitsToFloat(i):
>> +    return struct.unpack('f', struct.pack('i', i))[0]
>> +
>> +def uintBitsToFloat(u):
>> +    return struct.unpack('f', struct.pack('I', u))[0]
>> +
>> +def passthrough(f):
>> +    return f
>> +
>> +def vec4(f):
>> +    return [f, f, f, f]
>> +
>> +test_data = {
>> +    # Interesting floating-point inputs
>> +    'mixed':                        (2.0, 9.5, -4.5, -25.0),
>> +    '0.0':                          vec4( 0.0), # int 0
>> +    '-0.0':                         vec4(-0.0), # INT_MIN
>> +    '1.0':                          vec4( 1.0),
>> +    '-1.0':                         vec4(-1.0),
>> +    'subnormal smallest':           vec4( 1.401298e-45),
>> +    'subnormal smallest negative':  vec4(-1.401298e-45),
>> +    'subnormal middle':             vec4( 5.877472e-39),
>> +    'subnormal middle negative':    vec4(-5.877472e-39),
>> +    'subnormal largest':            vec4( 1.1754942e-38),
>> +    'subnormal largest negative':   vec4(-1.1754942e-38),
>> +    'normalized smallest':          vec4( 1.1754941e-38),
>> +    'normalized smallest negative': vec4(-1.1754941e-38),
>> +    'normalized largest':           vec4( 3.4028235e+38),
>> +    'normalized largest negative':  vec4(-3.4028235e+38)
>> +
>> +    # Don't test +inf or -inf, since we don't have a way to pass them via
>> +    # shader_runner [test] sections. Don't test NaN, since it has many
>> +    # representations.
>
>
> Is it worth also testing some cases of 'x ==
> intBitsToFloat(floatBitsToInt(x))' and similar?  This may require doing one
> of the functions in the vertex shader and the other in the fragment
> shader...

Not a bad idea. I'm not sure if I can do that in a nice way in this
generator. I'd like to do that either in a separate generator, or at
least as a follow-on patch.

>> +}
>> +
>> +funcs = {
>> +    'floatBitsToInt': {
>> +        'in_func':  passthrough,
>> +        'out_func': floatBitsToInt,
>> +        'input':    'vec4',
>> +        'output':   'ivec4'
>> +    },
>> +    'floatBitsToUint': {
>> +        'in_func':  passthrough,
>> +        'out_func': floatBitsToUint,
>> +        'input':    'vec4',
>> +        'output':   'uvec4'
>> +    },
>> +    'intBitsToFloat': {
>> +        'in_func':  floatBitsToInt,
>> +        'out_func': passthrough,
>> +        'input':    'ivec4',
>> +        'output':   'vec4'
>> +    },
>> +    'uintBitsToFloat': {
>> +        'in_func':  floatBitsToUint,
>> +        'out_func': passthrough,
>> +        'input':    'uvec4',
>> +        'output':   'vec4'
>> +    }
>> +}
>> +
>> +requirements = {
>> +    'ARB_shader_bit_encoding': {
>> +        'version': '1.30',
>> +        'extension': 'GL_ARB_shader_bit_encoding'
>> +    },
>> +    'ARB_gpu_shader5': {
>> +        'version': '1.50',
>> +        'extension': 'GL_ARB_gpu_shader5'
>> +    },
>> +    'glsl-4.00': {
>> +        'version': '4.00',
>> +        'extension': ''
>> +    }
>> +}
>> +
>> +template = Template(dedent("""\
>> +    [require]
>> +    GLSL >= ${version}
>> +    % for extension in extensions:
>> +    ${extension}
>> +    % endfor
>> +
>> +    [vertex shader]
>> +    % if execution_stage == 'vs':
>> +    % for extension in extensions:
>> +    #extension ${extension}: enable
>> +    % endfor
>> +
>> +    uniform ${input_type} given;
>> +    uniform ${output_type} expected;
>> +    out vec4 color;
>> +    % endif
>> +
>> +    in vec4 vertex;
>> +
>> +    void main() {
>> +        gl_Position = vertex;
>> +
>> +        % if execution_stage == 'vs':
>> +        color = vec4(0.0, 1.0, 0.0, 1.0);
>> +
>> +        if (expected.x != ${func}(given.x))
>> +                color.r = 1.0;
>> +        if (expected.xy != ${func}(given.xy))
>> +                color.r = 1.0;
>> +        if (expected.xyz != ${func}(given.xyz))
>> +                color.r = 1.0;
>> +        if (expected != ${func}(given))
>> +                color.r = 1.0;
>> +        % endif
>> +    }
>> +
>> +    [fragment shader]
>> +    % if execution_stage == 'fs':
>> +    % for extension in extensions:
>> +    #extension ${extension}: enable
>> +    % endfor
>> +
>> +    uniform ${input_type} given;
>> +    uniform ${output_type} expected;
>> +    % else:
>> +    in vec4 color;
>> +    % endif
>> +
>> +    out vec4 frag_color;
>> +
>> +    void main() {
>> +        % if execution_stage == 'fs':
>> +        frag_color = vec4(0.0, 1.0, 0.0, 1.0);
>> +
>> +        if (expected.x != ${func}(given.x))
>> +                frag_color.r = 1.0;
>> +        if (expected.xy != ${func}(given.xy))
>> +                frag_color.r = 1.0;
>> +        if (expected.xyz != ${func}(given.xyz))
>> +                frag_color.r = 1.0;
>> +        if (expected != ${func}(given))
>> +                frag_color.r = 1.0;
>> +        % else:
>> +        frag_color = color;
>> +        % endif
>> +    }
>> +
>> +    [vertex data]
>> +    vertex/float/2
>> +    -1.0 -1.0
>> +     1.0 -1.0
>> +     1.0  1.0
>> +    -1.0  1.0
>> +
>> +    [test]
>> +    % for name, data in test_data.iteritems():
>> +
>> +    # ${name}
>> +    uniform ${input_type} given ${' '.join(str(in_func(d)) for d in
>> data)}
>> +    uniform ${output_type} expected ${' '.join(str(out_func(d)) for d in
>> data)}
>> +    draw arrays GL_TRIANGLE_FAN 0 4
>> +    probe all rgba 0.0 1.0 0.0 1.0
>
>
> Why do this instead of just 'draw rect -1 -1 2 2'?

Copy-n-paste. That is better. Thanks.

>> +    % endfor
>> +"""))
>> +
>> +for api, requirement in requirements.iteritems():
>> +    version = requirement['version']
>> +    extensions = [requirement['extension']] if requirement['extension']
>> else []
>> +
>> +    for func, attrib in funcs.iteritems():
>> +        in_func = attrib['in_func']
>> +        out_func = attrib['out_func']
>> +        input_type = attrib['input']
>> +        output_type = attrib['output']
>> +
>> +        for execution_stage in ('vs', 'fs'):
>> +            file_extension = 'frag' if execution_stage == 'fs' else
>> 'vert'
>> +            filename = os.path.join('spec',
>> +                                    api,
>> +                                    'execution',
>> +                                    'built-in-functions',
>> +
>> "{0}-{1}.shader_test".format(execution_stage,
>> +                                                                 func))
>> +            print filename
>> +
>> +            dirname = os.path.dirname(filename)
>> +            if not os.path.exists(dirname):
>> +                os.makedirs(dirname)
>> +
>> +            f = open(filename, 'w')
>> +            f.write(template.render(version=version,
>> +                                    extensions=extensions,
>> +                                    execution_stage=execution_stage,
>> +                                    func=func,
>> +                                    in_func=in_func,
>> +                                    out_func=out_func,
>> +                                    input_type=input_type,
>> +                                    output_type=output_type,
>> +                                    test_data=test_data))
>> +            f.close()
>>
>


More information about the Piglit mailing list