[Piglit] [PATCH] gl-3.0: add a test to stress the bound resource limits

Matthew McClure mcclurem at vmware.com
Tue Jul 8 15:49:48 PDT 2014


Update to reflect feedback from Brian Paul. The update includes documentation for each function and removal of the "flat" qualifier, since this version of the test is using GLSL 1.30.

Verified on:

Ubuntu 12.04.3
OpenGL vendor string: NVIDIA Corporation
OpenGL renderer string: GeForce GTX 650/PCIe/SSE2
OpenGL version string: 4.2.0 NVIDIA 304.116
OpenGL shading language version string: 4.20 NVIDIA via Cg compiler

Thanks,
Matthew

--- Begin Updated Patch ---

With this patch, we add a test that will stress the bound resource limits
as determined by the GL API getInteger values. The bound resources are
populated with floats given a table of primes. Each contribution is
multiplied into the final expression, and uniquely represents the successful
reference of the resource's memory.
---
 tests/all.py                              |    1 +
 tests/spec/gl-3.0/CMakeLists.gl.txt       |    1 +
 tests/spec/gl-3.0/bound-resource-limits.c | 1262 +++++++++++++++++++++++++++++
 3 files changed, 1264 insertions(+)
 create mode 100644 tests/spec/gl-3.0/bound-resource-limits.c

diff --git a/tests/all.py b/tests/all.py
index 7ce90d8..27d620e 100644
--- a/tests/all.py
+++ b/tests/all.py
@@ -927,6 +927,7 @@ gl30['attribs'] = concurrent_test('attribs GL3')
 add_concurrent_test(gl30, 'bindfragdata-invalid-parameters')
 add_concurrent_test(gl30, 'bindfragdata-link-error')
 add_concurrent_test(gl30, 'bindfragdata-nonexistent-variable')
+gl30['bound-resource-limits'] = concurrent_test('gl-3.0-bound-resource-limits')
 add_concurrent_test(gl30, 'clearbuffer-depth')
 add_concurrent_test(gl30, 'clearbuffer-depth-stencil')
 add_plain_test(gl30, 'clearbuffer-display-lists')
diff --git a/tests/spec/gl-3.0/CMakeLists.gl.txt b/tests/spec/gl-3.0/CMakeLists.gl.txt
index 29c59ee..a802da3 100644
--- a/tests/spec/gl-3.0/CMakeLists.gl.txt
+++ b/tests/spec/gl-3.0/CMakeLists.gl.txt
@@ -9,6 +9,7 @@ link_libraries (
 	${OPENGL_glu_LIBRARY}
 )
 
+piglit_add_executable (gl-3.0-bound-resource-limits bound-resource-limits.c)
 piglit_add_executable (gl-3.0-minmax minmax.c)
 piglit_add_executable (gl-3.0-render-integer render-integer.c)
 piglit_add_executable (gl-3.0-required-sized-texture-formats required-sized-texture-formats.c)
