Add cases for structs as inout and out parameters.
authorKenneth Russell <kbr@google.com>
Mon, 23 Jul 2018 22:26:47 +0000 (15:26 -0700)
committerChris Forbes <chrisforbes@google.com>
Sat, 25 Aug 2018 02:22:56 +0000 (19:22 -0700)
Structs with lowp, mediump and highp (when supported in fragment
shaders) members are tested as inout and out parameters in both ES 2.0
and 3.0 shaders.

The highp variant of this test catches a bug which was found by the
Three.js community in https://github.com/mrdoob/three.js/issues/14137 .
Similar tests were integrated into the WebGL conformance suite in
https://github.com/KhronosGroup/WebGL/pull/2663 .

Verified on:
  Qualcomm Adreno 308 (LG Aristo) - bug reproduces in both ES2 and ES3
                                    highp fragment shaders
  Qualcomm Adreno 540 (Pixel 2),
  NVIDIA Tegra (SHIELD Tablet) - all tests pass

New tests:

dEQP-GLES[23].functional.shaders.struct.local.parameter_inout_*
dEQP-GLES[23].functional.shaders.struct.local.parameter_out_*

VK-GL-CTS Issue 1280

Change-Id: Ie332aede0ad52453815d9e123145ec035009430b
(cherry picked from commit 3b0365b1a090c4e15f72b2cb877ee15f65c8befe)

android/cts/master/gles2-master.txt
android/cts/master/gles3-master.txt
external/openglcts/data/mustpass/gles/aosp_mustpass/master/gles2-master.txt
external/openglcts/data/mustpass/gles/aosp_mustpass/master/gles3-master.txt
modules/gles2/functional/es2fShaderStructTests.cpp
modules/gles3/functional/es3fShaderStructTests.cpp

index f5b29ed..ddc36bd 100644 (file)
@@ -6813,8 +6813,20 @@ dEQP-GLES2.functional.shaders.struct.local.nested_struct_array_dynamic_index_ver
 dEQP-GLES2.functional.shaders.struct.local.nested_struct_array_dynamic_index_fragment
 dEQP-GLES2.functional.shaders.struct.local.parameter_vertex
 dEQP-GLES2.functional.shaders.struct.local.parameter_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_lowp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_lowp_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_mediump_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_mediump_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_highp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_highp_fragment
 dEQP-GLES2.functional.shaders.struct.local.parameter_nested_vertex
 dEQP-GLES2.functional.shaders.struct.local.parameter_nested_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_lowp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_lowp_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_mediump_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_mediump_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_highp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_highp_fragment
 dEQP-GLES2.functional.shaders.struct.local.return_vertex
 dEQP-GLES2.functional.shaders.struct.local.return_fragment
 dEQP-GLES2.functional.shaders.struct.local.return_nested_vertex
index e198645..8b61a93 100644 (file)
@@ -16259,8 +16259,20 @@ dEQP-GLES3.functional.shaders.struct.local.nested_struct_array_dynamic_index_ver
 dEQP-GLES3.functional.shaders.struct.local.nested_struct_array_dynamic_index_fragment
 dEQP-GLES3.functional.shaders.struct.local.parameter_vertex
 dEQP-GLES3.functional.shaders.struct.local.parameter_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_lowp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_lowp_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_mediump_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_mediump_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_highp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_highp_fragment
 dEQP-GLES3.functional.shaders.struct.local.parameter_nested_vertex
 dEQP-GLES3.functional.shaders.struct.local.parameter_nested_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_lowp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_lowp_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_mediump_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_mediump_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_highp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_highp_fragment
 dEQP-GLES3.functional.shaders.struct.local.return_vertex
 dEQP-GLES3.functional.shaders.struct.local.return_fragment
 dEQP-GLES3.functional.shaders.struct.local.return_nested_vertex
