Exemplo n.º 1
0
def test_nobuildmethod():
    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.Float(32), [2, 2])
    b_in.fill(123)

    b_out = hl.Buffer(hl.Int(32), [2, 2])

    f = nobuildmethod.generate(target, b_in, 1.0)
    f.realize(b_out)

    assert b_out.all_equal(123)
Exemplo n.º 2
0
def test_nobuildmethod():
    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.Float(32), [2, 2])
    b_in.fill(123)

    b_out = hl.Buffer(hl.Int(32), [2, 2])

    f = nobuildmethod.generate(target, b_in, 1.0)
    f.realize(b_out)

    assert b_out.all_equal(123)
Exemplo n.º 3
0
def test_partialbuildmethod():
    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.Float(32), [2, 2])
    b_in.fill(123)

    b_out = hl.Buffer(hl.Int(32), [2, 2])

    try:
        f = partialbuildmethod.generate(target, b_in, 1)
    except RuntimeError as e:
        assert "Generators that use build() (instead of generate()+Output<>) are not supported in the Python bindings." in str(e)
    else:
        assert False, 'Did not see expected exception!'
Exemplo n.º 4
0
def test_partialbuildmethod():
    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.Float(32), [2, 2])
    b_in.fill(123)

    b_out = hl.Buffer(hl.Int(32), [2, 2])

    try:
        f = partialbuildmethod.generate(target, b_in, 1)
    except RuntimeError as e:
        assert "Generators that use build() (instead of generate()+Output<>) are not supported in the Python bindings." in str(e)
    else:
        assert False, 'Did not see expected exception!'
Exemplo n.º 5
0
def test_looplevel():
    x, y = hl.Var('x'), hl.Var('y')
    target = hl.get_jit_target_from_environment()

    buffer_input = hl.Buffer(hl.UInt(8), [4, 4])
    buffer_input.fill(123)

    func_input = hl.Func("func_input")
    func_input[x, y] = x + y

    simple_compute_at = hl.LoopLevel()
    simple = simplestub.generate(target, buffer_input, func_input, 3.5,
        compute_level=simple_compute_at)

    computed_output = hl.Func('computed_output')
    computed_output[x, y] = simple[x, y] + 3

    simple_compute_at.set(hl.LoopLevel(computed_output, x))

    _realize_and_check(computed_output, 3)
Exemplo n.º 6
0
def test_looplevel():
    x, y = hl.Var('x'), hl.Var('y')
    target = hl.get_jit_target_from_environment()

    buffer_input = hl.Buffer(hl.UInt(8), [4, 4])
    buffer_input.fill(123)

    func_input = hl.Func("func_input")
    func_input[x, y] = x + y

    simple_compute_at = hl.LoopLevel()
    simple = simplestub.generate(target, buffer_input, func_input, 3.5,
        compute_level=simple_compute_at)

    computed_output = hl.Func('computed_output')
    computed_output[x, y] = simple[x, y] + 3

    simple_compute_at.set(hl.LoopLevel(computed_output, x))

    _realize_and_check(computed_output, 3)