diff --git a/tests/spec/gl-3.0/bound-resource-limits.c b/tests/spec/gl-3.0/bound-resource-limits.c
new file mode 100644
index 0000000..94cfe30
--- /dev/null
+++ b/tests/spec/gl-3.0/bound-resource-limits.c
@@ -0,0 +1,1262 @@
+/*
+ * Copyright 2014 VMware, Inc.
+ *
+ * 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.
+ */
+
+/**
+ * Test resource limits given the maximum supported by the implementation.
+ *
+ * Each component of the fragment output is derived using the following
+ * expression (indexed at the scalar level):
+ *
+ *   result[i] = texture[i] * texture[i] * ... * attrib[i + l * numOutputs]
+ *
+ * Depending on the limits for vertex/fragment image units, the texture
+ * contribution will vary. See the generation of g_expected at the end of
+ * piglit_init.
+ *
+ * Since the scalar inputs are primes, multiplication will yield a unique
+ * result. Results can be diagnosed by evaluating for their missing factor(s).
+ *
+ * Matthew McClure
+ * 7 July 2014
+ */
+
+#include "piglit-util-gl-common.h"
+
+PIGLIT_GL_TEST_CONFIG_BEGIN
+
+  config.supports_gl_compat_version = 30;
+  config.window_visual = PIGLIT_GL_VISUAL_DOUBLE | PIGLIT_GL_VISUAL_RGBA;
+
+PIGLIT_GL_TEST_CONFIG_END
+
+
+/*
+ * Definitions for the runtime behavior.
+ */
+#define GLSL_VERSION              "#version 130"
+#define BUFFER_WIDTH              32
+#define BUFFER_HEIGHT             32
+#define MAX_SHADER_LINE_CHARS     256
+#define MAX_SHADER_TEXT_CHARS     16*1024
+#define MAX_COMPONENTS            4
+#define MAX_EXPRESSION_OUTPUTS    1
+#define MAX_EXPRESSION_ARGUMENTS  2
+#define MAX_EXPRESSION_TEMPS      1
+#define TEMP_TEXT_SIZE            (MAX_EXPRESSION_OUTPUTS +  \
+                                   MAX_EXPRESSION_ARGUMENTS +  \
+                                   MAX_EXPRESSION_ARGUMENTS)
+
+#define NUM_PRIMES                512
+#define NUM_VERTICES              3
+#define DRAW_ARRAYS               0
+#define DRAW_ELEMENTS             1
+#define DRAW_IMMEDIATE            0
+
+#define DEBUG_INPUT               0
+#define DEBUG_READBACK            0
+#define DEBUG_SHADERS             0
+
+/*
+ * Type definitions for our working set.
+ */
+typedef struct MyVector4 {
+   float x, y, z, w;
+} MyVector4;
+
+typedef struct PackedTypeDesc {
+   char *typeName;
+   unsigned numComponents;
+   char *componentNames[MAX_COMPONENTS];
+   char *defaultValue;
+} PackedTypeDesc;
+
+typedef struct PackedDesc {
+   char *semanticName;
+   char *variableName;
+   bool isArray;
+   unsigned count;
+   const PackedTypeDesc *typeDesc;
+} PackedDesc;
+
+
+/*
+ * Global variables for the test's state.
+ */
+static GLint g_maxVaryingFloats = 0;
+static GLint g_maxVertexAttribs = 0;
+static GLint g_maxVertexTextureImageUnits = 0;
+static GLint g_maxTextureImageUnits = 0;
+static GLint g_maxCombinedTextureImageUnits = 0;
+
+static GLint g_maxAuxBuffers = 0;
+static GLint g_maxDrawBuffers = 0;
+static GLint g_maxColorAttachments = 0;
+
+static char *g_fragColor = "gl_FragColor";
+static char *g_fragData = "gl_FragData";
+
+static GLfloat g_primes[NUM_PRIMES] = {
+2.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0, 19.0,
+23.0, 29.0, 31.0, 37.0, 41.0, 43.0, 47.0, 53.0,
+59.0, 61.0, 67.0, 71.0, 73.0, 79.0, 83.0, 89.0,
+97.0, 101.0, 103.0, 107.0, 109.0, 113.0, 127.0, 131.0,
+137.0, 139.0, 149.0, 151.0, 157.0, 163.0, 167.0, 173.0,
+179.0, 181.0, 191.0, 193.0, 197.0, 199.0, 211.0, 223.0,
+227.0, 229.0, 233.0, 239.0, 241.0, 251.0, 257.0, 263.0,
+269.0, 271.0, 277.0, 281.0, 283.0, 293.0, 307.0, 311.0,
+313.0, 317.0, 331.0, 337.0, 347.0, 349.0, 353.0, 359.0,
+367.0, 373.0, 379.0, 383.0, 389.0, 397.0, 401.0, 409.0,
+419.0, 421.0, 431.0, 433.0, 439.0, 443.0, 449.0, 457.0,
+461.0, 463.0, 467.0, 479.0, 487.0, 491.0, 499.0, 503.0,
+509.0, 521.0, 523.0, 541.0, 547.0, 557.0, 563.0, 569.0,
+571.0, 577.0, 587.0, 593.0, 599.0, 601.0, 607.0, 613.0,
+617.0, 619.0, 631.0, 641.0, 643.0, 647.0, 653.0, 659.0,
+661.0, 673.0, 677.0, 683.0, 691.0, 701.0, 709.0, 719.0,
+727.0, 733.0, 739.0, 743.0, 751.0, 757.0, 761.0, 769.0,
+773.0, 787.0, 797.0, 809.0, 811.0, 821.0, 823.0, 827.0,
+829.0, 839.0, 853.0, 857.0, 859.0, 863.0, 877.0, 881.0,
+883.0, 887.0, 907.0, 911.0, 919.0, 929.0, 937.0, 941.0,
+947.0, 953.0, 967.0, 971.0, 977.0, 983.0, 991.0, 997.0,
+1009.0, 1013.0, 1019.0, 1021.0, 1031.0, 1033.0, 1039.0, 1049.0,
+1051.0, 1061.0, 1063.0, 1069.0, 1087.0, 1091.0, 1093.0, 1097.0,
+1103.0, 1109.0, 1117.0, 1123.0, 1129.0, 1151.0, 1153.0, 1163.0,
+1171.0, 1181.0, 1187.0, 1193.0, 1201.0, 1213.0, 1217.0, 1223.0,
+1229.0, 1231.0, 1237.0, 1249.0, 1259.0, 1277.0, 1279.0, 1283.0,
+1289.0, 1291.0, 1297.0, 1301.0, 1303.0, 1307.0, 1319.0, 1321.0,
+1327.0, 1361.0, 1367.0, 1373.0, 1381.0, 1399.0, 1409.0, 1423.0,
+1427.0, 1429.0, 1433.0, 1439.0, 1447.0, 1451.0, 1453.0, 1459.0,
+1471.0, 1481.0, 1483.0, 1487.0, 1489.0, 1493.0, 1499.0, 1511.0,
+1523.0, 1531.0, 1543.0, 1549.0, 1553.0, 1559.0, 1567.0, 1571.0,
+1579.0, 1583.0, 1597.0, 1601.0, 1607.0, 1609.0, 1613.0, 1619.0,
+1621.0, 1627.0, 1637.0, 1657.0, 1663.0, 1667.0, 1669.0, 1693.0,
+1697.0, 1699.0, 1709.0, 1721.0, 1723.0, 1733.0, 1741.0, 1747.0,
+1753.0, 1759.0, 1777.0, 1783.0, 1787.0, 1789.0, 1801.0, 1811.0,
+1823.0, 1831.0, 1847.0, 1861.0, 1867.0, 1871.0, 1873.0, 1877.0,
+1879.0, 1889.0, 1901.0, 1907.0, 1913.0, 1931.0, 1933.0, 1949.0,
+1951.0, 1973.0, 1979.0, 1987.0, 1993.0, 1997.0, 1999.0, 2003.0,
+2011.0, 2017.0, 2027.0, 2029.0, 2039.0, 2053.0, 2063.0, 2069.0,
+2081.0, 2083.0, 2087.0, 2089.0, 2099.0, 2111.0, 2113.0, 2129.0,
+2131.0, 2137.0, 2141.0, 2143.0, 2153.0, 2161.0, 2179.0, 2203.0,
+2207.0, 2213.0, 2221.0, 2237.0, 2239.0, 2243.0, 2251.0, 2267.0,
+2269.0, 2273.0, 2281.0, 2287.0, 2293.0, 2297.0, 2309.0, 2311.0,
+2333.0, 2339.0, 2341.0, 2347.0, 2351.0, 2357.0, 2371.0, 2377.0,
+2381.0, 2383.0, 2389.0, 2393.0, 2399.0, 2411.0, 2417.0, 2423.0,
+2437.0, 2441.0, 2447.0, 2459.0, 2467.0, 2473.0, 2477.0, 2503.0,
+2521.0, 2531.0, 2539.0, 2543.0, 2549.0, 2551.0, 2557.0, 2579.0,
+2591.0, 2593.0, 2609.0, 2617.0, 2621.0, 2633.0, 2647.0, 2657.0,
+2659.0, 2663.0, 2671.0, 2677.0, 2683.0, 2687.0, 2689.0, 2693.0,
+2699.0, 2707.0, 2711.0, 2713.0, 2719.0, 2729.0, 2731.0, 2741.0,
+2749.0, 2753.0, 2767.0, 2777.0, 2789.0, 2791.0, 2797.0, 2801.0,
+2803.0, 2819.0, 2833.0, 2837.0, 2843.0, 2851.0, 2857.0, 2861.0,
+2879.0, 2887.0, 2897.0, 2903.0, 2909.0, 2917.0, 2927.0, 2939.0,
+2953.0, 2957.0, 2963.0, 2969.0, 2971.0, 2999.0, 3001.0, 3011.0,
+3019.0, 3023.0, 3037.0, 3041.0, 3049.0, 3061.0, 3067.0, 3079.0,
+3083.0, 3089.0, 3109.0, 3119.0, 3121.0, 3137.0, 3163.0, 3167.0,
+3169.0, 3181.0, 3187.0, 3191.0, 3203.0, 3209.0, 3217.0, 3221.0,
+3229.0, 3251.0, 3253.0, 3257.0, 3259.0, 3271.0, 3299.0, 3301.0,
+3307.0, 3313.0, 3319.0, 3323.0, 3329.0, 3331.0, 3343.0, 3347.0,
+3359.0, 3361.0, 3371.0, 3373.0, 3389.0, 3391.0, 3407.0, 3413.0,
+3433.0, 3449.0, 3457.0, 3461.0, 3463.0, 3467.0, 3469.0, 3491.0,
+3499.0, 3511.0, 3517.0, 3527.0, 3529.0, 3533.0, 3539.0, 3541.0,
+3547.0, 3557.0, 3559.0, 3571.0, 3581.0, 3583.0, 3593.0, 3607.0,
+3613.0, 3617.0, 3623.0, 3631.0, 3637.0, 3643.0, 3659.0, 3671.0,
+};
+
+static const PackedTypeDesc g_rgbaDesc =
+   {
+      "vec4", 4, { ".r", ".g", ".b", ".a" },
+      "vec4(1.0, 1.0, 1.0, 1.0)"
+   };
+static const PackedTypeDesc g_vec4Desc =
+   {
+      "vec4", 4, { ".x", ".y", ".z", ".w" },
+      "vec4(1.0, 1.0, 1.0, 1.0)"
+   };
+static const PackedTypeDesc g_floatDesc =
+   {
+      "float", 1, { "" },
+      "1.0"
+   };
+static const PackedTypeDesc g_sampler2DDesc =
+   {
+      "sampler2D", 4, { "" },
+      "vec4(1.0, 1.0, 1.0, 1.0)"
+   };
+
+static const char *g_vectorComponents[MAX_COMPONENTS] =
+   {
+      ".x", ".y", ".z", ".w"
+   };
+//static MyVector4 one = { 1.0f, 1.0f, 1.0f, 1.0f };
+//static MyVector4 zero = { 0.0f, 0.0f, 0.0f, 0.0f };
+static MyVector4 g_positionBuffer[NUM_VERTICES] =
+   {
+      { -1.0, -1.0, 0.0, 0.0 },
+      { -1.0, 1.0, 0.0, 0.0 },
+      { 1.0, 1.0, 0.0, 0.0 }
+   };
+
+static GLuint g_elementVBO;
+static GLushort g_elementBuffer[NUM_VERTICES] = { 0, 1, 2 };
+static char *g_vertexShaderText =
+   "#version 110 \n"
+   " \n"
+   "void main() \n"
+   "{ \n"
+   "   gl_Position = gl_Vertex; \n"
+   "} \n";
+
+//static char *g_geometryShaderText = NULL;
+
+static char *g_fragmentShaderText =
+   "#version 110 \n"
+   " \n"
+   "void main()\n"
+   "{ \n"
+   "    gl_FragData[0] = vec4(1.0, 2.0, 3.0, 4.0);\n"
+   "    gl_FragData[1] = vec4(5.0, 6.0, 7.0, 8.0);\n"
+   "} \n";
+
+static GLuint g_program = 0;
+static GLfloat *g_expected;
+
+
+/**
+ * Format a string which contains the requested declaration for the variable.
+ * The desc structure will describe the variable, i.e. type, if it is an array,
+ * and how large the array is.
+ *
+ * \param desc Descriptor of the variable referenced. See PackedDesc.
+ * \param tmpStrSize Temporary string size for safe string formatting.
+ * \param tmpStr Temporary staging string.
+ * \param strSize Size of the formatted string.
+ * \param str An allocated temporary string for this function to populate with
+ *            the reference expression.
+ * \return Pointer to str.
+ */
+
+static char *
+get_packed_decl(const PackedDesc *desc,
+                const unsigned tmpStrSize,
+                char *tmpStr,
+                const unsigned strSize,
+                char *str)
+{
+   int i = 0;
+
+   if (NULL == str) {
+      return "";
+   }
+
+   if (desc->isArray) {
+      snprintf(tmpStr, tmpStrSize,
+               "%s %s %s%s%u%s;\n",
+               desc->semanticName,
+               desc->typeDesc->typeName,
+               desc->variableName,
+               desc->isArray ? "[" : "",
+               desc->count,
+               desc->isArray ? "]" : "");
+      strncat(str, tmpStr, strSize - strlen(str));
+   } else if (desc->count > 1) {
+      for (i = 0; i < desc->count; i++) {
+         snprintf(tmpStr, tmpStrSize,
+                  "%s %s %s%u;\n",
+                  desc->semanticName,
+                  desc->typeDesc->typeName,
+                  desc->variableName, i);
+         strncat(str, tmpStr, strSize - strlen(str));
+      }
+   } else {
+      snprintf(tmpStr, tmpStrSize,
+               "%s %s %s;\n",
+               desc->semanticName,
+               desc->typeDesc->typeName,
+               desc->variableName);
+      strncat(str, tmpStr, strSize - strlen(str));
+   }
+
+   return str;
+}
+
+
+/**
+ * Format a string which contains the requested referenced value. The desc
+ * structure will describe the variable which is sub-indexed by arrayIndex.
+ * To address individual components, a componentIndex translated to (x,y,z,w)
+ * is applied to the textual representation.
+ *
+ * \param desc Descriptor of the variable referenced. See PackedDesc.
+ * \param arrayIndex Sub-index into the variable described by desc.
+ * \param componentIndex Component of the variable, depends on the desc
+ *                       configuration for the variable.
+ * \param str An allocated temporary string for this function to populate with
+ *            the reference expression.
+ * \return Pointer to str.
+ */
+
+static char *
+get_packed_reference(const PackedDesc *desc,
+                     const unsigned arrayIndex,
+                     const unsigned componentIndex,
+                     const unsigned strSize,
+                     char *str)
+{
+#if DEBUG_INPUT
+   printf("desc=%p componentIndex=%u\n", desc, componentIndex);
+   printf("desc->typeDesc=%p\n", desc->typeDesc);
+   printf("desc->typeDesc->componentNames=%p\n",
+          desc->typeDesc->componentNames);
+#endif
+
+   if (componentIndex > desc->typeDesc->numComponents) {
+      snprintf(str, strSize, "%s", g_floatDesc.defaultValue);
+      return str;
+   }
+
+   if (arrayIndex > desc->count) {
+      snprintf(str, strSize, "%s%s",
+               desc->typeDesc->defaultValue,
+               desc->typeDesc->componentNames[componentIndex]);
+      return str;
+   }
+
+   if (desc->count > 1) {
+      snprintf(str, strSize, "%s%s%u%s%s",
+               desc->variableName,
+               desc->isArray ? "[" : "",
+               arrayIndex,
+               desc->isArray ? "]" : "",
+               desc->typeDesc->componentNames[componentIndex]);
+   } else {
+      snprintf(str, strSize, "%s%s",
+               desc->variableName,
+               desc->typeDesc->componentNames[componentIndex]);
+   }
+
+   return str;
+}
+
+
+/**
+ * Set up an FBO for the test.
+ *
+ * \param colorTarget Color attachment index relative to GL_COLOR_ATTACHMENT0
+ * \param internalFormat Internal GL format for the pixel data.
+ * \param format GL format for the pixel data.
+ * \param formatType Data type for the pixel data. 
+ * \param width Width of the requested FBO backing store.
+ * \param height Height of the requested FBO backing store.
+ * \param fbo FBO object allocated to bind with this texture.
+ * \param pTexture A pointer to the GLuint identifier storage for the allocated
+ *                 texture.
+ * \return true if the setup succeeded without error
+ *         false otherwise.
+ */
+
+static bool
+setup_fbo_2d(const GLuint colorTarget,
+             const GLenum internalFormat,
+             const GLenum format,
+             const GLenum formatType,
+             const GLuint width,
+             const GLuint height,
+             const GLuint fbo,
+             GLuint *pTexture)
+{
+   GLenum status;
+
+   glGenTextures(1, pTexture);
+   glBindTexture(GL_TEXTURE_2D, *pTexture);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0,
+                format, formatType, NULL);
+
+   /*
+    * Framebuffer object is implied to be bound.
+    */
+   glFramebufferTexture2D(GL_FRAMEBUFFER,
+                          GL_COLOR_ATTACHMENT0 + colorTarget,
+                          GL_TEXTURE_2D, *pTexture, 0);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Failed to create FBO %u.\n", colorTarget);
+      piglit_report_result(PIGLIT_FAIL);
+      return false;
+   }
+
+   status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+   if (status != GL_FRAMEBUFFER_COMPLETE) {
+      fprintf(stderr, "Incomplete fbo for format %s.%s (status %s)\n",
+              piglit_get_gl_enum_name(internalFormat),
+              piglit_get_gl_enum_name(format),
+              piglit_get_gl_enum_name(status));
+      piglit_report_result(PIGLIT_FAIL);
+      return false;
+   }
+
+   return true;
+}
+
+
+/**
+ * Set up the vertex buffer objects and element buffer objects for the
+ * test. To ensure constant values across the primitive, populate the same
+ * prime attribute value in each vertex.
+ *
+ * \return true if the setup succeeded without error
+ *         false otherwise.
+ */
+
+static bool
+setup_vertex_element_buffers(void)
+{
+   MyVector4 attrib[NUM_VERTICES];
+   GLuint buf;
+   GLuint attribLoc;
+   int i;
+
+   /*
+    * Setup the gl_Position attribute buffer.
+    */
+   glGenBuffers(1, &buf);
+   glBindBuffer(GL_ARRAY_BUFFER, buf);
+   glBufferData(GL_ARRAY_BUFFER, NUM_VERTICES*sizeof(MyVector4),
+                g_positionBuffer, GL_STATIC_DRAW);
+
+   attribLoc = glGetAttribLocation(g_program, "InPosition");
+   glEnableVertexAttribArray(attribLoc);
+   glVertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, 0);
+   glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+   /*
+    * Setup the vertex buffer objects.
+    */
+   for (i = 0; i < g_maxVertexAttribs - 1; i++) {
+      char strTemp[16];
+
+      if ((i + 1) * MAX_COMPONENTS < NUM_PRIMES) {
+         attrib[0].x = attrib[1].x = attrib[2].x = g_primes[i*MAX_COMPONENTS + 0];
+         attrib[0].y = attrib[1].y = attrib[2].y = g_primes[i*MAX_COMPONENTS + 1];
+         attrib[0].z = attrib[1].z = attrib[2].z = g_primes[i*MAX_COMPONENTS + 2];
+         attrib[0].w = attrib[1].w = attrib[2].w = g_primes[i*MAX_COMPONENTS + 3];
+      } else {
+         attrib[0].x = attrib[1].x = attrib[2].x = 1.0;
+         attrib[0].y = attrib[1].y = attrib[2].y = 1.0;
+         attrib[0].z = attrib[1].z = attrib[2].z = 1.0;
+         attrib[0].w = attrib[1].w = attrib[2].w = 1.0;
+      }
+
+      glGenBuffers(1, &buf);
+      glBindBuffer(GL_ARRAY_BUFFER, buf);
+      glBufferData(GL_ARRAY_BUFFER, sizeof(MyVector4)*NUM_VERTICES,
+                   attrib, GL_STATIC_DRAW);
+
+      snprintf(strTemp, sizeof(strTemp), "InValue%u", i);
+      attribLoc = glGetAttribLocation(g_program, strTemp);
+      glEnableVertexAttribArray(attribLoc);
+      glVertexAttribPointer(attribLoc, 4, GL_FLOAT, GL_FALSE, 0, 0);
+      glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR)) {
+         fprintf(stderr, "Failed to create VBO %u.\n", i);
+         piglit_report_result(PIGLIT_FAIL);
+         return false;
+      }
+   }
+
+   /*
+    * Setup the element buffers.
+    */
+   glGenBuffers(1, &g_elementVBO);
+   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_elementVBO);
+   glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(g_elementBuffer),
+                g_elementBuffer, GL_STATIC_DRAW);
+   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Failed to create IBO.\n");
+      piglit_report_result(PIGLIT_FAIL);
+      return false;
+   }
+
+   return true;
+}
+
+
+/**
+ * Build a GLSL shader for the given packedInput, packedUniform, packedOutput
+ * descriptors. Each GLSL shader will have inputs, uniforms, and outputs. To
+ * ensure all bound resources are made resident, this shader must use all the
+ * inputs, uniforms, and outputs requested by the describing PackedDesc
+ * structures. If the number of outputs are smaller than the number of inputs,
+ * the inputs will map as follows:
+ *
+ *   outputs[0] = uniforms[0] inputs[0] * ... * inputs[(i % numOutputs == 0)]
+ *
+ * where i >= numOutputs and represents a subsequent pass of inputs up
+ * until i == numInputs.
+ *
+ * If the number of outputs is larger than the number of inputs, the inputs
+ * and uniforms are referenced until exhausted. Once exhausted, an input
+ * or uniform will default to 1.0 to provide a multiplicative identity.
+ *
+ * \param packedInput A descriptor of the type and number of inputs to this
+ *                    shader.
+ * \param packedUniform A descriptor of the type and number of uniforms bound
+ *                      to the shader.
+ * \param packedOutput A descriptor of the type and number of outputs for this
+ *                     shader.
+ * \param outputDefaultSystemValue A required output for the GLSL shader.
+ *                                 i.e. gl_Position for a vertex shader.
+ * \param defaultSystemValueDecl Pre-defined output declaration.
+ * \param defaultSystemValue Pre-defined output value.
+ * \param pShaderText Output pointer for the allocated and generated shader
+ *                    text.
+ * \return true if the setup succeeded without error
+ *         false otherwise.
+ */
+
+static bool
+build_reduce_glsl_shader(const PackedDesc *packedInput,
+                         const PackedDesc *packedUniform,
+                         const PackedDesc *packedOutput,
+                         const char *outputDefaultSystemValue,
+                         const char *defaultSystemValueDecl,
+                         const char *defaultSystemValue,
+                         char **pShaderText)
+{
+   char *shaderTempText[TEMP_TEXT_SIZE];
+   char *shaderText = NULL;
+   unsigned shaderTextFree = 0;
+   unsigned numScalarInputs =
+      packedInput->count * packedInput->typeDesc->numComponents;
+   unsigned numScalarUniforms =
+      packedUniform->count * packedUniform->typeDesc->numComponents;
+   unsigned numScalarOutputs =
+      packedOutput->count * packedOutput->typeDesc->numComponents;
+
+   /* Prepare for reduction of input contributions to the output slots */
+   unsigned di_do = numScalarInputs / numScalarOutputs;
+   unsigned r = numScalarInputs % numScalarOutputs;
+   int i, j, k, l;
+
+#if DEBUG_INPUT
+   printf("di_do=%u r=%u\n", di_do, r);
+#endif
+
+   for (i = 0; i < sizeof(shaderTempText) / sizeof(char *); i++) {
+      shaderTempText[i] = calloc(MAX_SHADER_LINE_CHARS, sizeof(char));
+
+      if (NULL == shaderTempText[i]) {
+         fprintf(stderr, "Failed to allocate shader temporary text area\n");
+         piglit_report_result(PIGLIT_FAIL);
+         return false;
+      }
+   }
+
+   shaderText = calloc(MAX_SHADER_TEXT_CHARS, sizeof(char));
+   if (NULL == shaderText) {
+      fprintf(stderr, "Failed to allocate space for shader text\n");
+      piglit_report_result(PIGLIT_FAIL);
+      return false;
+   }
+
+   shaderTextFree = MAX_SHADER_TEXT_CHARS;
+
+   snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+            "%s\n", GLSL_VERSION);
+   strncat(shaderText, shaderTempText[0], shaderTextFree);
+   shaderTextFree -= strlen(shaderTempText[0]);
+
+   /*
+    * Declare the default system value input.
+    */
+   if (outputDefaultSystemValue) {
+      snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+               "%s\n", defaultSystemValueDecl);
+      strncat(shaderText, shaderTempText[0], shaderTextFree);
+      shaderTextFree -= strlen(defaultSystemValueDecl);
+   }
+
+   /*
+    * Declare the input attributes.
+    */
+   get_packed_decl(packedInput,
+                   MAX_SHADER_LINE_CHARS, shaderTempText[0],
+                   MAX_SHADER_TEXT_CHARS, shaderText);
+
+   /*
+    * Declare the uniform samplers using the vertex texture functionality.
+    */
+   get_packed_decl(packedUniform,
+                   MAX_SHADER_LINE_CHARS, shaderTempText[0],
+                   MAX_SHADER_TEXT_CHARS, shaderText);
+
+   /*
+    * Declare the outputs.
+    */
+   if (packedOutput->semanticName) {
+      get_packed_decl(packedOutput,
+                      MAX_SHADER_LINE_CHARS, shaderTempText[0],
+                      MAX_SHADER_TEXT_CHARS, shaderText);
+   }
+
+   shaderTextFree = MAX_SHADER_TEXT_CHARS - strlen(shaderText);
+
+   /*
+    * Begin main program block.
+    */
+   snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+            "void main()\n{\n");
+   strncat(shaderText, shaderTempText[0], shaderTextFree);
+   shaderTextFree -= strlen(shaderTempText[0]);
+
+   snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+            "  vec4 texel;\n");
+   strncat(shaderText, shaderTempText[0], shaderTextFree);
+   shaderTextFree -= strlen(shaderTempText[0]);
+
+   /*
+    * Passthru the attributes to the outputs.
+    */
+   i = j = k = l = 0;
+
+   while (i < numScalarOutputs)  {
+      char *resultStr = " ", *srcStr = " ";
+
+      if ((i < packedUniform->count*packedUniform->typeDesc->numComponents) &&
+          (j % packedUniform->typeDesc->numComponents) == 0) {
+         snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+                  "  texel = texture2D(Texture[%u], vec2(0.0, 0.0));\n",
+                  i / packedUniform->typeDesc->numComponents);
+         strncat(shaderText, shaderTempText[0], shaderTextFree);
+         shaderTextFree -= strlen(shaderTempText[0]);
+      }
+
+      /*
+       * Iterate through the contents of the texel
+       */
+      resultStr = get_packed_reference(packedOutput,
+                     (i / packedOutput->typeDesc->numComponents),
+                     (i % packedOutput->typeDesc->numComponents),
+                     MAX_SHADER_LINE_CHARS,
+                     shaderTempText[1]);
+
+      /* Reset the temp string to avoid cumulative contributions. */
+      memset(shaderTempText[2], 0, MAX_SHADER_LINE_CHARS);
+
+      if (k < numScalarInputs) {
+         /* Reduce the scalar multiple of the input contributions. */
+         for (l = 0; l < di_do; l++) {
+            srcStr = get_packed_reference(packedInput,
+                        (i + (l * numScalarOutputs)) /
+                           packedInput->typeDesc->numComponents,
+                        (i + (l * numScalarOutputs)) %
+                           packedInput->typeDesc->numComponents,
+                        MAX_SHADER_LINE_CHARS,
+                        shaderTempText[3]);
+
+            if (l > 0) {
+               strncat(shaderTempText[2], " * ",
+                       MAX_SHADER_LINE_CHARS - strlen(shaderTempText[2]));
+            }
+            strncat(shaderTempText[2], srcStr,
+                    MAX_SHADER_LINE_CHARS - strlen(shaderTempText[2]));
+
+            k++;
+         }
+
+         /* Reduce the remaining scalar contributions until exhausted */
+         if (r) {
+            srcStr = get_packed_reference(packedInput,
+                        (i + (l * numScalarOutputs)) /
+                           packedInput->typeDesc->numComponents,
+                        (i + (l * numScalarOutputs)) %
+                           packedInput->typeDesc->numComponents,
+                        MAX_SHADER_LINE_CHARS,
+                        shaderTempText[3]);
+            if (l > 0) {
+               strncat(shaderTempText[2], " * ",
+                       MAX_SHADER_LINE_CHARS - strlen(shaderTempText[2]));
+            }
+            strncat(shaderTempText[2], srcStr,
+                    MAX_SHADER_LINE_CHARS - strlen(shaderTempText[2]));
+            k++;
+            r--;
+         }
+         srcStr = shaderTempText[2];
+      } else {
+         snprintf(shaderTempText[2], MAX_SHADER_LINE_CHARS,
+                  "%s", g_floatDesc.defaultValue);
+         srcStr = shaderTempText[2];
+      }
+
+      if (j < numScalarUniforms) {
+         if (DEBUG_INPUT && outputDefaultSystemValue) {
+            snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+                     "  %s = texel%s;\n", resultStr,
+                     g_vectorComponents[j % packedUniform->typeDesc->numComponents]);
+         } else {
+            snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+                     "  %s = texel%s * %s;\n", resultStr,
+                     g_vectorComponents[j % packedUniform->typeDesc->numComponents],
+                     srcStr);
+         }
+         strncat(shaderText, shaderTempText[0], shaderTextFree);
+         shaderTextFree -= strlen(shaderTempText[0]);
+         j++;
+      } else {
+         snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+                  "  %s = %s%s * %s;\n", resultStr,
+                  packedUniform->typeDesc->defaultValue,
+                  g_vectorComponents[0],
+                  srcStr);
+         strncat(shaderText, shaderTempText[0], shaderTextFree);
+         shaderTextFree -= strlen(shaderTempText[0]);
+      }
+
+      /* Increment to the next output. */
+      i++;
+   }
+
+   /*
+    * End the main program block.
+    */
+   if (outputDefaultSystemValue) {
+      snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS,
+               "  %s = %s;\n",
+               outputDefaultSystemValue, defaultSystemValue);
+      strncat(shaderText, shaderTempText[0], shaderTextFree);
+      shaderTextFree -= strlen(shaderTempText[0]);
+   }
+
+   snprintf(shaderTempText[0], MAX_SHADER_LINE_CHARS, "}\n");
+   strncat(shaderText, shaderTempText[0], shaderTextFree);
+   shaderTextFree -= strlen(shaderTempText[0]);
+
+   for (i = 0; i < sizeof(shaderTempText) / sizeof(char *); i++) {
+      if (shaderTempText[i]) {
+         free(shaderTempText[i]);
+      }
+   }
+
+   *pShaderText = shaderText;
+   return true;
+}
+
+
+/**
+ * Core piglit_display callback. This function will bind the FBOs, Textures,
+ * VBOs, IBOs, and draw a primitive using the GLSL shader generated by
+ * build_reduce_glsl_shader.
+ *
+ * Once rendered, a pixel from each of the color attachments is read back and
+ * compared to the final expression value stored in g_expected given the
+ * associated color attachment index.
+ *
+ * \return PIGLIT_PASS if the setup succeeded without error
+ *         PIGLIT_FAIL otherwise.
+ */
+
+enum piglit_result
+piglit_display(void)
+{
+   GLuint vao = 0;
+   GLuint fbo = 0;
+   GLuint *fboTextures = NULL;
+   GLenum *colorBuffers = NULL;
+   GLuint attribLoc;
+   GLfloat result[4];
+   int i = 0;
+
+   /*
+    * Reserve memory for the FBO texture objects.
+    */
+   fboTextures = calloc(g_maxColorAttachments, sizeof(GLuint));
+
+   if (NULL == fboTextures) {
+      fprintf(stderr, "Failed to create FBO texture object container.\n");
+      goto fail;
+   }
+
+   /*
+    * Build the color attachments
+    */
+   colorBuffers = calloc(g_maxColorAttachments, sizeof(GLenum));
+
+   if (NULL == colorBuffers) {
+      fprintf(stderr, "Failed to create draw buffers descriptor.\n");
+      goto fail;
+   }
+
+   /*
+    * Generate an FBO container to hold the color attachment hierarchy.
+    */
+   glGenFramebuffers(1, &fbo);
+   glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+   for (i = 0; i < g_maxColorAttachments; i++) {
+      setup_fbo_2d(i, GL_RGBA32F, GL_RGBA, GL_FLOAT,
+                   BUFFER_WIDTH, BUFFER_HEIGHT,
+                   fbo, &fboTextures[i]);
+      colorBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
+   }
+
+   /*
+    * Build the textures sampled by the shaders
+    */
+   for (i = 0; i < g_maxCombinedTextureImageUnits; i++) {
+      GLuint tex;
+      GLuint uniformLoc;
+      char strTemp[16];
+
+      glGenTextures(1, &tex);
+      glActiveTexture(GL_TEXTURE0 + i);
+      glBindTexture(GL_TEXTURE_2D, tex);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+      if (((i+1) * MAX_COMPONENTS) > sizeof(g_primes)) {
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0,
+                      GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+      } else {
+         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 1, 1, 0,
+                      GL_RGBA, GL_FLOAT, &g_primes[i * MAX_COMPONENTS]);
+      }
+
+      if (!piglit_check_gl_error(GL_NO_ERROR)) {
+         fprintf(stderr, "Failed to create texture %u.\n", i);
+         goto fail;
+      }
+
+      snprintf(strTemp, sizeof(strTemp), "Texture[%u]", i);
+      uniformLoc = glGetUniformLocation(g_program, strTemp);
+      glUniform1i(uniformLoc, i);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR)) {
+         fprintf(stderr, "Unable to assign texture %u uniform.\n", i);
+         goto fail;
+      }
+   }
+
+   /*
+    * Setup the vertex and element buffers for drawing our points.
+    */
+   glGenVertexArrays(1, &vao);
+   glBindVertexArray(vao);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Unable to create VAO.\n");
+      goto fail;
+   }
+
+   setup_vertex_element_buffers();
+
+   /*
+    * Setup the raster state.
+    */
+   glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+   glDrawBuffers(g_maxColorAttachments, colorBuffers);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Unable to assign draw buffers.\n");
+      goto fail;
+   }
+
+   glClearColor(0.0, 1.0, 0.0, 0.0);
+   glClear(GL_COLOR_BUFFER_BIT);
+
+   /*
+    * Bind the vertex array and enable each attribute.
+    */
+   glBindVertexArray(vao);
+   attribLoc = glGetAttribLocation(g_program, "InPosition");
+   glEnableVertexAttribArray(attribLoc);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Unable to enable vertex array attribute %u.\n", attribLoc);
+      goto fail;
+   }
+
+   /*
+    * Enable the rest of the attributes.
+    */
+   for (i = 0; i < g_maxVertexAttribs - 1; i++) {
+      char strTemp[16];
+
+      snprintf(strTemp, sizeof(strTemp), "InValue%u", i);
+      attribLoc = glGetAttribLocation(g_program, strTemp);
+      glEnableVertexAttribArray(attribLoc);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR)) {
+         fprintf(stderr, "Unable to enable vertex array attribute %u.\n", attribLoc);
+         goto fail;
+      }
+   }
+
+#if DRAW_ARRAYS
+   glDrawArrays(GL_TRIANGLES, 0, NUM_VERTICES);
+#endif
+
+#if DRAW_ELEMENTS
+   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_elementVBO);
+   glDrawElements(GL_TRIANGLES, NUM_VERTICES, GL_UNSIGNED_SHORT, 0);
+   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+#endif
+
+   /*
+    * Blindly reset all the attributes.
+    */
+   for (i = 0; i < g_maxVertexAttribs; i++) {
+      glDisableVertexAttribArray(i);
+   }
+
+#if DRAW_IMMEDIATE
+   glBegin(GL_TRIANGLES);
+      glVertex3f(-1.0, -1.0, 0.0);
+      glVertex3f(-1.0, 1.0, 0.0);
+      glVertex3f(1.0, 1.0, 0.0);
+   glEnd();
+#endif
+
+   if (!piglit_check_gl_error(GL_NO_ERROR))
+      goto fail;
+
+   /*
+    * Read back the FBO contents.
+    */
+
+   /*
+    * Disable color clamping so we don't encounter result
+    * collisions attempting to use a normalized color space.
+    *
+    * Requires OpenGL 3.0
+    */
+   glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE);
+
+   for (i = 0; i < g_maxColorAttachments; i++) {
+#if DEBUG_READBACK
+      printf("GL_READ_FRAMEBUFFER <- fbo=%u\n", fbo);
+#endif
+
+      glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR))
+         goto fail;
+
+      glFramebufferTexture2D(GL_READ_FRAMEBUFFER,
+                             GL_COLOR_ATTACHMENT0,
+                             GL_TEXTURE_2D,
+                             fboTextures[i],
+                             0);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR))
+         goto fail;
+
+      glPixelStorei(GL_PACK_ALIGNMENT, 1);
+      glReadBuffer(GL_COLOR_ATTACHMENT0);
+
+      if (!piglit_check_gl_error(GL_NO_ERROR))
+         goto fail;
+
+      glReadPixels(0, BUFFER_HEIGHT - 1,
+                   1, 1, GL_RGBA, GL_FLOAT, result);
+
+      if ((g_expected[(i * MAX_COMPONENTS) + 0] != result[0]) ||
+          (g_expected[(i * MAX_COMPONENTS) + 1] != result[1]) ||
+          (g_expected[(i * MAX_COMPONENTS) + 2] != result[2]) ||
+          (g_expected[(i * MAX_COMPONENTS) + 3] != result[3])) {
+         fprintf(stderr, "GL_COLOR_ATTACHMENT%u: expected (%f, %f, %f, %f) != (%f, %f, %f, %f)\n",
+                 i, g_expected[(i * MAX_COMPONENTS) + 0],
+                 g_expected[(i * MAX_COMPONENTS) + 1],
+                 g_expected[(i * MAX_COMPONENTS) + 2],
+                 g_expected[(i * MAX_COMPONENTS) + 3],
+                 result[0], result[1], result[2], result[3]);
+
+         goto fail;
+      }
+   }
+
+   piglit_present_results();
+
+   /*
+    * Cleanup the allocations.
+    */
+   free(colorBuffers);
+   free(fboTextures);
+
+   piglit_report_result(PIGLIT_PASS);
+
+   return PIGLIT_PASS;
+
+fail:
+
+   if (colorBuffers)
+      free(colorBuffers);
+
+   if (fboTextures)
+      free(fboTextures);
+
+   piglit_report_result(PIGLIT_FAIL);
+
+   return PIGLIT_FAIL;
+}
+
+
+/**
+ * Core piglit_init callback. This function will query the implementation for
+ * the maximum number of supported resources. We attempt to create a GLSL
+ * shader which references all supported resources bindable within the GL 3.0
+ * specification.
+ *
+ * Each resource will be populated with a unique prime value. This function is
+ * also responsible for calculating the expected value and storing this in
+ * the g_expected array.
+ *
+ * Note: If the number of primes is insufficient to assign a unique prime to
+ *       each resource, we will exit with PIGLIT_SKIP.
+ *
+ * Results: PIGLIT_PASS if the setup succeeded without error
+ *          PIGLIT_FAIL otherwise.
+ */
+
+void
+piglit_init(int argc, char **argv)
+{
+   GLfloat *var;
+   PackedDesc vsInput = { "in", "InValue", false, 0, &g_vec4Desc };
+   PackedDesc vsUniform = { "uniform", "Texture", true, 0, &g_sampler2DDesc };
+   PackedDesc vsOutput = { "out", "Variable", true, 0, &g_floatDesc };
+   PackedDesc fsInput = { "in", "Variable", true, 0, &g_floatDesc };
+   PackedDesc fsUniform = { "uniform", "Texture", true, 0, &g_sampler2DDesc };
+   PackedDesc fsOutput = { NULL, g_fragData, true, 0, &g_rgbaDesc };
+   char shaderTempText[MAX_SHADER_LINE_CHARS];
+   char *vertexShaderText = g_vertexShaderText;
+   char *fragmentShaderText = g_fragmentShaderText;
+   int i = 0;
+
+   piglit_require_gl_version(30);
+
+   /*
+    * Query the sampler capabilities.
+    */
+   glGetIntegerv(GL_MAX_VARYING_FLOATS, &g_maxVaryingFloats);
+   glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &g_maxVertexAttribs);
+   glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+                 &g_maxVertexTextureImageUnits);
+   glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS,
+                 &g_maxTextureImageUnits);
+   glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+                 &g_maxCombinedTextureImageUnits);
+
+   printf("GL_MAX_VARYING_FLOATS: %d\n", g_maxVaryingFloats);
+   printf("GL_MAX_VERTEX_ATTRIBS: %d\n", g_maxVertexAttribs);
+   printf("GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: %d\n",
+          g_maxVertexTextureImageUnits);
+   printf("GL_MAX_TEXTURE_IMAGE_UNITS: %d\n",
+          g_maxTextureImageUnits);
+   printf("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d\n",
+          g_maxCombinedTextureImageUnits);
+
+   /*
+    * Query the render target capabilities.
+    */
+   glGetIntegerv(GL_AUX_BUFFERS, &g_maxAuxBuffers);
+   glGetIntegerv(GL_MAX_DRAW_BUFFERS, &g_maxDrawBuffers);
+   glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &g_maxColorAttachments);
+
+   if (g_maxColorAttachments == 1) {
+      fsOutput.variableName = g_fragColor;
+   }
+
+   printf("GL_AUX_BUFFERS: %d\n", g_maxAuxBuffers);
+   printf("GL_MAX_DRAW_BUFFERS: %d\n", g_maxDrawBuffers);
+   printf("GL_MAX_COLOR_ATTACHMENTS: %d\n", g_maxColorAttachments);
+
+   if ((g_maxColorAttachments * MAX_COMPONENTS > NUM_PRIMES) ||
+       (g_maxVaryingFloats > NUM_PRIMES) ||
+       (g_maxVertexAttribs * MAX_COMPONENTS > NUM_PRIMES) ||
+       (g_maxVertexTextureImageUnits * MAX_COMPONENTS > NUM_PRIMES) ||
+       (g_maxTextureImageUnits * MAX_COMPONENTS > NUM_PRIMES)) {
+      fprintf(stderr, "Unable to uniquely represent a result path.\n");
+      piglit_report_result(PIGLIT_SKIP);
+   }
+
+   /*
+    * Build the shaders based upon the queried limits.
+    */
+   vsInput.count = g_maxVertexAttribs - 1;
+   vsUniform.count = g_maxVertexTextureImageUnits;
+   vsOutput.count = g_maxVaryingFloats;
+   if (!build_reduce_glsl_shader(&vsInput,
+                                 &vsUniform,
+                                 &vsOutput,
+                                 "gl_Position",
+                                 "in vec4 InPosition;",
+                                 "InPosition",
+                                 &vertexShaderText)) {
+      fprintf(stderr, "Failed to build GLSL vertex shader\n");
+      piglit_report_result(PIGLIT_SKIP);
+   }
+
+#if DEBUG_SHADERS
+   printf("vertexShaderText:\n%s", vertexShaderText);
+#endif
+
+   fsInput.count = g_maxVaryingFloats;
+   fsUniform.count = g_maxTextureImageUnits;
+   fsOutput.count = g_maxColorAttachments;
+   if (!build_reduce_glsl_shader(&fsInput,
+                                 &fsUniform,
+                                 &fsOutput,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &fragmentShaderText)) {
+      fprintf(stderr, "Failed to build GLSL vertex shader\n");
+      piglit_report_result(PIGLIT_SKIP);
+   }
+
+#if DEBUG_SHADERS
+   printf("fragmentShaderText:\n%s", fragmentShaderText);
+#endif
+
+   /*
+    * Build the vertex and fragment shaders.
+    */
+   g_program = piglit_build_simple_program(vertexShaderText,
+                                           fragmentShaderText);
+   if (!g_program) {
+      fprintf(stderr, "Failed to compile/link program\n");
+      piglit_report_result(PIGLIT_SKIP);
+   }
+
+   snprintf(shaderTempText, sizeof(shaderTempText), "InPosition");
+   glBindAttribLocation(g_program, 0, shaderTempText);
+
+   for (i = 0; i < g_maxVertexAttribs - 1; i++) {
+      snprintf(shaderTempText, sizeof(shaderTempText), "InValue%u", i);
+      glBindAttribLocation(g_program, i+1, shaderTempText);
+   }
+
+#if DEBUG_SHADERS
+   printf("Linking program...\n");
+#endif
+
+   glLinkProgram(g_program);
+   glUseProgram(g_program);
+
+   if (!piglit_check_gl_error(GL_NO_ERROR)) {
+      fprintf(stderr, "Failure to link shaders\n");
+      fprintf(stderr, "vertexShaderText:\n%s", vertexShaderText);
+      fprintf(stderr, "fragmentShaderText:\n%s", fragmentShaderText);
+      free(vertexShaderText);
+      free(fragmentShaderText);
+      piglit_report_result(PIGLIT_FAIL);
+   }
+
+#if DEBUG_SHADERS
+   printf("Using program %u...\n", g_program);
+#endif
+
+   /* Delete the interim copies generated by build_reduce_glsl_shader */ 
+   free(vertexShaderText);
+   free(fragmentShaderText);
+
+   /*
+    * Calculate the expected results for the bound resource limits.
+    */
+   var = calloc(g_maxVaryingFloats, sizeof(GLfloat));
+
+   if (NULL == var) {
+      fprintf(stderr, "Failed to allocate temporary array for expected calculation.\n");
+      piglit_report_result(PIGLIT_FAIL);
+   }
+
+   g_expected = calloc(g_maxColorAttachments, sizeof(GLfloat)*MAX_COMPONENTS);
+
+   if (NULL == g_expected) {
+      fprintf(stderr, "Failed to allocate array for expected calculation.\n");
+      piglit_report_result(PIGLIT_FAIL);
+   }
+
+   /*
+    * Sampler cover up to the total number of varying floats.
+    */
+   for (i = 0; i < g_maxVaryingFloats; i++) {
+      if ((i < g_maxVertexTextureImageUnits*MAX_COMPONENTS) &&
+          (i < NUM_PRIMES)) {
+         var[i] = g_primes[i];
+      } else {
+         var[i] = 1.0;
+      }
+   }
+
+   /*
+    * Multiply in all vertex attributes.
+    */
+   i = 0;
+   while (i < (g_maxVertexAttribs-1)*MAX_COMPONENTS) {
+      if (i < NUM_PRIMES) {
+         var[i % g_maxVaryingFloats] *= g_primes[i];
+      } else {
+         var[i % g_maxVaryingFloats] *= 1.0;
+      }
+      i++;
+   }
+
+   /*
+    * Calculate the expected values for the FS stage.
+    *
+    * Sampler cover up to the total number of varying floats.
+    */
+   for (i = 0; i < g_maxColorAttachments*MAX_COMPONENTS; i++) {
+      if ((i < g_maxVertexTextureImageUnits*MAX_COMPONENTS) &&
+          (i < NUM_PRIMES)) {
+         g_expected[i] = g_primes[i];
+      } else {
+         g_expected[i] = 1.0;
+      }
+   }
+
+   /*
+    * Multiply in all the varying contributions generated by the VS.
+    */
+   i = 0;
+   while (i < g_maxVaryingFloats) {
+      g_expected[i % (g_maxColorAttachments*MAX_COMPONENTS)] *= var[i];
+      i++;
+   }
+
+   for (i = 0; i < g_maxColorAttachments; i++) {
+      printf("g_expected[%u]=(%f, %f, %f, %f)\n", i,
+             g_expected[(i * MAX_COMPONENTS) + 0],
+             g_expected[(i * MAX_COMPONENTS) + 1],
+             g_expected[(i * MAX_COMPONENTS) + 2],
+             g_expected[(i * MAX_COMPONENTS) + 3]);
+   }
+
+   free(var);
+}
-- 
1.7.9.5