index b593acc..0803920 100644 (file)
@@ -7800,8 +7800,20 @@ dEQP-GLES2.functional.shaders.struct.local.nested_struct_array_dynamic_index_ver
 dEQP-GLES2.functional.shaders.struct.local.nested_struct_array_dynamic_index_fragment
 dEQP-GLES2.functional.shaders.struct.local.parameter_vertex
 dEQP-GLES2.functional.shaders.struct.local.parameter_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_lowp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_lowp_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_mediump_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_mediump_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_highp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_inout_highp_fragment
 dEQP-GLES2.functional.shaders.struct.local.parameter_nested_vertex
 dEQP-GLES2.functional.shaders.struct.local.parameter_nested_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_lowp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_lowp_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_mediump_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_mediump_fragment
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_highp_vertex
+dEQP-GLES2.functional.shaders.struct.local.parameter_out_highp_fragment
 dEQP-GLES2.functional.shaders.struct.local.return_vertex
 dEQP-GLES2.functional.shaders.struct.local.return_fragment
 dEQP-GLES2.functional.shaders.struct.local.return_nested_vertex
index e37db5d..c300c8c 100644 (file)
@@ -16431,8 +16431,20 @@ dEQP-GLES3.functional.shaders.struct.local.nested_struct_array_dynamic_index_ver
 dEQP-GLES3.functional.shaders.struct.local.nested_struct_array_dynamic_index_fragment
 dEQP-GLES3.functional.shaders.struct.local.parameter_vertex
 dEQP-GLES3.functional.shaders.struct.local.parameter_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_lowp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_lowp_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_mediump_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_mediump_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_highp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_inout_highp_fragment
 dEQP-GLES3.functional.shaders.struct.local.parameter_nested_vertex
 dEQP-GLES3.functional.shaders.struct.local.parameter_nested_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_lowp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_lowp_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_mediump_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_mediump_fragment
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_highp_vertex
+dEQP-GLES3.functional.shaders.struct.local.parameter_out_highp_fragment
 dEQP-GLES3.functional.shaders.struct.local.return_vertex
 dEQP-GLES3.functional.shaders.struct.local.return_fragment
 dEQP-GLES3.functional.shaders.struct.local.return_nested_vertex
index 21d84c5..b7354d8 100644 (file)
@@ -56,6 +56,7 @@ enum CaseFlags
        FLAG_USES_TEXTURES                              = (1<<0),
        FLAG_REQUIRES_DYNAMIC_LOOPS             = (1<<1),
        FLAG_REQUIRES_DYNAMIC_INDEXING  = (1<<2),
+       FLAG_REQUIRES_HIGHP_FRAGMENT    = (1<<3),
 };
 
 typedef void (*SetupUniformsFunc) (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords);
@@ -122,6 +123,10 @@ void ShaderStructCase::init (void)
                if (m_flags & FLAG_REQUIRES_DYNAMIC_INDEXING)
                        throw tcu::NotSupportedError("Dynamic indexing not supported");
 
+               if (!m_isVertexCase && (m_flags & FLAG_REQUIRES_HIGHP_FRAGMENT) &&
+                       !m_ctxInfo.isFragmentHighPrecisionSupported())
+                       throw tcu::NotSupportedError("Highp in fragment shaders not supported");
+
                throw;
        }
 
@@ -148,7 +153,7 @@ void ShaderStructCase::setupUniforms (int programID, const tcu::Vec4& constCoord
                m_setupUniforms(m_renderCtx.getFunctions(), programID, constCoords);
 }
 
-static ShaderStructCase* createStructCase (Context& context, const char* name, const char* description, bool isVertexCase, deUint32 flags, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms, const LineStream& shaderSrc)
+static ShaderStructCase* createStructCase (Context& context, const char* name, const char* description, bool isVertexCase, deUint32 flags, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms, const LineStream& shaderSrc, const std::map<std::string, std::string>* additionalParams)
 {
        static const char* defaultVertSrc =
                "attribute highp vec4 a_position;\n"
@@ -185,6 +190,8 @@ static ShaderStructCase* createStructCase (Context& context, const char* name, c
                spParams["DST"]                         = "gl_FragColor";
                spParams["ASSIGN_POS"]          = "";
        }
+       if (additionalParams)
+               spParams.insert(additionalParams->begin(), additionalParams->end());
 
        if (isVertexCase)
                return new ShaderStructCase(context, name, description, isVertexCase, flags, evalFunc, setupUniforms, StringTemplate(shaderSrc.str()).specialize(spParams).c_str(), defaultFragSrc);
@@ -209,13 +216,16 @@ public:
 
 void LocalStructTests::init (void)
 {
-       #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, FLAGS, SHADER_SRC, EVAL_FUNC_BODY)                                                                                                                         \
+       #define LOCAL_STRUCT_CASE_PARAMETERIZED(NAME, DESCRIPTION, FLAGS, SHADER_SRC, EVAL_FUNC_BODY, PARAMS)                                                                           \
                do {                                                                                                                                                                                                                                                                    \
                        struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };  /* NOLINT(EVAL_FUNC_BODY) */                                            \
-                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, FLAGS, &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                      \
-                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, FLAGS,&Eval_##NAME::eval, DE_NULL, SHADER_SRC));            \
+                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, FLAGS, &Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));      \
+                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, FLAGS,&Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));\
                } while (deGetFalse())
 
