render_test: Add std140 layout test
diff --git a/tests/render_tests.cpp b/tests/render_tests.cpp
index c38fe7b..3cda530 100644
--- a/tests/render_tests.cpp
+++ b/tests/render_tests.cpp
@@ -2916,6 +2916,259 @@
 
 }
 
+TEST_F(XglRenderTest, TriangleUniformBufferLayout)
+{
+    // This test populates a buffer with a variety of different data
+    // types, then reads them out with a shader.
+    // The expected result from this test is a green triangle
+
+    static const char *vertShaderText =
+            "#version 140\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout (std140, binding = 0) uniform mixedBuffer {\n"
+            "    vec4 fRed;\n"
+            "    vec4 fGreen;\n"
+            "    layout(row_major) mat4 worldToProj;\n"
+            "    layout(row_major) mat4 projToWorld;\n"
+            "    layout(row_major) mat4 worldToView;\n"
+            "    layout(row_major) mat4 viewToProj;\n"
+            "    layout(row_major) mat4 worldToShadow[4];\n"
+            "    float fZero;\n"
+            "    float fOne;\n"
+            "    float fTwo;\n"
+            "    float fThree;\n"
+            "    vec3 fZeroZeroZero;\n"
+            "    float fFour;\n"
+            "    vec3 fZeroZeroOne;\n"
+            "    float fFive;\n"
+            "    vec3 fZeroOneZero;\n"
+            "    float fSix;\n"
+            "    float fSeven;\n"
+            "    float fEight;\n"
+            "    float fNine;\n"
+            "    vec2 fZeroZero;\n"
+            "    vec2 fZeroOne;\n"
+            "    vec4 fBlue;\n"
+            "    vec2 fOneZero;\n"
+            "    vec2 fOneOne;\n"
+            "    vec3 fZeroOneOne;\n"
+            "    float fTen;\n"
+            "    float fEleven;\n"
+            "    float fTwelve;\n"
+            "    vec3 fOneZeroZero;\n"
+            "    vec4 uvOffsets[4];\n"
+            "};\n"
+            "layout (location = 0) out vec4 color;"
+            "void main() {\n"
+
+            "   vec4 right = vec4(0.0, 1.0, 0.0, 1.0);\n"
+            "   vec4 wrong = vec4(1.0, 0.0, 0.0, 1.0);\n"
+            "   \n"
+
+            // do some exact comparisons, even though we should
+            // really have an epsilon involved.
+            "   vec4 outColor = right;\n"
+            "   if (fRed != vec4(1.0, 0.0, 0.0, 1.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fGreen != vec4(0.0, 1.0, 0.0, 1.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fBlue != vec4(0.0, 0.0, 1.0, 1.0))\n"
+            "       outColor = wrong;\n"
+
+            "   color = outColor;\n"
+
+            // generic position stuff
+            "   vec2 vertices;\n"
+            "   int vertexSelector = gl_VertexID;\n"
+            "   if (vertexSelector == 0)\n"
+            "      vertices = vec2(-0.5, -0.5);\n"
+            "   else if (vertexSelector == 1)\n"
+            "      vertices = vec2( 0.5, -0.5);\n"
+            "   else if (vertexSelector == 2)\n"
+            "      vertices = vec2( 0.5, 0.5);\n"
+            "   else\n"
+            "      vertices = vec2( 0.0,  0.0);\n"
+            "   gl_Position = vec4(vertices, 0.0, 1.0);\n"
+            "}\n";
+
+    static const char *fragShaderText =
+            "#version 140\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout (std140, binding = 0) uniform mixedBuffer {\n"
+            "    vec4 fRed;\n"
+            "    vec4 fGreen;\n"
+            "    layout(row_major) mat4 worldToProj;\n"
+            "    layout(row_major) mat4 projToWorld;\n"
+            "    layout(row_major) mat4 worldToView;\n"
+            "    layout(row_major) mat4 viewToProj;\n"
+            "    layout(row_major) mat4 worldToShadow[4];\n"
+            "    float fZero;\n"
+            "    float fOne;\n"
+            "    float fTwo;\n"
+            "    float fThree;\n"
+            "    vec3 fZeroZeroZero;\n"
+            "    float fFour;\n"
+            "    vec3 fZeroZeroOne;\n"
+            "    float fFive;\n"
+            "    vec3 fZeroOneZero;\n"
+            "    float fSix;\n"
+            "    float fSeven;\n"
+            "    float fEight;\n"
+            "    float fNine;\n"
+            "    vec2 fZeroZero;\n"
+            "    vec2 fZeroOne;\n"
+            "    vec4 fBlue;\n"
+            "    vec2 fOneZero;\n"
+            "    vec2 fOneOne;\n"
+            "    vec3 fZeroOneOne;\n"
+            "    float fTen;\n"
+            "    float fEleven;\n"
+            "    float fTwelve;\n"
+            "    vec3 fOneZeroZero;\n"
+            "    vec4 uvOffsets[4];\n"
+            "};\n"
+            "layout (location = 0) in vec4 color;\n"
+            "void main() {\n"
+            "   vec4 right = vec4(0.0, 1.0, 0.0, 1.0);\n"
+            "   vec4 wrong = vec4(1.0, 0.0, 0.0, 1.0);\n"
+            "   \n"
+
+            // start with VS value to ensure it passed
+            "   vec4 outColor = color;\n"
+
+            // do some exact comparisons, even though we should
+            // really have an epsilon involved.
+            "   if (fRed != vec4(1.0, 0.0, 0.0, 1.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fGreen != vec4(0.0, 1.0, 0.0, 1.0))\n"
+            "       outColor = wrong;\n"
+            "   if (projToWorld[1] != vec4(0.0, 2.0, 0.0, 0.0))\n"
+            "       outColor = wrong;\n"
+            "   if (worldToShadow[2][1] != vec4(0.0, 7.0, 0.0, 0.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fTwo != 2.0)\n"
+            "       outColor = wrong;\n"
+            "   if (fOneOne != vec2(1.0, 1.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fTen != 10.0)\n"
+            "       outColor = wrong;\n"
+            "   if (uvOffsets[2] != vec4(0.9, 1.0, 1.1, 1.2))\n"
+            "       outColor = wrong;\n"
+            "   \n"
+            "   gl_FragColor = outColor;\n"
+            "}\n";
+
+
+    const float mixedVals[196] = {   1.0, 0.0, 0.0, 1.0,   //        vec4 fRed;            // align
+                                     0.0, 1.0, 0.0, 1.0,   //        vec4 fGreen;          // align
+                                     1.0, 0.0, 0.0, 1.0,   //        layout(row_major) mat4 worldToProj;
+                                     0.0, 1.0, 0.0, 1.0,   //        align
+                                     0.0, 0.0, 1.0, 1.0,   //        align
+                                     0.0, 0.0, 0.0, 1.0,   //        align
+                                     2.0, 0.0, 0.0, 2.0,   //        layout(row_major) mat4 projToWorld;
+                                     0.0, 2.0, 0.0, 2.0,   //        align
+                                     0.0, 0.0, 2.0, 2.0,   //        align
+                                     0.0, 0.0, 0.0, 2.0,   //        align
+                                     3.0, 0.0, 0.0, 3.0,   //        layout(row_major) mat4 worldToView;
+                                     0.0, 3.0, 0.0, 3.0,   //        align
+                                     0.0, 0.0, 3.0, 3.0,   //        align
+                                     0.0, 0.0, 0.0, 3.0,   //        align
+                                     4.0, 0.0, 0.0, 4.0,   //        layout(row_major) mat4 viewToProj;
+                                     0.0, 4.0, 0.0, 4.0,   //        align
+                                     0.0, 0.0, 4.0, 4.0,   //        align
+                                     0.0, 0.0, 0.0, 4.0,   //        align
+                                     5.0, 0.0, 0.0, 5.0,   //        layout(row_major) mat4 worldToShadow[4];
+                                     0.0, 5.0, 0.0, 5.0,   //        align
+                                     0.0, 0.0, 5.0, 5.0,   //        align
+                                     0.0, 0.0, 0.0, 5.0,   //        align
+                                     6.0, 0.0, 0.0, 6.0,   //        align
+                                     0.0, 6.0, 0.0, 6.0,   //        align
+                                     0.0, 0.0, 6.0, 6.0,   //        align
+                                     0.0, 0.0, 0.0, 6.0,   //        align
+                                     7.0, 0.0, 0.0, 7.0,   //        align
+                                     0.0, 7.0, 0.0, 7.0,   //        align
+                                     0.0, 0.0, 7.0, 7.0,   //        align
+                                     0.0, 0.0, 0.0, 7.0,   //        align
+                                     8.0, 0.0, 0.0, 8.0,   //        align
+                                     0.0, 8.0, 0.0, 8.0,   //        align
+                                     0.0, 0.0, 8.0, 8.0,   //        align
+                                     0.0, 0.0, 0.0, 8.0,   //        align
+                                     0.0,                  //        float fZero;          // align
+                                     1.0,                  //        float fOne;           // pack
+                                     2.0,                  //        float fTwo;           // pack
+                                     3.0,                  //        float fThree;         // pack
+                                     0.0, 0.0, 0.0,        //        vec3 fZeroZeroZero;   // align
+                                     4.0,                  //        float fFour;          // pack
+                                     0.0, 0.0, 1.0,        //        vec3 fZeroZeroOne;    // align
+                                     5.0,                  //        float fFive;          // pack
+                                     0.0, 1.0, 0.0,        //        vec3 fZeroOneZero;    // align
+                                     6.0,                  //        float fSix;           // pack
+                                     7.0,                  //        float fSeven;         // align
+                                     8.0,                  //        float fEight;         // pack
+                                     9.0,                  //        float fNine;          // pack
+                                     0.0,                  //        BUFFER
+                                     0.0, 0.0,             //        vec2 fZeroZero;       // align
+                                     0.0, 1.0,             //        vec2 fZeroOne;        // pack
+                                     0.0, 0.0, 1.0, 1.0,   //        vec4 fBlue;           // align
+                                     1.0, 0.0,             //        vec2 fOneZero;        // align
+                                     1.0, 1.0,             //        vec2 fOneOne;         // pack
+                                     0.0, 1.0, 1.0,        //        vec3 fZeroOneOne;     // align
+                                     10.0,                 //        float fTen;           // pack
+                                     11.0,                 //        float fEleven;        // align
+                                     12.0,                 //        float fTwelve;        // pack
+                                     0.0, 0.0,             //        BUFFER
+                                     1.0, 0.0, 0.0,        //        vec3 fOneZeroZero;    // align
+                                     0.0,                  //        BUFFER
+                                     0.1, 0.2, 0.3, 0.4,   //        vec4 uvOffsets[4];
+                                     0.5, 0.6, 0.7, 0.8,   //        align
+                                     0.9, 1.0, 1.1, 1.2,   //        align
+                                     1.3, 1.4, 1.5, 1.6,   //        align
+                                  };
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitViewport());
+
+    const int constCount   = sizeof(mixedVals)   / sizeof(float);
+
+    XglShaderObj vs(m_device,vertShaderText,XGL_SHADER_STAGE_VERTEX, this);
+    XglShaderObj ps(m_device,fragShaderText, XGL_SHADER_STAGE_FRAGMENT, this);
+
+    XglConstantBufferObj mixedBuffer(m_device, constCount, sizeof(mixedVals[0]), (const void*) mixedVals);
+    vs.BindShaderEntitySlotToMemory(0, XGL_SLOT_SHADER_RESOURCE, &mixedBuffer);
+    ps.BindShaderEntitySlotToMemory(0, XGL_SLOT_SHADER_RESOURCE, &mixedBuffer);
+
+    XglPipelineObj pipelineobj(m_device);
+    pipelineobj.AddShader(&vs);
+    pipelineobj.AddShader(&ps);
+
+    XglDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AttachMemoryView(&mixedBuffer);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+    XglCommandBufferObj cmdBuffer(m_device);
+    cmdBuffer.AddRenderTarget(m_renderTargets[0]);
+
+    ASSERT_XGL_SUCCESS(cmdBuffer.BeginCommandBuffer(0));
+
+    GenericDrawPreparation(&cmdBuffer, &pipelineobj, &descriptorSet);
+
+#ifdef DUMP_STATE_DOT
+    DRAW_STATE_DUMP_DOT_FILE pDSDumpDot = (DRAW_STATE_DUMP_DOT_FILE)xglGetProcAddr(gpu(), (XGL_CHAR*)"drawStateDumpDotFile");
+    pDSDumpDot((char*)"triTest2.dot");
+#endif
+    // render triangle
+    cmdBuffer.Draw(0, 3, 0, 1);
+
+    // finalize recording of the command buffer
+    cmdBuffer.EndCommandBuffer();
+    cmdBuffer.QueueCommandBuffer(NULL, 0);
+
+    for (int i = 0; i < m_renderTargetCount; i++)
+        RecordImage(m_renderTargets[i]);
+}
+
 int main(int argc, char **argv) {
     int result;