----- Original Message -----
From: "Brian Paul" <brianp at vmware.com>
To: "Matthew McClure" <mcclurem at vmware.com>
Cc: piglit at lists.freedesktop.org
Sent: Tuesday, July 8, 2014 11:02:23 AM
Subject: Re: [Piglit] [PATCH] gl-3.0: add a test to stress the bound resource limits

On 07/08/2014 11:01 AM, Matthew McClure wrote:
> I ran this on Ubuntu 12.04.3 with:
>
> OpenGL vendor string: NVIDIA Corporation
> OpenGL renderer string: GeForce GTX 650/PCIe/SSE2
> OpenGL version string: 4.2.0 NVIDIA 304.116
> OpenGL shading language version string: 4.20 NVIDIA via Cg compiler
> OpenGL extensions:
>
> .../Devel/fdo.piglit$ bin/gl-3.0-bound-resource-limits -auto
> GL_MAX_VARYING_FLOATS: 124
> GL_MAX_VERTEX_ATTRIBS: 16
> GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: 32
> GL_MAX_TEXTURE_IMAGE_UNITS: 32
> GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: 160
> GL_AUX_BUFFERS: 4
> GL_MAX_DRAW_BUFFERS: 8
> GL_MAX_COLOR_ATTACHMENTS: 8
> g_expected[0]=(23921766400.000000, 86156951552.000000, 480410238976.000000, 1425854431232.000000)
> g_expected[1]=(6227219709952.000000, 11347125338112.000000, 27230952488960.000000, 41933363740672.000000)
> g_expected[2]=(81694296113152.000000, 171963293106176.000000, 241784881938432.000000, 428522141122560.000000)
> g_expected[3]=(623247401943040.000000, 751236219404288.000000, 1125101110034432.000000, 1856184336252928.000000)
> g_expected[4]=(2735942485934080.000000, 3101938392498176.000000, 4440612589797376.000000, 5674358320136192.000000)
> g_expected[5]=(6377906712346624.000000, 8903007106236416.000000, 11072865923235840.000000, 14685310302552064.000000)
> g_expected[6]=(20124361323184128.000000, 23577553683873792.000000, 26507988395098112.000000, 31646100720975872.000000)
> g_expected[7]=(178482200576.000000, 207579496448.000000, 313797935104.000000, 351675613184.000000)
> PIGLIT: {"result": "pass" }
>
> Below are my replies:
>
>>> +static char *
>>> +get_packed_decl(PackedDesc *desc,
>>> +                char *str,
>>> +                unsigned strSize,
>>> +                char *tmpStr,
>>> +                unsigned tmpStrSize)
>>
>> Here and elsewhere, can you const-qualify any pointer args to help
>> understand which are inputs vs. outputs?
>>
>
> Sounds good. I'll make the changes.
>
>>> +setup_vertex_element_buffers()
>>
>> I think MSVC warns on () so we use (void) usually.
>
> Thanks, I'll go ahead and add that.
>
>> The code generally looks good, but is a bit dense.  It would take me a
>> while to understand the intricacies.
>>
>> In any case, when I tested it with my nvidia driver I got a failure:
>>
>> $ bin/gl-3.0-bound-resource-limits -auto
>> GL_MAX_VARYING_FLOATS: 124
>> GL_MAX_VERTEX_ATTRIBS: 16
>> GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: 32
>> GL_MAX_TEXTURE_IMAGE_UNITS: 32
>> GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: 192
>> GL_AUX_BUFFERS: 4
>> GL_MAX_DRAW_BUFFERS: 8
>> GL_MAX_COLOR_ATTACHMENTS: 8
>> Failed to link: Fragment info
>> -------------
>> 0(8) : warning C7533: global variable gl_FragData is deprecated after
>> version 120
>> 0(2) : error C5041: cannot locate suitable resource to bind variable
>> "Variable". Possibly large array.
>>
>> PIGLIT: {"result": "fail" }
>
> What was your NVIDIA driver version?

325.15

-Brian


More information about the Piglit mailing list