+       #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, FLAGS, SHADER_SRC, EVAL_FUNC_BODY) \
+               LOCAL_STRUCT_CASE_PARAMETERIZED(NAME, DESCRIPTION, FLAGS, SHADER_SRC, EVAL_FUNC_BODY, DE_NULL)
+
        LOCAL_STRUCT_CASE(basic, "Basic struct usage", 0,
                LineStream()
                << "${DECLARATIONS}"
@@ -526,6 +536,61 @@ void LocalStructTests::init (void)
                        c.color.xyz() = c.coords.swizzle(0,1,2);
                });
 
+       LineStream inoutSrc;
+       inoutSrc
+                       << "${DECLARATIONS}"
+                       << ""
+                       << "struct S {"
+                       << "    ${PRECISION} vec3 red;"
+                       << "    ${PRECISION} vec3 blue;"
+                       << "};"
+                       << ""
+                       << "void modify (inout S s)"
+                       << "{"
+                       << "    s.red += vec3(0.5, 0.0, 0.0);"
+                       << "    s.blue += vec3(0.0, 0.0, 0.5);"
+                       << "}"
+                       << ""
+                       << "void main (void)"
+                       << "{"
+                       << "    S s;"
+                       << "    s.red = vec3(0.5, 0.0, 0.0);"
+                       << "    s.blue = vec3(0.0, 0.0, 0.5);"
+                       << "    modify(s);"
+                       << "    ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+                       << "    if (s.red == vec3(1.0, 0.0, 0.0) && s.blue == vec3(0.0, 0.0, 1.0))"
+                       << "            ${DST} = vec4(1.0, 1.0, 1.0, 1.0);"
+                       << "    ${ASSIGN_POS}"
+                       << "}";
+
+       std::map<std::string, std::string> precisionParams;
+       precisionParams["PRECISION"] = "lowp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_lowp, "Struct with lowp members as an inout function parameter", 0,
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "mediump";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_mediump, "Struct with mediump members as an inout function parameter", 0,
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "highp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_highp, "Struct with highp members as an inout function parameter", FLAG_REQUIRES_HIGHP_FRAGMENT,
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
        LOCAL_STRUCT_CASE(parameter_nested, "Nested struct as a function parameter", 0,
                LineStream()
                << "${DECLARATIONS}"
@@ -558,6 +623,58 @@ void LocalStructTests::init (void)
                        c.color.xyz() = c.coords.swizzle(0,1,2);
                });
 
+       LineStream outSrc;
+       outSrc
+                       << "${DECLARATIONS}"
+                       << ""
+                       << "struct S {"
+                       << "    ${PRECISION} vec3 red;"
+                       << "    ${PRECISION} vec3 blue;"
+                       << "};"
+                       << ""
+                       << "void modify (out S s)"
+                       << "{"
+                       << "    s.red = vec3(1.0, 0.0, 0.0);"
+                       << "    s.blue = vec3(0.0, 0.0, 1.0);"
+                       << "}"
+                       << ""
+                       << "void main (void)"
+                       << "{"
+                       << "    S s;"
+                       << "    modify(s);"
+                       << "    ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+                       << "    if (s.red == vec3(1.0, 0.0, 0.0) && s.blue == vec3(0.0, 0.0, 1.0))"
+                       << "            ${DST} = vec4(1.0, 1.0, 1.0, 1.0);"
+                       << "    ${ASSIGN_POS}"
+                       << "}",
+
+
+       precisionParams["PRECISION"] = "lowp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_out_lowp, "Struct with lowp members as an out function parameter", 0,
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "mediump";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(parameter_out_mediump, "Struct with mediump members as an out function parameter", 0,
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "highp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_out_highp, "Struct with highp members as an out function parameter", FLAG_REQUIRES_HIGHP_FRAGMENT,
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
        LOCAL_STRUCT_CASE(return, "Struct as a return value", 0,
                LineStream()
                << "${DECLARATIONS}"
@@ -1221,8 +1338,8 @@ void UniformStructTests::init (void)
                                 static void setUniforms (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords) SET_UNIFORMS_BODY /* NOLINT(SET_UNIFORMS_BODY) */ \
                        };                                                                                                                                                                                                                                                                                                                      \
                        struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };  /* NOLINT(EVAL_FUNC_BODY) */                                                                                            \