Exemplo n.º 7
0
def get_bilateral_grid(input, r_sigma, s_sigma, aot=False):
    x = hl.Var('x')
    y = hl.Var('y')
    z = hl.Var('z')
    c = hl.Var('c')

    # Add a boundary condition
    clamped = hl.BoundaryConditions.repeat_edge(input)

    # Construct the bilateral grid
    r = hl.RDom([(0, s_sigma), (0, s_sigma)], 'r')
    val = clamped[x * s_sigma + r.x - s_sigma // 2,
                  y * s_sigma + r.y - s_sigma // 2]
    val = hl.clamp(val, 0.0, 1.0)

    zi = hl.i32(val / r_sigma + 0.5)

    histogram = hl.Func('histogram')
    histogram[x, y, z, c] = 0.0
    histogram[x, y, zi, c] += hl.select(c == 0, val, 1.0)

    # Blur the histogram using a five-tap filter
    blurx, blury, blurz = hl.Func('blurx'), hl.Func('blury'), hl.Func('blurz')
    blurz[x, y, z, c] = histogram[x, y, z - 2, c] + histogram[
        x, y, z - 1, c] * 4 + histogram[x, y, z, c] * 6 + histogram[
            x, y, z + 1, c] * 4 + histogram[x, y, z + 2, c]
    blurx[x, y, z,
          c] = blurz[x - 2, y, z, c] + blurz[x - 1, y, z, c] * 4 + blurz[
              x, y, z, c] * 6 + blurz[x + 1, y, z, c] * 4 + blurz[x + 2, y, z,
                                                                  c]
    blury[x, y, z,
          c] = blurx[x, y - 2, z, c] + blurx[x, y - 1, z, c] * 4 + blurx[
              x, y, z, c] * 6 + blurx[x, y + 1, z, c] * 4 + blurx[x, y + 2, z,
                                                                  c]

    # Take trilinear samples to compute the output
    val = hl.clamp(clamped[x, y], 0.0, 1.0)
    zv = val / r_sigma
    zi = hl.i32(zv)
    zf = zv - zi
    xf = hl.f32(x % s_sigma) / s_sigma
    yf = hl.f32(y % s_sigma) / s_sigma
    xi = x / s_sigma
    yi = y / s_sigma
    interpolated = hl.Func('interpolated')
    interpolated[x, y, c] = hl.lerp(
        hl.lerp(
            hl.lerp(blury[xi, yi, zi, c], blury[xi + 1, yi, zi, c], xf),
            hl.lerp(blury[xi, yi + 1, zi, c], blury[xi + 1, yi + 1, zi, c],
                    xf), yf),
        hl.lerp(
            hl.lerp(blury[xi, yi, zi + 1, c], blury[xi + 1, yi, zi + 1, c],
                    xf),
            hl.lerp(blury[xi, yi + 1, zi + 1, c], blury[xi + 1, yi + 1, zi + 1,
                                                        c], xf), yf), zf)

    # Normalize
    bilateral_grid = hl.Func('bilateral_grid')
    bilateral_grid[x, y] = interpolated[x, y, 0] / interpolated[x, y, 1]

    if aot:
        target = hl.get_target_from_environment()
    else:
        target = hl.get_jit_target_from_environment()
    if target.has_gpu_feature():
        # GPU schedule
        # Currently running this directly from the Python code is very slow.
        # Probably because of the dispatch time because generated code
        # is same speed as C++ generated code.
        print("Compiling for GPU.")
        xb = hl.Var('xb')
        yb = hl.Var('yb')
        zb = hl.Var('zb')
        histogram.compute_root().reorder(c, z, x,
                                         y).gpu_tile(x, y, xb, yb, 8, 8)
        histogram.update().reorder(c, r.x, r.y, x,
                                   y).gpu_tile(x, y, xb, yb, 8, 8).unroll(c)
        blurx.compute_root().gpu_tile(x, y, z, xb, yb, zb, 16, 16, 1)
        blury.compute_root().gpu_tile(x, y, z, xb, yb, zb, 16, 16, 1)
        blurz.compute_root().gpu_tile(x, y, z, xb, yb, zb, 8, 8, 4)
        bilateral_grid.compute_root().gpu_tile(x, y, xb, yb, s_sigma, s_sigma)
    else:
        # CPU schedule
        print("Compiling for CPU.")
        histogram.compute_root().parallel(z)
        histogram.update().reorder(c, r.x, r.y, x, y).unroll(c)
        blurz.compute_root().reorder(c, z, x,
                                     y).parallel(y).vectorize(x, 4).unroll(c)
        blurx.compute_root().reorder(c, x, y,
                                     z).parallel(z).vectorize(x, 4).unroll(c)
        blury.compute_root().reorder(c, x, y,
                                     z).parallel(z).vectorize(x, 4).unroll(c)
        bilateral_grid.compute_root().parallel(y).vectorize(x, 4)

    return bilateral_grid
Exemplo n.º 8
0
def test_simplestub():
    x, y = hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.UInt(8), [2, 2])
    b_in.fill(123)

    f_in = hl.Func("f")
    f_in[x, y] = x + y

    # ----------- Inputs by-position
    f = simplestub.generate(target, b_in, f_in, 3.5)
    _realize_and_check(f)

    # ----------- Inputs by-name
    f = simplestub.generate(target,
                            buffer_input=b_in,
                            func_input=f_in,
                            float_arg=3.5)
    _realize_and_check(f)

    # ----------- Inputs w/ mixed by-position and by-name
    f = simplestub.generate(target, b_in, f_in, float_arg=3.5)
    _realize_and_check(f)

    f = simplestub.generate(target, b_in, float_arg=3.5, func_input=f_in)
    _realize_and_check(f)

    # ----------- Above set again, w/ GeneratorParam mixed in
    k = 42

    f = simplestub.generate(target, b_in, f_in, 3.5, offset=k)
    _realize_and_check(f, k)

    f = simplestub.generate(target,
                            offset=k,
                            buffer_input=b_in,
                            func_input=f_in,
                            float_arg=3.5)
    _realize_and_check(f, k)

    f = simplestub.generate(target, b_in, f_in, offset=k, float_arg=3.5)
    _realize_and_check(f, k)

    f = simplestub.generate(target,
                            b_in,
                            float_arg=3.5,
                            offset=k,
                            func_input=f_in)
    _realize_and_check(f, k)

    # ----------- Test various failure modes
    try:
        # too many positional args
        f = simplestub.generate(target, b_in, f_in, 3.5, 4)
    except RuntimeError as e:
        assert 'Expected at most 3 positional args, but saw 4.' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (positional)
        f = simplestub.generate(target, 3.141592, "happy")
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (named)
        f = simplestub.generate(target, b_in, f_in, float_arg="bogus")
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Missing required inputs
        f = simplestub.generate(target, b_in, f_in)
    except RuntimeError as e:
        assert "Generator Input named 'float_arg' was not specified." in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Input specified by both pos and kwarg
        f = simplestub.generate(target, b_in, f_in, 3.5, float_arg=4.5)
    except RuntimeError as e:
        assert "Generator Input named 'float_arg' was specified by both position and keyword." in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad input name
        f = simplestub.generate(target,
                                b_in,
                                float_arg=3.5,
                                offset=k,
                                funk_input=f_in)
    except RuntimeError as e:
        assert "Generator Input named 'func_input' was not specified." in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad gp name
        f = simplestub.generate(target,
                                b_in,
                                float_arg=3.5,
                                offset=k,
                                func_input=f_in,
                                nonexistent_generator_param="wat")
    except RuntimeError as e:
        assert "Generator simplestub has no GeneratorParam named: nonexistent_generator_param" in str(
            e)
    else:
        assert False, 'Did not see expected exception!'
