[Piglit] [PATCH 04/25] arb_shader_image_load_store: Import grid execution helpers.

Francisco Jerez currojerez at riseup.net
Thu Oct 9 02:10:08 PDT 2014


Ian Romanick <idr at freedesktop.org> writes:

> On 10/05/2014 11:00 PM, Francisco Jerez wrote:
>> Define helper functions that are able to run a piece of GLSL code on
>> an arbitrary shader stage (as of now VS, TCS, TES, GS, FS and CS are
>> supported) for a given execution size.  This makes every shader stage
>> expose a consistent interface that looks like a sort of primitive
>> two-dimensional compute grid, with the peculiarity that you can run
>> several stages at the same time and chain the results of one stage
>> into the arguments of the next.
>> 
>> This is useful in cases where one needs to run the exact same test on
>> a number of shader stages and using code generators or duplicating
>> code would be inconvenient.
>
> This is a really good idea.  More comments below...
>
>> ---
>>  tests/spec/arb_shader_image_load_store/grid.c | 445 ++++++++++++++++++++++++++
>>  tests/spec/arb_shader_image_load_store/grid.h | 155 +++++++++
>>  2 files changed, 600 insertions(+)
>>  create mode 100644 tests/spec/arb_shader_image_load_store/grid.c
>>  create mode 100644 tests/spec/arb_shader_image_load_store/grid.h
>> 
>> diff --git a/tests/spec/arb_shader_image_load_store/grid.c b/tests/spec/arb_shader_image_load_store/grid.c
>> new file mode 100644
>> index 0000000..4c27349
>> --- /dev/null
>> +++ b/tests/spec/arb_shader_image_load_store/grid.c
>> @@ -0,0 +1,445 @@
>> +/*
>> + * 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.
>> + */
>> +
>> +/** @file grid.c
>> + *
>> + * Utility code for running a grid of shader invocations abstracting
>> + * out the details of the specific shader stage it's run on.
>> + */
>> +
>> +#include "common.h"
>> +
>> +char *
>> +concat(char *hunk0, ...)
>> +{
>
> I'm not a huge fan of having this function release storage.  Needing to
> use hunk() on the constant string parameters is surprising.  All of the
> callers appear to be in generate_stage_source, and that function could
> just free header and body after the big switch.  That's seems pretty
> straightforward and clean.
>

Oh, the intended usage idiom for this function is as follows:

char *generated_source =
concat(generate_some_hunk_dynamically(run_time_parameters_like_image_target_format_or_current_test),
       hunk(constant_string), 
       some_other_dynamically_generated_hunk(),
       NULL);

Which IMHO would be harder to follow and a lot more typing if we had to
define temporaries for each dynamically generated hunk and then remember
to deallocate them.

It's not only used by generated_stage_source() BTW, it's also used by
most of the tests to concatenate a number of static and dynamic strings
together.  The fact that concat() takes ownership of its arguments lets
you do that with a concise syntax.

> Also... this seems like a useful enough function to have in tests/util/
> somewhere.
>
Right, we could do that.  I guess in that case it would make sense to
stress the unusual memory transfer behavior and explain the expected
usage pattern of this function in the docs to avoid surprises.

>> +        char *s = hunk0;
>> +        char *hunk;
>> +        va_list ap;
>> +
>> +        va_start(ap, hunk0);
>> +
>> +        while ((hunk = va_arg(ap, char *))) {
>> +                char *t = s;
>> +                asprintf(&s, "%s\n%s", t, hunk);
>> +                free(t);
>> +                free(hunk);
>> +        }
>> +
>> +        va_end(ap);
>> +        return s;
>> +}
>> +
>> +char *
>> +image_hunk(const struct image_info img, const char *prefix)
>> +{
>> +        char *s = NULL;
>> +
>> +        asprintf(&s,
>> +                 "#define %sBASE_T %s\n"
>> +                 "#define %sDATA_T %s\n"
>> +                 "#define %sSCALE vec4(%.8e, %.8e, %.8e, %.8e)\n"
>> +                 "#define %sIMAGE_ADDR_(addr_t, ext, i) %s\n"
>> +                 "#define %sIMAGE_ADDR(idx)"
>> +                 "        %sIMAGE_ADDR_(%s, ivec4(%d, %d, %d, %d),"
>> +                 "                      ((idx).x + W * (idx).y))\n"
>> +                 "#define %sIMAGE_LAYOUT_Q layout(%s)\n"
>> +                 "#define %sIMAGE_BARE_T %s%s\n"
>> +                 "#define %sIMAGE_T %sIMAGE_LAYOUT_Q %sIMAGE_BARE_T\n",
>> +                 prefix, image_scalar_type_name(img.format),
>> +                 prefix, image_vector_type_name(img.format),
>> +                 prefix, image_format_scale(img.format).x,
>> +                 image_format_scale(img.format).y,
>> +                 image_format_scale(img.format).z,
>> +                 image_format_scale(img.format).w,
>> +                 prefix, (image_target_samples(img.target) > 1 ?
>> +                          "addr_t(ivec3(i / ext.x % ext.y,"
>> +                          "             i / ext.x / ext.y % ext.z,"
>> +                          "             i / ext.x / ext.y / ext.z)),"
>> +                          "(i % ext.x)" :
>> +                          "addr_t(ivec3(i % ext.x,"
>> +                          "             i / ext.x % ext.y,"
>> +                          "             i / ext.x / ext.y))"),
>> +                 prefix, prefix, img.target->addr_type_name,
>> +                 img.size.x, img.size.y, img.size.z, img.size.w,
>> +                 prefix, img.format->name,
>> +                 prefix, image_type_name(img.format), img.target->name,
>> +                 prefix, prefix, prefix);
>> +        return s;
>> +}
>> +
>> +static char *
>> +header_hunk(const struct grid_info grid)
>> +{
>> +        char *s = NULL;
>> +
>> +        asprintf(&s, "#version 150\n"
>> +                 "#extension GL_ARB_shader_image_load_store : enable\n"
>> +                 "#define W %d\n"
>> +                 "#define H %d\n"
>> +                 "#define N %d\n"
>> +                 "#define GRID_T %s\n"
>> +                 "#define RET_IMAGE_T layout(%s) %s2D\n",
>> +                 grid.size.x, grid.size.y, product(grid.size),
>> +                 image_vector_type_name(grid.format),
>> +                 grid.format->name, image_type_name(grid.format));
>> +        return s;
>> +}
>> +
>> +static char *
>> +generate_stage_source(const struct grid_info grid,
>> +                      unsigned stage, const char *_body)
>> +{
>> +        char *header = header_hunk(grid);
>> +        char *body = hunk(_body ? _body :
>> +                          "GRID_T op(ivec2 idx, GRID_T x) {\n"
>> +                          "        return x;\n"
>> +                          "}\n");
>> +
>> +        switch (stage) {
>> +        case GL_VERTEX_SHADER:
>> +                return concat(
>> +                        header, body,
>> +                        hunk("in vec4 piglit_vertex;\n"
>> +                             "out ivec2 vidx;\n"
>> +                             "flat out GRID_T vcolor;\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "        ivec2 idx = ivec2((piglit_vertex + 1.0).xy *"
>> +                             "                          vec2(W, H) / 2);\n"
>> +                             "\n"
>> +                             "        vcolor = op(idx, GRID_T(0));\n"
>> +                             "        vidx = idx;\n"
>> +                             "        gl_Position = piglit_vertex;\n"
>> +                             "}\n"), NULL);
>> +
>> +        case GL_TESS_CONTROL_SHADER:
>> +                return concat(
>> +                        header,
>> +                        hunk("#extension GL_ARB_tessellation_shader : enable\n"),
>> +                        body,
>> +                        hunk("layout(vertices=4) out;\n"
>> +                             "\n"
>> +                             "in ivec2 vidx[];\n"
>> +                             "flat in GRID_T vcolor[];\n"
>> +                             "out ivec2 tcidx[];\n"
>> +                             "out GRID_T tccolor[];\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "        if (gl_InvocationID == 0) {\n"
>> +                             "                /* No subdivisions, thanks. */\n"
>> +                             "                gl_TessLevelInner[0] = 1;\n"
>> +                             "                gl_TessLevelInner[1] = 1;\n"
>> +                             "                gl_TessLevelOuter[0] = 1;\n"
>> +                             "                gl_TessLevelOuter[1] = 1;\n"
>> +                             "                gl_TessLevelOuter[2] = 1;\n"
>> +                             "                gl_TessLevelOuter[3] = 1;\n"
>> +                             "        }\n"
>> +                             "        tccolor[gl_InvocationID] ="
>> +                             "               op(vidx[gl_InvocationID],"
>> +                             "                  vcolor[gl_InvocationID]);\n"
>> +                             "        tcidx[gl_InvocationID] = vidx[gl_InvocationID];\n"
>> +                             "        gl_out[gl_InvocationID].gl_Position ="
>> +                             "               gl_in[gl_InvocationID].gl_Position;\n"
>> +                             "}\n"), NULL);
>> +
>> +        case GL_TESS_EVALUATION_SHADER:
>> +                return concat(
>> +                        header,
>> +                        hunk("#extension GL_ARB_tessellation_shader : enable\n"),
>> +                        body,
>> +                        hunk("layout(quads, point_mode) in;\n"
>> +                             "\n"
>> +                             "in ivec2 tcidx[];\n"
>> +                             "in GRID_T tccolor[];\n"
>> +                             "out ivec2 teidx;\n"
>> +                             "flat out GRID_T tecolor;\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "        int idx = ((gl_TessCoord.x > 0.5 ? 1 : 0) +"
>> +                             "                   (gl_TessCoord.y > 0.5 ? 2 : 0));\n"
>> +                             "\n"
>> +                             "        tecolor = op(tcidx[idx], tccolor[idx]);\n"
>> +                             "        teidx = tcidx[idx];\n"
>> +                             "        gl_Position = gl_in[idx].gl_Position;\n"
>> +                             "}\n"), NULL);
>> +
>> +        case GL_GEOMETRY_SHADER:
>> +                return concat(
>> +                        header,
>> +                        hunk(grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
>> +                                            GL_TESS_EVALUATION_SHADER_BIT) ?
>> +                             "#define IN(name) te##name\n" :
>> +                             "#define IN(name) v##name\n"),
>> +                        body,
>> +                        hunk("layout(points) in;\n"
>> +                             "layout(points, max_vertices=1) out;\n"
>> +                             "\n"
>> +                             "in ivec2 IN(idx)[];\n"
>> +                             "flat in GRID_T IN(color)[];\n"
>> +                             "flat out GRID_T gcolor;\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "        gcolor = op(IN(idx)[0], IN(color)[0]);\n"
>> +                             "        gl_Position = gl_in[0].gl_Position;\n"
>> +                             "        EmitVertex();\n"
>> +                             "}\n"), NULL);
>> +
>> +        case GL_FRAGMENT_SHADER:
>> +                return concat(
>> +                        header,
>> +                        hunk(grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
>> +                                            GL_TESS_EVALUATION_SHADER_BIT |
>> +                                            GL_GEOMETRY_SHADER_BIT) ?
>> +                             "#define IN(name) g##name\n" :
>> +                             "#define IN(name) v##name\n"),
>> +                        body,
>> +                        hunk("flat in GRID_T IN(color);\n"
>> +                             "out GRID_T fcolor;\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "        fcolor = op(ivec2(gl_FragCoord), IN(color));\n"
>> +                             "}\n"), NULL);
>> +
>> +        case GL_COMPUTE_SHADER:
>> +                return concat(
>> +                        header,
>> +                        hunk("#extension GL_ARB_compute_shader : enable\n"),
>> +                        body,
>> +                        hunk("layout (local_size_x = W) in;\n"
>> +                             "\n"
>> +                             "uniform RET_IMAGE_T ret_img;\n"
>> +                             "\n"
>> +                             "void main() {\n"
>> +                             "       ivec2 idx = ivec2(gl_GlobalInvocationID);\n"
>> +                             "       GRID_T x = op(idx, GRID_T(0));\n"
>> +                             "       imageStore(ret_img, idx, x);\n"
>> +                             "}\n"), NULL);
>> +
>> +        default:
>> +                abort();
>> +        }
>> +}
>> +
>> +static inline unsigned
>> +get_stage_idx(const struct image_stage_info *stage)
>> +{
>> +        return stage - image_stages();
>> +}
>> +
>> +/**
>> + * Generate a full program pipeline using the shader code provided in
>> + * the \a sources array.
>> + */
>> +static GLuint
>> +generate_program_v(const struct grid_info grid, const char **sources)
>> +{
>> +        const unsigned basic_stages = (GL_FRAGMENT_SHADER_BIT |
>> +                                       GL_VERTEX_SHADER_BIT);
>> +        const unsigned tess_stages = (GL_TESS_CONTROL_SHADER_BIT |
>> +                                      GL_TESS_EVALUATION_SHADER_BIT);
>> +        const unsigned graphic_stages = (basic_stages | tess_stages |
>> +                                         GL_GEOMETRY_SHADER_BIT);
>> +        const unsigned stages =
>> +                (grid.stages |
>> +                 /* Make a full pipeline if a tesselation shader was
>> +                  * requested. */
>> +                 (grid.stages & tess_stages ? graphic_stages : 0) |
>> +                 /* Make sure there is always a vertex and fragment
>> +                  * shader if we're doing graphics. */
>> +                 (grid.stages & graphic_stages ? basic_stages : 0));
>> +        GLuint prog = glCreateProgram();
>> +        const struct image_stage_info *stage;
>> +
>> +        for (stage = image_stages(); stage->stage; ++stage) {
>> +                if (stages & stage->bit) {
>> +                        char *source = generate_stage_source(
>> +                                grid, stage->stage,
>> +                                sources[get_stage_idx(stage)]);
>> +                        GLuint shader = piglit_compile_shader_text_nothrow(
>> +                                stage->stage, source);
>> +
>> +                        free(source);
>> +
>> +                        if (!shader) {
>> +                                glDeleteProgram(prog);
>> +                                return 0;
>> +                        }
>> +
>> +                        glAttachShader(prog, shader);
>> +                        glDeleteShader(shader);
>> +                }
>> +        }
>> +
>> +        glBindAttribLocation(prog, PIGLIT_ATTRIB_POS, "piglit_vertex");
>> +        glBindAttribLocation(prog, PIGLIT_ATTRIB_TEX, "piglit_texcoord");
>> +        glLinkProgram(prog);
>> +
>> +        if (!piglit_link_check_status(prog)) {
>> +                glDeleteProgram(prog);
>> +                return 0;
>> +        }
>> +
>> +        return prog;
>> +}
>> +
>> +GLuint
>> +generate_program(const struct grid_info grid, ...)
>> +{
>> +        char *sources[6] = { NULL };
>> +        va_list ap;
>> +        const struct image_stage_info *stage;
>> +        unsigned stages, i;
>> +        GLuint prog;
>> +
>> +        va_start(ap, grid);
>> +
>> +        for (stages = grid.stages; stages; stages &= ~stage->bit) {
>> +                stage = get_image_stage(va_arg(ap, GLenum));
>> +                assert(get_stage_idx(stage) < ARRAY_SIZE(sources));
>> +                sources[get_stage_idx(stage)] = va_arg(ap, char *);
>> +        }
>> +
>> +        va_end(ap);
>> +
>> +        prog = generate_program_v(grid, (const char **)sources);
>> +
>> +        for (i = 0; i < ARRAY_SIZE(sources); ++i)
>> +                free(sources[i]);
>> +
>> +        return prog;
>> +}
>> +
>> +bool
>> +draw_grid(const struct grid_info grid, GLuint prog)
>> +{
>> +        static GLuint lprog;
>> +
>> +        if (lprog != prog) {
>> +                glUseProgram(prog);
>> +                lprog = prog;
>> +        }
>> +
>> +        if (grid.stages & GL_COMPUTE_SHADER_BIT) {
>> +                set_uniform_int(prog, "ret_img", 7);
>> +                glDispatchCompute(1, grid.size.y, 1);
>> +
>> +        } else if (grid.stages & (GL_TESS_CONTROL_SHADER_BIT |
>> +                                  GL_TESS_EVALUATION_SHADER_BIT)) {
>> +                static struct image_extent size;
>> +                static GLuint vao, vbo;
>> +
>> +                if (size.x != grid.size.x || size.y != grid.size.y) {
>> +                        size = grid.size;
>> +
>> +                        if (!generate_grid_arrays(
>> +                                    &vao, &vbo,
>> +                                    1.0 / size.x - 1.0, 1.0 / size.y - 1.0,
>> +                                    2.0 / size.x, 2.0 / size.y,
>> +                                    size.x, size.y))
>> +                                return false;
>> +                }
>> +
>> +                glBindVertexArray(vao);
>> +                glPatchParameteri(GL_PATCH_VERTICES, 4);
>> +                glDrawArrays(GL_PATCHES, 0, product(size));
>> +
>> +        } else if (grid.stages & (GL_VERTEX_SHADER_BIT |
>> +                                  GL_GEOMETRY_SHADER_BIT)) {
>> +                static struct image_extent size;
>> +                static GLuint vao, vbo;
>> +
>> +                if (size.x != grid.size.x || size.y != grid.size.y) {
>> +                        size = grid.size;
>> +
>> +                        if (!generate_grid_arrays(
>> +                                    &vao, &vbo,
>> +                                    1.0 / size.x - 1.0, 1.0 / size.y - 1.0,
>> +                                    2.0 / size.x, 2.0 / size.y,
>> +                                    size.x, size.y))
>> +                                return false;
>> +                }
>> +
>> +                glBindVertexArray(vao);
>> +                glDrawArrays(GL_POINTS, 0, product(size));
>> +
>> +        } else {
>> +                static struct image_extent size;
>> +                static GLuint vao, vbo;
>> +
>> +                if (size.x != grid.size.x || size.y != grid.size.y) {
>> +                        float vp[4];
>> +
>> +                        glGetFloati_v(GL_VIEWPORT, 0, vp);
>> +                        size = grid.size;
>> +
>> +                        if (!generate_grid_arrays(
>> +                                    &vao, &vbo, -1.0, -1.0,
>> +                                    2.0 * size.x / vp[2], 2.0 * size.y / vp[3],
>> +                                    2, 2))
>> +                                return false;
>> +                }
>> +
>> +
>> +                glBindVertexArray(vao);
>> +                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
>> +        }
>> +
>> +        return piglit_check_gl_error(GL_NO_ERROR);
>> +}
>> +
>> +bool
>> +generate_grid_arrays(GLuint *vao, GLuint *vbo,
>> +                     float x, float y, float dx, float dy,
>> +                     unsigned nx, unsigned ny)
>> +{
>> +        float (*verts)[4] = malloc(sizeof(*verts) * nx * ny);
>> +        int i, j;
>> +
>> +        for (i = 0; i < nx; ++i) {
>> +                for (j = 0; j < ny; ++j) {
>> +                        const unsigned k = (nx * (j & ~1) + 2 * (i & ~1) +
>> +                                            (i & 1) + 2 * (j & 1));
>> +                        verts[k][0] = x + i * dx;
>> +                        verts[k][1] = y + j * dy;
>> +                        verts[k][2] = 0.0;
>> +                        verts[k][3] = 1.0;
>> +                }
>> +        }
>> +
>> +        if (!*vao) {
>> +                glGenVertexArrays(1, vao);
>> +                glGenBuffers(1, vbo);
>> +        }
>> +
>> +        glBindVertexArray(*vao);
>> +        glBindBuffer(GL_ARRAY_BUFFER, *vbo);
>> +        glBufferData(GL_ARRAY_BUFFER, sizeof(*verts) * nx * ny,
>> +                     verts, GL_STATIC_DRAW);
>> +
>> +        glVertexAttribPointer(PIGLIT_ATTRIB_POS, 4, GL_FLOAT,
>> +                              GL_FALSE, 0, 0);
>> +        glEnableVertexAttribArray(PIGLIT_ATTRIB_POS);
>> +
>> +        free(verts);
>> +        return piglit_check_gl_error(GL_NO_ERROR);
>> +}
>> diff --git a/tests/spec/arb_shader_image_load_store/grid.h b/tests/spec/arb_shader_image_load_store/grid.h
>> new file mode 100644
>> index 0000000..fca67ce
>> --- /dev/null
>> +++ b/tests/spec/arb_shader_image_load_store/grid.h
>> @@ -0,0 +1,155 @@
>> +/*
>> + * 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.
>> + */
>> +
>> +/** @file grid.h
>> + *
>> + * Utility code for running a grid of shader invocations abstracting
>> + * out the details of the specific shader stage it's run on.
>> + */
>> +
>> +#ifndef __PIGLIT_ARB_SHADER_IMAGE_LOAD_STORE_GRID_H__
>> +#define __PIGLIT_ARB_SHADER_IMAGE_LOAD_STORE_GRID_H__
>> +
>> +#include "image.h"
>> +
>> +struct grid_info {
>> +        /** Bitfield of shader stages present in the pipeline
>> +         * (GL_*_SHADER_BIT). */
>> +        unsigned stages;
>> +
>> +        /** Data type used to hold the values that are passed down
>> +         * through the pipeline. */
>> +        const struct image_format_info *format;
>> +
>> +        /** Size of the two-dimensional grid. */
>> +        struct image_extent size;
>> +};
>> +
>> +/**
>> + * Construct a grid_info object.
>> + */
>> +static inline struct grid_info
>> +grid_info(GLenum stage, GLenum format, unsigned w, unsigned h)
>> +{
>> +        const struct grid_info grid = {
>> +                get_image_stage(stage)->bit,
>> +                get_image_format(format),
>> +                { w, h, 1, 1 }
>> +        };
>> +
>> +        return grid;
>> +}
>> +
>> +static inline struct grid_info
>> +set_grid_size(struct grid_info grid, unsigned x, unsigned y)
>> +{
>> +        const struct image_extent size = { x, y, 1, 1 };
>> +        grid.size = size;
>> +        return grid;
>> +}
>> +
>> +/**
>> + * Construct an image_info structure with the same dimensions and
>> + * format as the specified grid.
>> + */
>> +static inline struct image_info
>> +image_info_for_grid(const struct grid_info grid)
>> +{
>> +        const struct image_info img = {
>> +                get_image_target(GL_TEXTURE_2D),
>> +                grid.format, grid.size,
>> +                image_format_epsilon(grid.format)
>> +        };
>> +
>> +        return img;
>> +}
>> +
>> +/**
>> + * Concatenate a variable number of strings into a newly allocated
>> + * buffer.  Note that concat() assumes ownership of the provided
>> + * arguments and that the argument list must be NULL-terminated.
>> + */
>> +char *
>> +concat(char *hunk0, ...);
>> +
>> +static inline char *
>> +hunk(const char *s)
>> +{
>> +        return strdup(s);
>> +}
>> +
>> +/**
>> + * Generate preprocessor defines containing geometry and data type
>> + * information for a shader image object.
>> + */
>> +char *
>> +image_hunk(const struct image_info img, const char *prefix);
>> +
>> +/**
>> + * Generate a shader program containing all the required stages to run
>> + * the provided shader source from \a grid.  A series of (GLenum, char *)
>> + * pairs should follow as variadic arguments, where the GLenum
>> + * argument specifies an additional shader stage (GL_*_SHADER) and the
>> + * string specifies a fragment of GLSL code to be included in the same
>> + * shader stage.  Note that generate_program() takes ownership of the
>> + * provided argument strings.
>> + *
>> + * Each fragment should define a GLSL function with prototype
>> + * "GRID_T op(ivec2 idx, GRID_T x)", where \a idx is the
>> + * two-dimensional coordinate of a particular shader invocation within
>> + * the grid and \a x is the result of the last invocation of op() from
>> + * a previous shader stage at the same grid coordinate.  Zero is
>> + * passed as argument to the topmost invocation of op() in the chain.
>> + *
>> + * The final result from the chain of op() calls is written as
>> + * fragment color to the framebuffer, or written to the read-back
>> + * buffer when running a compute shader.
>> + *
>> + * The generated program will typically be passed as argument to
>> + * draw_grid() in order to launch the grid.
>> + */
>> +GLuint
>> +generate_program(const struct grid_info grid, ...);
>> +
>> +/**
>> + * Launch a grid of shader invocations of the specified size.
>> + * Depending on the specified shader stages an array of triangles,
>> + * points or patches will be drawn or a compute grid will be
>> + * executed.
>> + */
>> +bool
>> +draw_grid(const struct grid_info grid, GLuint prog);
>> +
>> +/**
>> + * Generate vertex arrays intended to be used to launch a grid of
>> + * shader invocations using the specified origin (\a x, \a y), spacing
>> + * (\a dx, \a dy) and dimensions (\a nx, \a ny).  This is done
>> + * internally by draw_grid(), but it could be useful on its own for
>> + * applications that require more control.
>> + */
>> +bool
>> +generate_grid_arrays(GLuint *vao, GLuint *vbo,
>> +                     float x, float y, float dx, float dy,
>> +                     unsigned nx, unsigned ny);
>> +
>> +#endif
>> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 212 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/piglit/attachments/20141009/d113f15e/attachment-0001.sig>


More information about the Piglit mailing list