-                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, FLAGS, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));                       \
-                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, FLAGS, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));            \
+                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, FLAGS, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC, DE_NULL));      \
+                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, FLAGS, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC, DE_NULL));\
                } while (deGetFalse())
 
        UNIFORM_STRUCT_CASE(basic, "Basic struct usage", 0,
index 66b9559..526db73 100644 (file)
@@ -115,7 +115,7 @@ void ShaderStructCase::setupUniforms (int programID, const tcu::Vec4& constCoord
                m_setupUniforms(m_renderCtx.getFunctions(), programID, constCoords);
 }
 
-static ShaderStructCase* createStructCase (Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms, const LineStream& shaderSrc)
+static ShaderStructCase* createStructCase (Context& context, const char* name, const char* description, bool isVertexCase, bool usesTextures, ShaderEvalFunc evalFunc, SetupUniformsFunc setupUniforms, const LineStream& shaderSrc, const std::map<std::string, std::string>* additionalParams)
 {
        static const char* defaultVertSrc =
                "#version 300 es\n"
@@ -159,6 +159,8 @@ static ShaderStructCase* createStructCase (Context& context, const char* name, c
                spParams["DST"]                         = "o_color";
                spParams["ASSIGN_POS"]          = "";
        }
+       if (additionalParams)
+               spParams.insert(additionalParams->begin(), additionalParams->end());
 
        if (isVertexCase)
                return new ShaderStructCase(context, name, description, isVertexCase, usesTextures, evalFunc, setupUniforms, StringTemplate(shaderSrc.str()).specialize(spParams).c_str(), defaultFragSrc);
@@ -183,13 +185,16 @@ public:
 
 void LocalStructTests::init (void)
 {
-       #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY)                                                                                                                                        \
+       #define LOCAL_STRUCT_CASE_PARAMETERIZED(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY, PARAMS)                                                                                          \
                do {                                                                                                                                                                                                                                                                    \
                        struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };  /* NOLINT(EVAL_FUNC_BODY) */                                            \
-                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, false, &Eval_##NAME::eval, DE_NULL, SHADER_SRC));                      \
-                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, false,&Eval_##NAME::eval, DE_NULL, SHADER_SRC));            \
+                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, false, &Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));      \
+                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, false,&Eval_##NAME::eval, DE_NULL, SHADER_SRC, PARAMS));\
                } while (deGetFalse())
 
+       #define LOCAL_STRUCT_CASE(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY) \
+               LOCAL_STRUCT_CASE_PARAMETERIZED(NAME, DESCRIPTION, SHADER_SRC, EVAL_FUNC_BODY, DE_NULL)
+
        LOCAL_STRUCT_CASE(basic, "Basic struct usage",
                LineStream()
                << "${HEADER}"
@@ -500,6 +505,63 @@ void LocalStructTests::init (void)
                        c.color.xyz() = c.coords.swizzle(0,1,2);
                });
 
