tests: Add some geometry shader tests

render_test GeometryShaderHelloWorld
render_test GSUniformBufferLayout
render_test GSPositions
render_test GSTriStrip
diff --git a/tests/render_tests.cpp b/tests/render_tests.cpp
index bbfaa73..6c305d8 100644
--- a/tests/render_tests.cpp
+++ b/tests/render_tests.cpp
@@ -3158,6 +3158,725 @@
     RecordImages(m_renderTargets);
 }
 
+TEST_F(VkRenderTest, GeometryShaderHelloWorld)
+{
+    // This test introduces a geometry shader that simply
+    // changes the color of each vertex to red, green, blue
+
+    static const char *vertShaderText =
+            "#version 140\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout (location = 0) out vec4 color;"
+            "void main() {\n"
+
+            // VS writes out red
+            "   color = vec4(1.0, 0.0, 0.0, 1.0);\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 *geomShaderText =
+            "#version 330\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout( triangles ) in;\n"
+            "layout( triangle_strip, max_vertices = 3 ) out;\n"
+            "layout( location = 0 ) in vec4 inColor[3];\n"
+            "layout( location = 0 ) out vec4 outColor;\n"
+            "void main()\n"
+            "{\n"
+
+            // first vertex, pass through red
+            "    gl_Position = gl_in[0].gl_Position;\n"
+            "    outColor = inColor[0];\n"
+            "    EmitVertex();\n"
+
+            // second vertex, green
+            "    gl_Position = gl_in[1].gl_Position;\n"
+            "    outColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+            "    EmitVertex();\n"
+
+            // third vertex, blue
+            "    gl_Position = gl_in[2].gl_Position;\n"
+            "    outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
+            "    EmitVertex();\n"
+
+            // done
+            "    EndPrimitive();\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 (location = 0) in vec4 color;\n"
+            "void main() {\n"
+            // pass through
+            "   gl_FragColor = color;\n"
+            "}\n";
+
+
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitViewport());
+
+    VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX,   this);
+    VkShaderObj gs(m_device, geomShaderText, VK_SHADER_STAGE_GEOMETRY, this);
+    VkShaderObj ps(m_device, fragShaderText, VK_SHADER_STAGE_FRAGMENT, this);
+
+    VkPipelineObj pipelineobj(m_device);
+    pipelineobj.AddShader(&vs);
+    pipelineobj.AddShader(&gs);
+    pipelineobj.AddShader(&ps);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+    VkCommandBufferObj cmdBuffer(m_device);
+    cmdBuffer.AddRenderTarget(m_renderTargets[0]);
+
+    ASSERT_VK_SUCCESS(BeginCommandBuffer(cmdBuffer));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+
+    GenericDrawPreparation(&cmdBuffer, pipelineobj, descriptorSet);
+
+    // render triangle
+    cmdBuffer.Draw(0, 3, 0, 1);
+
+    // finalize recording of the command buffer
+    EndCommandBuffer(cmdBuffer);
+    cmdBuffer.QueueCommandBuffer();
+
+    RecordImages(m_renderTargets);
+}
+
+TEST_F(VkRenderTest, GSUniformBufferLayout)
+{
+    // This test is just like TriangleUniformBufferLayout but adds
+    // geometry as a stage that also does UBO lookups
+    // 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 *geomShaderText =
+            "#version 330\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+            // GS layout stuff
+            "layout( triangles ) in;\n"
+            "layout( triangle_strip, max_vertices = 3 ) out;\n"
+
+            // Between stage IO
+            "layout( location = 0 ) in vec4 inColor[3];\n"
+            "layout( location = 0 ) out vec4 color;\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"
+
+            "void main()\n"
+            "{\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"
+
+            // Each vertex will validate it can read VS output
+            // then check a few values from the UBO
+
+            // first vertex
+            "   vec4 outColor = inColor[0];\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"
+            "   if (projToWorld[1] != vec4(0.0, 2.0, 0.0, 0.0))\n"
+            "       outColor = wrong;\n"
+
+            "   gl_Position = gl_in[0].gl_Position;\n"
+            "   color = outColor;\n"
+            "   EmitVertex();\n"
+
+            // second vertex
+            "   outColor = inColor[1];\n"
+
+            "   if (worldToShadow[2][1] != vec4(0.0, 7.0, 0.0, 0.0))\n"
+            "       outColor = wrong;\n"
+            "   if (fSix != 6.0)\n"
+            "       outColor = wrong;\n"
+            "   if (fOneOne != vec2(1.0, 1.0))\n"
+            "       outColor = wrong;\n"
+
+            "   gl_Position = gl_in[1].gl_Position;\n"
+            "   color = outColor;\n"
+            "   EmitVertex();\n"
+
+            // third vertex
+            "   outColor = inColor[2];\n"
+
+            "   if (fSeven != 7.0)\n"
+            "       outColor = wrong;\n"
+            "   if (uvOffsets[2] != vec4(0.9, 1.0, 1.1, 1.2))\n"
+            "       outColor = wrong;\n"
+
+            "   gl_Position = gl_in[2].gl_Position;\n"
+            "   color = outColor;\n"
+            "   EmitVertex();\n"
+
+            // done
+            "    EndPrimitive();\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 GS 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);
+
+    VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX,   this);
+    VkShaderObj gs(m_device, geomShaderText, VK_SHADER_STAGE_GEOMETRY, this);
+    VkShaderObj ps(m_device, fragShaderText, VK_SHADER_STAGE_FRAGMENT, this);
+
+    VkConstantBufferObj mixedBuffer(m_device, constCount, sizeof(mixedVals[0]), (const void*) mixedVals);
+
+    VkPipelineObj pipelineobj(m_device);
+    pipelineobj.AddShader(&vs);
+    pipelineobj.AddShader(&gs);
+    pipelineobj.AddShader(&ps);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+    VkCommandBufferObj cmdBuffer(m_device);
+    cmdBuffer.AddRenderTarget(m_renderTargets[0]);
+
+    ASSERT_VK_SUCCESS(BeginCommandBuffer(cmdBuffer));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, mixedBuffer);
+
+    GenericDrawPreparation(&cmdBuffer, pipelineobj, descriptorSet);
+
+    // render triangle
+    cmdBuffer.Draw(0, 3, 0, 1);
+
+    // finalize recording of the command buffer
+    EndCommandBuffer(cmdBuffer);
+    cmdBuffer.QueueCommandBuffer();
+
+    RecordImages(m_renderTargets);
+}
+
+TEST_F(VkRenderTest, GSPositions)
+{
+    // This test adds more inputs from the vertex shader and perturbs positions
+    // Expected result is white triangle with weird positions
+
+    static const char *vertShaderText =
+            "#version 140\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+            "layout(location = 0) out vec3 out_a;\n"
+            "layout(location = 1) out vec3 out_b;\n"
+            "layout(location = 2) out vec3 out_c;\n"
+
+            "void main() {\n"
+
+            // write a solid color to each
+            "   out_a = vec3(1.0, 0.0, 0.0);\n"
+            "   out_b = vec3(0.0, 1.0, 0.0);\n"
+            "   out_c = vec3(0.0, 0.0, 1.0);\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 *geomShaderText =
+            "#version 330\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout( triangles ) in;\n"
+            "layout( triangle_strip, max_vertices = 3 ) out;\n"
+
+            "layout(location = 0) in vec3 in_a[3];\n"
+            "layout(location = 1) in vec3 in_b[3];\n"
+            "layout(location = 2) in vec3 in_c[3];\n"
+
+            "layout(location = 0) out vec3 out_a;\n"
+            "layout(location = 1) out vec3 out_b;\n"
+            "layout(location = 2) out vec3 out_c;\n"
+
+            "void main()\n"
+            "{\n"
+
+            "    gl_Position = gl_in[0].gl_Position;\n"
+            "    gl_Position.xy *= vec2(0.75);\n"
+            "    out_a = in_a[0];\n"
+            "    out_b = in_b[0];\n"
+            "    out_c = in_c[0];\n"
+            "    EmitVertex();\n"
+
+            "    gl_Position = gl_in[1].gl_Position;\n"
+            "    gl_Position.xy *= vec2(1.5);\n"
+            "    out_a = in_a[1];\n"
+            "    out_b = in_b[1];\n"
+            "    out_c = in_c[1];\n"
+            "    EmitVertex();\n"
+
+            "    gl_Position = gl_in[2].gl_Position;\n"
+            "    gl_Position.xy *= vec2(-0.1);\n"
+            "    out_a = in_a[2];\n"
+            "    out_b = in_b[2];\n"
+            "    out_c = in_c[2];\n"
+            "    EmitVertex();\n"
+
+            "    EndPrimitive();\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(location = 0) in vec3 in_a;\n"
+            "layout(location = 1) in vec3 in_b;\n"
+            "layout(location = 2) in vec3 in_c;\n"
+
+            "void main() {\n"
+            "   gl_FragColor = vec4(in_a.x, in_b.y, in_c.z, 1.0);\n"
+            "}\n";
+
+
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitViewport());
+
+    VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX,   this);
+    VkShaderObj gs(m_device, geomShaderText, VK_SHADER_STAGE_GEOMETRY, this);
+    VkShaderObj ps(m_device, fragShaderText, VK_SHADER_STAGE_FRAGMENT, this);
+
+    VkPipelineObj pipelineobj(m_device);
+    pipelineobj.AddShader(&vs);
+    pipelineobj.AddShader(&gs);
+    pipelineobj.AddShader(&ps);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+    VkCommandBufferObj cmdBuffer(m_device);
+    cmdBuffer.AddRenderTarget(m_renderTargets[0]);
+
+    ASSERT_VK_SUCCESS(BeginCommandBuffer(cmdBuffer));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+
+    GenericDrawPreparation(&cmdBuffer, pipelineobj, descriptorSet);
+
+    // render triangle
+    cmdBuffer.Draw(0, 3, 0, 1);
+
+    // finalize recording of the command buffer
+    EndCommandBuffer(cmdBuffer);
+    cmdBuffer.QueueCommandBuffer();
+
+    RecordImages(m_renderTargets);
+}
+
+TEST_F(VkRenderTest, GSTriStrip)
+{
+    // This test emits multiple multiple triangles using a GS
+    // Correct result is an multicolor circle
+
+    static const char *vertShaderText =
+            "#version 140\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+            "void main() {\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 *geomShaderText =
+            "#version 330\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+            "layout( triangles ) in;\n"
+            "layout( triangle_strip, max_vertices = 18 ) out;\n"
+
+            "layout(location = 0) out vec4 outColor;\n"
+
+            "void main()\n"
+            "{\n"
+            // init with first position to get zw
+            "    gl_Position = gl_in[0].gl_Position;\n"
+
+            "    vec4 red    = vec4(1.0, 0.0, 0.0, 1.0);\n"
+            "    vec4 yellow = vec4(1.0, 1.0, 0.0, 1.0);\n"
+            "    vec4 blue   = vec4(0.0, 0.0, 1.0, 1.0);\n"
+            "    vec4 white  = vec4(1.0, 1.0, 1.0, 1.0);\n"
+
+            // different color per tri
+            "    vec4[6] colors = { red,    white,   \n"
+            "                       yellow, white,   \n"
+            "                       blue,   white }; \n"
+
+            // fan out the triangles
+            "    vec2[18] positions = { vec2(0.0, 0.0), vec2(-0.5,   0.0), vec2(-0.25, -0.5),   \n"
+            "                           vec2(0.0, 0.0), vec2(-0.25, -0.5), vec2( 0.25, -0.5),   \n"
+            "                           vec2(0.0, 0.0), vec2( 0.25, -0.5), vec2( 0.5,   0.0),   \n"
+            "                           vec2(0.0, 0.0), vec2( 0.5,   0.0), vec2( 0.25,  0.5),   \n"
+            "                           vec2(0.0, 0.0), vec2( 0.25,  0.5), vec2(-0.25,  0.5),   \n"
+            "                           vec2(0.0, 0.0), vec2(-0.25,  0.5), vec2(-0.5,   0.0) }; \n"
+
+            // make a triangle list of 6
+            "    for (int i = 0; i < 6; ++i) { \n"
+            "        outColor = colors[i]; \n"
+            "        for (int j = 0; j < 3; ++j) { \n"
+            "            gl_Position.xy = positions[i * 3 + j]; \n"
+            "            EmitVertex(); \n"
+            "        } \n"
+            "        EndPrimitive();\n"
+            "    } \n"
+
+            "}\n";
+
+
+    static const char *fragShaderText =
+            "#version 150\n"
+            "#extension GL_ARB_separate_shader_objects : enable\n"
+            "#extension GL_ARB_shading_language_420pack : enable\n"
+
+
+            "layout(binding = 0) uniform windowDimensions {\n"
+            "    vec4 dimensions;\n"
+            "};\n"
+
+            "layout(location = 0) in vec4 inColor;\n"
+            "layout(origin_upper_left) in vec4 gl_FragCoord;\n"
+
+            "void main() {\n"
+
+            // discard to make a nice circle
+            "    vec2 pos = abs(gl_FragCoord.xy) - vec2(dimensions.x, dimensions.y) / 2;\n"
+            "    float dist = sqrt(dot(pos, pos));\n"
+            "    if (dist > 50.0)\n"
+            "        discard;\n"
+
+            "    gl_FragColor = inColor;\n"
+
+            "}\n";
+
+
+
+    ASSERT_NO_FATAL_FAILURE(InitState());
+    ASSERT_NO_FATAL_FAILURE(InitViewport());
+
+    VkShaderObj vs(m_device, vertShaderText, VK_SHADER_STAGE_VERTEX,   this);
+    VkShaderObj gs(m_device, geomShaderText, VK_SHADER_STAGE_GEOMETRY, this);
+    VkShaderObj ps(m_device, fragShaderText, VK_SHADER_STAGE_FRAGMENT, this);
+
+    VkPipelineObj pipelineobj(m_device);
+    pipelineobj.AddShader(&vs);
+    pipelineobj.AddShader(&gs);
+    pipelineobj.AddShader(&ps);
+
+    const float dimensions[4]  = { VkRenderFramework::m_width, VkRenderFramework::m_height , 0.0, 0.0};
+
+    VkConstantBufferObj windowDimensions(m_device, sizeof(dimensions) / sizeof(dimensions[0]), sizeof(dimensions[0]), (const void*) dimensions);
+
+    ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
+    VkCommandBufferObj cmdBuffer(m_device);
+    cmdBuffer.AddRenderTarget(m_renderTargets[0]);
+
+    ASSERT_VK_SUCCESS(BeginCommandBuffer(cmdBuffer));
+
+    VkDescriptorSetObj descriptorSet(m_device);
+    descriptorSet.AppendBuffer(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, windowDimensions);
+
+    GenericDrawPreparation(&cmdBuffer, pipelineobj, descriptorSet);
+
+    // render triangle
+    cmdBuffer.Draw(0, 3, 0, 1);
+
+    // finalize recording of the command buffer
+    EndCommandBuffer(cmdBuffer);
+    cmdBuffer.QueueCommandBuffer();
+
+    RecordImages(m_renderTargets);
+}
+
 int main(int argc, char **argv) {
     int result;
 
diff --git a/tests/vkrenderframework.cpp b/tests/vkrenderframework.cpp
index 9def17d..3bfa49a 100644
--- a/tests/vkrenderframework.cpp
+++ b/tests/vkrenderframework.cpp
@@ -956,8 +956,10 @@
         createInfo.codeSize = spv.size() * sizeof(unsigned int);
         createInfo.flags = 0;
 
-        init(*m_device, createInfo);
+        err = init_try(*m_device, createInfo);
     }
+
+    assert(VK_SUCCESS == err);
 }
 
 VkPipelineObj::VkPipelineObj(VkDeviceObj *device)