Exemplo n.º 9
0
def test_complexstub():
    constant_image = _make_constant_image()
    input = hl.ImageParam(hl.UInt(8), 3, 'input')
    input.set(constant_image)

    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    float_arg = 1.25
    int_arg = 33

    r = complexstub(target,
                    typed_buffer_input=constant_image,
                    untyped_buffer_input=constant_image,
                    simple_input=input,
                    array_input=[input, input],
                    float_arg=float_arg,
                    int_arg=[int_arg, int_arg],
                    untyped_buffer_output_type="uint8",
                    vectorize=True)

    # return value is a tuple; unpack separately to avoid
    # making the callsite above unreadable
    (simple_output, tuple_output, array_output, typed_buffer_output,
     untyped_buffer_output, static_compiled_buffer_output) = r

    b = simple_output.realize(32, 32, 3, target)
    assert b.type() == hl.Float(32)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected,
                                                                      actual)

    b = tuple_output.realize(32, 32, 3, target)
    assert b[0].type() == hl.Float(32)
    assert b[1].type() == hl.Float(32)
    assert len(b) == 2
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected1 = constant_image[x, y, c] * float_arg
                expected2 = expected1 + int_arg
                actual1, actual2 = b[0][x, y, c], b[1][x, y, c]
                assert expected1 == actual1, "Expected1 %s Actual1 %s" % (
                    expected1, actual1)
                assert expected2 == actual2, "Expected2 %s Actual1 %s" % (
                    expected2, actual2)

    assert len(array_output) == 2
    for a in array_output:
        b = a.realize(32, 32, target)
        assert b.type() == hl.Int(16)
        for x in range(32):
            for y in range(32):
                expected = constant_image[x, y, 0] + int_arg
                actual = b[x, y]
                assert expected == actual, "Expected %s Actual %s" % (expected,
                                                                      actual)

    # TODO: Output<Buffer<>> has additional behaviors useful when a Stub
    # is used within another Generator; this isn't yet implemented since there
    # isn't yet Python bindings for Generator authoring. This section
    # of the test may need revision at that point.
    b = typed_buffer_output.realize(32, 32, 3, target)
    assert b.type() == hl.Float(32)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected,
                                                                      actual)

    b = untyped_buffer_output.realize(32, 32, 3, target)
    assert b.type() == hl.UInt(8)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected,
                                                                      actual)

    b = static_compiled_buffer_output.realize(4, 4, 1, target)
    assert b.type() == hl.UInt(8)
    for x in range(4):
        for y in range(4):
            for c in range(1):
                expected = constant_image[x, y, c] + 42
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected,
                                                                      actual)