+       LineStream inoutSrc;
+       inoutSrc
+                       << "${HEADER}"
+                       << ""
+                       << "struct S {"
+                       << "    ${PRECISION} vec3 red;"
+                       << "    ${PRECISION} vec3 blue;"
+                       << "};"
+                       << ""
+                       << "void modify (inout S s)"
+                       << "{"
+                       << "    s.red += vec3(0.5, 0.0, 0.0);"
+                       << "    s.blue += vec3(0.0, 0.0, 0.5);"
+                       << "}"
+                       << ""
+                       << "void main (void)"
+                       << "{"
+                       << "    S s;"
+                       << "    s.red = vec3(0.5, 0.0, 0.0);"
+                       << "    s.blue = vec3(0.0, 0.0, 0.5);"
+                       << "    modify(s);"
+                       << "    ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+                       << "    if (s.red == vec3(1.0, 0.0, 0.0) && s.blue == vec3(0.0, 0.0, 1.0))"
+                       << "            ${DST} = vec4(1.0, 1.0, 1.0, 1.0);"
+                       << "    ${ASSIGN_POS}"
+                       << "}";
+
+
+       std::map<std::string, std::string> precisionParams;
+
+       precisionParams["PRECISION"] = "lowp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_lowp, "Struct with lowp members as an inout function parameter",
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "mediump";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_mediump, "Struct with mediump members as an inout function parameter",
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "highp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_inout_highp, "Struct with highp members as an inout function parameter",
+               inoutSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
        LOCAL_STRUCT_CASE(parameter_nested, "Nested struct as a function parameter",
                LineStream()
                << "${HEADER}"
@@ -532,6 +594,58 @@ void LocalStructTests::init (void)
                        c.color.xyz() = c.coords.swizzle(0,1,2);
                });
 
+       LineStream outSrc;
+       outSrc
+                       << "${HEADER}"
+                       << ""
+                       << "struct S {"
+                       << "    ${PRECISION} vec3 red;"
+                       << "    ${PRECISION} vec3 blue;"
+                       << "};"
+                       << ""
+                       << "void modify (out S s)"
+                       << "{"
+                       << "    s.red = vec3(1.0, 0.0, 0.0);"
+                       << "    s.blue = vec3(0.0, 0.0, 1.0);"
+                       << "}"
+                       << ""
+                       << "void main (void)"
+                       << "{"
+                       << "    S s;"
+                       << "    modify(s);"
+                       << "    ${DST} = vec4(0.0, 0.0, 0.0, 1.0);"
+                       << "    if (s.red == vec3(1.0, 0.0, 0.0) && s.blue == vec3(0.0, 0.0, 1.0))"
+                       << "            ${DST} = vec4(1.0, 1.0, 1.0, 1.0);"
+                       << "    ${ASSIGN_POS}"
+                       << "}";
+
+       precisionParams["PRECISION"] = "lowp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_out_lowp, "Struct with lowp members as an out function parameter",
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "mediump";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_out_mediump, "Struct with mediump members as an out function parameter",
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
+       precisionParams["PRECISION"] = "highp";
+       LOCAL_STRUCT_CASE_PARAMETERIZED(
+               parameter_out_highp, "Struct with highp members as an out function parameter",
+               outSrc,
+               {
+                       c.color.xyz() = tcu::Vec3(1.0, 1.0, 1.0);
+               },
+               &precisionParams);
+
        LOCAL_STRUCT_CASE(return, "Struct as a return value",
                LineStream()
                << "${HEADER}"
@@ -1228,8 +1342,8 @@ void UniformStructTests::init (void)
                                 static void setUniforms (const glw::Functions& gl, deUint32 programID, const tcu::Vec4& constCoords) SET_UNIFORMS_BODY /* NOLINT(SET_UNIFORMS_BODY) */ \
                        };                                                                                                                                                                                                                                                                                                                      \
                        struct Eval_##NAME { static void eval (ShaderEvalContext& c) EVAL_FUNC_BODY };  /* NOLINT(EVAL_FUNC_BODY) */                                                                                            \
-                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));            \
-                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC));         \
+                       addChild(createStructCase(m_context, #NAME "_vertex", DESCRIPTION, true, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC, DE_NULL));\
+                       addChild(createStructCase(m_context, #NAME "_fragment", DESCRIPTION, false, TEXTURES, Eval_##NAME::eval, SetUniforms_##NAME::setUniforms, SHADER_SRC, DE_NULL));\
                } while (deGetFalse())
 
        UNIFORM_STRUCT_CASE(basic, "Basic struct usage", false,