[Piglit] [PATCHv2 02/23] arb_shader_image_load_store: Add common image metadata.

Francisco Jerez currojerez at riseup.net
Sat Jan 31 07:41:24 PST 2015


Define helper data structures and functions to query several kinds of
information for any supported image format, target or shader stage,
like the matching pixel transfer type and format for a given image
format, GLSL type information, error tolerance, maximum supported
dimensions and samples for a given image dimensionality, number of
supported image uniforms for a given shader stage, etc.

This also defines the image_info data structure that aggregates some
combination of image target, format and dimensions in a single object
to avoid having to repeat the same three arguments constantly when
working with images.

v2: Encode per-image base datatype information in a struct instead of
    having separate switch-case statements spread over several query
    functions.  Add comment explaining the reason why there are no
    specific semantics attached to image dimensions.  (Ian)
---
 tests/spec/arb_shader_image_load_store/image.c | 743 +++++++++++++++++++++++++
 tests/spec/arb_shader_image_load_store/image.h | 386 +++++++++++++
 2 files changed, 1129 insertions(+)
 create mode 100644 tests/spec/arb_shader_image_load_store/image.c
 create mode 100644 tests/spec/arb_shader_image_load_store/image.h

diff --git a/tests/spec/arb_shader_image_load_store/image.c b/tests/spec/arb_shader_image_load_store/image.c
new file mode 100644
index 0000000..58cda9b
--- /dev/null
+++ b/tests/spec/arb_shader_image_load_store/image.c
@@ -0,0 +1,743 @@
+/*
+ * 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 image.c
+ *
+ * Common image format, target and shader stage metadata.
+ */
+
+#include "image.h"
+
+struct image_extent
+image_optimal_extent(struct image_extent ext)
+{
+        const unsigned n = product(ext);
+        const unsigned w = 1 << MIN2(ffs(n) - 1, (int)log2(n) / 2);
+        const struct image_extent opt = {
+                w, n / w, 1, 1
+        };
+
+        return opt;
+}
+
+const struct image_format_info image_formats_load_store[] = {
+        { "rgba32f", GL_RGBA32F, GL_RGBA, GL_FLOAT, { 32, 32, 32, 32 } },
+        { "rgba16f", GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, { 16, 16, 16, 16 } },
+        { "rg32f", GL_RG32F, GL_RG, GL_FLOAT, { 32, 32, 0, 0 } },
+        { "rg16f", GL_RG16F, GL_RG, GL_HALF_FLOAT, { 16, 16, 0, 0 } },
+        { "r11f_g11f_b10f", GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, { 11, 11, 10, 0 } },
+        { "r32f", GL_R32F, GL_RED, GL_FLOAT, { 32, 0, 0, 0 } },
+        { "r16f", GL_R16F, GL_RED, GL_HALF_FLOAT, { 16, 0, 0, 0 } },
+        { "rgba32ui", GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT, { 32, 32, 32, 32 } },
+        { "rgba16ui", GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, { 16, 16, 16, 16 } },
+        { "rgb10_a2ui", GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV, { 10, 10, 10, 2 } },
+        { "rgba8ui", GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, { 8, 8, 8, 8 } },
+        { "rg32ui", GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, { 32, 32, 0, 0 } },
+        { "rg16ui", GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT, { 16, 16, 0, 0 } },
+        { "rg8ui", GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE, { 8, 8, 0, 0 } },
+        { "r32ui", GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, { 32, 0, 0, 0 } },
+        { "r16ui", GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT, { 16, 0, 0, 0 } },
+        { "r8ui", GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, { 8, 0, 0, 0 } },
+        { "rgba32i", GL_RGBA32I, GL_RGBA_INTEGER, GL_INT, { 32, 32, 32, 32 } },
+        { "rgba16i", GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT, { 16, 16, 16, 16 } },
+        { "rgba8i", GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE, { 8, 8, 8, 8 } },
+        { "rg32i", GL_RG32I, GL_RG_INTEGER, GL_INT, { 32, 32, 0, 0 } },
+        { "rg16i", GL_RG16I, GL_RG_INTEGER, GL_SHORT, { 16, 16, 0, 0 } },
+        { "rg8i", GL_RG8I, GL_RG_INTEGER, GL_BYTE, { 8, 8, 0, 0 } },
+        { "r32i", GL_R32I, GL_RED_INTEGER, GL_INT, { 32, 0, 0, 0 } },
+        { "r16i", GL_R16I, GL_RED_INTEGER, GL_SHORT, { 16, 0, 0, 0 } },
+        { "r8i", GL_R8I, GL_RED_INTEGER, GL_BYTE, { 8, 0, 0, 0 } },
+        { "rgba16", GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, { 16, 16, 16, 16 } },
+        { "rgb10_a2", GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, { 10, 10, 10, 2 } },
+        { "rgba8", GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, { 8, 8, 8, 8 } },
+        { "rg16", GL_RG16, GL_RG, GL_UNSIGNED_SHORT, { 16, 16, 0, 0 } },
+        { "rg8", GL_RG8, GL_RG, GL_UNSIGNED_BYTE, { 8, 8, 0, 0 } },
+        { "r16", GL_R16, GL_RED, GL_UNSIGNED_SHORT, { 16, 0, 0, 0 } },
+        { "r8", GL_R8, GL_RED, GL_UNSIGNED_BYTE, { 8, 0, 0, 0 } },
+        { "rgba16_snorm", GL_RGBA16_SNORM, GL_RGBA, GL_SHORT, { 16, 16, 16, 16 } },
+        { "rgba8_snorm", GL_RGBA8_SNORM, GL_RGBA, GL_BYTE, { 8, 8, 8, 8 } },
+        { "rg16_snorm", GL_RG16_SNORM, GL_RG, GL_SHORT, { 16, 16, 0, 0 } },
+        { "rg8_snorm", GL_RG8_SNORM, GL_RG, GL_BYTE, { 8, 8, 0, 0 } },
+        { "r16_snorm", GL_R16_SNORM, GL_RED, GL_SHORT, { 16, 0, 0, 0 } },
+        { "r8_snorm", GL_R8_SNORM, GL_RED, GL_BYTE, { 8, 0, 0, 0 } },
+        { 0 }
+};
+
+const struct image_format_info image_formats_atomic[] = {
+        { "r32ui", GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, { 32, 0, 0, 0 } },
+        { "r32i", GL_R32I, GL_RED_INTEGER, GL_INT, { 32, 0, 0, 0 } },
+        { 0 }
+};
+
+const struct image_format_info *
+get_image_format(GLenum f)
+{
+        const struct image_format_info *format;
+
+        for (format = image_formats_load_store; format->format; ++format) {
+                if (format->format == f)
+                        return format;
+        }
+
+        return NULL;
+}
+
+/**
+ * Information specific to an image base data type as seen by the
+ * shader.
+ */
+struct image_type_info {
+        /** Logical base format as seen by the shader. */
+        GLenum base_format;
+
+        /** Logical component type as seen by the shader. */
+        GLenum base_type;
+
+        /** Logical internal format as seen by the shader. */
+        GLenum base_internal_format;
+
+        /** Matching GLSL component data type. */
+        const char *scalar_type_name;
+
+        /** Matching GLSL vector data type. */
+        const char *vector_type_name;
+
+        /** GLSL image type prefix ("i", "u" or ""). */
+        const char *image_type_name;
+};
+
+static const struct image_type_info *
+get_image_type(const struct image_format_info *format)
+{
+        switch (format->pixel_format) {
+        case GL_RGBA:
+        case GL_RGB:
+        case GL_RG:
+        case GL_RED: {
+                static const struct image_type_info type = {
+                        GL_RGBA, GL_FLOAT, GL_RGBA32F,
+                        "float", "vec4", "image"
+                };
+                return &type;
+        }
+        case GL_RGBA_INTEGER:
+        case GL_RG_INTEGER:
+        case GL_RED_INTEGER:
+                switch (format->pixel_type) {
+                case GL_INT:
+                case GL_SHORT:
+                case GL_BYTE: {
+                        static const struct image_type_info type = {
+                                GL_RGBA_INTEGER, GL_INT, GL_RGBA32I,
+                                "int", "ivec4", "iimage"
+                        };
+                        return &type;
+                }
+                case GL_UNSIGNED_INT:
+                case GL_UNSIGNED_SHORT:
+                case GL_UNSIGNED_INT_2_10_10_10_REV:
+                case GL_UNSIGNED_BYTE: {
+                        static const struct image_type_info type = {
+                                GL_RGBA_INTEGER, GL_UNSIGNED_INT, GL_RGBA32UI,
+                                "uint", "uvec4", "uimage"
+                        };
+                        return &type;
+                }
+                default:
+                        abort();
+                }
+        default:
+                abort();
+        }
+}
+
+GLenum
+image_base_format(const struct image_format_info *format)
+{
+        return get_image_type(format)->base_format;
+}
+
+GLenum
+image_base_type(const struct image_format_info *format)
+{
+        return get_image_type(format)->base_type;
+}
+
+GLenum
+image_base_internal_format(const struct image_format_info *format)
+{
+        return get_image_type(format)->base_internal_format;
+}
+
+const char *
+image_scalar_type_name(const struct image_format_info *format)
+{
+        return get_image_type(format)->scalar_type_name;
+}
+
+const char *
+image_vector_type_name(const struct image_format_info *format)
+{
+        return get_image_type(format)->vector_type_name;
+}
+
+const char *
+image_type_name(const struct image_format_info *format)
+{
+        return get_image_type(format)->image_type_name;
+}
+
+GLenum
+image_compat_format(const struct image_format_info *format)
+{
+        const unsigned bits = (format->bits[0] + format->bits[1] +
+                               format->bits[2] + format->bits[3]);
+
+        switch (bits) {
+        case 128:
+                return GL_RGBA32UI;
+
+        case 64:
+                return GL_RG32UI;
+
+        case 32:
+                return GL_R32UI;
+
+        case 16:
+                return GL_R16UI;
+
+        case 8:
+                return GL_R8UI;
+
+        default:
+                abort();
+        }
+}
+
+unsigned
+image_num_components(const struct image_format_info *format)
+{
+        return (!!format->bits[0] + !!format->bits[1] +
+                !!format->bits[2] + !!format->bits[3]);
+}
+
+struct image_datum
+image_format_scale(const struct image_format_info *format)
+{
+        struct image_datum v = { 0.0 };
+        int i;
+
+        for (i = 0; i < 4 && format->bits[i]; ++i) {
+                switch (image_base_type(format)) {
+                case GL_FLOAT:
+                        set_idx(v, i, 1.0);
+                        break;
+
+                case GL_INT:
+                        set_idx(v, i, 1u << (format->bits[i] - 2));
+                        break;
+
+                case GL_UNSIGNED_INT:
+                        set_idx(v, i, 1u << (format->bits[i] - 1));
+                        break;
+
+                default:
+                        abort();
+                }
+        }
+
+        return v;
+}
+
+static unsigned
+image_channel_fraction_bits(const struct image_format_info *format, unsigned i)
+{
+        if (image_base_type(format) == GL_FLOAT && format->bits[i]) {
+                switch (format->pixel_type) {
+                case GL_FLOAT:
+                        return 23;
+
+                case GL_HALF_FLOAT:
+                        return 10;
+
+                case GL_UNSIGNED_INT_10F_11F_11F_REV:
+                        return format->bits[i] - 5;
+
+                case GL_SHORT:
+                case GL_BYTE:
+                        return format->bits[i] - 1;
+
+                case GL_UNSIGNED_SHORT:
+                case GL_UNSIGNED_INT_2_10_10_10_REV:
+                case GL_UNSIGNED_BYTE:
+                        return format->bits[i];
+
+                default:
+                        abort();
+                }
+        } else {
+                return 0;
+        }
+}
+
+struct image_datum
+image_format_epsilon(const struct image_format_info *format)
+{
+        struct image_datum v = { 0.0 };
+        int i;
+
+        for (i = 0; i < 4; ++i) {
+                unsigned p = image_channel_fraction_bits(format, i);
+                set_idx(v, i, (p ? MAX2(1.0 / ((1 << p) - 1), 1e-5) : 0));
+        }
+
+        return v;
+}
+
+uint32_t
+encode(const struct image_format_info *format, double x)
+{
+        switch (image_base_type(format)) {
+        case GL_UNSIGNED_INT:
+                return x;
+
+        case GL_INT:
+                return (int32_t)x;
+
+        case GL_FLOAT: {
+                float y = x;
+                return *(uint32_t *)&y;
+        }
+        default:
+                abort();
+        }
+}
+
+double
+decode(const struct image_format_info *format, uint32_t x)
+{
+        switch (image_base_type(format)) {
+        case GL_UNSIGNED_INT:
+                return x;
+
+        case GL_INT:
+                return (int32_t)x;
+
+        case GL_FLOAT:
+                return *(float *)&x;
+
+        default:
+                abort();
+        }
+}
+
+const struct image_target_info *
+image_targets(void)
+{
+        const struct image_target_info known[] = {
+                { "1D", GL_TEXTURE_1D, "int" },
+                { "2D", GL_TEXTURE_2D, "ivec2" },
+                { "3D", GL_TEXTURE_3D, "ivec3" },
+                { "2DRect", GL_TEXTURE_RECTANGLE, "ivec2" },
+                { "Cube", GL_TEXTURE_CUBE_MAP, "ivec3" },
+                { "Buffer", GL_TEXTURE_BUFFER, "int" },
+                { "1DArray", GL_TEXTURE_1D_ARRAY, "ivec2" },
+                { "2DArray", GL_TEXTURE_2D_ARRAY, "ivec3" },
+                { "CubeArray", GL_TEXTURE_CUBE_MAP_ARRAY, "ivec3" },
+                { "2DMS", GL_TEXTURE_2D_MULTISAMPLE, "ivec2" },
+                { "2DMSArray", GL_TEXTURE_2D_MULTISAMPLE_ARRAY, "ivec3" },
+                { 0 }
+        };
+        static struct image_target_info supported[ARRAY_SIZE(known)];
+
+        if (!supported[0].name) {
+                int max_samples = 0, i, n = 0;
+
+                glGetIntegerv(GL_MAX_IMAGE_SAMPLES, &max_samples);
+
+                for (i = 0; i < ARRAY_SIZE(known); ++i) {
+                        if ((known[i].target != GL_TEXTURE_2D_MULTISAMPLE &&
+                             known[i].target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY) ||
+                            max_samples > 1) {
+                                supported[n++] = known[i];
+                        }
+                }
+        }
+
+        return supported;
+}
+
+const struct image_target_info *
+get_image_target(GLenum t)
+{
+        const struct image_target_info *target;
+
+        for (target = image_targets(); target->target; ++target) {
+                if (target->target == t)
+                        return target;
+        }
+
+        return NULL;
+}
+
+struct image_extent
+image_target_limits(const struct image_target_info *target)
+{
+        struct image_extent ext = { 1, 1, 1, 1 };
+
+        switch (target->target) {
+        case GL_TEXTURE_1D:
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.x);
+                break;
+
+        case GL_TEXTURE_2D:
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.y);
+                break;
+
+        case GL_TEXTURE_3D:
+                glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (int *)&ext.y);
+                glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (int *)&ext.z);
+                break;
+
+        case GL_TEXTURE_RECTANGLE:
+                glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_RECTANGLE_TEXTURE_SIZE, (int *)&ext.y);
+                break;
+
+        case GL_TEXTURE_CUBE_MAP:
+                glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (int *)&ext.y);
+                ext.z = 6;
+                break;
+
+        case GL_TEXTURE_BUFFER:
+                glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, (int *)&ext.x);
+                break;
+
+        case GL_TEXTURE_1D_ARRAY:
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, (int *)&ext.y);
+                break;
+
+        case GL_TEXTURE_2D_ARRAY:
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.y);
+                glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, (int *)&ext.z);
+                break;
+
+        case GL_TEXTURE_CUBE_MAP_ARRAY:
+                glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (int *)&ext.y);
+                glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, (int *)&ext.z);
+                break;
+
+        case GL_TEXTURE_2D_MULTISAMPLE:
+                glGetIntegerv(GL_MAX_IMAGE_SAMPLES, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.y);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.z);
+                break;
+
+        case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+                glGetIntegerv(GL_MAX_IMAGE_SAMPLES, (int *)&ext.x);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.y);
+                glGetIntegerv(GL_MAX_TEXTURE_SIZE, (int *)&ext.z);
+                glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, (int *)&ext.w);
+                break;
+
+        default:
+                abort();
+        }
+
+        return ext;
+}
+
+unsigned
+image_target_samples(const struct image_target_info *target)
+{
+        if (target->target == GL_TEXTURE_2D_MULTISAMPLE ||
+            target->target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY) {
+                return image_target_limits(target).x;
+        } else {
+                return 1;
+        }
+}
+
+struct image_extent
+image_extent_for_target(const struct image_target_info *target,
+                        unsigned w, unsigned h)
+{
+        switch (target->target) {
+        case GL_TEXTURE_1D: {
+                struct image_extent ext = { w * h, 1, 1, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_2D: {
+                struct image_extent ext = { w, h, 1, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_3D: {
+                struct image_extent ext = { w, w, h / w, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_RECTANGLE: {
+                struct image_extent ext = { w, h, 1, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_CUBE_MAP: {
+                struct image_extent ext = { w, w, h / w, 1 };
+                assert(ext.z == 6);
+                return ext;
+        }
+        case GL_TEXTURE_BUFFER: {
+                struct image_extent ext = { w * h, 1, 1, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_1D_ARRAY: {
+                struct image_extent ext = { w, h, 1, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_2D_ARRAY: {
+                struct image_extent ext = { w, w, h / w, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_CUBE_MAP_ARRAY: {
+                struct image_extent ext = { w, w, h / w, 1 };
+                assert(ext.z % 6 == 0);
+                return ext;
+        }
+        case GL_TEXTURE_2D_MULTISAMPLE: {
+                struct image_extent ext = { 2, w / 2, h, 1 };
+                return ext;
+        }
+        case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: {
+                struct image_extent ext = { 2, w / 2, w, h / w };
+                return ext;
+        }
+        default:
+                abort();
+        }
+}
+
+GLenum
+image_layer_target(const struct image_target_info *target)
+{
+        switch (target->target) {
+        case GL_TEXTURE_1D:
+        case GL_TEXTURE_1D_ARRAY:
+                return GL_TEXTURE_1D;
+
+        case GL_TEXTURE_2D:
+        case GL_TEXTURE_3D:
+        case GL_TEXTURE_CUBE_MAP:
+        case GL_TEXTURE_2D_ARRAY:
+        case GL_TEXTURE_CUBE_MAP_ARRAY:
+                return GL_TEXTURE_2D;
+
+        case GL_TEXTURE_RECTANGLE:
+                return GL_TEXTURE_RECTANGLE;
+
+        case GL_TEXTURE_BUFFER:
+                return GL_TEXTURE_BUFFER;
+
+        case GL_TEXTURE_2D_MULTISAMPLE:
+        case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+                return GL_TEXTURE_2D_MULTISAMPLE;
+
+        default:
+                abort();
+        }
+}
+
+unsigned
+image_target_mipmapping_dimensions(const struct image_target_info *target)
+{
+        switch (target->target) {
+        case GL_TEXTURE_RECTANGLE:
+        case GL_TEXTURE_BUFFER:
+        case GL_TEXTURE_2D_MULTISAMPLE:
+        case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
+                return 0;
+
+        case GL_TEXTURE_1D:
+        case GL_TEXTURE_1D_ARRAY:
+                return 1;
+
+        case GL_TEXTURE_2D:
+        case GL_TEXTURE_CUBE_MAP:
+        case GL_TEXTURE_2D_ARRAY:
+        case GL_TEXTURE_CUBE_MAP_ARRAY:
+                return 2;
+
+        case GL_TEXTURE_3D:
+                return 3;
+
+        default:
+                abort();
+        }
+}
+
+const struct image_stage_info *
+image_stages(void)
+{
+        const struct image_stage_info known[] = {
+                { "Vertex", GL_VERTEX_SHADER, GL_VERTEX_SHADER_BIT },
+                { "Tessellation control", GL_TESS_CONTROL_SHADER,
+                  GL_TESS_CONTROL_SHADER_BIT },
+                { "Tessellation evaluation", GL_TESS_EVALUATION_SHADER,
+                  GL_TESS_EVALUATION_SHADER_BIT },
+                { "Geometry", GL_GEOMETRY_SHADER, GL_GEOMETRY_SHADER_BIT },
+                { "Fragment", GL_FRAGMENT_SHADER, GL_FRAGMENT_SHADER_BIT },
+                { "Compute", GL_COMPUTE_SHADER, GL_COMPUTE_SHADER_BIT },
+        };
+        static struct image_stage_info supported[ARRAY_SIZE(known) + 1];
+
+        if (!supported[0].name) {
+                int i, n = 0;
+
+                for (i = 0; i < ARRAY_SIZE(known); ++i) {
+                        if (image_stage_max_images(&known[i]))
+                                supported[n++] = known[i];
+                }
+        }
+
+        return supported;
+}
+
+const struct image_stage_info *
+get_image_stage(GLenum s)
+{
+        const struct image_stage_info *stage;
+
+        for (stage = image_stages(); stage->stage; ++stage) {
+                if (stage->stage == s)
+                        return stage;
+        }
+
+        return NULL;
+}
+
+unsigned
+image_stage_max_images(const struct image_stage_info *stage)
+{
+        int n = 0;
+
+        switch (stage->stage) {
+        case GL_FRAGMENT_SHADER:
+                glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &n);
+                return n;
+
+        case GL_VERTEX_SHADER:
+                glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &n);
+                return n;
+
+        case GL_GEOMETRY_SHADER:
+                if (piglit_get_gl_version() >= 32)
+                        glGetIntegerv(GL_MAX_GEOMETRY_IMAGE_UNIFORMS, &n);
+                return n;
+
+        case GL_TESS_CONTROL_SHADER:
+                if (piglit_is_extension_supported("GL_ARB_tessellation_shader"))
+                        glGetIntegerv(GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS, &n);
+                return n;
+
+        case GL_TESS_EVALUATION_SHADER:
+                if (piglit_is_extension_supported("GL_ARB_tessellation_shader"))
+                        glGetIntegerv(GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS,
+                                      &n);
+                return n;
+
+        case GL_COMPUTE_SHADER:
+                if (piglit_is_extension_supported("GL_ARB_compute_shader"))
+                        glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &n);
+                return n;
+
+        default:
+                return 0;
+        }
+}
+
+unsigned
+max_combined_images(void)
+{
+        int n;
+
+        glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &n);
+        return n;
+}
+
+unsigned
+max_image_units(void)
+{
+        int n;
+
+        glGetIntegerv(GL_MAX_IMAGE_UNITS, &n);
+        return n;
+}
+
+unsigned
+image_num_layers(const struct image_info img)
+{
+        switch (image_layer_target(img.target)) {
+        case GL_TEXTURE_1D:
+                return img.size.y;
+
+        case GL_TEXTURE_2D:
+                return img.size.z;
+
+        case GL_TEXTURE_2D_MULTISAMPLE:
+                return img.size.w;
+
+        default:
+                return 1;
+        }
+}
+
+unsigned
+image_num_levels(const struct image_info img)
+{
+        const unsigned d = image_target_mipmapping_dimensions(img.target);
+        unsigned i, size = 1;
+
+        for (i = 0; i < d; ++i)
+                size = MAX2(size, get_idx(img.size, i));
+
+        return (unsigned)log2(size) + 1;
+}
+
+struct image_extent
+image_level_size(const struct image_info img, unsigned l)
+{
+        const unsigned d = image_target_mipmapping_dimensions(img.target);
+        struct image_extent size;
+        int i;
+
+        for (i = 0; i < d; ++i)
+                set_idx(size, i, MAX2(get_idx(img.size, i) >> l, 1));
+
+        for (i = d; i < 4; ++i)
+                set_idx(size, i, get_idx(img.size, i));
+
+        return size;
+}
diff --git a/tests/spec/arb_shader_image_load_store/image.h b/tests/spec/arb_shader_image_load_store/image.h
new file mode 100644
index 0000000..54d32ed
--- /dev/null
+++ b/tests/spec/arb_shader_image_load_store/image.h
@@ -0,0 +1,386 @@
+/*
+ * 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 image.h
+ *
+ * Common image format, target and shader stage metadata.
+ */
+
+#ifndef __PIGLIT_ARB_SHADER_IMAGE_LOAD_STORE_IMAGE_H__
+#define __PIGLIT_ARB_SHADER_IMAGE_LOAD_STORE_IMAGE_H__
+
+#include "piglit-util-gl.h"
+
+/**
+ * Image color value.
+ */
+struct image_datum {
+        double x;
+        double y;
+        double z;
+        double w;
+};
+
+/**
+ * Size of an image.
+ *
+ * Note that most tests treat images as a 4-dimensional array of
+ * pixels with no specific semantics attached to each dimension
+ * (e.g. the x dimension will be the number of samples for multisample
+ * images but the horizontal coordinate for 2D textures).  This is a
+ * deliberate decision that greatly reduces the amount of duplication,
+ * as in many cases you can just run the same test in a loop for all
+ * image targets.
+ *
+ * Unused dimensions equal 1 by convention.
+ */
+struct image_extent {
+        unsigned x;
+        unsigned y;
+        unsigned z;
+        unsigned w;
+};
+
+#define get_idx(v, i)                          \
+        ((i) == 0 ? (v).x :                    \
+         (i) == 1 ? (v).y :                    \
+         (i) == 2 ? (v).z :                    \
+         (i) == 3 ? (v).w : 0)
+
+#define set_idx(v, i, a)                       \
+        (*((i) == 0 ? &(v).x :                 \
+           (i) == 1 ? &(v).y :                 \
+           (i) == 2 ? &(v).z :                 \
+           (i) == 3 ? &(v).w : NULL)) = (a)
+
+#define product(v) ((v).x * (v).y * (v).z * (v).w)
+
+/**
+ * Get a two-dimensional image_extent with the same number of elements
+ * as the argument, where each dimension is reasonably close to the
+ * square root of the total number of elements, e.g. for use as grid
+ * invocation size.
+ */
+struct image_extent
+image_optimal_extent(struct image_extent ext);
+
+struct image_format_info {
+        /** Format name as specified by GLSL. */
+        const char *name;
+
+        /** Format enum. */
+        GLenum format;
+
+        /** Pixel transfer format (e.g. as specified for glGetTexImage()). */
+        GLenum pixel_format;
+
+        /** Pixel transfer type (e.g. as specified for glGetTexImage()). */
+        GLenum pixel_type;
+
+        /** Number of storage bits for each component. */
+        unsigned bits[4];
+};
+
+/**
+ * Image formats supported by image load and store built-ins.
+ */
+extern const struct image_format_info image_formats_load_store[];
+
+/**
+ * Image formats supported by image atomic built-ins.
+ */
+extern const struct image_format_info image_formats_atomic[];
+
+/**
+ * Get information for the specified image format.
+ */
+const struct image_format_info *
+get_image_format(GLenum format);
+
+/**
+ * Get the logical base format as seen by the shader (either GL_RGBA
+ * or GL_RGBA_INTEGER).
+ */
+GLenum
+image_base_format(const struct image_format_info *format);
+
+/**
+ * Get the logical component type as seen by the shader.
+ */
+GLenum
+image_base_type(const struct image_format_info *format);
+
+/**
+ * Get the logical internal format as seen by the shader.
+ */
+GLenum
+image_base_internal_format(const struct image_format_info *format);
+
+/**
+ * Get the GLSL component data type for an image format.
+ */
+const char *
+image_scalar_type_name(const struct image_format_info *format);
+
+/**
+ * Get the GLSL vector data type for an image format.
+ */
+const char *
+image_vector_type_name(const struct image_format_info *format);
+
+/**
+ * Get the GLSL image type prefix for an image format ("i", "u" or
+ * "").
+ */
+const char *
+image_type_name(const struct image_format_info *format);
+
+/**
+ * Get a compatible unsigned integer format of the same size.
+ */
+GLenum
+image_compat_format(const struct image_format_info *format);
+
+/**
+ * Get the number of color components representable in an image format.
+ */
+unsigned
+image_num_components(const struct image_format_info *format);
+
+/**
+ * Get an arbitrary per-component test scale used to make sure that we
+ * exercise a significant portion of the representable range without
+ * overflowing it.
+ */
+struct image_datum
+image_format_scale(const struct image_format_info *format);
+
+/**
+ * Get the per-component error tolerance for an image format.
+ */
+struct image_datum
+image_format_epsilon(const struct image_format_info *format);
+
+/**
+ * Convert \a x to the base data type of the specified image format.
+ */
+uint32_t
+encode(const struct image_format_info *format, double x);
+
+/**
+ * Convert \a x from the base data type of the specified image format.
+ */
+double
+decode(const struct image_format_info *format, uint32_t x);
+
+struct image_target_info {
+        /** Target name and GLSL image type suffix. */
+        const char *name;
+
+        /** Target enum. */
+        GLenum target;
+
+        /** Vector type used as address argument for this target. */
+        const char *addr_type_name;
+};
+
+/**
+ * Get all image targets supported by the implementation.
+ */
+const struct image_target_info *
+image_targets(void);
+
+/**
+ * Get information for the specified target.
+ */
+const struct image_target_info *
+get_image_target(GLenum t);
+
+/**
+ * Get the maximum supported dimensions for the specified target.
+ */
+struct image_extent
+image_target_limits(const struct image_target_info *target);
+
+/**
+ * Get the maximum supported number of samples for the specified
+ * target.
+ */
+unsigned
+image_target_samples(const struct image_target_info *target);
+
+/**
+ * Get reasonable dimensions for an image of type \a target intended
+ * to be in one-to-one mapping to a two-dimensional grid of dimensions
+ * \a w and \a h.
+ */
+struct image_extent
+image_extent_for_target(const struct image_target_info *target,
+                        unsigned w, unsigned h);
+
+/**
+ * Get the target type for a single layer of the specified image
+ * target.
+ */
+GLenum
+image_layer_target(const struct image_target_info *target);
+
+/**
+ * Get the number of dimensions of an image target that are minified
+ * in higher mipmap levels.
+ */
+unsigned
+image_target_mipmapping_dimensions(const struct image_target_info *target);
+
+struct image_stage_info {
+        /** Shader stage name. */
+        const char *name;
+
+        /** Target enum. */
+        GLenum stage;
+
+        /** Value used in bit sets for this shader stage. */
+        GLbitfield bit;
+};
+
+/**
+ * Get all shader stages that support image access in pipeline order.
+ */
+const struct image_stage_info *
+image_stages(void);
+
+/**
+ * Get information for the specified stage.
+ */
+const struct image_stage_info *
+get_image_stage(GLenum s);
+
+/**
+ * Get the maximum number of supported image uniforms from the
+ * specified stage.
+ */
+unsigned
+image_stage_max_images(const struct image_stage_info *stage);
+
+/**
+ * Get the maximum sum of image uniforms from all shaders.
+ */
+unsigned
+max_combined_images(void);
+
+/**
+ * Get the maximum number of independent image units.
+ */
+unsigned
+max_image_units(void);
+
+struct image_info {
+        /** Texture target of this image object. */
+        const struct image_target_info *target;
+
+        /** Format of this image object. */
+        const struct image_format_info *format;
+
+        /** Dimensions of this image object. */
+        struct image_extent size;
+
+        /** Error tolerance for this image object. */
+        struct image_datum epsilon;
+};
+
+/**
+ * Construct an image_info object.
+ */
+static inline struct image_info
+image_info(GLenum target, GLenum format, unsigned w, unsigned h)
+{
+        const struct image_target_info *t = get_image_target(target);
+        const struct image_format_info *f = get_image_format(format);
+        const struct image_info img = {
+                t, f,
+                image_extent_for_target(t, w, h),
+                image_format_epsilon(f)
+        };
+
+        return img;
+}
+
+/**
+ * Set the dimensions of an image.
+ */
+static inline struct image_info
+set_image_size(struct image_info img,
+               unsigned x, unsigned y, unsigned z, unsigned w)
+{
+        const struct image_extent size = { x, y, z, w };
+        img.size = size;
+        return img;
+}
+
+/**
+ * Get the number of layers of an image.
+ */
+unsigned
+image_num_layers(const struct image_info img);
+
+/**
+ * Get the maximum number of mipmap levels for an image.
+ */
+unsigned
+image_num_levels(const struct image_info img);
+
+/**
+ * Get the dimensions of the specified mipmap level of an image.
+ */
+struct image_extent
+image_level_size(const struct image_info img, unsigned l);
+
+/**
+ * Get the offset in texels of the specified mipmap level of an
+ * image.
+ */
+static inline unsigned
+image_level_offset(const struct image_info img, unsigned l)
+{
+        return (l == 0 ? 0 :
+                image_level_offset(img, l - 1) +
+                product(image_level_size(img, l - 1)));
+}
+
+/**
+ * Construct an image_info object for mipmap level \a l of the
+ * specified base image.
+ */
+static inline struct image_info
+image_info_for_level(struct image_info img, unsigned l)
+{
+        const struct image_info level_img = {
+                img.target, img.format,
+                image_level_size(img, l),
+                img.epsilon
+        };
+
+        return level_img;
+}
+
+#endif
-- 
2.1.3



More information about the Piglit mailing list