Exemplo n.º 10
0
            implicit_bounds_args['exterior'] = test_exterior

        realize_and_check(
                bc(**func_input_args), checker, input, test_min, test_extent, test_min,
                test_extent, vector_width, target)
        realize_and_check(
                bc(**image_input_args), checker, input, test_min, test_extent, test_min,
                test_extent, vector_width, target)
        realize_and_check(
                bc(**undef_min_args), checker, input, 0, W, test_min, test_extent,
                vector_width, target)
        realize_and_check(
                bc(**undef_max_args), checker, input, test_min, test_extent, 0, H,
                vector_width, target)
        realize_and_check(
                bc(**implicit_bounds_args), checker, input, test_min, test_extent,
                test_min, test_extent, vector_width, target)


if __name__ == '__main__':
    target = hl.get_jit_target_from_environment()

    vector_width_power_max = 6
    # https://github.com/halide/Halide/issues/2148
    if target.has_feature(hl.TargetFeature.Metal):
        vector_width_power_max = 3;

    for i in range(0, vector_width_power_max):
        vector_width = 1 << i
        test_all(vector_width, target)
Exemplo n.º 11
0
def test_simple(gen):
    x, y = hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.UInt(8), [2, 2])
    b_in.fill(123)

    f_in = hl.Func("f")
    f_in[x, y] = x + y

    # ----------- Inputs by-position
    f = gen(target, b_in, f_in, 3.5)
    _realize_and_check(f)

    # ----------- Inputs by-name
    f = gen(target, buffer_input=b_in, func_input=f_in, float_arg=3.5)
    _realize_and_check(f)

    f = gen(target, float_arg=3.5, buffer_input=b_in, func_input=f_in)
    _realize_and_check(f)

    # ----------- Above set again, w/ GeneratorParam mixed in
    k = 42

    gp = {"offset": k}

    # (positional)
    f = gen(target, b_in, f_in, 3.5, generator_params=gp)
    _realize_and_check(f, k)

    # (keyword)
    f = gen(target,
            generator_params=gp,
            buffer_input=b_in,
            func_input=f_in,
            float_arg=3.5)
    _realize_and_check(f, k)

    f = gen(target,
            buffer_input=b_in,
            generator_params=gp,
            func_input=f_in,
            float_arg=3.5)
    _realize_and_check(f, k)

    f = gen(target,
            buffer_input=b_in,
            func_input=f_in,
            generator_params=gp,
            float_arg=3.5)
    _realize_and_check(f, k)

    f = gen(target,
            buffer_input=b_in,
            float_arg=3.5,
            func_input=f_in,
            generator_params=gp)
    _realize_and_check(f, k)

    # ----------- Test various failure modes
    try:
        # Inputs w/ mixed by-position and by-name
        f = gen(target, b_in, f_in, float_arg=3.5)
    except RuntimeError as e:
        assert 'Cannot use both positional and keyword arguments for inputs.' in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # too many positional args
        f = gen(target, b_in, f_in, 3.5, 4)
    except RuntimeError as e:
        assert 'Expected exactly 3 positional args for inputs, but saw 4.' in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # too few positional args
        f = gen(target, b_in, f_in)
    except RuntimeError as e:
        assert 'Expected exactly 3 positional args for inputs, but saw 2.' in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (positional)
        f = gen(target, hl.f32(3.141592), "happy", k)
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (named)
        f = gen(target, b_in, f_in, float_arg="bogus")
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Input specified by both pos and kwarg
        f = gen(target, b_in, f_in, 3.5, float_arg=4.5)
    except RuntimeError as e:
        assert "Cannot use both positional and keyword arguments for inputs." in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # generator_params is not a dict
        f = gen(target, b_in, f_in, 3.5, generator_params=[1, 2, 3])
    except TypeError as e:
        assert "cannot convert dictionary" in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad gp name
        f = gen(target, b_in, f_in, 3.5, generator_params={"foo": 0})
    except RuntimeError as e:
        assert "has no GeneratorParam named: foo" in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad input name
        f = gen(target,
                buffer_input=b_in,
                float_arg=3.5,
                generator_params=gp,
                funk_input=f_in)
    except RuntimeError as e:
        assert "Unknown input 'funk_input' specified via keyword argument." in str(
            e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad gp name
        f = gen(target,
                buffer_input=b_in,
                float_arg=3.5,
                generator_params=gp,
                func_input=f_in,
                nonexistent_generator_param="wat")
    except RuntimeError as e:
        assert "Unknown input 'nonexistent_generator_param' specified via keyword argument." in str(
            e)
    else:
        assert False, 'Did not see expected exception!'
Exemplo n.º 12
0
def test_simplestub():
    x, y = hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    b_in = hl.Buffer(hl.UInt(8), [2, 2])
    b_in.fill(123)

    f_in = hl.Func("f")
    f_in[x, y] = x + y

    # ----------- Inputs by-position
    f = simplestub.generate(target, b_in, f_in, 3.5)
    _realize_and_check(f)

    # ----------- Inputs by-name
    f = simplestub.generate(target, buffer_input=b_in, func_input=f_in, float_arg=3.5)
    _realize_and_check(f)

    # ----------- Inputs w/ mixed by-position and by-name
    f = simplestub.generate(target, b_in, f_in, float_arg=3.5)
    _realize_and_check(f)

    f = simplestub.generate(target, b_in, float_arg=3.5, func_input=f_in)
    _realize_and_check(f)

    # ----------- Above set again, w/ GeneratorParam mixed in
    k = 42

    f = simplestub.generate(target, b_in, f_in, 3.5, offset=k)
    _realize_and_check(f, k)

    f = simplestub.generate(target, offset=k, buffer_input=b_in, func_input=f_in, float_arg=3.5)
    _realize_and_check(f, k)

    f = simplestub.generate(target, b_in, f_in, offset=k, float_arg=3.5)
    _realize_and_check(f, k)

    f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in)
    _realize_and_check(f, k)

    # ----------- Test various failure modes
    try:
        # too many positional args
        f = simplestub.generate(target, b_in, f_in, 3.5, 4)
    except RuntimeError as e:
        assert 'Expected at most 3 positional args, but saw 4.' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (positional)
        f = simplestub.generate(target, 3.141592, "happy")
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Inputs that can't be converted to what the receiver needs (named)
        f = simplestub.generate(target, b_in, f_in, float_arg="bogus")
    except RuntimeError as e:
        assert 'Unable to cast Python instance' in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Missing required inputs
        f = simplestub.generate(target, b_in, f_in)
    except RuntimeError as e:
        assert "Generator Input named 'float_arg' was not specified." in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Input specified by both pos and kwarg
        f = simplestub.generate(target, b_in, f_in, 3.5, float_arg=4.5)
    except RuntimeError as e:
        assert "Generator Input named 'float_arg' was specified by both position and keyword." in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad input name
        f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, funk_input=f_in)
    except RuntimeError as e:
        assert "Generator Input named 'func_input' was not specified." in str(e)
    else:
        assert False, 'Did not see expected exception!'

    try:
        # Bad gp name
        f = simplestub.generate(target, b_in, float_arg=3.5, offset=k, func_input=f_in, nonexistent_generator_param="wat")
    except RuntimeError as e:
        assert "Generator has no GeneratorParam named: nonexistent_generator_param" in str(e)
    else:
        assert False, 'Did not see expected exception!'
Exemplo n.º 13
0
def test_complexstub():
    constant_image = _make_constant_image()
    input = hl.ImageParam(hl.UInt(8), 3, 'input')
    input.set(constant_image)

    x, y, c = hl.Var(), hl.Var(), hl.Var()
    target = hl.get_jit_target_from_environment()

    float_arg = 1.25
    int_arg = 33

    r = complexstub(target,
                    typed_buffer_input=constant_image,
                    untyped_buffer_input=constant_image,
                    simple_input=input,
                    array_input=[ input, input ],
                    float_arg=float_arg,
                    int_arg=[ int_arg, int_arg ],
                    untyped_buffer_output_type="uint8",
                    vectorize=True)

    # return value is a tuple; unpack separately to avoid
    # making the callsite above unreadable
    (simple_output,
        tuple_output,
        array_output,
        typed_buffer_output,
        untyped_buffer_output,
        static_compiled_buffer_output) = r

    b = simple_output.realize(32, 32, 3, target)
    assert b.type() == hl.Float(32)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected, actual)

    b = tuple_output.realize(32, 32, 3, target)
    assert b[0].type() == hl.Float(32)
    assert b[1].type() == hl.Float(32)
    assert len(b) == 2
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected1 = constant_image[x, y, c] * float_arg
                expected2 = expected1 + int_arg
                actual1, actual2 = b[0][x, y, c], b[1][x, y, c]
                assert expected1 == actual1, "Expected1 %s Actual1 %s" % (expected1, actual1)
                assert expected2 == actual2, "Expected2 %s Actual1 %s" % (expected2, actual2)

    assert len(array_output) == 2
    for a in array_output:
        b = a.realize(32, 32, target)
        assert b.type() == hl.Int(16)
        for x in range(32):
            for y in range(32):
                expected = constant_image[x, y, 0] + int_arg
                actual = b[x, y]
                assert expected == actual, "Expected %s Actual %s" % (expected, actual)

    # TODO: Output<Buffer<>> has additional behaviors useful when a Stub
    # is used within another Generator; this isn't yet implemented since there
    # isn't yet Python bindings for Generator authoring. This section
    # of the test may need revision at that point.
    b = typed_buffer_output.realize(32, 32, 3, target)
    assert b.type() == hl.Float(32)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected, actual)

    b = untyped_buffer_output.realize(32, 32, 3, target)
    assert b.type() == hl.UInt(8)
    for x in range(32):
        for y in range(32):
            for c in range(3):
                expected = constant_image[x, y, c]
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected, actual)

    b = static_compiled_buffer_output.realize(4, 4, 1, target)
    assert b.type() == hl.UInt(8)
    for x in range(4):
        for y in range(4):
            for c in range(1):
                expected = constant_image[x, y, c] + 42
                actual = b[x, y, c]
                assert expected == actual, "Expected %s Actual %s" % (expected, actual)