Add ShaderExecutor implementation and tests
authorRobert Sipka <rsipka.uszeged@partner.samsung.com>
Fri, 28 Aug 2015 10:09:30 +0000 (12:09 +0200)
committerPeter Gal <pgal.u-szeged@partner.samsung.com>
Mon, 14 Dec 2015 16:16:53 +0000 (17:16 +0100)
14 files changed:
external/vulkancts/framework/vulkan/vkDefs.hpp
external/vulkancts/modules/vulkan/CMakeLists.txt
external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/vktTestPackage.cpp

index aff6ac4..af1c558 100644 (file)
@@ -104,8 +104,9 @@ enum { VK_NO_ATTACHMENT                             = 0xffffffff    };
 
 enum
 {
-       VK_FALSE        = 0,
-       VK_TRUE         = 1
+       VK_FALSE                = 0,
+       VK_TRUE                 = 1,
+       VK_WHOLE_SIZE   = (~0ULL),
 };
 
 typedef VKAPI_ATTR void                (VKAPI_CALL* PFN_vkVoidFunction)                                        (void);
index 7140bbc..919ef4b 100644 (file)
@@ -5,6 +5,7 @@ add_subdirectory(pipeline)
 add_subdirectory(binding_model)
 add_subdirectory(spirv_assembly)
 add_subdirectory(shaderrender)
+add_subdirectory(shaderexecutor)
 add_subdirectory(memory)
 
 include_directories(
@@ -13,6 +14,7 @@ include_directories(
        binding_model
        spirv_assembly
        shaderrender
+       shaderexecutor
        memory
        )
 
@@ -40,6 +42,7 @@ set(DEQP_VK_COMMON_LIBS
        deqp-vk-binding-model
        deqp-vk-spirv-assembly
        deqp-vk-shaderrender
+       deqp-vk-shaderexecutor
        deqp-vk-memory
        )
 
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt b/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..08eb081
--- /dev/null
@@ -0,0 +1,23 @@
+include_directories(..)
+
+set(DEQP_VK_SHADEREXECUTOR_SRCS
+   vktShaderExecutor.cpp
+   vktShaderExecutor.hpp
+   vktShaderExecutorTests.cpp
+   vktShaderExecutorTests.hpp
+
+   vktShaderCommonFunctionTests.cpp
+   vktShaderCommonFunctionTests.hpp
+   vktShaderIntegerFunctionTests.cpp
+   vktShaderIntegerFunctionTests.hpp
+   vktShaderPackingFunctionTests.cpp
+   vktShaderPackingFunctionTests.hpp
+)
+
+set(DEQP_VK_SHADEREXECUTOR_LIBS
+   tcutil
+   vkutil
+)
+
+add_library(deqp-vk-shaderexecutor STATIC ${DEQP_VK_SHADEREXECUTOR_SRCS})
+target_link_libraries(deqp-vk-shaderexecutor ${DEQP_VK_SHADEREXECUTOR_LIBS})
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.cpp
new file mode 100644 (file)
index 0000000..9902d1f
--- /dev/null
@@ -0,0 +1,2512 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Common built-in function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderCommonFunctionTests.hpp"
+#include "vktShaderExecutor.hpp"
+#include "gluContextInfo.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuFloat.hpp"
+#include "tcuInterval.hpp"
+#include "tcuFloatFormat.hpp"
+#include "deRandom.hpp"
+#include "deMath.h"
+#include "deString.h"
+#include "deArrayUtil.hpp"
+#include "deSharedPtr.hpp"
+
+namespace vkt
+{
+
+namespace shaderexecutor
+{
+
+
+using std::vector;
+using std::string;
+using tcu::TestLog;
+
+using tcu::Vec2;
+using tcu::Vec3;
+using tcu::Vec4;
+using tcu::IVec2;
+using tcu::IVec3;
+using tcu::IVec4;
+
+namespace
+{
+
+// Utilities
+
+template<typename T, int Size>
+struct VecArrayAccess
+{
+public:
+                                                                       VecArrayAccess  (const void* ptr) : m_array((tcu::Vector<T, Size>*)ptr) {}
+                                                                       ~VecArrayAccess (void) {}
+
+       const tcu::Vector<T, Size>&             operator[]              (size_t offset) const   { return m_array[offset];       }
+       tcu::Vector<T, Size>&                   operator[]              (size_t offset)                 { return m_array[offset];       }
+
+private:
+       tcu::Vector<T, Size>*                   m_array;
+};
+
+template<typename T>   T                       randomScalar    (de::Random& rnd, T minValue, T maxValue);
+template<> inline              float           randomScalar    (de::Random& rnd, float minValue, float maxValue)               { return rnd.getFloat(minValue, maxValue);      }
+template<> inline              deInt32         randomScalar    (de::Random& rnd, deInt32 minValue, deInt32 maxValue)   { return rnd.getInt(minValue, maxValue);        }
+
+template<typename T, int Size>
+inline tcu::Vector<T, Size> randomVector (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue)
+{
+       tcu::Vector<T, Size> res;
+       for (int ndx = 0; ndx < Size; ndx++)
+               res[ndx] = randomScalar<T>(rnd, minValue[ndx], maxValue[ndx]);
+       return res;
+}
+
+template<typename T, int Size>
+static void fillRandomVectors (de::Random& rnd, const tcu::Vector<T, Size>& minValue, const tcu::Vector<T, Size>& maxValue, void* dst, int numValues, int offset = 0)
+{
+       VecArrayAccess<T, Size> access(dst);
+       for (int ndx = 0; ndx < numValues; ndx++)
+               access[offset + ndx] = randomVector<T, Size>(rnd, minValue, maxValue);
+}
+
+template<typename T>
+static void fillRandomScalars (de::Random& rnd, T minValue, T maxValue, void* dst, int numValues, int offset = 0)
+{
+       T* typedPtr = (T*)dst;
+       for (int ndx = 0; ndx < numValues; ndx++)
+               typedPtr[offset + ndx] = randomScalar<T>(rnd, minValue, maxValue);
+}
+
+inline int numBitsLostInOp (float input, float output)
+{
+       const int       inExp           = tcu::Float32(input).exponent();
+       const int       outExp          = tcu::Float32(output).exponent();
+
+       return de::max(0, inExp-outExp); // Lost due to mantissa shift.
+}
+
+inline deUint32 getUlpDiff (float a, float b)
+{
+       const deUint32  aBits   = tcu::Float32(a).bits();
+       const deUint32  bBits   = tcu::Float32(b).bits();
+       return aBits > bBits ? aBits - bBits : bBits - aBits;
+}
+
+inline deUint32 getUlpDiffIgnoreZeroSign (float a, float b)
+{
+       if (tcu::Float32(a).isZero())
+               return getUlpDiff(tcu::Float32::construct(tcu::Float32(b).sign(), 0, 0).asFloat(), b);
+       else if (tcu::Float32(b).isZero())
+               return getUlpDiff(a, tcu::Float32::construct(tcu::Float32(a).sign(), 0, 0).asFloat());
+       else
+               return getUlpDiff(a, b);
+}
+
+inline bool supportsSignedZero (glu::Precision precision)
+{
+       // \note GLSL ES 3.1 doesn't really require support for -0, but we require it for highp
+       //               as it is very widely supported.
+       return precision == glu::PRECISION_HIGHP;
+}
+
+inline float getEpsFromMaxUlpDiff (float value, deUint32 ulpDiff)
+{
+       const int exp = tcu::Float32(value).exponent();
+       return tcu::Float32::construct(+1, exp, (1u<<23) | ulpDiff).asFloat() - tcu::Float32::construct(+1, exp, 1u<<23).asFloat();
+}
+
+inline deUint32 getMaxUlpDiffFromBits (int numAccurateBits)
+{
+       const int               numGarbageBits  = 23-numAccurateBits;
+       const deUint32  mask                    = (1u<<numGarbageBits)-1u;
+
+       return mask;
+}
+
+inline float getEpsFromBits (float value, int numAccurateBits)
+{
+       return getEpsFromMaxUlpDiff(value, getMaxUlpDiffFromBits(numAccurateBits));
+}
+
+static int getMinMantissaBits (glu::Precision precision)
+{
+       const int bits[] =
+       {
+               7,              // lowp
+               10,             // mediump
+               23              // highp
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bits) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(bits)));
+       return bits[precision];
+}
+
+static int getMaxNormalizedValueExponent (glu::Precision precision)
+{
+       const int exponent[] =
+       {
+               0,              // lowp
+               13,             // mediump
+               127             // highp
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
+       return exponent[precision];
+}
+
+static int getMinNormalizedValueExponent (glu::Precision precision)
+{
+       const int exponent[] =
+       {
+               -7,             // lowp
+               -13,    // mediump
+               -126    // highp
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(exponent) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(exponent)));
+       return exponent[precision];
+}
+
+static float makeFloatRepresentable (float f, glu::Precision precision)
+{
+       if (precision == glu::PRECISION_HIGHP)
+       {
+               // \note: assuming f is not extended-precision
+               return f;
+       }
+       else
+       {
+               const int                       numMantissaBits                         = getMinMantissaBits(precision);
+               const int                       maxNormalizedValueExponent      = getMaxNormalizedValueExponent(precision);
+               const int                       minNormalizedValueExponent      = getMinNormalizedValueExponent(precision);
+               const deUint32          representableMantissaMask       = ((deUint32(1) << numMantissaBits) - 1) << (23 - (deUint32)numMantissaBits);
+               const float                     largestRepresentableValue       = tcu::Float32::constructBits(+1, maxNormalizedValueExponent, ((1u << numMantissaBits) - 1u) << (23u - (deUint32)numMantissaBits)).asFloat();
+               const bool                      zeroNotRepresentable            = (precision == glu::PRECISION_LOWP);
+
+               // if zero is not required to be representable, use smallest positive non-subnormal value
+               const float                     zeroValue                                       = (zeroNotRepresentable) ? (tcu::Float32::constructBits(+1, minNormalizedValueExponent, 1).asFloat()) : (0.0f);
+
+               const tcu::Float32      float32Representation           (f);
+
+               if (float32Representation.exponent() < minNormalizedValueExponent)
+               {
+                       // flush too small values to zero
+                       return zeroValue;
+               }
+               else if (float32Representation.exponent() > maxNormalizedValueExponent)
+               {
+                       // clamp too large values
+                       return (float32Representation.sign() == +1) ? (largestRepresentableValue) : (-largestRepresentableValue);
+               }
+               else
+               {
+                       // remove unrepresentable mantissa bits
+                       const tcu::Float32 targetRepresentation(tcu::Float32::constructBits(float32Representation.sign(),
+                                                                                                       float32Representation.exponent(),
+                                                                                                       float32Representation.mantissaBits() & representableMantissaMask));
+
+                       return targetRepresentation.asFloat();
+               }
+       }
+}
+
+static vector<int> getScalarSizes (const vector<Symbol>& symbols)
+{
+       vector<int> sizes(symbols.size());
+       for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
+               sizes[ndx] = symbols[ndx].varType.getScalarSize();
+       return sizes;
+}
+
+static int computeTotalScalarSize (const vector<Symbol>& symbols)
+{
+       int totalSize = 0;
+       for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
+               totalSize += sym->varType.getScalarSize();
+       return totalSize;
+}
+
+static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
+{
+       vector<void*>   pointers                (symbols.size());
+       int                             curScalarOffset = 0;
+
+       for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
+       {
+               const Symbol&   var                             = symbols[varNdx];
+               const int               scalarSize              = var.varType.getScalarSize();
+
+               // Uses planar layout as input/output specs do not support strides.
+               pointers[varNdx] = &data[curScalarOffset];
+               curScalarOffset += scalarSize*numValues;
+       }
+
+       DE_ASSERT(curScalarOffset == (int)data.size());
+
+       return pointers;
+}
+
+// \todo [2013-08-08 pyry] Make generic utility and move to glu?
+
+struct HexFloat
+{
+       const float value;
+       HexFloat (const float value_) : value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const HexFloat& v)
+{
+       return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
+}
+
+struct HexBool
+{
+       const deUint32 value;
+       HexBool (const deUint32 value_) : value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const HexBool& v)
+{
+       return str << (v.value ? "true" : "false") << " / " << tcu::toHex(v.value);
+}
+
+struct VarValue
+{
+       const glu::VarType&     type;
+       const void*                     value;
+
+       VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
+{
+       DE_ASSERT(varValue.type.isBasicType());
+
+       const glu::DataType             basicType               = varValue.type.getBasicType();
+       const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
+       const int                               numComponents   = glu::getDataTypeScalarSize(basicType);
+
+       if (numComponents > 1)
+               str << glu::getDataTypeName(basicType) << "(";
+
+       for (int compNdx = 0; compNdx < numComponents; compNdx++)
+       {
+               if (compNdx != 0)
+                       str << ", ";
+
+               switch (scalarType)
+               {
+                       case glu::TYPE_FLOAT:   str << HexFloat(((const float*)varValue.value)[compNdx]);                       break;
+                       case glu::TYPE_INT:             str << ((const deInt32*)varValue.value)[compNdx];                                       break;
+                       case glu::TYPE_UINT:    str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);          break;
+                       case glu::TYPE_BOOL:    str << HexBool(((const deUint32*)varValue.value)[compNdx]);                     break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+
+       if (numComponents > 1)
+               str << ")";
+
+       return str;
+}
+
+static const char* getPrecisionPostfix (glu::Precision precision)
+{
+       static const char* s_postfix[] =
+       {
+               "_lowp",
+               "_mediump",
+               "_highp"
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[precision];
+}
+
+static const char* getShaderTypePostfix (glu::ShaderType shaderType)
+{
+       static const char* s_postfix[] =
+       {
+               "_vertex",
+               "_fragment",
+               "_geometry",
+               "_tess_control",
+               "_tess_eval",
+               "_compute"
+       };
+       DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[shaderType];
+}
+
+static std::string getCommonFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+{
+       return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
+}
+
+static inline void frexp (float in, float* significand, int* exponent)
+{
+       const tcu::Float32 fpValue(in);
+
+       if (!fpValue.isZero())
+       {
+               // Construct float that has exactly the mantissa, and exponent of -1.
+               *significand    = tcu::Float32::construct(fpValue.sign(), -1, fpValue.mantissa()).asFloat();
+               *exponent               = fpValue.exponent()+1;
+       }
+       else
+       {
+               *significand    = fpValue.sign() < 0 ? -0.0f : 0.0f;
+               *exponent               = 0;
+       }
+}
+
+static inline float ldexp (float significand, int exponent)
+{
+       const tcu::Float32 mant(significand);
+
+       if (exponent == 0 && mant.isZero())
+       {
+               return mant.sign() < 0 ? -0.0f : 0.0f;
+       }
+       else
+       {
+               return tcu::Float32::construct(mant.sign(), exponent+mant.exponent(), mant.mantissa()).asFloat();
+       }
+}
+
+template<class TestClass>
+static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, bool floatTypes, bool intTypes, bool uintTypes, deUint32 shaderBits)
+{
+       tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
+       parent->addChild(group);
+
+       const glu::DataType scalarTypes[] =
+       {
+               glu::TYPE_FLOAT,
+               glu::TYPE_INT,
+               glu::TYPE_UINT
+       };
+
+       for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
+       {
+               const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
+
+               if ((!floatTypes && scalarType == glu::TYPE_FLOAT)      ||
+                       (!intTypes && scalarType == glu::TYPE_INT)              ||
+                       (!uintTypes && scalarType == glu::TYPE_UINT))
+                       continue;
+
+               for (int vecSize = 1; vecSize <= 4; vecSize++)
+               {
+                       for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
+                       {
+                               for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
+                               {
+                                       if (shaderBits & (1<<shaderTypeNdx))
+                                               group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
+                               }
+                       }
+               }
+       }
+}
+
+// CommonFunctionCase
+
+class CommonFunctionCase : public TestCase
+{
+public:
+                                                                               CommonFunctionCase                      (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
+                                                                               ~CommonFunctionCase                     (void);
+       virtual void                                            initPrograms                            (vk::SourceCollections& programCollection) const
+                                                                               {
+                                                                                       m_executor->setShaderSources(programCollection);
+                                                                               }
+
+       virtual TestInstance*                           createInstance                          (Context& context) const = 0;
+
+       void                                                            init                                            (void);
+
+protected:
+                                                                               CommonFunctionCase                      (const CommonFunctionCase& other);
+       CommonFunctionCase&                                     operator=                                       (const CommonFunctionCase& other);
+
+       const glu::ShaderType                           m_shaderType;
+       ShaderSpec                                                      m_spec;
+       const int                                                       m_numValues;
+       de::MovePtr<ShaderExecutor>                     m_executor;
+};
+
+CommonFunctionCase::CommonFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
+       : TestCase              (testCtx, name, description)
+       , m_shaderType  (shaderType)
+       , m_numValues   (100)
+       , m_executor    (DE_NULL)
+{
+}
+
+CommonFunctionCase::~CommonFunctionCase (void)
+{
+}
+
+void CommonFunctionCase::init (void)
+{
+       DE_ASSERT(!m_executor);
+
+       m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_spec));
+       m_testCtx.getLog() << *m_executor;
+}
+
+// CommonFunctionTestInstance
+
+class CommonFunctionTestInstance : public TestInstance
+{
+public:
+                                                                               CommonFunctionTestInstance      (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+                                                                                       : TestInstance  (context)
+                                                                                       , m_shaderType  (shaderType)
+                                                                                       , m_spec                (spec)
+                                                                                       , m_numValues   (numValues)
+                                                                                       , m_name                (name)
+                                                                                       , m_executor    (executor)
+                                                                               {
+                                                                               }
+       virtual tcu::TestStatus                         iterate                                         (void);
+
+protected:
+       virtual void                                            getInputValues                          (int numValues, void* const* values) const = 0;
+       virtual bool                                            compare                                         (const void* const* inputs, const void* const* outputs) = 0;
+
+       const glu::ShaderType                           m_shaderType;
+       ShaderSpec                                                      m_spec;
+       const int                                                       m_numValues;
+
+       const char*                                             m_name;
+
+       std::ostringstream                                      m_failMsg;                                      //!< Comparison failure help message.
+
+       ShaderExecutor&                                         m_executor;
+};
+
+tcu::TestStatus CommonFunctionTestInstance::iterate (void)
+{
+       const int                               numInputScalars                 = computeTotalScalarSize(m_spec.inputs);
+       const int                               numOutputScalars                = computeTotalScalarSize(m_spec.outputs);
+       vector<deUint32>                inputData                               (numInputScalars * m_numValues);
+       vector<deUint32>                outputData                              (numOutputScalars * m_numValues);
+       const vector<void*>             inputPointers                   = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
+       const vector<void*>             outputPointers                  = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
+
+       // Initialize input data.
+       getInputValues(m_numValues, &inputPointers[0]);
+
+       // Execute shader.
+       m_executor.execute(m_context, m_numValues, &inputPointers[0], &outputPointers[0]);
+
+       // Compare results.
+       {
+               const vector<int>               inScalarSizes           = getScalarSizes(m_spec.inputs);
+               const vector<int>               outScalarSizes          = getScalarSizes(m_spec.outputs);
+               vector<void*>                   curInputPtr                     (inputPointers.size());
+               vector<void*>                   curOutputPtr            (outputPointers.size());
+               int                                             numFailed                       = 0;
+               tcu::TestContext&               testCtx                         = m_context.getTestContext();
+
+               for (int valNdx = 0; valNdx < m_numValues; valNdx++)
+               {
+                       // Set up pointers for comparison.
+                       for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
+                               curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
+
+                       for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
+                               curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
+
+                       if (!compare(&curInputPtr[0], &curOutputPtr[0]))
+                       {
+                               // \todo [2013-08-08 pyry] We probably want to log reference value as well?
+
+                               testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
+
+                               testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
+                               for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
+                                       testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
+                                                                                                                  << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
+                                                                          << TestLog::EndMessage;
+
+                               testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
+                               for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
+                                       testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
+                                                                                                                  << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
+                                                                          << TestLog::EndMessage;
+
+                               m_failMsg.str("");
+                               m_failMsg.clear();
+                               numFailed += 1;
+                       }
+               }
+
+               testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
+
+               if (numFailed == 0)
+                       return tcu::TestStatus::pass("Pass");
+               else
+                       return tcu::TestStatus::fail("Result comparison failed");
+       }
+}
+
+// Test cases
+
+class AbsCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       AbsCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 floatRanges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+               const IVec2 intRanges[] =
+               {
+                       IVec2(-(1<<7)+1,        (1<<7)-1),
+                       IVec2(-(1<<15)+1,       (1<<15)-1),
+                       IVec2(0x80000001,       0x7fffffff)
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x235facu);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               if (glu::isDataTypeFloatOrVec(type))
+                       fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), values[0], numValues*scalarSize);
+               else
+                       fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), values[0], numValues*scalarSize);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (glu::isDataTypeFloatOrVec(type))
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = (1u<<(23-mantissaBits))-1u;
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref0            = de::abs(in0);
+                               const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
+
+                               if (ulpDiff0 > maxUlpDiff)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const int       in0             = ((const int*)inputs[0])[compNdx];
+                               const int       out0    = ((const int*)outputs[0])[compNdx];
+                               const int       ref0    = de::abs(in0);
+
+                               if (out0 != ref0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << ref0;
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class AbsCase : public CommonFunctionCase
+{
+public:
+       AbsCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "abs", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = abs(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new AbsCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class SignCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       SignCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 floatRanges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e4f,             1e4f),  // mediump      - note: may end up as inf
+                       Vec2(-1e8f,             1e8f)   // highp        - note: may end up as inf
+               };
+               const IVec2 intRanges[] =
+               {
+                       IVec2(-(1<<7),          (1<<7)-1),
+                       IVec2(-(1<<15),         (1<<15)-1),
+                       IVec2(0x80000000,       0x7fffffff)
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x324u);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               if (glu::isDataTypeFloatOrVec(type))
+               {
+                       // Special cases.
+                       std::fill((float*)values[0], (float*)values[0] + scalarSize, +1.0f);
+                       std::fill((float*)values[0], (float*)values[0] + scalarSize, -1.0f);
+                       std::fill((float*)values[0], (float*)values[0] + scalarSize,  0.0f);
+                       fillRandomScalars(rnd, floatRanges[precision].x(), floatRanges[precision].y(), (float*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
+               }
+               else
+               {
+                       std::fill((int*)values[0], (int*)values[0] + scalarSize, +1);
+                       std::fill((int*)values[0], (int*)values[0] + scalarSize, -1);
+                       std::fill((int*)values[0], (int*)values[0] + scalarSize,  0);
+                       fillRandomScalars(rnd, intRanges[precision].x(), intRanges[precision].y(), (int*)values[0] + scalarSize*3, (numValues-3)*scalarSize);
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (glu::isDataTypeFloatOrVec(type))
+               {
+                       // Both highp and mediump should be able to represent -1, 0, and +1 exactly
+                       const deUint32 maxUlpDiff = precision == glu::PRECISION_LOWP ? getMaxUlpDiffFromBits(getMinMantissaBits(precision)) : 0;
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref0            = in0 < 0.0f ? -1.0f :
+                                                                                         in0 > 0.0f ? +1.0f : 0.0f;
+                               const deUint32  ulpDiff0        = getUlpDiff(out0, ref0);
+
+                               if (ulpDiff0 > maxUlpDiff)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " with ULP threshold " << maxUlpDiff << ", got ULP diff " << ulpDiff0;
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const int       in0             = ((const int*)inputs[0])[compNdx];
+                               const int       out0    = ((const int*)outputs[0])[compNdx];
+                               const int       ref0    = in0 < 0 ? -1 :
+                                                                         in0 > 0 ? +1 : 0;
+
+                               if (out0 != ref0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << ref0;
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class SignCase : public CommonFunctionCase
+{
+public:
+       SignCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "sign", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = sign(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new SignCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+static float roundEven (float v)
+{
+       const float             q                       = deFloatFrac(v);
+       const int               truncated       = int(v-q);
+       const int               rounded         = (q > 0.5f)                                                    ? (truncated + 1) :     // Rounded up
+                                                                       (q == 0.5f && (truncated % 2 != 0))     ? (truncated + 1) :     // Round to nearest even at 0.5
+                                                                       truncated;                                                                                              // Rounded down
+
+       return float(rounded);
+}
+
+class RoundEvenCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       RoundEvenCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               int                                             numSpecialCases = 0;
+
+               // Special cases.
+               if (precision != glu::PRECISION_LOWP)
+               {
+                       DE_ASSERT(numValues >= 20);
+                       for (int ndx = 0; ndx < 20; ndx++)
+                       {
+                               const float v = de::clamp(float(ndx) - 10.5f, ranges[precision].x(), ranges[precision].y());
+                               std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
+                               numSpecialCases += 1;
+                       }
+               }
+
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              hasSignedZero   = supportsSignedZero(precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Require exact rounding result.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref                     = roundEven(in0);
+
+                               const deUint32  ulpDiff         = hasSignedZero ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
+
+                               if (ulpDiff > 0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const int               minRes          = int(roundEven(in0-eps));
+                               const int               maxRes          = int(roundEven(in0+eps));
+                               bool                    anyOk           = false;
+
+                               for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
+                               {
+                                       const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
+
+                                       if (ulpDiff <= maxUlpDiff)
+                                       {
+                                               anyOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!anyOk)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class RoundEvenCase : public CommonFunctionCase
+{
+public:
+       RoundEvenCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "roundEven", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = roundEven(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new RoundEvenCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class ModfCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       ModfCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              hasZeroSign             = supportsSignedZero(precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               const int                               mantissaBits    = getMinMantissaBits(precision);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float             in0                     = ((const float*)inputs[0])[compNdx];
+                       const float             out0            = ((const float*)outputs[0])[compNdx];
+                       const float             out1            = ((const float*)outputs[1])[compNdx];
+
+                       const float             refOut1         = float(int(in0));
+                       const float             refOut0         = in0 - refOut1;
+
+                       const int               bitsLost        = precision != glu::PRECISION_HIGHP ? numBitsLostInOp(in0, refOut0) : 0;
+                       const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(mantissaBits - bitsLost, 0));
+
+                       const float             resSum          = out0 + out1;
+
+                       const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(resSum, in0) : getUlpDiffIgnoreZeroSign(resSum, in0);
+
+                       if (ulpDiff > maxUlpDiff)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = (" << HexFloat(refOut0) << ") + (" << HexFloat(refOut1) << ") = " << HexFloat(in0) << " with ULP threshold "
+                                                       << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class ModfCase : public CommonFunctionCase
+{
+public:
+       ModfCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "modf", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out1", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = modf(in0, out1);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new ModfCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class IsnanCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       IsnanCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xc2a39fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               mantissaBits    = getMinMantissaBits(precision);
+               const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
+
+               for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
+               {
+                       const bool              isNan           = rnd.getFloat() > 0.3f;
+                       const bool              isInf           = !isNan && rnd.getFloat() > 0.4f;
+                       const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
+                       const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
+                       const deUint32  sign            = rnd.getUint32() & 0x1u;
+                       const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
+
+                       DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
+
+                       ((deUint32*)values[0])[valNdx] = value;
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP)
+               {
+                       // Only highp is required to support inf/nan
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isNaN();
+
+                               if (out0 != ref)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
+                                       return false;
+                               }
+                       }
+               }
+               else if (precision == glu::PRECISION_MEDIUMP || precision == glu::PRECISION_LOWP)
+               {
+                       // NaN support is optional, check that inputs that are not NaN don't result in true.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isNaN();
+
+                               if (!ref && out0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class IsnanCase : public CommonFunctionCase
+{
+public:
+       IsnanCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isnan", shaderType)
+       {
+               DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
+
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
+               m_spec.source = "out0 = isnan(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new IsnanCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class IsinfCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       IsinfCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xc2a39fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               mantissaBits    = getMinMantissaBits(precision);
+               const deUint32                  mantissaMask    = ~getMaxUlpDiffFromBits(mantissaBits) & ((1u<<23)-1u);
+
+               for (int valNdx = 0; valNdx < numValues*scalarSize; valNdx++)
+               {
+                       const bool              isInf           = rnd.getFloat() > 0.3f;
+                       const bool              isNan           = !isInf && rnd.getFloat() > 0.4f;
+                       const deUint32  mantissa        = !isInf ? ((1u<<22) | (rnd.getUint32() & mantissaMask)) : 0;
+                       const deUint32  exp                     = !isNan && !isInf ? (rnd.getUint32() & 0x7fu) : 0xffu;
+                       const deUint32  sign            = rnd.getUint32() & 0x1u;
+                       const deUint32  value           = (sign << 31) | (exp << 23) | mantissa;
+
+                       DE_ASSERT(tcu::Float32(value).isInf() == isInf && tcu::Float32(value).isNaN() == isNan);
+
+                       ((deUint32*)values[0])[valNdx] = value;
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP)
+               {
+                       // Only highp is required to support inf/nan
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float32(in0).isInf();
+
+                               if (out0 != ref)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexBool(ref);
+                                       return false;
+                               }
+                       }
+               }
+               else if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Inf support is optional, check that inputs that are not Inf in mediump don't result in true.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0             = ((const float*)inputs[0])[compNdx];
+                               const bool              out0    = ((const deUint32*)outputs[0])[compNdx] != 0;
+                               const bool              ref             = tcu::Float16(in0).isInf();
+
+                               if (!ref && out0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << (ref ? "true" : "false");
+                                       return false;
+                               }
+                       }
+               }
+               // else: no verification can be performed
+
+               return true;
+       }
+};
+
+class IsinfCase : public CommonFunctionCase
+{
+public:
+       IsinfCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "isinf", shaderType)
+       {
+               DE_ASSERT(glu::isDataTypeFloatOrVec(baseType));
+
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     boolType        = vecSize > 1 ? glu::getDataTypeBoolVec(vecSize) : glu::TYPE_BOOL;
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(boolType, glu::PRECISION_LAST)));
+               m_spec.source = "out0 = isinf(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new IsinfCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FloatBitsToUintIntCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       FloatBitsToUintIntCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x2790au);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), values[0], numValues*scalarSize);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               const int                               mantissaBits    = getMinMantissaBits(precision);
+               const int                               maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float             in0                     = ((const float*)inputs[0])[compNdx];
+                       const deUint32  out0            = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  refOut0         = tcu::Float32(in0).bits();
+                       const int               ulpDiff         = de::abs((int)out0 - (int)refOut0);
+
+                       if (ulpDiff > maxUlpDiff)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(refOut0) << " with threshold "
+                                                       << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FloatBitsToUintIntCase : public CommonFunctionCase
+{
+public:
+       FloatBitsToUintIntCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType, bool outIsSigned)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), outIsSigned ? "floatBitsToInt" : "floatBitsToUint", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = outIsSigned ? (vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT)
+                                                                                                         : (vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT);
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(intType, glu::PRECISION_HIGHP)));
+               m_spec.source = outIsSigned ? "out0 = floatBitsToInt(in0);" : "out0 = floatBitsToUint(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new IsinfCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FloatBitsToIntCaseInstance : public FloatBitsToUintIntCaseInstance
+{
+public:
+       FloatBitsToIntCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : FloatBitsToUintIntCaseInstance        (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+};
+
+class FloatBitsToIntCase : public FloatBitsToUintIntCase
+{
+public:
+       FloatBitsToIntCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : FloatBitsToUintIntCase        (testCtx, baseType, precision, shaderType, true)
+       {
+       }
+
+};
+
+class FloatBitsToUintCaseInstance : public FloatBitsToUintIntCaseInstance
+{
+public:
+       FloatBitsToUintCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : FloatBitsToUintIntCaseInstance        (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+};
+
+class FloatBitsToUintCase : public FloatBitsToUintIntCase
+{
+public:
+       FloatBitsToUintCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : FloatBitsToUintIntCase        (testCtx, baseType, precision, shaderType, false)
+       {
+       }
+};
+
+class BitsToFloatCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       BitsToFloatCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xbbb225u);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+               const Vec2                              range           (-1e8f, +1e8f);
+
+               // \note Filled as floats.
+               fillRandomScalars(rnd, range.x(), range.y(), values[0], numValues*scalarSize);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const deUint32                  maxUlpDiff              = 0;
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float             in0                     = ((const float*)inputs[0])[compNdx];
+                       const float             out0            = ((const float*)outputs[0])[compNdx];
+                       const deUint32  ulpDiff         = getUlpDiff(in0, out0);
+
+                       if (ulpDiff > maxUlpDiff)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(tcu::Float32(in0).bits()) << " with ULP threshold "
+                                                       << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class BitsToFloatCase : public CommonFunctionCase
+{
+public:
+       BitsToFloatCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, glu::PRECISION_HIGHP, shaderType).c_str(), glu::isDataTypeIntOrIVec(baseType) ? "intBitsToFloat" : "uintBitsToFloat", shaderType)
+       {
+               const bool                      inIsSigned      = glu::isDataTypeIntOrIVec(baseType);
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     floatType       = vecSize > 1 ? glu::getDataTypeFloatVec(vecSize) : glu::TYPE_FLOAT;
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(floatType, glu::PRECISION_HIGHP)));
+               m_spec.source = inIsSigned ? "out0 = intBitsToFloat(in0);" : "out0 = uintBitsToFloat(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new BitsToFloatCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FloorCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       FloorCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Require exact result.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref                     = deFloatFloor(in0);
+
+                               const deUint32  ulpDiff         = getUlpDiff(out0, ref);
+
+                               if (ulpDiff > 0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const int               minRes          = int(deFloatFloor(in0-eps));
+                               const int               maxRes          = int(deFloatFloor(in0+eps));
+                               bool                    anyOk           = false;
+
+                               for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
+                               {
+                                       const deUint32 ulpDiff = getUlpDiff(out0, float(roundedVal));
+
+                                       if (ulpDiff <= maxUlpDiff)
+                                       {
+                                               anyOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!anyOk)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FloorCase : public CommonFunctionCase
+{
+public:
+       FloorCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "floor", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = floor(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new FloorCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class TruncCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       TruncCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const float                             specialCases[]  = { 0.0f, -0.0f, -0.9f, 0.9f, 1.0f, -1.0f };
+               const int                               numSpecialCases = DE_LENGTH_OF_ARRAY(specialCases);
+
+               // Special cases
+               for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
+               {
+                       for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
+                               ((float*)values[0])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx];
+               }
+
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + scalarSize*numSpecialCases, (numValues-numSpecialCases)*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Require exact result.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const bool              isNeg           = tcu::Float32(in0).sign() < 0;
+                               const float             ref                     = isNeg ? (-float(int(-in0))) : float(int(in0));
+
+                               // \note: trunc() function definition is a bit broad on negative zeros. Ignore result sign if zero.
+                               const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
+
+                               if (ulpDiff > 0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const int               minRes          = int(in0-eps);
+                               const int               maxRes          = int(in0+eps);
+                               bool                    anyOk           = false;
+
+                               for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
+                               {
+                                       const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
+
+                                       if (ulpDiff <= maxUlpDiff)
+                                       {
+                                               anyOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!anyOk)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class TruncCase : public CommonFunctionCase
+{
+public:
+       TruncCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "trunc", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = trunc(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new TruncCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class RoundCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       RoundCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               int                                             numSpecialCases = 0;
+
+               // Special cases.
+               if (precision != glu::PRECISION_LOWP)
+               {
+                       DE_ASSERT(numValues >= 10);
+                       for (int ndx = 0; ndx < 10; ndx++)
+                       {
+                               const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
+                               std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
+                               numSpecialCases += 1;
+                       }
+               }
+
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              hasZeroSign             = supportsSignedZero(precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+
+                               if (deFloatFrac(in0) == 0.5f)
+                               {
+                                       // Allow both ceil(in) and floor(in)
+                                       const float             ref0            = deFloatFloor(in0);
+                                       const float             ref1            = deFloatCeil(in0);
+                                       const deUint32  ulpDiff0        = hasZeroSign ? getUlpDiff(out0, ref0) : getUlpDiffIgnoreZeroSign(out0, ref0);
+                                       const deUint32  ulpDiff1        = hasZeroSign ? getUlpDiff(out0, ref1) : getUlpDiffIgnoreZeroSign(out0, ref1);
+
+                                       if (ulpDiff0 > 0 && ulpDiff1 > 0)
+                                       {
+                                               m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref0) << " or " << HexFloat(ref1) << ", got ULP diff " << tcu::toHex(de::min(ulpDiff0, ulpDiff1));
+                                               return false;
+                                       }
+                               }
+                               else
+                               {
+                                       // Require exact result
+                                       const float             ref             = roundEven(in0);
+                                       const deUint32  ulpDiff = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
+
+                                       if (ulpDiff > 0)
+                                       {
+                                               m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const int               minRes          = int(roundEven(in0-eps));
+                               const int               maxRes          = int(roundEven(in0+eps));
+                               bool                    anyOk           = false;
+
+                               for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
+                               {
+                                       const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
+
+                                       if (ulpDiff <= maxUlpDiff)
+                                       {
+                                               anyOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!anyOk)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class RoundCase : public CommonFunctionCase
+{
+public:
+       RoundCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "round", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = round(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new RoundCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class CeilCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       CeilCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0], numValues*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              hasZeroSign             = supportsSignedZero(precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Require exact result.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref                     = deFloatCeil(in0);
+
+                               const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
+
+                               if (ulpDiff > 0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const deUint32  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);  // ULP diff for rounded integer value.
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const int               minRes          = int(deFloatCeil(in0-eps));
+                               const int               maxRes          = int(deFloatCeil(in0+eps));
+                               bool                    anyOk           = false;
+
+                               for (int roundedVal = minRes; roundedVal <= maxRes; roundedVal++)
+                               {
+                                       const deUint32 ulpDiff = getUlpDiffIgnoreZeroSign(out0, float(roundedVal));
+
+                                       if (ulpDiff <= maxUlpDiff)
+                                       {
+                                               anyOk = true;
+                                               break;
+                                       }
+                               }
+
+                               if (!anyOk && de::inRange(0, minRes, maxRes))
+                               {
+                                       // Allow -0 as well.
+                                       const int ulpDiff = de::abs((int)tcu::Float32(out0).bits() - (int)0x80000000u);
+                                       anyOk = ((deUint32)ulpDiff <= maxUlpDiff);
+                               }
+
+                               if (!anyOk)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = [" << minRes << ", " << maxRes << "] with ULP threshold " << tcu::toHex(maxUlpDiff);
+                                       return false;
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class CeilCase : public CommonFunctionCase
+{
+public:
+       CeilCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ceil", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = ceil(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new CeilCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FractCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       FractCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               int                                             numSpecialCases = 0;
+
+               // Special cases.
+               if (precision != glu::PRECISION_LOWP)
+               {
+                       DE_ASSERT(numValues >= 10);
+                       for (int ndx = 0; ndx < 10; ndx++)
+                       {
+                               const float v = de::clamp(float(ndx) - 5.5f, ranges[precision].x(), ranges[precision].y());
+                               std::fill((float*)values[0], (float*)values[0] + scalarSize, v);
+                               numSpecialCases += 1;
+                       }
+               }
+
+               // Random cases.
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + numSpecialCases*scalarSize, (numValues-numSpecialCases)*scalarSize);
+
+               // If precision is mediump, make sure values can be represented in fp16 exactly
+               if (precision == glu::PRECISION_MEDIUMP)
+               {
+                       for (int ndx = 0; ndx < numValues*scalarSize; ndx++)
+                               ((float*)values[0])[ndx] = tcu::Float16(((float*)values[0])[ndx]).asFloat();
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              hasZeroSign             = supportsSignedZero(precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               if (precision == glu::PRECISION_HIGHP || precision == glu::PRECISION_MEDIUMP)
+               {
+                       // Require exact result.
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+                               const float             ref                     = deFloatFrac(in0);
+
+                               const deUint32  ulpDiff         = hasZeroSign ? getUlpDiff(out0, ref) : getUlpDiffIgnoreZeroSign(out0, ref);
+
+                               if (ulpDiff > 0)
+                               {
+                                       m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                                       return false;
+                               }
+                       }
+               }
+               else
+               {
+                       const int               mantissaBits    = getMinMantissaBits(precision);
+                       const float             eps                             = getEpsFromBits(1.0f, mantissaBits);   // epsilon for rounding bounds
+
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const float             in0                     = ((const float*)inputs[0])[compNdx];
+                               const float             out0            = ((const float*)outputs[0])[compNdx];
+
+                               if (int(deFloatFloor(in0-eps)) == int(deFloatFloor(in0+eps)))
+                               {
+                                       const float             ref                     = deFloatFrac(in0);
+                                       const int               bitsLost        = numBitsLostInOp(in0, ref);
+                                       const deUint32  maxUlpDiff      = getMaxUlpDiffFromBits(de::max(0, mantissaBits-bitsLost));     // ULP diff for rounded integer value.
+                                       const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, ref);
+
+                                       if (ulpDiff > maxUlpDiff)
+                                       {
+                                               m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(ref) << " with ULP threshold " << tcu::toHex(maxUlpDiff) << ", got diff " << tcu::toHex(ulpDiff);
+                                               return false;
+                                       }
+                               }
+                               else
+                               {
+                                       if (out0 >= 1.0f)
+                                       {
+                                               m_failMsg << "Expected [" << compNdx << "] < 1.0";
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FractCase : public CommonFunctionCase
+{
+public:
+       FractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fract", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, precision)));
+               m_spec.source = "out0 = fract(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new FractCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FrexpCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       FrexpCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x2790au);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+
+               // Special cases
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       ((float*)values[0])[scalarSize*0 + compNdx] = 0.0f;
+                       ((float*)values[0])[scalarSize*1 + compNdx] = -0.0f;
+                       ((float*)values[0])[scalarSize*2 + compNdx] = 0.5f;
+                       ((float*)values[0])[scalarSize*3 + compNdx] = -0.5f;
+                       ((float*)values[0])[scalarSize*4 + compNdx] = 1.0f;
+                       ((float*)values[0])[scalarSize*5 + compNdx] = -1.0f;
+                       ((float*)values[0])[scalarSize*6 + compNdx] = 2.0f;
+                       ((float*)values[0])[scalarSize*7 + compNdx] = -2.0f;
+               }
+
+               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[0] + 8*scalarSize, (numValues-8)*scalarSize);
+
+               // Make sure the values are representable in the target format
+               for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
+               {
+                       for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
+                       {
+                               float* const valuePtr = &((float*)values[0])[caseNdx * scalarSize + scalarNdx];
+
+                               *valuePtr = makeFloatRepresentable(*valuePtr, precision);
+                       }
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                                            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision                                       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize                                      = glu::getDataTypeScalarSize(type);
+               const bool                              transitSupportsSignedZero       = (m_shaderType != glu::SHADERTYPE_FRAGMENT); // executor cannot reliably transit negative zero to fragment stage
+               const bool                              signedZero                                      = supportsSignedZero(precision) && transitSupportsSignedZero;
+
+               const int                               mantissaBits                            = getMinMantissaBits(precision);
+               const deUint32                  maxUlpDiff                                      = getMaxUlpDiffFromBits(mantissaBits);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float             in0                     = ((const float*)inputs[0])[compNdx];
+                       const float             out0            = ((const float*)outputs[0])[compNdx];
+                       const int               out1            = ((const int*)outputs[1])[compNdx];
+
+                       float                   refOut0;
+                       int                             refOut1;
+
+                       frexp(in0, &refOut0, &refOut1);
+
+                       const deUint32  ulpDiff0        = signedZero ? getUlpDiff(out0, refOut0) : getUlpDiffIgnoreZeroSign(out0, refOut0);
+
+                       if (ulpDiff0 > maxUlpDiff || out1 != refOut1)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", " << refOut1 << " with ULP threshold "
+                                                 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff0);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FrexpCase : public CommonFunctionCase
+{
+public:
+       FrexpCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "frexp", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out1", glu::VarType(intType, glu::PRECISION_HIGHP)));
+               m_spec.source = "out0 = frexp(in0, out1);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new FrexpCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class LdexpCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       LdexpCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-1e3f,             1e3f),  // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                                     (deStringHash(m_name) ^ 0x2790au);
+               const glu::DataType             type                            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision                       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize                      = glu::getDataTypeScalarSize(type);
+               int                                             valueNdx                        = 0;
+
+               {
+                       const float easySpecialCases[] = { 0.0f, -0.0f, 0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f };
+
+                       DE_ASSERT(valueNdx + DE_LENGTH_OF_ARRAY(easySpecialCases) <= numValues);
+                       for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(easySpecialCases); caseNdx++)
+                       {
+                               float   in0;
+                               int             in1;
+
+                               frexp(easySpecialCases[caseNdx], &in0, &in1);
+
+                               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               {
+                                       ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
+                                       ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
+                               }
+
+                               valueNdx += 1;
+                       }
+               }
+
+               {
+                       // \note lowp and mediump can not necessarily fit the values in hard cases, so we'll use only easy ones.
+                       const int numEasyRandomCases = precision == glu::PRECISION_HIGHP ? 50 : (numValues-valueNdx);
+
+                       DE_ASSERT(valueNdx + numEasyRandomCases <= numValues);
+                       for (int caseNdx = 0; caseNdx < numEasyRandomCases; caseNdx++)
+                       {
+                               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               {
+                                       const float     in      = rnd.getFloat(ranges[precision].x(), ranges[precision].y());
+                                       float           in0;
+                                       int                     in1;
+
+                                       frexp(in, &in0, &in1);
+
+                                       ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
+                                       ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
+                               }
+
+                               valueNdx += 1;
+                       }
+               }
+
+               {
+                       const int numHardRandomCases = numValues-valueNdx;
+                       DE_ASSERT(numHardRandomCases >= 0 && valueNdx + numHardRandomCases <= numValues);
+
+                       for (int caseNdx = 0; caseNdx < numHardRandomCases; caseNdx++)
+                       {
+                               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               {
+                                       const int               fpExp           = rnd.getInt(-126, 127);
+                                       const int               sign            = rnd.getBool() ? -1 : +1;
+                                       const deUint32  mantissa        = (1u<<23) | (rnd.getUint32() & ((1u<<23)-1));
+                                       const int               in1                     = rnd.getInt(de::max(-126, -126-fpExp), de::min(127, 127-fpExp));
+                                       const float             in0                     = tcu::Float32::construct(sign, fpExp, mantissa).asFloat();
+
+                                       DE_ASSERT(de::inRange(in1, -126, 127)); // See Khronos bug 11180
+                                       DE_ASSERT(de::inRange(in1+fpExp, -126, 127));
+
+                                       const float             out                     = ldexp(in0, in1);
+
+                                       DE_ASSERT(!tcu::Float32(out).isInf() && !tcu::Float32(out).isDenorm());
+                                       DE_UNREF(out);
+
+                                       ((float*)values[0])[valueNdx*scalarSize + compNdx] = in0;
+                                       ((int*)values[1])[valueNdx*scalarSize + compNdx] = in1;
+                               }
+
+                               valueNdx += 1;
+                       }
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               const int                               mantissaBits    = getMinMantissaBits(precision);
+               const deUint32                  maxUlpDiff              = getMaxUlpDiffFromBits(mantissaBits);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float             in0                     = ((const float*)inputs[0])[compNdx];
+                       const int               in1                     = ((const int*)inputs[1])[compNdx];
+                       const float             out0            = ((const float*)outputs[0])[compNdx];
+                       const float             refOut0         = ldexp(in0, in1);
+                       const deUint32  ulpDiff         = getUlpDiffIgnoreZeroSign(out0, refOut0);
+
+                       const int               inExp           = tcu::Float32(in0).exponent();
+
+                       if (ulpDiff > maxUlpDiff)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << HexFloat(refOut0) << ", (exp = " << inExp << ") with ULP threshold "
+                                                 << tcu::toHex(maxUlpDiff) << ", got ULP diff " << tcu::toHex(ulpDiff);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class LdexpCase : public CommonFunctionCase
+{
+public:
+       LdexpCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "ldexp", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("in1", glu::VarType(intType, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(baseType, glu::PRECISION_HIGHP)));
+               m_spec.source = "out0 = ldexp(in0, in1);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new LdexpCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FmaCaseInstance : public CommonFunctionTestInstance
+{
+public:
+       FmaCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : CommonFunctionTestInstance    (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               const Vec2 ranges[] =
+               {
+                       Vec2(-2.0f,             2.0f),  // lowp
+                       Vec2(-127.f,    127.f), // mediump
+                       Vec2(-1e7f,             1e7f)   // highp
+               };
+
+               de::Random                              rnd                                                     (deStringHash(m_name) ^ 0xac23fu);
+               const glu::DataType             type                                            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision                                       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize                                      = glu::getDataTypeScalarSize(type);
+               const float                             specialCases[][3]                       =
+               {
+                       // a            b               c
+                       { 0.0f,         0.0f,   0.0f },
+                       { 0.0f,         1.0f,   0.0f },
+                       { 0.0f,         0.0f,   -1.0f },
+                       { 1.0f,         1.0f,   0.0f },
+                       { 1.0f,         1.0f,   1.0f },
+                       { -1.0f,        1.0f,   0.0f },
+                       { 1.0f,         -1.0f,  0.0f },
+                       { -1.0f,        -1.0f,  0.0f },
+                       { -0.0f,        1.0f,   0.0f },
+                       { 1.0f,         -0.0f,  0.0f }
+               };
+               const int                               numSpecialCases                         = DE_LENGTH_OF_ARRAY(specialCases);
+
+               // Special cases
+               for (int caseNdx = 0; caseNdx < numSpecialCases; caseNdx++)
+               {
+                       for (int inputNdx = 0; inputNdx < 3; inputNdx++)
+                       {
+                               for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
+                                       ((float*)values[inputNdx])[caseNdx*scalarSize + scalarNdx] = specialCases[caseNdx][inputNdx];
+                       }
+               }
+
+               // Random cases.
+               {
+                       const int       numScalars      = (numValues-numSpecialCases)*scalarSize;
+                       const int       offs            = scalarSize*numSpecialCases;
+
+                       for (int inputNdx = 0; inputNdx < 3; inputNdx++)
+                               fillRandomScalars(rnd, ranges[precision].x(), ranges[precision].y(), (float*)values[inputNdx] + offs, numScalars);
+               }
+
+               // Make sure the values are representable in the target format
+               for (int inputNdx = 0; inputNdx < 3; inputNdx++)
+               {
+                       for (int caseNdx = 0; caseNdx < numValues; ++caseNdx)
+                       {
+                               for (int scalarNdx = 0; scalarNdx < scalarSize; scalarNdx++)
+                               {
+                                       float* const valuePtr = &((float*)values[inputNdx])[caseNdx * scalarSize + scalarNdx];
+
+                                       *valuePtr = makeFloatRepresentable(*valuePtr, precision);
+                               }
+                       }
+               }
+       }
+
+       static tcu::Interval fma (glu::Precision precision, float a, float b, float c)
+       {
+               const tcu::FloatFormat formats[] =
+               {
+                       //                               minExp         maxExp          mantissa        exact,          subnormals      infinities      NaN
+                       tcu::FloatFormat(0,                     0,                      7,                      false,          tcu::YES,       tcu::MAYBE,     tcu::MAYBE),
+                       tcu::FloatFormat(-13,           13,                     9,                      false,          tcu::MAYBE,     tcu::MAYBE,     tcu::MAYBE),
+                       tcu::FloatFormat(-126,          127,            23,                     true,           tcu::MAYBE, tcu::YES,   tcu::MAYBE)
+               };
+               const tcu::FloatFormat& format  = de::getSizedArrayElement<glu::PRECISION_LAST>(formats, precision);
+               const tcu::Interval             ia              = format.convert(a);
+               const tcu::Interval             ib              = format.convert(b);
+               const tcu::Interval             ic              = format.convert(c);
+               tcu::Interval                   prod0;
+               tcu::Interval                   prod1;
+               tcu::Interval                   prod2;
+               tcu::Interval                   prod3;
+               tcu::Interval                   prod;
+               tcu::Interval                   res;
+
+               TCU_SET_INTERVAL(prod0, tmp, tmp = ia.lo() * ib.lo());
+               TCU_SET_INTERVAL(prod1, tmp, tmp = ia.lo() * ib.hi());
+               TCU_SET_INTERVAL(prod2, tmp, tmp = ia.hi() * ib.lo());
+               TCU_SET_INTERVAL(prod3, tmp, tmp = ia.hi() * ib.hi());
+
+               prod = format.convert(format.roundOut(prod0 | prod1 | prod2 | prod3, ia.isFinite() && ib.isFinite()));
+
+               TCU_SET_INTERVAL_BOUNDS(res, tmp,
+                                                               tmp = prod.lo() + ic.lo(),
+                                                               tmp = prod.hi() + ic.hi());
+
+               return format.convert(format.roundOut(res, prod.isFinite() && ic.isFinite()));
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const float                     a                       = ((const float*)inputs[0])[compNdx];
+                       const float                     b                       = ((const float*)inputs[1])[compNdx];
+                       const float                     c                       = ((const float*)inputs[2])[compNdx];
+                       const float                     res                     = ((const float*)outputs[0])[compNdx];
+                       const tcu::Interval     ref                     = fma(precision, a, b, c);
+
+                       if (!ref.contains(res))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << ref;
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FmaCase : public CommonFunctionCase
+{
+public:
+       void init (void)
+       {
+               CommonFunctionCase::init();
+       }
+
+       FmaCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : CommonFunctionCase    (testCtx, getCommonFuncCaseName(baseType, precision, shaderType).c_str(), "fma", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("a", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("b", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("c", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("res", glu::VarType(baseType, precision)));
+               m_spec.source = "res = fma(a, b, c);";
+               m_spec.globalDeclarations = "#extension GL_EXT_gpu_shader5 : require\n";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new FmaCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+} // anonymous
+
+ShaderCommonFunctionTests::ShaderCommonFunctionTests (tcu::TestContext& testCtx)
+       : tcu::TestCaseGroup    (testCtx, "common", "Common function tests")
+{
+}
+
+ShaderCommonFunctionTests::~ShaderCommonFunctionTests (void)
+{
+}
+
+void ShaderCommonFunctionTests::init (void)
+{
+       enum
+       {
+               VS = (1<<glu::SHADERTYPE_VERTEX),
+               TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
+               TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
+               GS = (1<<glu::SHADERTYPE_GEOMETRY),
+               FS = (1<<glu::SHADERTYPE_FRAGMENT),
+               CS = (1<<glu::SHADERTYPE_COMPUTE),
+
+               ALL_SHADERS = VS|TC|TE|GS|FS|CS,
+               NEW_SHADERS = TC|TE|GS|CS,
+       };
+
+       //                                                                                                                                      Float?  Int?    Uint?   Shaders
+       addFunctionCases<AbsCase>                               (this,  "abs",                          true,   true,   false,  ALL_SHADERS);
+       addFunctionCases<SignCase>                              (this,  "sign",                         true,   true,   false,  ALL_SHADERS);
+       addFunctionCases<FloorCase>                             (this,  "floor",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<TruncCase>                             (this,  "trunc",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<RoundCase>                             (this,  "round",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<RoundEvenCase>                 (this,  "roundeven",            true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<CeilCase>                              (this,  "ceil",                         true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<FractCase>                             (this,  "fract",                        true,   false,  false,  ALL_SHADERS);
+       // mod
+       addFunctionCases<ModfCase>                              (this,  "modf",                         true,   false,  false,  ALL_SHADERS);
+       // min
+       // max
+       // clamp
+       // mix
+       // step
+       // smoothstep
+       addFunctionCases<IsnanCase>                             (this,  "isnan",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<IsinfCase>                             (this,  "isinf",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<FloatBitsToIntCase>    (this,  "floatbitstoint",       true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<FloatBitsToUintCase>   (this,  "floatbitstouint",      true,   false,  false,  ALL_SHADERS);
+
+       addFunctionCases<FrexpCase>                             (this,  "frexp",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<LdexpCase>                             (this,  "ldexp",                        true,   false,  false,  ALL_SHADERS);
+       addFunctionCases<FmaCase>                               (this,  "fma",                          true,   false,  false,  ALL_SHADERS);
+
+       // (u)intBitsToFloat()
+       {
+               const deUint32          shaderBits      = NEW_SHADERS;
+               tcu::TestCaseGroup* intGroup    = new tcu::TestCaseGroup(m_testCtx, "intbitstofloat",   "intBitsToFloat() Tests");
+               tcu::TestCaseGroup* uintGroup   = new tcu::TestCaseGroup(m_testCtx, "uintbitstofloat",  "uintBitsToFloat() Tests");
+
+               addChild(intGroup);
+               addChild(uintGroup);
+
+               for (int vecSize = 1; vecSize < 4; vecSize++)
+               {
+                       const glu::DataType             intType         = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+                       const glu::DataType             uintType        = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
+
+                       for (int shaderType = 0; shaderType < glu::SHADERTYPE_LAST; shaderType++)
+                       {
+                               if (shaderBits & (1<<shaderType))
+                               {
+                                       intGroup->addChild(new BitsToFloatCase(getTestContext(), intType, glu::ShaderType(shaderType)));
+                                       uintGroup->addChild(new BitsToFloatCase(getTestContext(), uintType, glu::ShaderType(shaderType)));
+                               }
+                       }
+               }
+       }
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderCommonFunctionTests.hpp
new file mode 100644 (file)
index 0000000..b63cd3e
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _VKTSHADERCOMMONFUNCTIONTESTS_HPP
+#define _VKTSHADERCOMMONFUNCTIONTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Common built-in function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+// ShaderCommonFunctionTests
+
+class ShaderCommonFunctionTests : public tcu::TestCaseGroup
+{
+public:
+                                                                               ShaderCommonFunctionTests       (tcu::TestContext& testCtx);
+       virtual                                                         ~ShaderCommonFunctionTests      (void);
+
+       virtual void                                            init                                            (void);
+
+private:
+                                                                               ShaderCommonFunctionTests       (const ShaderCommonFunctionTests&);             // not allowed!
+       ShaderCommonFunctionTests&                      operator=                                       (const ShaderCommonFunctionTests&);             // not allowed!
+};
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTSHADERCOMMONFUNCTIONTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp
new file mode 100644 (file)
index 0000000..2d7249e
--- /dev/null
@@ -0,0 +1,2963 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan ShaderExecutor
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderExecutor.hpp"
+#include <map>
+#include <sstream>
+#include <iostream>
+
+#include "tcuVector.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuTextureUtil.hpp"
+#include "deUniquePtr.hpp"
+#include "deStringUtil.hpp"
+#include "deSharedPtr.hpp"
+
+#include "vkMemUtil.hpp"
+#include "vkRef.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkStrUtil.hpp"
+#include "vkRefUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkDeviceUtil.hpp"
+
+#include "gluShaderUtil.hpp"
+
+using std::vector;
+using namespace vk;
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+namespace
+{
+
+enum
+{
+       DEFAULT_RENDER_WIDTH    = 100,
+       DEFAULT_RENDER_HEIGHT   = 100,
+};
+
+// Shader utilities
+
+static VkClearValue    getDefaultClearColor (void)
+{
+       return makeClearValueColorF32(0.125f, 0.25f, 0.5f, 1.0f);
+}
+
+static void checkSupported (const Context& ctx, glu::ShaderType shaderType)
+{
+       const VkPhysicalDeviceFeatures& features = ctx.getDeviceFeatures();
+
+       if (shaderType == glu::SHADERTYPE_GEOMETRY && !features.geometryShader)
+               TCU_THROW(NotSupportedError, "Geometry shader type not supported by device");
+       else if (shaderType == glu::SHADERTYPE_TESSELLATION_CONTROL && !features.tessellationShader)
+               TCU_THROW(NotSupportedError, "Tessellation shader type not supported by device");
+       else if (shaderType == glu::SHADERTYPE_TESSELLATION_EVALUATION && !features.tessellationShader)
+               TCU_THROW(NotSupportedError, "Tessellation shader type not supported by device");
+}
+
+static std::string generateEmptyFragmentSource ()
+{
+       std::ostringstream src;
+
+       src <<  "#version 310 es\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n"
+                       "layout(location=0) out highp vec4 o_color;\n";
+
+       src << "void main (void)\n{\n";
+       src << "        o_color = vec4(0.0);\n";
+       src << "}\n";
+
+       return src.str();
+}
+
+static std::string generatePassthroughVertexShader (const std::vector<Symbol>& inputs, const char* inputPrefix, const char* outputPrefix)
+{
+
+       std::ostringstream      src;
+       int                                     location        = 0;
+
+       src <<  "#version 310 es\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n"
+                       "layout(location = " << location << ") in highp vec4 a_position;\n";
+
+       for (vector<Symbol>::const_iterator input = inputs.begin(); input != inputs.end(); ++input)
+       {
+               location++;
+               src << "layout(location = "<< location << ") in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n"
+                       << "layout(location = " << location - 1 << ") flat out " << glu::declare(input->varType, outputPrefix + input->name) << ";\n";
+       }
+
+       src << "\nvoid main (void)\n{\n"
+               << "    gl_Position = a_position;\n"
+               << "    gl_PointSize = 1.0;\n";
+
+       for (vector<Symbol>::const_iterator input = inputs.begin(); input != inputs.end(); ++input)
+               src << "\t" << outputPrefix << input->name << " = " << inputPrefix << input->name << ";\n";
+
+       src << "}\n";
+
+       return src.str();
+}
+
+static std::string generateVertexShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix)
+{
+       DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
+
+       std::ostringstream      src;
+
+       src <<  "#version 310 es\n"
+               "#extension GL_ARB_separate_shader_objects : enable\n"
+               "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       src << "layout(location = 0) in highp vec4 a_position;\n";
+
+       int locationNumber = 1;
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber)
+               src <<  "layout(location = " << locationNumber << ") in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
+
+       locationNumber = 0;
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber)
+       {
+               DE_ASSERT(output->varType.isBasicType());
+
+               if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+                       const glu::VarType              intType         (intBaseType, glu::PRECISION_HIGHP);
+
+                       src << "layout(location = " << locationNumber << ") flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n";
+               }
+               else
+                       src << "layout(location = " << locationNumber << ") flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
+       }
+
+       src << "\n"
+               << "void main (void)\n"
+               << "{\n"
+               << "    gl_Position = a_position;\n"
+               << "    gl_PointSize = 1.0;\n";
+
+       // Declare & fetch local input variables
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
+               src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
+
+       // Declare local output variables
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+               src << "\t" << glu::declare(output->varType, output->name) << ";\n";
+
+       // Operation - indented to correct level.
+       {
+               std::istringstream      opSrc   (shaderSpec.source);
+               std::string                     line;
+
+               while (std::getline(opSrc, line))
+                       src << "\t" << line << "\n";
+       }
+
+       // Assignments to outputs.
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+       {
+               if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+
+                       src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
+               }
+               else
+                       src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
+       }
+
+       src << "}\n";
+
+       return src.str();
+}
+
+struct FragmentOutputLayout
+{
+       std::vector<const Symbol*>              locationSymbols;                //! Symbols by location
+       std::map<std::string, int>              locationMap;                    //! Map from symbol name to start location
+};
+
+static void generateFragShaderOutputDecl (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& outputPrefix)
+{
+       for (int outNdx = 0; outNdx < (int)shaderSpec.outputs.size(); ++outNdx)
+       {
+               const Symbol&                           output          = shaderSpec.outputs[outNdx];
+               const int                                       location        = de::lookup(outLocationMap, output.name);
+               const std::string                       outVarName      = outputPrefix + output.name;
+               glu::VariableDeclaration        decl            (output.varType, outVarName, glu::STORAGE_OUT, glu::INTERPOLATION_LAST, glu::Layout(location));
+
+               TCU_CHECK_INTERNAL(output.varType.isBasicType());
+
+               if (useIntOutputs && glu::isDataTypeFloatOrVec(output.varType.getBasicType()))
+               {
+                       const int                       vecSize                 = glu::getDataTypeScalarSize(output.varType.getBasicType());
+                       const glu::DataType     uintBasicType   = vecSize > 1 ? glu::getDataTypeUintVec(vecSize) : glu::TYPE_UINT;
+                       const glu::VarType      uintType                (uintBasicType, glu::PRECISION_HIGHP);
+
+                       decl.varType = uintType;
+                       src << decl << ";\n";
+               }
+               else if (glu::isDataTypeBoolOrBVec(output.varType.getBasicType()))
+               {
+                       const int                       vecSize                 = glu::getDataTypeScalarSize(output.varType.getBasicType());
+                       const glu::DataType     intBasicType    = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+                       const glu::VarType      intType                 (intBasicType, glu::PRECISION_HIGHP);
+
+                       decl.varType = intType;
+                       src << decl << ";\n";
+               }
+               else if (glu::isDataTypeMatrix(output.varType.getBasicType()))
+               {
+                       const int                       vecSize                 = glu::getDataTypeMatrixNumRows(output.varType.getBasicType());
+                       const int                       numVecs                 = glu::getDataTypeMatrixNumColumns(output.varType.getBasicType());
+                       const glu::DataType     uintBasicType   = glu::getDataTypeUintVec(vecSize);
+                       const glu::VarType      uintType                (uintBasicType, glu::PRECISION_HIGHP);
+
+                       decl.varType = uintType;
+                       for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
+                       {
+                               decl.name                               = outVarName + "_" + de::toString(vecNdx);
+                               decl.layout.location    = location + vecNdx;
+                               src << decl << ";\n";
+                       }
+               }
+               else
+                       src << decl << ";\n";
+       }
+}
+
+static void generateFragShaderOutAssign (std::ostream& src, const ShaderSpec& shaderSpec, bool useIntOutputs, const std::string& valuePrefix, const std::string& outputPrefix)
+{
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+       {
+               if (useIntOutputs && glu::isDataTypeFloatOrVec(output->varType.getBasicType()))
+                       src << "        o_" << output->name << " = floatBitsToUint(" << valuePrefix << output->name << ");\n";
+               else if (glu::isDataTypeMatrix(output->varType.getBasicType()))
+               {
+                       const int       numVecs         = glu::getDataTypeMatrixNumColumns(output->varType.getBasicType());
+
+                       for (int vecNdx = 0; vecNdx < numVecs; ++vecNdx)
+                               if (useIntOutputs)
+                                       src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = floatBitsToUint(" << valuePrefix << output->name << "[" << vecNdx << "]);\n";
+                               else
+                                       src << "\t" << outputPrefix << output->name << "_" << vecNdx << " = " << valuePrefix << output->name << "[" << vecNdx << "];\n";
+               }
+               else if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+
+                       src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << valuePrefix << output->name << ");\n";
+               }
+               else
+                       src << "\t" << outputPrefix << output->name << " = " << valuePrefix << output->name << ";\n";
+       }
+}
+
+static std::string generatePassthroughFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix)
+{
+       std::ostringstream      src;
+
+       src <<  "#version 310 es\n"
+               "#extension GL_ARB_separate_shader_objects : enable\n"
+               "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       int locationNumber = 0;
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber)
+       {
+               if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+                       const glu::VarType              intType         (intBaseType, glu::PRECISION_HIGHP);
+
+                       src << "layout(location = " << locationNumber << ") flat in " << glu::declare(intType, inputPrefix + output->name) << ";\n";
+               }
+               else
+                       src << "layout(location = " << locationNumber << ") flat in " << glu::declare(output->varType, inputPrefix + output->name) << ";\n";
+       }
+
+       generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
+
+       src << "\nvoid main (void)\n{\n";
+
+       generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, inputPrefix, outputPrefix);
+
+       src << "}\n";
+
+       return src.str();
+}
+
+static std::string generateGeometryShader (const ShaderSpec& shaderSpec, const std::string& inputPrefix, const std::string& outputPrefix)
+{
+       DE_ASSERT(!inputPrefix.empty() && !outputPrefix.empty());
+
+       std::ostringstream      src;
+
+       src <<  "#version 310 es\n"
+               "#extension GL_EXT_geometry_shader : require\n"
+               "#extension GL_ARB_separate_shader_objects : enable\n"
+               "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       src << "layout(points) in;\n"
+               << "layout(points, max_vertices = 1) out;\n";
+
+       int locationNumber = 0;
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber)
+               src << "layout(location = " << locationNumber << ") flat in " << glu::declare(input->varType, inputPrefix + input->name) << "[];\n";
+
+       locationNumber = 0;
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output, ++locationNumber)
+       {
+               DE_ASSERT(output->varType.isBasicType());
+
+               if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+                       const glu::VarType              intType         (intBaseType, glu::PRECISION_HIGHP);
+
+                       src << "layout(location = " << locationNumber << ") flat out " << glu::declare(intType, outputPrefix + output->name) << ";\n";
+               }
+               else
+                       src << "layout(location = " << locationNumber << ") flat out " << glu::declare(output->varType, outputPrefix + output->name) << ";\n";
+       }
+
+       src << "\n"
+               << "void main (void)\n"
+               << "{\n"
+               << "    gl_Position = gl_in[0].gl_Position;\n\n";
+
+       // Fetch input variables
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
+               src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << "[0];\n";
+
+       // Declare local output variables.
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+               src << "\t" << glu::declare(output->varType, output->name) << ";\n";
+
+       src << "\n";
+
+       // Operation - indented to correct level.
+       {
+               std::istringstream      opSrc   (shaderSpec.source);
+               std::string                     line;
+
+               while (std::getline(opSrc, line))
+                       src << "\t" << line << "\n";
+       }
+
+       // Assignments to outputs.
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+       {
+               if (glu::isDataTypeBoolOrBVec(output->varType.getBasicType()))
+               {
+                       const int                               vecSize         = glu::getDataTypeScalarSize(output->varType.getBasicType());
+                       const glu::DataType             intBaseType     = vecSize > 1 ? glu::getDataTypeIntVec(vecSize) : glu::TYPE_INT;
+
+                       src << "\t" << outputPrefix << output->name << " = " << glu::getDataTypeName(intBaseType) << "(" << output->name << ");\n";
+               }
+               else
+                       src << "\t" << outputPrefix << output->name << " = " << output->name << ";\n";
+       }
+
+       src << "        EmitVertex();\n"
+               << "    EndPrimitive();\n"
+               << "}\n";
+
+       return src.str();
+}
+
+static std::string generateFragmentShader (const ShaderSpec& shaderSpec, bool useIntOutputs, const std::map<std::string, int>& outLocationMap, const std::string& inputPrefix, const std::string& outputPrefix)
+{
+       std::ostringstream src;
+       src <<  "#version 310 es\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       int locationNumber = 0;
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input, ++locationNumber)
+               src << "layout(location = " << locationNumber << ") flat in " << glu::declare(input->varType, inputPrefix + input->name) << ";\n";
+
+       generateFragShaderOutputDecl(src, shaderSpec, useIntOutputs, outLocationMap, outputPrefix);
+
+       src << "\nvoid main (void)\n{\n";
+
+       // Declare & fetch local input variables
+       for (vector<Symbol>::const_iterator input = shaderSpec.inputs.begin(); input != shaderSpec.inputs.end(); ++input)
+               src << "\t" << glu::declare(input->varType, input->name) << " = " << inputPrefix << input->name << ";\n";
+
+       // Declare output variables
+       for (vector<Symbol>::const_iterator output = shaderSpec.outputs.begin(); output != shaderSpec.outputs.end(); ++output)
+               src << "\t" << glu::declare(output->varType, output->name) << ";\n";
+
+       // Operation - indented to correct level.
+       {
+               std::istringstream      opSrc   (shaderSpec.source);
+               std::string                     line;
+
+               while (std::getline(opSrc, line))
+                       src << "\t" << line << "\n";
+       }
+
+       generateFragShaderOutAssign(src, shaderSpec, useIntOutputs, "", outputPrefix);
+
+       src << "}\n";
+
+       return src.str();
+}
+
+// FragmentOutExecutor
+
+class FragmentOutExecutor : public ShaderExecutor
+{
+public:
+                                                                                                               FragmentOutExecutor             (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                                                                                         ~FragmentOutExecutor    (void);
+
+       virtual void                                                                            execute                                 (const Context&                 ctx,
+                                                                                                                                                                int                                    numValues,
+                                                                                                                                                                const void* const*             inputs,
+                                                                                                                                                                void* const*                   outputs);
+
+protected:
+       const FragmentOutputLayout                                                      m_outputLayout;
+private:
+       void                                                                                            bindAttributes                  (const Context&                 ctx,
+                                                                                                                                                                Allocator&                             memAlloc,
+                                                                                                                                                                int                                    numValues,
+                                                                                                                                                                const void* const*             inputs);
+                                                                                                                                                                
+       void                                                                                            addAttribute                    (const Context&                 ctx,
+                                                                                                                                                                Allocator&                             memAlloc,
+                                                                                                                                                                deUint32                               bindingLocation,
+                                                                                                                                                                VkFormat                               format,
+                                                                                                                                                                deUint32                               sizePerElement,
+                                                                                                                                                                deUint32                               count,
+                                                                                                                                                                const void*                    dataPtr);
+       // reinit render data members
+       virtual void                                                                            clearRenderData                 (void);
+       
+       typedef de::SharedPtr<Unique<VkImage> >                         VkImageSp;
+       typedef de::SharedPtr<Unique<VkImageView> >                     VkImageViewSp;
+       typedef de::SharedPtr<Unique<VkBuffer> >                        VkBufferSp;
+       typedef de::SharedPtr<de::UniquePtr<Allocation> >       AllocationSp;
+
+       std::vector<VkVertexInputBindingDescription>            m_vertexBindingDescriptions;
+       std::vector<VkVertexInputAttributeDescription>          m_vertexAttributeDescriptions;
+       std::vector<VkBufferSp>                                                         m_vertexBuffers;
+       std::vector<AllocationSp>                                                       m_vertexBufferAllocs;
+};
+
+static FragmentOutputLayout computeFragmentOutputLayout (const std::vector<Symbol>& symbols)
+{
+       FragmentOutputLayout    ret;
+       int                                             location        = 0;
+
+       for (std::vector<Symbol>::const_iterator it = symbols.begin(); it != symbols.end(); ++it)
+       {
+               const int       numLocations    = glu::getDataTypeNumLocations(it->varType.getBasicType());
+
+               TCU_CHECK_INTERNAL(!de::contains(ret.locationMap, it->name));
+               de::insert(ret.locationMap, it->name, location);
+               location += numLocations;
+
+               for (int ndx = 0; ndx < numLocations; ++ndx)
+                       ret.locationSymbols.push_back(&*it);
+       }
+
+       return ret;
+}
+
+FragmentOutExecutor::FragmentOutExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : ShaderExecutor        (shaderSpec, shaderType)
+       , m_outputLayout        (computeFragmentOutputLayout(m_shaderSpec.outputs))
+{
+}
+
+FragmentOutExecutor::~FragmentOutExecutor (void)
+{
+}
+
+static std::vector<tcu::Vec2> computeVertexPositions (int numValues, const tcu::IVec2& renderSize)
+{
+       std::vector<tcu::Vec2> positions(numValues);
+       for (int valNdx = 0; valNdx < numValues; valNdx++)
+       {
+               const int               ix              = valNdx % renderSize.x();
+               const int               iy              = valNdx / renderSize.x();
+               const float             fx              = -1.0f + 2.0f*((float(ix) + 0.5f) / float(renderSize.x()));
+               const float             fy              = -1.0f + 2.0f*((float(iy) + 0.5f) / float(renderSize.y()));
+
+               positions[valNdx] = tcu::Vec2(fx, fy);
+       }
+
+       return positions;
+}
+
+static tcu::TextureFormat getRenderbufferFormatForOutput (const glu::VarType& outputType, bool useIntOutputs)
+{
+       const tcu::TextureFormat::ChannelOrder channelOrderMap[] =
+       {
+               tcu::TextureFormat::R,
+               tcu::TextureFormat::RG,
+               tcu::TextureFormat::RGBA,       // No RGB variants available.
+               tcu::TextureFormat::RGBA
+       };
+
+       const glu::DataType                                     basicType               = outputType.getBasicType();
+       const int                                                       numComps                = glu::getDataTypeNumComponents(basicType);
+       tcu::TextureFormat::ChannelType         channelType;
+
+       switch (glu::getDataTypeScalarType(basicType))
+       {
+               case glu::TYPE_UINT:    channelType = tcu::TextureFormat::UNSIGNED_INT32;                                                                                               break;
+               case glu::TYPE_INT:             channelType = tcu::TextureFormat::SIGNED_INT32;                                                                                                 break;
+               case glu::TYPE_BOOL:    channelType = tcu::TextureFormat::SIGNED_INT32;                                                                                                 break;
+               case glu::TYPE_FLOAT:   channelType = useIntOutputs ? tcu::TextureFormat::UNSIGNED_INT32 : tcu::TextureFormat::FLOAT;   break;
+               default:
+                       throw tcu::InternalError("Invalid output type");
+       }
+
+       DE_ASSERT(de::inRange<int>(numComps, 1, DE_LENGTH_OF_ARRAY(channelOrderMap)));
+
+       return tcu::TextureFormat(channelOrderMap[numComps-1], channelType);
+}
+
+
+static VkFormat getAttributeFormat (const glu::DataType dataType)
+{
+       switch (dataType)
+       {
+               case glu::TYPE_FLOAT:                   return VK_FORMAT_R32_SFLOAT;
+               case glu::TYPE_FLOAT_VEC2:              return VK_FORMAT_R32G32_SFLOAT;
+               case glu::TYPE_FLOAT_VEC3:              return VK_FORMAT_R32G32B32_SFLOAT;
+               case glu::TYPE_FLOAT_VEC4:              return VK_FORMAT_R32G32B32A32_SFLOAT;
+
+               case glu::TYPE_INT:                             return VK_FORMAT_R32_SINT;
+               case glu::TYPE_INT_VEC2:                return VK_FORMAT_R32G32_SINT;
+               case glu::TYPE_INT_VEC3:                return VK_FORMAT_R32G32B32_SINT;
+               case glu::TYPE_INT_VEC4:                return VK_FORMAT_R32G32B32A32_SINT;
+
+               case glu::TYPE_UINT:                    return VK_FORMAT_R32_UINT;
+               case glu::TYPE_UINT_VEC2:               return VK_FORMAT_R32G32_UINT;
+               case glu::TYPE_UINT_VEC3:               return VK_FORMAT_R32G32B32_UINT;
+               case glu::TYPE_UINT_VEC4:               return VK_FORMAT_R32G32B32A32_UINT;
+
+               case glu::TYPE_FLOAT_MAT2:              return VK_FORMAT_R32G32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT2X3:    return VK_FORMAT_R32G32B32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT2X4:    return VK_FORMAT_R32G32B32A32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT3X2:    return VK_FORMAT_R32G32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT3:              return VK_FORMAT_R32G32B32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT3X4:    return VK_FORMAT_R32G32B32A32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT4X2:    return VK_FORMAT_R32G32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT4X3:    return VK_FORMAT_R32G32B32_SFLOAT;
+               case glu::TYPE_FLOAT_MAT4:              return VK_FORMAT_R32G32B32A32_SFLOAT;
+               default:
+                       DE_ASSERT(false);
+                       return VK_FORMAT_UNDEFINED;
+       }
+}
+
+void FragmentOutExecutor::addAttribute (const Context& ctx, Allocator& memAlloc, deUint32 bindingLocation, VkFormat format, deUint32 sizePerElement, deUint32 count, const void* dataPtr)
+{
+       // Add binding specification
+       const deUint32 binding = (deUint32)m_vertexBindingDescriptions.size();
+       const VkVertexInputBindingDescription bindingDescription =
+       {
+               binding,
+               sizePerElement,
+               VK_VERTEX_INPUT_RATE_VERTEX
+       };
+
+       m_vertexBindingDescriptions.push_back(bindingDescription);
+
+       // Add location and format specification
+       const VkVertexInputAttributeDescription attributeDescription =
+       {
+               bindingLocation,                        // deUint32     location;
+               binding,                                        // deUint32     binding;
+               format,                                         // VkFormat     format;
+               0u,                                                     // deUint32     offsetInBytes;
+       };
+
+       m_vertexAttributeDescriptions.push_back(attributeDescription);
+
+       // Upload data to buffer
+       const VkDevice                          vkDevice                        = ctx.getDevice();
+       const DeviceInterface&          vk                                      = ctx.getDeviceInterface();
+       const deUint32                          queueFamilyIndex        = ctx.getUniversalQueueFamilyIndex();
+
+       const VkDeviceSize inputSize = sizePerElement * count;
+       const VkBufferCreateInfo vertexBufferParams =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+               DE_NULL,                                                                        // const void*                  pNext;
+               0u,                                                                                     // VkBufferCreateFlags  flags;
+               inputSize,                                                                      // VkDeviceSize                 size;
+               VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,                      // VkBufferUsageFlags   usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+               1u,                                                                                     // deUint32                             queueFamilyCount;
+               &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+       };
+
+       Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &vertexBufferParams);
+       de::MovePtr<Allocation> alloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *buffer), MemoryRequirement::HostVisible);
+       VK_CHECK(vk.bindBufferMemory(vkDevice, *buffer, alloc->getMemory(), alloc->getOffset()));
+
+       deMemcpy(alloc->getHostPtr(), dataPtr, inputSize);
+       flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), inputSize);
+
+       m_vertexBuffers.push_back(de::SharedPtr<Unique<VkBuffer> >(new Unique<VkBuffer>(buffer)));
+       m_vertexBufferAllocs.push_back(de::SharedPtr<de::UniquePtr<Allocation> >(new de::UniquePtr<Allocation>(alloc)));
+}
+
+void FragmentOutExecutor::bindAttributes (const Context& ctx, Allocator& memAlloc, int numValues, const void* const* inputs)
+{
+       // Input attributes
+       for (int inputNdx = 0; inputNdx < (int)m_shaderSpec.inputs.size(); inputNdx++)
+       {
+               const Symbol&           symbol                  = m_shaderSpec.inputs[inputNdx];
+               const void*                     ptr                             = inputs[inputNdx];
+               const glu::DataType     basicType               = symbol.varType.getBasicType();
+               const int                       vecSize                 = glu::getDataTypeScalarSize(basicType);
+               const VkFormat          format                  = getAttributeFormat(basicType);
+               int                                     elementSize     = 0;
+               int                                     numAttrsToAdd   = 1;
+
+               if (glu::isDataTypeFloatOrVec(basicType))
+                       elementSize = sizeof(float);
+               else if (glu::isDataTypeIntOrIVec(basicType))
+                       elementSize = sizeof(int);
+               else if (glu::isDataTypeUintOrUVec(basicType))
+                       elementSize = sizeof(deUint32);
+               else if (glu::isDataTypeMatrix(basicType))
+               {
+                       int             numRows = glu::getDataTypeMatrixNumRows(basicType);
+                       int             numCols = glu::getDataTypeMatrixNumColumns(basicType);
+
+                       elementSize = numRows * numCols * (int)sizeof(float);
+                       numAttrsToAdd = numCols;
+               }
+               else
+                       DE_ASSERT(false);
+
+               // add attributes, in case of matrix every column is binded as an attribute
+               for (int attrNdx = 0; attrNdx < numAttrsToAdd; attrNdx++)
+               {
+                       addAttribute(ctx, memAlloc, (deUint32)m_vertexBindingDescriptions.size(), format, elementSize * vecSize, numValues, ptr);
+               }
+       }
+}
+
+void FragmentOutExecutor::clearRenderData (void)
+{
+       m_vertexBindingDescriptions.clear();
+       m_vertexAttributeDescriptions.clear();
+       m_vertexBuffers.clear();
+       m_vertexBufferAllocs.clear();
+}
+
+void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs)
+{
+       checkSupported(ctx, m_shaderType);
+
+       const VkDevice                                                                          vkDevice                                = ctx.getDevice();
+       const DeviceInterface&                                                          vk                                              = ctx.getDeviceInterface();
+       const VkQueue                                                                           queue                                   = ctx.getUniversalQueue();
+       const deUint32                                                                          queueFamilyIndex                = ctx.getUniversalQueueFamilyIndex();
+       Allocator&                                                                                      memAlloc                                = ctx.getDefaultAllocator();
+
+       const deInt32                                                                           renderSizeX                             = de::min(static_cast<int>(DEFAULT_RENDER_WIDTH), numValues);
+       const deInt32                                                                           renderSizeY                             = (numValues / renderSizeX) + ((numValues % renderSizeX != 0) ? 1 : 0);
+       const tcu::IVec2                                                                        renderSize                              (renderSizeX, renderSizeY);
+       std::vector<tcu::Vec2>                                                          positions;
+
+       VkFormat                                                                                        colorFormat                     = VK_FORMAT_R32G32B32A32_SFLOAT;
+
+       const bool                                                                                      useGeometryShader               = m_shaderType == glu::SHADERTYPE_GEOMETRY;
+
+       std::vector<VkImageSp>                                                          colorImages;
+       std::vector<AllocationSp>                                                       colorImageAllocs;
+       std::vector<VkAttachmentDescription>                            attachments;
+       std::vector<VkClearValue>                                                       attachmentClearValues;
+       std::vector<VkImageViewSp>                                                      colorImageViews;
+
+       std::vector<VkPipelineColorBlendAttachmentState>        colorBlendAttachmentStates;
+       std::vector<VkAttachmentReference>                                      colorAttachmentReferences;
+
+       Move<VkRenderPass>                                                                      renderPass;
+       Move<VkFramebuffer>                                                                     framebuffer;
+       Move<VkPipelineLayout>                                                          pipelineLayout;
+       Move<VkPipeline>                                                                        graphicsPipeline;
+
+       Move<VkShaderModule>                                                            vertexShaderModule;
+       Move<VkShaderModule>                                                            geometryShaderModule;
+       Move<VkShaderModule>                                                            fragmentShaderModule;
+
+       Move<VkCommandPool>                                                                     cmdPool;
+       Move<VkCommandBuffer>                                                           cmdBuffer;
+
+       Move<VkFence>                                                                           fence;
+
+       clearRenderData();
+
+       // Compute positions - 1px points are used to drive fragment shading.
+       positions = computeVertexPositions(numValues, renderSize);
+
+       // Bind attributes
+       addAttribute(ctx, memAlloc, 0u, VK_FORMAT_R32G32_SFLOAT, sizeof(tcu::Vec2), (deUint32)positions.size(), &positions[0]);
+       bindAttributes(ctx, memAlloc, numValues, inputs);
+
+       // Create color images
+       {
+               const VkImageCreateInfo  colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                              sType;
+                       DE_NULL,                                                                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags                   flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                                  imageType;
+                       colorFormat,                                                                                                                            // VkFormat                                             format;
+                       { renderSize.x(), renderSize.y(), 1u },                                                                         // VkExtent3D                                   extent;
+                       1u,                                                                                                                                                     // deUint32                                             mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                             arraySize;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits                samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                                tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags                    usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                                sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                             queueFamilyCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                              pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED,                                                                                                      // VkImageLayout                                initialLayout;
+               };
+
+               const VkAttachmentDescription colorAttachmentDescription =
+               {
+                       0u,                                                                                                                                                     // VkAttachmentDescriptorFlags  flags;
+                       colorFormat,                                                                                                                            // VkFormat                                             format;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits                samples;
+                       VK_ATTACHMENT_LOAD_OP_CLEAR,                                                                                            // VkAttachmentLoadOp                   loadOp;
+                       VK_ATTACHMENT_STORE_OP_STORE,                                                                                           // VkAttachmentStoreOp                  storeOp;
+                       VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                                                                        // VkAttachmentLoadOp                   stencilLoadOp;
+                       VK_ATTACHMENT_STORE_OP_DONT_CARE,                                                                                       // VkAttachmentStoreOp                  stencilStoreOp;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                                                       // VkImageLayout                                initialLayout;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                                                                       // VkImageLayout                                finalLayout;
+               };
+
+               const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+               {
+                       VK_FALSE,                                                                                                                                       // VkBool32                                             blendEnable;
+                       VK_BLEND_FACTOR_ONE,                                                                                                            // VkBlendFactor                                srcColorBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlendFactor                                dstColorBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp                                    blendOpColor;
+                       VK_BLEND_FACTOR_ONE,                                                                                                            // VkBlendFactor                                srcAlphaBlendFactor;
+                       VK_BLEND_FACTOR_ZERO,                                                                                                           // VkBlendFactor                                destAlphaBlendFactor;
+                       VK_BLEND_OP_ADD,                                                                                                                        // VkBlendOp                                    blendOpAlpha;
+                       (VK_COLOR_COMPONENT_R_BIT |
+                        VK_COLOR_COMPONENT_G_BIT |
+                        VK_COLOR_COMPONENT_B_BIT |
+                        VK_COLOR_COMPONENT_A_BIT)                                                                                                      // VkColorComponentFlags                colorWriteMask;
+               };
+
+               for (int outNdx = 0; outNdx < (int)m_outputLayout.locationSymbols.size(); ++outNdx)
+               {
+                       Move<VkImage> colorImage = createImage(vk, vkDevice, &colorImageParams);
+                       colorImages.push_back(de::SharedPtr<Unique<VkImage> >(new Unique<VkImage>(colorImage)));
+                       attachmentClearValues.push_back(getDefaultClearColor());
+
+                       // Allocate and bind color image memory
+                       {
+                               de::MovePtr<Allocation> colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *((const VkImage*) colorImages.back().get())), MemoryRequirement::Any);
+                               VK_CHECK(vk.bindImageMemory(vkDevice, colorImages.back().get()->get(), colorImageAlloc->getMemory(), colorImageAlloc->getOffset()));
+                               colorImageAllocs.push_back(de::SharedPtr<de::UniquePtr<Allocation> >(new de::UniquePtr<Allocation>(colorImageAlloc)));
+
+                               attachments.push_back(colorAttachmentDescription);
+                               colorBlendAttachmentStates.push_back(colorBlendAttachmentState);
+
+                               const VkAttachmentReference colorAttachmentReference = {
+                                       (deUint32) (colorImages.size() - 1),                    //      deUint32                attachment;
+                                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                //      VkImageLayout   layout;
+                               };
+
+                               colorAttachmentReferences.push_back(colorAttachmentReference);
+                       }
+
+                       // Create color attachment view
+                       {
+                               const VkImageViewCreateInfo colorImageViewParams =
+                               {
+                                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,                       // VkStructureType                      sType;
+                                       DE_NULL,                                                                                        // const void*                          pNext;
+                                       0u,                                                                                                     // VkImageViewCreateFlags       flags;
+                                       colorImages.back().get()->get(),                                        // VkImage                                      image;
+                                       VK_IMAGE_VIEW_TYPE_2D,                                                          // VkImageViewType                      viewType;
+                                       colorFormat,                                                                            // VkFormat                                     format;
+                                       {
+                                               VK_COMPONENT_SWIZZLE_R,                                                 // VkComponentSwizzle           r;
+                                               VK_COMPONENT_SWIZZLE_G,                                                 // VkComponentSwizzle           g;
+                                               VK_COMPONENT_SWIZZLE_B,                                                 // VkComponentSwizzle           b;
+                                               VK_COMPONENT_SWIZZLE_A                                                  // VkComponentSwizzle           a;
+                                       },                                                                                                      // VkComponentMapping           components;
+                                       {
+                                               VK_IMAGE_ASPECT_COLOR_BIT,                                              // VkImageAspectFlags           aspectMask;
+                                               0u,                                                                                             // deUint32                                     baseMipLevel;
+                                               0u,                                                                                             // deUint32                                     mipLevels;
+                                               0u,                                                                                             // deUint32                                     baseArraySlice;
+                                               1u                                                                                              // deUint32                                     arraySize;
+                                       }                                                                                                       // VkImageSubresourceRange      subresourceRange;
+                               };
+
+                               Move<VkImageView> colorImageView = createImageView(vk, vkDevice, &colorImageViewParams);
+                               colorImageViews.push_back(de::SharedPtr<Unique<VkImageView> >(new Unique<VkImageView>(colorImageView)));
+                       }
+               }
+       }
+
+       // Create render pass
+       {
+               const VkSubpassDescription subpassDescription =
+               {
+                       0u,                                                                                                     // VkSubpassDescriptionFlags    flags;
+                       VK_PIPELINE_BIND_POINT_GRAPHICS,                                        // VkPipelineBindPoint                  pipelineBindPoint;
+                       0u,                                                                                                     // deUint32                                             inputCount;
+                       DE_NULL,                                                                                        // const VkAttachmentReference* pInputAttachments;
+                       (deUint32)colorImages.size(),                                           // deUint32                                             colorCount;
+                       &colorAttachmentReferences[0],                                          // const VkAttachmentReference* colorAttachments;
+                       DE_NULL,                                                                                        // const VkAttachmentReference* resolveAttachments;
+                       DE_NULL,                                                                                        // VkAttachmentReference                depthStencilAttachment;
+                       0u,                                                                                                     // deUint32                                             preserveCount;
+                       DE_NULL                                                                                         // const VkAttachmentReference* pPreserveAttachments;
+               };
+
+               const VkRenderPassCreateInfo renderPassParams =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // const void*                                          pNext;
+                       (VkRenderPassCreateFlags)0,                                                     // VkRenderPassCreateFlags                      flags;
+                       (deUint32)attachments.size(),                                           // deUint32                                                     attachmentCount;
+                       &attachments[0],                                                                        // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               std::vector<VkImageView> views(colorImageViews.size());
+               for (size_t i = 0; i < colorImageViews.size(); i++)
+               {
+                       views[i] = colorImageViews[i].get()->get();
+               }
+
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags     flags;
+                       *renderPass,                                                                            // VkRenderPass                                 renderPass;
+                       (deUint32)views.size(),                                                         // deUint32                                             attachmentCount;
+                       &views[0],                                                                                      // const VkImageView*                   pAttachments;
+                       (deUint32)renderSize.x(),                                                       // deUint32                                             width;
+                       (deUint32)renderSize.y(),                                                       // deUint32                                             height;
+                       1u                                                                                                      // deUint32                                             layers;
+               };
+
+               framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       (VkPipelineLayoutCreateFlags)0,                                         // VkPipelineLayoutCreateFlags  flags;
+                       0u,                                                                                                     // deUint32                                             descriptorSetCount;
+                       DE_NULL,                                                                                        // const VkDescriptorSetLayout* pSetLayouts;
+                       0u,                                                                                                     // deUint32                                             pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*   pPushConstantRanges;
+               };
+
+               pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       // Create shaders
+       {
+               vertexShaderModule              = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("vert"), 0);
+               fragmentShaderModule    = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("frag"), 0);
+
+               if (useGeometryShader)
+               {
+                       geometryShaderModule = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("geom"), 0);
+               }
+       }
+
+       // Create pipeline
+       {
+               std::vector<VkPipelineShaderStageCreateInfo> shaderStageParams;
+
+               const VkPipelineShaderStageCreateInfo vertexShaderStageParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                        // const void*                                                  pNext;
+                       (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags     flags;
+                       VK_SHADER_STAGE_VERTEX_BIT,                                                                     // VkShaderStageFlagBits                                stage;
+                       *vertexShaderModule,                                                                            // VkShaderModule                                               module;
+                       "main",                                                                                                         // const char*                                                  pName;
+                       DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+               };
+
+               const VkPipelineShaderStageCreateInfo fragmentShaderStageParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                        // const void*                                                  pNext;
+                       (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags     flags;
+                       VK_SHADER_STAGE_FRAGMENT_BIT,                                                           // VkShaderStageFlagBits                                stage;
+                       *fragmentShaderModule,                                                                          // VkShaderModule                                               module;
+                       "main",                                                                                                         // const char*                                                  pName;
+                       DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+               };
+
+               shaderStageParams.push_back(vertexShaderStageParams);
+               shaderStageParams.push_back(fragmentShaderStageParams);
+
+               if (useGeometryShader)
+               {
+                       const VkPipelineShaderStageCreateInfo geometryShaderStageParams =
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags     flags;
+                               VK_SHADER_STAGE_GEOMETRY_BIT,                                                           // VkShaderStageFlagBits                                stage;
+                               *geometryShaderModule,                                                                          // VkShaderModule                                               module;
+                               "main",                                                                                                         // VkShader                                                             shader;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       };
+
+                       shaderStageParams.push_back(geometryShaderStageParams);
+               }
+
+               const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,      // VkStructureType                                                              sType;
+                       DE_NULL,                                                                                                        // const void*                                                                  pNext;
+                       (VkPipelineVertexInputStateCreateFlags)0,                                       // VkPipelineVertexInputStateCreateFlags                flags;
+                       (deUint32)m_vertexBindingDescriptions.size(),                           // deUint32                                                                             bindingCount;
+                       &m_vertexBindingDescriptions[0],                                                        // const VkVertexInputBindingDescription*               pVertexBindingDescriptions;
+                       (deUint32)m_vertexAttributeDescriptions.size(),                         // deUint32                                                                             attributeCount;
+                       &m_vertexAttributeDescriptions[0],                                                      // const VkVertexInputAttributeDescription*             pvertexAttributeDescriptions;
+               };
+
+               const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       (VkPipelineInputAssemblyStateCreateFlags)0,                                             // VkPipelineInputAssemblyStateCreateFlags      flags;
+                       VK_PRIMITIVE_TOPOLOGY_POINT_LIST,                                                               // VkPrimitiveTopology                                          topology;
+                       DE_FALSE                                                                                                                // VkBool32                                                                     primitiveRestartEnable;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        originX;
+                       0.0f,                                           // float        originY;
+                       (float)renderSize.x(),          // float        width;
+                       (float)renderSize.y(),          // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor =
+               {
+                       {
+                               0u,                                             // deUint32     x;
+                               0u,                                             // deUint32     y;
+                       },                                                      // VkOffset2D   offset;
+                       {
+                               renderSize.x(),                 // deUint32     width;
+                               renderSize.y(),                 // deUint32     height;
+                       },                                                      // VkExtent2D   extent;
+               };
+
+               const VkPipelineViewportStateCreateInfo viewportStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,  // VkStructureType                                                                              sType;
+                       DE_NULL,                                                                                                // const void*                                                                                  pNext;
+                       0u,                                                                                                             // VkPipelineViewportStateCreateFlags                                   flags;
+                       1u,                                                                                                             // deUint32                                                                                             viewportCount;
+                       &viewport,                                                                                              // const VkViewport*                                                                    pViewports;
+                       1u,                                                                                                             // deUint32                                                                                             scissorsCount;
+                       &scissor                                                                                                // const VkRect2D*                                                                              pScissors;
+               };
+
+               const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,             // VkStructureType                                                              sType;
+                       DE_NULL,                                                                                                                // const void*                                                                  pNext;
+                       (VkPipelineRasterizationStateCreateFlags)0u,                                    //VkPipelineRasterizationStateCreateFlags               flags;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                             depthClipEnable;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                             rasterizerDiscardEnable;
+                       VK_POLYGON_MODE_FILL,                                                                                   // VkPolygonMode                                                                polygonMode;
+                       VK_CULL_MODE_NONE,                                                                                              // VkCullModeFlags                                                              cullMode;
+                       VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace                                                                  frontFace;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                             depthBiasEnable;
+                       0.0f,                                                                                                                   // float                                                                                depthBias;
+                       0.0f,                                                                                                                   // float                                                                                depthBiasClamp;
+                       0.0f,                                                                                                                   // float                                                                                slopeScaledDepthBias;
+                       1.0f                                                                                                                    // float                                                                                lineWidth;
+               };
+
+               const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,               // VkStructureType                                                              sType;
+                       DE_NULL,                                                                                                                // const void*                                                                  pNext;
+                       (VkPipelineColorBlendStateCreateFlags)0,                                                // VkPipelineColorBlendStateCreateFlags                 flags;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                             logicOpEnable;
+                       VK_LOGIC_OP_COPY,                                                                                               // VkLogicOp                                                                    logicOp;
+                       (deUint32)colorBlendAttachmentStates.size(),                                    // deUint32                                                                             attachmentCount;
+                       &colorBlendAttachmentStates[0],                                                                 // const VkPipelineColorBlendAttachmentState*   pAttachments;
+                       { 0.0f, 0.0f, 0.0f, 0.0f }                                                                              // float                                                                                blendConst[4];
+               };
+
+               const VkPipelineDynamicStateCreateInfo dynamicStateInfo =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,           // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                                        // const void*                                                                          pNext;
+                       (VkPipelineDynamicStateCreateFlags)0,                                           // VkPipelineDynamicStateCreateFlags                            flags;
+                       0u,                                                                                                                     // deUint32                                                                                     dynamicStateCount;
+                       DE_NULL                                                                                                         // const VkDynamicState*                                                        pDynamicStates;
+               };
+
+               const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       (VkPipelineCreateFlags)0,                                                       // VkPipelineCreateFlags                                                        flags;
+                       (deUint32)shaderStageParams.size(),                                     // deUint32                                                                                     stageCount;
+                       &shaderStageParams[0],                                                          // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       DE_NULL,                                                                                        // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
+                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *pipelineLayout,                                                                        // VkPipelineLayout                                                                     layout;
+                       *renderPass,                                                                            // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,                     // VkStructureType              sType;
+                       DE_NULL,                                                                                        // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                           // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex,                                                                       // deUint32                             queueFamilyIndex;
+               };
+
+               cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *cmdPool,                                                                               // VkCmdPool                            cmdPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCmdBufferLevel                     level;
+                       1                                                                                               // deUint32                                     bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                              sType;
+                       DE_NULL,                                                                                // const void*                                  pNext;
+                       0u,                                                                                             // VkCmdBufferOptimizeFlags             flags;
+                       DE_NULL,                                                                                // VkRenderPass                                 renderPass;
+                       0u,                                                                                             // deUint32                                             subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                framebuffer;
+                       VK_FALSE,                                                                               // VkBool32                                     occlusionQueryEnable;
+                       (VkQueryControlFlags)0u,                                                //VkQueryControlFlags                   queryFlags;
+                       (VkQueryPipelineStatisticFlags)0u                               //VkQueryPipelineStatisticFlags pipelineStatistics;
+               };
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *renderPass,                                                                                    // VkRenderPass                 renderPass;
+                       *framebuffer,                                                                                   // VkFramebuffer                framebuffer;
+                       { { 0, 0 }, { renderSize.x(), renderSize.y() } },               // VkRect2D                             renderArea;
+                       (deUint32)attachmentClearValues.size(),                                 // deUint32                             attachmentCount;
+                       &attachmentClearValues[0]                                                               // const VkClearValue*  pAttachmentClearValues;
+               };
+
+               cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+               VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
+
+               const deUint32 numberOfVertexAttributes = (deUint32)m_vertexBuffers.size();
+               std::vector<VkDeviceSize> offsets(numberOfVertexAttributes, 0);
+
+               std::vector<VkBuffer> buffers(numberOfVertexAttributes);
+               for (size_t i = 0; i < numberOfVertexAttributes; i++)
+               {
+                       buffers[i] = m_vertexBuffers[i].get()->get();
+               }
+
+               vk.cmdBindVertexBuffers(*cmdBuffer, 0, numberOfVertexAttributes, &buffers[0], &offsets[0]);
+               vk.cmdDraw(*cmdBuffer, (deUint32)positions.size(), 1u, 0u, 0u);
+
+               vk.cmdEndRenderPass(*cmdBuffer);
+               VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+
+               fence = createFence(vk, vkDevice, &fenceParams);
+       }
+
+       // Execute Draw
+       {
+
+               const VkSubmitInfo submitInfo =
+               {
+                       VK_STRUCTURE_TYPE_SUBMIT_INFO,                  // sType
+                       DE_NULL,                                                                // pNext
+                       0u,                                                                             // waitSemaphoreCount
+                       DE_NULL,                                                                // pWaitSemaphores
+                       1u,                                                                             // commandBufferCount
+                       &cmdBuffer.get(),                                               // pCommandBuffers
+                       0u,                                                                             // signalSemaphoreCount
+                       DE_NULL                                                                 // pSignalSemaphores
+               };
+
+               VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
+               VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
+               VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), DE_TRUE, ~(0ull) /* infinity*/));
+       }
+
+       // Read back result and output
+       {
+               const VkDeviceSize imageSizeBytes = (VkDeviceSize)(4 * sizeof(deUint32) * renderSize.x() * renderSize.y());
+               const VkBufferCreateInfo readImageBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       0u,                                                                                     // VkBufferCreateFlags  flags;
+                       imageSizeBytes,                                                         // VkDeviceSize                 size;
+                       VK_BUFFER_USAGE_TRANSFER_DST_BIT,                       // VkBufferUsageFlags   usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+                       1u,                                                                                     // deUint32                             queueFamilyCount;
+                       &queueFamilyIndex,                                                      // const deUint32*              pQueueFamilyIndices;
+               };
+
+               // constants for image copy
+
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,     // VkStructureType              sType;
+                       DE_NULL,                                                                        // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,           // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex                                                        // deUint32                             queueFamilyIndex;
+               };
+
+               Move<VkCommandPool>     copyCmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+
+               const VkCommandBufferAllocateInfo cmdBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *copyCmdPool,                                                                   // VkCmdPool                            cmdPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCmdBufferLevel                     level;
+                       1u                                                                                              // deUint32                                     bufferCount;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCmdBufferOptimizeFlags                     flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       VK_FALSE,                                                                               // VkBool32                                                     occlusionQueryEnable;
+                       (VkQueryControlFlags)0,                                                 // VkQueryControlFlags                          queryFlags;
+                       (VkQueryPipelineStatisticFlags)0                                // VkQueryPipelineStatisticFlags        pipelineStatistics;
+
+               };
+
+               const VkBufferImageCopy copyParams =
+               {
+                       0u,                                                                                     // VkDeviceSize                 bufferOffset;
+                       (deUint32)renderSize.x(),                                       // deUint32                             bufferRowLength;
+                       (deUint32)renderSize.y(),                                       // deUint32                             bufferImageHeight;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                              // VkImageAspect                aspect;
+                               0u,                                                                             // deUint32                             mipLevel;
+                               0u,                                                                             // deUint32                             arraySlice;
+                               1u,                                                                             // deUint32                             arraySize;
+                       },                                                                                      // VkImageSubresource   imageSubresource;
+                       { 0u, 0u, 0u },                                                         // VkOffset3D                   imageOffset;
+                       { renderSize.x(), renderSize.y(), 1u }          // VkExtent3D                   imageExtent;
+               };
+
+               // Read back pixels.
+               for (int outNdx = 0; outNdx < (int)m_shaderSpec.outputs.size(); ++outNdx)
+               {
+                       const Symbol&                           output                  = m_shaderSpec.outputs[outNdx];
+                       const int                                       outSize                 = output.varType.getScalarSize();
+                       const int                                       outVecSize              = glu::getDataTypeNumComponents(output.varType.getBasicType());
+                       const int                                       outNumLocs              = glu::getDataTypeNumLocations(output.varType.getBasicType());
+                       deUint32*                                       dstPtrBase              = static_cast<deUint32*>(outputs[outNdx]);
+                       const int                                       outLocation             = de::lookup(m_outputLayout.locationMap, output.name);
+
+                       for (int locNdx = 0; locNdx < outNumLocs; ++locNdx)
+                       {
+                               tcu::TextureLevel                       tmpBuf;
+                               const tcu::TextureFormat        format = getRenderbufferFormatForOutput(output.varType, false);
+                               const tcu::TextureFormat        readFormat (tcu::TextureFormat::RGBA, format.type);
+                               const Unique<VkBuffer>          readImageBuffer(createBuffer(vk, vkDevice, &readImageBufferParams));
+                               const de::UniquePtr<Allocation> readImageBufferMemory(memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *readImageBuffer), MemoryRequirement::HostVisible));
+
+                               VK_CHECK(vk.bindBufferMemory(vkDevice, *readImageBuffer, readImageBufferMemory->getMemory(), readImageBufferMemory->getOffset()));
+
+                               // Copy image to buffer
+                               {
+
+                                       const VkSubmitInfo submitInfo =
+                                       {
+                                               VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                                               DE_NULL,
+                                               0u,
+                                               (const VkSemaphore*)DE_NULL,
+                                               1u,
+                                               &cmdBuffer.get(),
+                                               0u,
+                                               (const VkSemaphore*)DE_NULL,
+                                       };
+
+                                       Move<VkCommandBuffer> copyCmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+                                       VK_CHECK(vk.beginCommandBuffer(*copyCmdBuffer, &cmdBufferBeginInfo));
+                                       vk.cmdCopyImageToBuffer(*copyCmdBuffer, colorImages[outLocation + locNdx].get()->get(), VK_IMAGE_LAYOUT_UNDEFINED, *readImageBuffer, 1u, &copyParams);
+                                       VK_CHECK(vk.endCommandBuffer(*copyCmdBuffer));
+
+                                       VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
+                                       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
+                                       VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity */));
+                               }
+
+                               const VkMappedMemoryRange range =
+                               {
+                                       VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,  // VkStructureType      sType;
+                                       DE_NULL,                                                                // const void*          pNext;
+                                       readImageBufferMemory->getMemory(),             // VkDeviceMemory       mem;
+                                       0,                                                                              // VkDeviceSize         offset;
+                                       imageSizeBytes,                                                 // VkDeviceSize         size;
+                               };
+
+                               VK_CHECK(vk.invalidateMappedMemoryRanges(vkDevice, 1u, &range));
+
+                               tmpBuf.setStorage(readFormat, renderSize.x(), renderSize.y());
+
+                               const tcu::TextureFormat resultFormat(tcu::TextureFormat::RGBA, format.type);
+                               const tcu::ConstPixelBufferAccess resultAccess(resultFormat, renderSize.x(), renderSize.y(), 1, readImageBufferMemory->getHostPtr());
+
+                               tcu::copy(tmpBuf.getAccess(), resultAccess);
+
+                               if (outSize == 4 && outNumLocs == 1)
+                                       deMemcpy(dstPtrBase, tmpBuf.getAccess().getDataPtr(), numValues * outVecSize * sizeof(deUint32));
+                               else
+                               {
+                                       for (int valNdx = 0; valNdx < numValues; valNdx++)
+                                       {
+                                               const deUint32* srcPtr = (const deUint32*)tmpBuf.getAccess().getDataPtr() + valNdx * 4;
+                                               deUint32*               dstPtr = &dstPtrBase[outSize * valNdx + outVecSize * locNdx];
+                                               deMemcpy(dstPtr, srcPtr, outVecSize * sizeof(deUint32));
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+// VertexShaderExecutor
+
+class VertexShaderExecutor : public FragmentOutExecutor
+{
+public:
+                                                               VertexShaderExecutor    (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                                         ~VertexShaderExecutor   (void);
+
+       virtual void                            log                                             (tcu::TestLog& dst) const { /* TODO */ (void)dst;}
+
+       virtual void                            setShaderSources                (SourceCollections& programCollection) const;
+
+};
+
+VertexShaderExecutor::VertexShaderExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : FragmentOutExecutor           (shaderSpec, shaderType)
+{
+}
+
+VertexShaderExecutor::~VertexShaderExecutor (void)
+{
+}
+
+void VertexShaderExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("vert") << glu::VertexSource(generateVertexShader(m_shaderSpec, "a_", "vtx_out_"));
+       /* \todo [2015-09-11 hegedusd] set useIntOutputs parameter if needed. */
+       programCollection.glslSources.add("frag") << glu::FragmentSource(generatePassthroughFragmentShader(m_shaderSpec, false,  m_outputLayout.locationMap, "vtx_out_", "o_"));
+}
+
+// GeometryShaderExecutor
+
+class GeometryShaderExecutor : public FragmentOutExecutor
+{
+public:
+                                                               GeometryShaderExecutor  (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                                         ~GeometryShaderExecutor (void);
+
+       virtual void                            log                                             (tcu::TestLog& dst) const       { /* TODO */ (void)dst; }
+
+       virtual void                            setShaderSources                (SourceCollections& programCollection) const;
+
+};
+
+GeometryShaderExecutor::GeometryShaderExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : FragmentOutExecutor           (shaderSpec, shaderType)
+{
+}
+
+GeometryShaderExecutor::~GeometryShaderExecutor (void)
+{
+}
+
+void GeometryShaderExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("vert") << glu::VertexSource(generatePassthroughVertexShader(m_shaderSpec.inputs, "a_", "vtx_out_"));
+
+       programCollection.glslSources.add("geom") << glu::GeometrySource(generateGeometryShader(m_shaderSpec, "vtx_out_", "geom_out_"));
+
+       /* \todo [2015-09-18 rsipka] set useIntOutputs parameter if needed. */
+       programCollection.glslSources.add("frag") << glu::FragmentSource(generatePassthroughFragmentShader(m_shaderSpec, false, m_outputLayout.locationMap, "geom_out_", "o_"));
+
+}
+
+// FragmentShaderExecutor
+
+class FragmentShaderExecutor : public FragmentOutExecutor
+{
+public:
+                                                               FragmentShaderExecutor  (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                                         ~FragmentShaderExecutor (void);
+
+       virtual void                            log                                             (tcu::TestLog& dst) const { /* TODO */ (void)dst; }
+
+       virtual void                            setShaderSources                (SourceCollections& programCollection) const;
+
+};
+
+FragmentShaderExecutor::FragmentShaderExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : FragmentOutExecutor           (shaderSpec, shaderType)
+{
+}
+
+FragmentShaderExecutor::~FragmentShaderExecutor (void)
+{
+}
+
+void FragmentShaderExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("vert") << glu::VertexSource(generatePassthroughVertexShader(m_shaderSpec.inputs, "a_", "vtx_out_"));
+       /* \todo [2015-09-11 hegedusd] set useIntOutputs parameter if needed. */
+       programCollection.glslSources.add("frag") << glu::FragmentSource(generateFragmentShader(m_shaderSpec, false,  m_outputLayout.locationMap, "vtx_out_", "o_"));
+}
+
+// Shared utilities for compute and tess executors
+
+static deUint32 getVecStd430ByteAlignment (glu::DataType type)
+{
+       switch (glu::getDataTypeScalarSize(type))
+       {
+               case 1:         return 4u;
+               case 2:         return 8u;
+               case 3:         return 16u;
+               case 4:         return 16u;
+               default:
+                       DE_ASSERT(false);
+                       return 0u;
+       }
+}
+
+class BufferIoExecutor : public ShaderExecutor
+{
+public:
+                                                       BufferIoExecutor        (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                                 ~BufferIoExecutor       (void);
+
+       virtual void                    log                                     (tcu::TestLog& dst) const       { /* TODO */ (void)dst; }
+
+protected:
+       enum
+       {
+               INPUT_BUFFER_BINDING    = 0,
+               OUTPUT_BUFFER_BINDING   = 1,
+       };
+
+       void                                    initBuffers                     (const Context& ctx, int numValues);
+       VkBuffer                                getInputBuffer          (void) const            { return *m_inputBuffer;                                        }
+       VkBuffer                                getOutputBuffer         (void) const            { return *m_outputBuffer;                                       }
+       deUint32                                getInputStride          (void) const            { return getLayoutStride(m_inputLayout);        }
+       deUint32                                getOutputStride         (void) const            { return getLayoutStride(m_outputLayout);       }
+
+       void                                    uploadInputBuffer       (const Context& ctx, const void* const* inputPtrs, int numValues);
+       void                                    readOutputBuffer        (const Context& ctx, void* const* outputPtrs, int numValues);
+
+       static void                             declareBufferBlocks     (std::ostream& src, const ShaderSpec& spec);
+       static void                             generateExecBufferIo(std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName);
+
+protected:
+       Move<VkBuffer>                  m_inputBuffer;
+       Move<VkBuffer>                  m_outputBuffer;
+
+private:
+       struct VarLayout
+       {
+               deUint32                offset;
+               deUint32                stride;
+               deUint32                matrixStride;
+
+               VarLayout (void) : offset(0), stride(0), matrixStride(0) {}
+       };
+
+       static void                             computeVarLayout        (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout);
+       static deUint32                 getLayoutStride         (const vector<VarLayout>& layout);
+
+       static void                             copyToBuffer            (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
+       static void                             copyFromBuffer          (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr);
+
+       de::MovePtr<Allocation> m_inputAlloc;
+       de::MovePtr<Allocation> m_outputAlloc;
+
+       vector<VarLayout>               m_inputLayout;
+       vector<VarLayout>               m_outputLayout;
+};
+
+BufferIoExecutor::BufferIoExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : ShaderExecutor (shaderSpec, shaderType)
+{
+       computeVarLayout(m_shaderSpec.inputs, &m_inputLayout);
+       computeVarLayout(m_shaderSpec.outputs, &m_outputLayout);
+}
+
+BufferIoExecutor::~BufferIoExecutor (void)
+{
+}
+
+inline deUint32 BufferIoExecutor::getLayoutStride (const vector<VarLayout>& layout)
+{
+       return layout.empty() ? 0 : layout[0].stride;
+}
+
+void BufferIoExecutor::computeVarLayout (const std::vector<Symbol>& symbols, std::vector<VarLayout>* layout)
+{
+       deUint32        maxAlignment    = 0;
+       deUint32        curOffset               = 0;
+
+       DE_ASSERT(layout != DE_NULL);
+       DE_ASSERT(layout->empty());
+       layout->resize(symbols.size());
+
+       for (size_t varNdx = 0; varNdx < symbols.size(); varNdx++)
+       {
+               const Symbol&           symbol          = symbols[varNdx];
+               const glu::DataType     basicType       = symbol.varType.getBasicType();
+               VarLayout&                      layoutEntry     = (*layout)[varNdx];
+
+               if (glu::isDataTypeScalarOrVector(basicType))
+               {
+                       const deUint32  alignment       = getVecStd430ByteAlignment(basicType);
+                       const deUint32  size            = (deUint32)glu::getDataTypeScalarSize(basicType) * (int)sizeof(deUint32);
+
+                       curOffset               = (deUint32)deAlign32((int)curOffset, (int)alignment);
+                       maxAlignment    = de::max(maxAlignment, alignment);
+
+                       layoutEntry.offset                      = curOffset;
+                       layoutEntry.matrixStride        = 0;
+
+                       curOffset += size;
+               }
+               else if (glu::isDataTypeMatrix(basicType))
+               {
+                       const int                               numVecs                 = glu::getDataTypeMatrixNumColumns(basicType);
+                       const glu::DataType             vecType                 = glu::getDataTypeFloatVec(glu::getDataTypeMatrixNumRows(basicType));
+                       const deUint32                  vecAlignment    = getVecStd430ByteAlignment(vecType);
+
+                       curOffset               = (deUint32)deAlign32((int)curOffset, (int)vecAlignment);
+                       maxAlignment    = de::max(maxAlignment, vecAlignment);
+
+                       layoutEntry.offset                      = curOffset;
+                       layoutEntry.matrixStride        = vecAlignment;
+
+                       curOffset += vecAlignment*numVecs;
+               }
+               else
+                       DE_ASSERT(false);
+       }
+
+       {
+               const deUint32  totalSize       = (deUint32)deAlign32(curOffset, maxAlignment);
+
+               for (vector<VarLayout>::iterator varIter = layout->begin(); varIter != layout->end(); ++varIter)
+                       varIter->stride = totalSize;
+       }
+}
+
+void BufferIoExecutor::declareBufferBlocks (std::ostream& src, const ShaderSpec& spec)
+{
+       // Input struct
+       if (!spec.inputs.empty())
+       {
+               glu::StructType inputStruct("Inputs");
+               for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
+                       inputStruct.addMember(symIter->name.c_str(), symIter->varType);
+               src << glu::declare(&inputStruct) << ";\n";
+       }
+
+       // Output struct
+       {
+               glu::StructType outputStruct("Outputs");
+               for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
+                       outputStruct.addMember(symIter->name.c_str(), symIter->varType);
+               src << glu::declare(&outputStruct) << ";\n";
+       }
+
+       src << "\n";
+
+       if (!spec.inputs.empty())
+       {
+               src     << "layout(set = 0, binding = " << int(INPUT_BUFFER_BINDING) << ", std140) buffer InBuffer\n"
+                       << "{\n"
+                       << "    Inputs inputs[];\n"
+                       << "};\n";
+       }
+
+       src     << "layout(set = 0, binding = " << int(OUTPUT_BUFFER_BINDING) << ", std140) buffer OutBuffer\n"
+               << "{\n"
+               << "    Outputs outputs[];\n"
+               << "};\n"
+               << "\n";
+}
+
+void BufferIoExecutor::generateExecBufferIo (std::ostream& src, const ShaderSpec& spec, const char* invocationNdxName)
+{
+       for (vector<Symbol>::const_iterator symIter = spec.inputs.begin(); symIter != spec.inputs.end(); ++symIter)
+               src << "\t" << glu::declare(symIter->varType, symIter->name) << " = inputs[" << invocationNdxName << "]." << symIter->name << ";\n";
+
+       for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
+               src << "\t" << glu::declare(symIter->varType, symIter->name) << ";\n";
+
+       src << "\n";
+
+       {
+               std::istringstream      opSrc   (spec.source);
+               std::string                     line;
+
+               while (std::getline(opSrc, line))
+                       src << "\t" << line << "\n";
+       }
+
+       src << "\n";
+       for (vector<Symbol>::const_iterator symIter = spec.outputs.begin(); symIter != spec.outputs.end(); ++symIter)
+               src << "\toutputs[" << invocationNdxName << "]." << symIter->name << " = " << symIter->name << ";\n";
+}
+
+void BufferIoExecutor::copyToBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
+{
+       if (varType.isBasicType())
+       {
+               const glu::DataType             basicType               = varType.getBasicType();
+               const bool                              isMatrix                = glu::isDataTypeMatrix(basicType);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(basicType);
+               const int                               numVecs                 = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
+               const int                               numComps                = scalarSize / numVecs;
+
+               for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
+               {
+                       for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
+                       {
+                               const int               srcOffset               = (int)sizeof(deUint32) * (elemNdx * scalarSize + vecNdx * numComps);
+                               const int               dstOffset               = layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0);
+                               const deUint8*  srcPtr                  = (const deUint8*)srcBasePtr + srcOffset;
+                               deUint8*                dstPtr                  = (deUint8*)dstBasePtr + dstOffset;
+
+                               deMemcpy(dstPtr, srcPtr, sizeof(deUint32) * numComps);
+                       }
+               }
+       }
+       else
+               throw tcu::InternalError("Unsupported type");
+}
+
+void BufferIoExecutor::copyFromBuffer (const glu::VarType& varType, const VarLayout& layout, int numValues, const void* srcBasePtr, void* dstBasePtr)
+{
+       if (varType.isBasicType())
+       {
+               const glu::DataType             basicType               = varType.getBasicType();
+               const bool                              isMatrix                = glu::isDataTypeMatrix(basicType);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(basicType);
+               const int                               numVecs                 = isMatrix ? glu::getDataTypeMatrixNumColumns(basicType) : 1;
+               const int                               numComps                = scalarSize / numVecs;
+
+               for (int elemNdx = 0; elemNdx < numValues; elemNdx++)
+               {
+                       for (int vecNdx = 0; vecNdx < numVecs; vecNdx++)
+                       {
+                               const int               srcOffset               = layout.offset + layout.stride * elemNdx + (isMatrix ? layout.matrixStride * vecNdx : 0);
+                               const int               dstOffset               = (int)sizeof(deUint32) * (elemNdx * scalarSize + vecNdx * numComps);
+                               const deUint8*  srcPtr                  = (const deUint8*)srcBasePtr + srcOffset;
+                               deUint8*                dstPtr                  = (deUint8*)dstBasePtr + dstOffset;
+
+                               deMemcpy(dstPtr, srcPtr, sizeof(deUint32) * numComps);
+                       }
+               }
+       }
+       else
+               throw tcu::InternalError("Unsupported type");
+}
+
+void BufferIoExecutor::uploadInputBuffer (const Context& ctx, const void* const* inputPtrs, int numValues)
+{
+       const VkDevice                  vkDevice                        = ctx.getDevice();
+       const DeviceInterface&  vk                                      = ctx.getDeviceInterface();
+
+       const deUint32                  inputStride                     = getLayoutStride(m_inputLayout);
+       const int                               inputBufferSize         = inputStride * numValues;
+
+       if (inputBufferSize == 0)
+               return; // No inputs
+
+       DE_ASSERT(m_shaderSpec.inputs.size() == m_inputLayout.size());
+       for (size_t inputNdx = 0; inputNdx < m_shaderSpec.inputs.size(); ++inputNdx)
+       {
+               const glu::VarType&             varType         = m_shaderSpec.inputs[inputNdx].varType;
+               const VarLayout&                layout          = m_inputLayout[inputNdx];
+
+               copyToBuffer(varType, layout, numValues, inputPtrs[inputNdx], m_inputAlloc->getHostPtr());
+       }
+
+       flushMappedMemoryRange(vk, vkDevice, m_inputAlloc->getMemory(), m_inputAlloc->getOffset(), inputBufferSize);
+}
+
+void BufferIoExecutor::readOutputBuffer (const Context& ctx, void* const* outputPtrs, int numValues)
+{
+       const VkDevice                  vkDevice                        = ctx.getDevice();
+       const DeviceInterface&  vk                                      = ctx.getDeviceInterface();
+
+       const deUint32                  outputStride            = getLayoutStride(m_outputLayout);
+       const int                               outputBufferSize        = numValues * outputStride;
+
+       DE_ASSERT(outputBufferSize > 0); // At least some outputs are required.
+
+       invalidateMappedMemoryRange(vk, vkDevice, m_outputAlloc->getMemory(), m_outputAlloc->getOffset(), outputBufferSize);
+
+       DE_ASSERT(m_shaderSpec.outputs.size() == m_outputLayout.size());
+       for (size_t outputNdx = 0; outputNdx < m_shaderSpec.outputs.size(); ++outputNdx)
+       {
+               const glu::VarType&             varType         = m_shaderSpec.outputs[outputNdx].varType;
+               const VarLayout&                layout          = m_outputLayout[outputNdx];
+
+               copyFromBuffer(varType, layout, numValues, m_outputAlloc->getHostPtr(), outputPtrs[outputNdx]);
+       }
+}
+
+void BufferIoExecutor::initBuffers (const Context& ctx, int numValues)
+{
+       const deUint32                          inputStride                     = getLayoutStride(m_inputLayout);
+       const deUint32                          outputStride            = getLayoutStride(m_outputLayout);
+       const size_t                            inputBufferSize         = numValues * inputStride;
+       const size_t                            outputBufferSize        = numValues * outputStride;
+
+       // Upload data to buffer
+       const VkDevice                          vkDevice                        = ctx.getDevice();
+       const DeviceInterface&          vk                                      = ctx.getDeviceInterface();
+       const deUint32                          queueFamilyIndex        = ctx.getUniversalQueueFamilyIndex();
+       Allocator&                                      memAlloc                        = ctx.getDefaultAllocator();
+
+       const VkBufferCreateInfo inputBufferParams =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+               DE_NULL,                                                                        // const void*                  pNext;
+               0u,                                                                                     // VkBufferCreateFlags  flags;
+               inputBufferSize,                                                        // VkDeviceSize                 size;
+               VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,                     // VkBufferUsageFlags   usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+               1u,                                                                                     // deUint32                             queueFamilyCount;
+               &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+       };
+
+       m_inputBuffer = createBuffer(vk, vkDevice, &inputBufferParams);
+       m_inputAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_inputBuffer), MemoryRequirement::HostVisible);
+
+       VK_CHECK(vk.bindBufferMemory(vkDevice, *m_inputBuffer, m_inputAlloc->getMemory(), m_inputAlloc->getOffset()));
+
+       const VkBufferCreateInfo outputBufferParams =
+       {
+               VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,           // VkStructureType              sType;
+               DE_NULL,                                                                        // const void*                  pNext;
+               0u,                                                                                     // VkBufferCreateFlags  flags;
+               outputBufferSize,                                                       // VkDeviceSize                 size;
+               VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,                     // VkBufferUsageFlags   usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                      // VkSharingMode                sharingMode;
+               1u,                                                                                     // deUint32                             queueFamilyCount;
+               &queueFamilyIndex                                                       // const deUint32*              pQueueFamilyIndices;
+       };
+
+       m_outputBuffer = createBuffer(vk, vkDevice, &outputBufferParams);
+       m_outputAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outputBuffer), MemoryRequirement::HostVisible);
+
+       VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outputBuffer, m_outputAlloc->getMemory(), m_outputAlloc->getOffset()));
+}
+
+// ComputeShaderExecutor
+
+class ComputeShaderExecutor : public BufferIoExecutor
+{
+public:
+                                               ComputeShaderExecutor   (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                         ~ComputeShaderExecutor  (void);
+
+       virtual void            setShaderSources                (SourceCollections& programCollection) const;
+
+       virtual void            execute                                 (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs);
+
+protected:
+       static std::string      generateComputeShader   (const ShaderSpec& spec);
+
+       tcu::IVec3                      m_maxWorkSize;
+};
+
+ComputeShaderExecutor::ComputeShaderExecutor   (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : BufferIoExecutor      (shaderSpec, shaderType)
+{
+}
+
+ComputeShaderExecutor::~ComputeShaderExecutor  (void)
+{
+}
+
+std::string ComputeShaderExecutor::generateComputeShader (const ShaderSpec& spec)
+{
+       std::ostringstream src;
+       src <<  "#version 310 es\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!spec.globalDeclarations.empty())
+               src << spec.globalDeclarations << "\n";
+
+       src << "layout(local_size_x = 1) in;\n"
+               << "\n";
+
+       declareBufferBlocks(src, spec);
+
+       src << "void main (void)\n"
+               << "{\n"
+               << "    uint invocationNdx = gl_NumWorkGroups.x*gl_NumWorkGroups.y*gl_WorkGroupID.z\n"
+               << "                       + gl_NumWorkGroups.x*gl_WorkGroupID.y + gl_WorkGroupID.x;\n";
+
+       generateExecBufferIo(src, spec, "invocationNdx");
+
+       src << "}\n";
+
+       return src.str();
+}
+
+void ComputeShaderExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("compute") << glu::ComputeSource(generateComputeShader(m_shaderSpec));
+}
+
+void ComputeShaderExecutor::execute (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs)
+{
+       checkSupported(ctx, m_shaderType);
+
+       const int                                               maxValuesPerInvocation  = m_maxWorkSize[0];
+
+       const VkDevice                                  vkDevice                                = ctx.getDevice();
+       const DeviceInterface&                  vk                                              = ctx.getDeviceInterface();
+       const VkQueue                                   queue                                   = ctx.getUniversalQueue();
+       const deUint32                                  queueFamilyIndex                = ctx.getUniversalQueueFamilyIndex();
+
+       Move<VkShaderModule>                    computeShaderModule;
+       Move<VkPipeline>                                computePipeline;
+       Move<VkPipelineLayout>                  pipelineLayout;
+       Move<VkCommandPool>                             cmdPool;
+       Move<VkDescriptorPool>                  descriptorPool;
+       Move<VkDescriptorSetLayout>             descriptorSetLayout;
+       Move<VkDescriptorSet>                   descriptorSet;
+       Move<VkFence>                                   fence;
+
+       initBuffers(ctx, numValues);
+
+       // Setup input buffer & copy data
+       uploadInputBuffer(ctx, inputs, numValues);
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,             // VkStructureType              sType;
+                       DE_NULL,                                                                                // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                   // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex                                                                // deUint32                             queueFamilyIndex;
+               };
+
+               cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       const VkCommandBufferAllocateInfo cmdBufferParams =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+               DE_NULL,                                                                                // const void*                          pNext;
+               *cmdPool,                                                                               // VkCmdPool                            cmdPool;
+               VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCmdBufferLevel                     level;
+               1u                                                                                              // deUint32                                     bufferCount;
+       };
+
+       const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+       {
+               VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+               DE_NULL,                                                                                // const void*                                          pNext;
+               0u,                                                                                             // VkCmdBufferOptimizeFlags                     flags;
+               DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+               0u,                                                                                             // deUint32                                                     subpass;
+               DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+               VK_FALSE,                                                                               // VkBool32                                             occlusionQueryEnable;
+               (VkQueryControlFlags)0,                                                 // VkQueryControlFlags                          queryFlags;
+               (VkQueryPipelineStatisticFlags)0                                // VkQueryPipelineStatisticFlags        pipelineStatistics;
+
+       };
+
+       const VkDescriptorSetLayoutBinding layoutBindings[2] =
+       {
+               {
+                       0u,                                                                                     // deUint32                             binding;
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType                     descriptorType;
+                       1u,                                                                                             // deUint32                                     descriptorCount;
+                       VK_SHADER_STAGE_COMPUTE_BIT,                                    // VkShaderStageFlags           stageFlags;
+                       DE_NULL                                                                                 // const VkSampler*                     pImmutableSamplers;
+               },
+               {
+                       0u,                                                                                             // deUint32                                     binding;
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType                     descriptorType;
+                       1u,                                                                                             // deUint32                                     descriptorCount;
+                       VK_SHADER_STAGE_COMPUTE_BIT,                                    // VkShaderStageFlags           stageFlags;
+                       DE_NULL                                                                                 // const VkSampler*                     pImmutableSamplers;
+               }
+       };
+
+       const VkDescriptorSetLayoutCreateInfo descriptorLayoutParams =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,    // VkStructureType                                              sType;
+               DE_NULL,                                                                                                // cost void*                                                   pNexŧ;
+               (VkDescriptorSetLayoutCreateFlags)0,                                    // VkDescriptorSetLayoutCreateFlags     flags;
+               DE_LENGTH_OF_ARRAY(layoutBindings),                                             // deUint32                                                             count;
+               layoutBindings                                                                                  // const VkDescriptorSetLayoutBinding   pBinding;
+       };
+
+       descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams);
+
+       const VkDescriptorPoolSize descriptorPoolSizes[] =
+       {
+               {
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                                      // VkDescriptorType             type;
+                       1u                                                                                                      // deUint32                             count;
+               },
+               {
+                       VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                                      // VkDescriptorType             type;
+                       1u                                                                                                      // deUint32                             count;
+               }
+       };
+
+       const VkDescriptorPoolCreateInfo descriptorPoolParams =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,                  // VkStructureType                                      sType;
+               DE_NULL,                                                                                                // void*                                                        pNext;
+               VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,              // VkDescriptorPoolUsage                        poolUsage;
+               1u,                                                                                                             // deUint32                                                     maxSets;
+               DE_LENGTH_OF_ARRAY(descriptorPoolSizes),                                // deUint32                                                     count;
+               descriptorPoolSizes                                                                             // const VkDescriptorPoolSize*          pPoolSizes;
+       };
+
+       descriptorPool = createDescriptorPool(vk, vkDevice, &descriptorPoolParams);
+
+       const VkDescriptorSetAllocateInfo allocInfo =
+       {
+               VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+               DE_NULL,
+               *descriptorPool,
+               1u,
+               &*descriptorSetLayout
+       };
+
+       descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       (VkPipelineLayoutCreateFlags)0,                                         // VkPipelineLayoutCreateFlags  flags;
+                       0u,                                                                                                     // deUint32                                             CdescriptorSetCount;
+                       DE_NULL,                                                                                        // const VkDescriptorSetLayout* pSetLayouts;
+                       0u,                                                                                                     // deUint32                                             pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*   pPushConstantRanges;
+               };
+
+               pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       // Create shaders
+       {
+               computeShaderModule             = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("compute"), 0);
+       }
+
+       // create pipeline
+       {
+               const VkPipelineShaderStageCreateInfo shaderStageParams[1] =
+               {
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0u,                                           // VkPipelineShaderStageCreateFlags             flags;
+                               VK_SHADER_STAGE_COMPUTE_BIT,                                                            // VkShaderStageFlagsBit                                stage;
+                               *computeShaderModule,                                                                           // VkShaderModule                                               shader;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       }
+               };
+
+               const VkComputePipelineCreateInfo computePipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,         // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       (VkPipelineCreateFlags)0,                                                       // VkPipelineCreateFlags                                                        flags;
+                       *shaderStageParams,                                                                     // VkPipelineShaderStageCreateInfo                                      cs;
+                       *pipelineLayout,                                                                        // VkPipelineLayout                                                                     layout;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u,                                                                                                     // int32_t                                                                                      basePipelineIndex;
+               };
+
+               computePipeline = createComputePipeline(vk, vkDevice, DE_NULL, &computePipelineParams);
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+               fence = createFence(vk, vkDevice, &fenceParams);
+       }
+
+       int                                     curOffset               = 0;
+       const deUint32          inputStride             = getInputStride();
+       const deUint32          outputStride    = getOutputStride();
+
+       while (curOffset < numValues)
+       {
+               Move<VkCommandBuffer>           cmdBuffer;
+               const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset);
+
+               const VkDescriptorBufferInfo descriptorBufferInfo[] =
+               {
+                       {
+                               *m_inputBuffer,                                 // VkBuffer                     buffer;
+                               curOffset * inputStride,                // VkDeviceSize         offset;
+                               numToExec * inputStride                 // VkDeviceSize         range;
+                       },
+                       {
+                               *m_outputBuffer,                                // VkBuffer                     buffer;
+                               curOffset * outputStride,               // VkDeviceSize         offset;
+                               numToExec * outputStride                // VkDeviceSize         range;
+                       }
+               };
+
+               const VkWriteDescriptorSet writeDescritporSets[] =
+               {
+                       {
+                               VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,         // VkStructureType                                      sType;
+                               DE_NULL,                                                                        // const void*                                          pNext;
+                               *descriptorSet,                                                         // VkDescriptorSet                                      destSet;
+                               0u,                                                                                     // deUint32                                                     destBinding;
+                               0u,                                                                                     // deUint32                                                     destArrayElement;
+                               2u,                                                                             // deUint32                                                     count;
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                      // VkDescriptorType                                     descriptorType;
+                               DE_NULL,                                                                        // const VkDescriptorImageInfo*         pImageInfo;
+                               descriptorBufferInfo,                                           // const VkDescriptorBufferInfo*        pBufferInfo;
+                               DE_NULL                                                                         // const VkBufferView*                          pTexelBufferView;
+                       }
+               };
+
+               vk.updateDescriptorSets(vkDevice, 1, writeDescritporSets, 0u, DE_NULL);
+
+               cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
+               VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
+
+               vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
+
+               vk.cmdDispatch(*cmdBuffer, numToExec, 1, 1);
+
+               VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+
+               curOffset += numToExec;
+
+               // Execute
+               {
+                       VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
+
+                       const VkSubmitInfo submitInfo =
+                       {
+                               VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                               DE_NULL,
+                               0u,
+                               (const VkSemaphore*)DE_NULL,
+                               1u,
+                               &cmdBuffer.get(),
+                               0u,
+                               (const VkSemaphore*)DE_NULL,
+                       };
+
+                       VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
+                       VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity*/));
+               }
+       }
+
+       // Read back data
+       readOutputBuffer(ctx, outputs, numValues);
+}
+
+// Tessellation utils
+
+static std::string generateVertexShaderForTess (void)
+{
+       std::ostringstream      src;
+       src <<  "#version 310 es\n"
+
+               << "void main (void)\n{\n"
+               << "    gl_Position = vec4(gl_VertexID/2, gl_VertexID%2, 0.0, 1.0);\n"
+               << "}\n";
+
+       return src.str();
+}
+
+class TessellationExecutor : public BufferIoExecutor
+{
+public:
+                                               TessellationExecutor            (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                         ~TessellationExecutor           (void);
+
+       void                            renderTess                                      (const Context& ctx, deUint32 vertexCount);
+};
+
+TessellationExecutor::TessellationExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : BufferIoExecutor      (shaderSpec, shaderType)
+{
+}
+
+TessellationExecutor::~TessellationExecutor (void)
+{
+}
+
+void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount)
+{
+       const VkDevice                                          vkDevice                                        = ctx.getDevice();
+       const DeviceInterface&                          vk                                                      = ctx.getDeviceInterface();
+       const VkQueue                                           queue                                           = ctx.getUniversalQueue();
+       const deUint32                                          queueFamilyIndex                        = ctx.getUniversalQueueFamilyIndex();
+       Allocator&                                                      memAlloc                                        = ctx.getDefaultAllocator();
+
+       const tcu::IVec2                                        renderSize                                      (DEFAULT_RENDER_WIDTH, DEFAULT_RENDER_HEIGHT);
+
+       Move<VkImage>                                           colorImage;
+       de::MovePtr<Allocation>                         colorImageAlloc;
+       VkFormat                                                        colorFormat                                     = VK_FORMAT_R8G8B8A8_UNORM;
+       Move<VkImageView>                                       colorImageView;
+
+       Move<VkRenderPass>                                      renderPass;
+       Move<VkFramebuffer>                                     framebuffer;
+       Move<VkPipelineLayout>                          pipelineLayout;
+       Move<VkPipeline>                                        graphicsPipeline;
+
+       Move<VkShaderModule>                            vertexShaderModule;
+       Move<VkShaderModule>                            tessControlShaderModule;
+       Move<VkShaderModule>                            tessEvalShaderModule;
+       Move<VkShaderModule>                            fragmentShaderModule;
+
+       Move<VkCommandPool>                                     cmdPool;
+       Move<VkCommandBuffer>                           cmdBuffer;
+
+       Move<VkFence>                                           fence;
+
+       Move<VkDescriptorPool>                          descriptorPool;
+       Move<VkDescriptorSetLayout>                     descriptorSetLayout;
+       Move<VkDescriptorSet>                           descriptorSet;
+
+       // Create color image
+       {
+               const VkImageCreateInfo colorImageParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                            // VkStructureType                      sType;
+                       DE_NULL,                                                                                                                                        // const void*                          pNext;
+                       0u,                                                                                                                                                     // VkImageCreateFlags           flags;
+                       VK_IMAGE_TYPE_2D,                                                                                                                       // VkImageType                          imageType;
+                       colorFormat,                                                                                                                            // VkFormat                                     format;
+                       { renderSize.x(), renderSize.y(), 1u },                                                                         // VkExtent3D                           extent;
+                       1u,                                                                                                                                                     // deUint32                                     mipLevels;
+                       1u,                                                                                                                                                     // deUint32                                     arraySize;
+                       VK_SAMPLE_COUNT_1_BIT,                                                                                                          // VkSampleCountFlagBits        samples;
+                       VK_IMAGE_TILING_OPTIMAL,                                                                                                        // VkImageTiling                        tiling;
+                       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,          // VkImageUsageFlags            usage;
+                       VK_SHARING_MODE_EXCLUSIVE,                                                                                                      // VkSharingMode                        sharingMode;
+                       1u,                                                                                                                                                     // deUint32                                     queueFamilyCount;
+                       &queueFamilyIndex,                                                                                                                      // const deUint32*                      pQueueFamilyIndices;
+                       VK_IMAGE_LAYOUT_UNDEFINED                                                                                                       // VkImageLayout                        initialLayout;
+               };
+
+               colorImage = createImage(vk, vkDevice, &colorImageParams);
+
+               // Allocate and bind color image memory
+               colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *colorImage), MemoryRequirement::Any);
+               VK_CHECK(vk.bindImageMemory(vkDevice, *colorImage, colorImageAlloc->getMemory(), colorImageAlloc->getOffset()));
+       }
+
+       // Create color attachment view
+       {
+               const VkImageViewCreateInfo colorImageViewParams =
+               {
+                       VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,                       // VkStructureType                      sType;
+                       DE_NULL,                                                                                        // const void*                          pNext;
+                       0u,                                                                                                     // VkImageViewCreateFlags       flags;
+                       *colorImage,                                                                            // VkImage                                      image;
+                       VK_IMAGE_VIEW_TYPE_2D,                                                          // VkImageViewType                      viewType;
+                       colorFormat,                                                                            // VkFormat                                     format;
+                       {
+                               VK_COMPONENT_SWIZZLE_R,                                                 // VkComponentSwizzle           r;
+                               VK_COMPONENT_SWIZZLE_G,                                                 // VkComponentSwizzle           g;
+                               VK_COMPONENT_SWIZZLE_B,                                                 // VkComponentSwizzle           b;
+                               VK_COMPONENT_SWIZZLE_A                                                  // VkComponentSwizzle           a;
+                       },                                                                                                      // VkComponentsMapping          components;
+                       {
+                               VK_IMAGE_ASPECT_COLOR_BIT,                                              // VkImageAspectFlags           aspectMask;
+                               0u,                                                                                             // deUint32                                     baseMipLevel;
+                               1u,                                                                                             // deUint32                                     mipLevels;
+                               0u,                                                                                             // deUint32                                     baseArraylayer;
+                               1u                                                                                              // deUint32                                     layerCount;
+                       }                                                                                                       // VkImageSubresourceRange      subresourceRange;
+               };
+
+               colorImageView = createImageView(vk, vkDevice, &colorImageViewParams);
+       }
+
+       // Create render pass
+       {
+               const VkAttachmentDescription colorAttachmentDescription =
+               {
+                       0u,                                                                                                     // VkAttachmentDescriptorFlags  flags;
+                       colorFormat,                                                                            // VkFormat                                             format;
+                       VK_SAMPLE_COUNT_1_BIT,                                                          // VkSampleCountFlagBits                samples;
+                       VK_ATTACHMENT_LOAD_OP_CLEAR,                                            // VkAttachmentLoadOp                   loadOp;
+                       VK_ATTACHMENT_STORE_OP_STORE,                                           // VkAttachmentStoreOp                  storeOp;
+                       VK_ATTACHMENT_LOAD_OP_DONT_CARE,                                        // VkAttachmentLoadOp                   stencilLoadOp;
+                       VK_ATTACHMENT_STORE_OP_DONT_CARE,                                       // VkAttachmentStoreOp                  stencilStoreOp;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,                       // VkImageLayout                                initialLayout;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout                                finalLayout
+               };
+
+               const VkAttachmentDescription attachments[1] =
+               {
+                       colorAttachmentDescription
+               };
+
+               const VkAttachmentReference colorAttachmentReference =
+               {
+                       0u,                                                                                                     // deUint32                     attachment;
+                       VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                        // VkImageLayout        layout;
+               };
+
+               const VkSubpassDescription subpassDescription =
+               {
+                       0u,                                                                                                     // VkSubpassDescriptionFlags    flags;
+                       VK_PIPELINE_BIND_POINT_GRAPHICS,                                        // VkPipelineBindPoint                  pipelineBindPoint;
+                       0u,                                                                                                     // deUint32                                             inputCount;
+                       DE_NULL,                                                                                        // const VkAttachmentReference* pInputAttachments;
+                       1u,                                                                                                     // deUint32                                             colorCount;
+                       &colorAttachmentReference,                                                      // const VkAttachmentReference* pColorAttachments;
+                       DE_NULL,                                                                                        // const VkAttachmentReference* pResolveAttachments;
+                       DE_NULL,                                                                                        // VkAttachmentReference                depthStencilAttachment;
+                       0u,                                                                                                     // deUint32                                             preserveCount;
+                       DE_NULL                                                                                         // const VkAttachmentReference* pPreserveAttachments;
+               };
+
+
+               const VkRenderPassCreateInfo renderPassParams =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                      // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // const void*                                          pNext;
+                       0u,                                                                                                     // VkRenderPassCreateFlags                      flags;
+                       1u,                                                                                                     // deUint32                                                     attachmentCount;
+                       attachments,                                                                            // const VkAttachmentDescription*       pAttachments;
+                       1u,                                                                                                     // deUint32                                                     subpassCount;
+                       &subpassDescription,                                                            // const VkSubpassDescription*          pSubpasses;
+                       0u,                                                                                                     // deUint32                                                     dependencyCount;
+                       DE_NULL                                                                                         // const VkSubpassDependency*           pDependencies;
+               };
+
+               renderPass = createRenderPass(vk, vkDevice, &renderPassParams);
+       }
+
+       // Create framebuffer
+       {
+               const VkFramebufferCreateInfo framebufferParams =
+               {
+                       VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,                      // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       0u,                                                                                                     // VkFramebufferCreateFlags     flags;
+                       *renderPass,                                                                            // VkRenderPass                                 renderPass;
+                       1u,                                                                                                     // deUint32                                             attachmentCount;
+                       &*colorImageView,                                                                       // const VkAttachmentBindInfo*  pAttachments;
+                       (deUint32)renderSize.x(),                                                       // deUint32                                             width;
+                       (deUint32)renderSize.y(),                                                       // deUint32                                             height;
+                       1u                                                                                                      // deUint32                                             layers;
+               };
+
+               framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
+       }
+
+       // Create descriptors
+       {
+               const VkDescriptorSetLayoutBinding layoutBindings[2] =
+               {
+                       {
+                               0u,                                                                                             // deUint32                                     binding;
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType                     descriptorType;
+                               1u,                                                                                             // deUint32                                     arraySize;
+                               VK_SHADER_STAGE_ALL,                                                    // VkShaderStageFlags           stageFlags;
+                               DE_NULL                                                                                 // const VkSampler*                     pImmutableSamplers;
+                       },
+                       {
+                               0u,                                                                                             // deUint32                                     binding;
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType                     descriptorType;
+                               1u,                                                                                             // deUint32                                     arraySize;
+                               VK_SHADER_STAGE_ALL,                                                    // VkShaderStageFlags           stageFlags;
+                               DE_NULL                                                                                 // const VkSampler*                     pImmutableSamplers;
+                       }
+               };
+
+               const VkDescriptorSetLayoutCreateInfo descriptorLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,    // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                // cost void*                                                   pNexŧ;
+                       (VkDescriptorSetLayoutCreateFlags)0,                                    // VkDescriptorSetLayoutCreateFlags             flags;
+                       DE_LENGTH_OF_ARRAY(layoutBindings),                                             // deUint32                                                             count;
+                       layoutBindings                                                                                  // const VkDescriptorSetLayoutBinding   pBinding;
+               };
+
+               descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams);
+
+               const VkDescriptorPoolSize descriptorPoolSizes[] =
+               {
+                       {
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType             type;
+                               1u                                                                                              // deUint32                             count;
+                       },
+                       {
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                              // VkDescriptorType             type;
+                               1u                                                                                              // deUint32                             count;
+                       }
+               };
+
+               const VkDescriptorPoolCreateInfo descriptorPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,          // VkStructureType                                      sType;
+                       DE_NULL,                                                                                        // void*                                                        pNext;
+                       VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,      //VkDescriptorPoolUsage                         poolUsage;
+                       1u,                                                                                                     //deUint32                                                      maxSets;
+                       DE_LENGTH_OF_ARRAY(descriptorPoolSizes),                        // deUint32                                                     count;
+                       descriptorPoolSizes                                                                     // const VkDescriptorPoolSize*          pTypeCount
+               };
+
+               descriptorPool = createDescriptorPool(vk, vkDevice, &descriptorPoolParams);
+
+               const VkDescriptorSetAllocateInfo allocInfo =
+               {
+                       VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+                       DE_NULL,
+                       *descriptorPool,
+                       1u,
+                       &*descriptorSetLayout
+               };
+
+               descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+
+               const VkDescriptorBufferInfo descriptorBufferInfo[] =
+               {
+                       {
+                               *m_inputBuffer,                                 // VkBuffer                     buffer;
+                               0u,                                                             // VkDeviceSize         offset;
+                               VK_WHOLE_SIZE                                   // VkDeviceSize         range;
+                       },
+                       {
+                               *m_outputBuffer,                                // VkBuffer                     buffer;
+                               0u,                                                             // VkDeviceSize         offset;
+                               VK_WHOLE_SIZE                                   // VkDeviceSize         range;
+                       },
+               };
+
+               const VkWriteDescriptorSet writeDescritporSets[] =
+               {
+                       {
+                               VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,         // VkStructureType                                      sType;
+                               DE_NULL,                                                                        // const void*                                          pNext;
+                               *descriptorSet,                                                         // VkDescriptorSet                                      destSet;
+                               0u,                                                                                     // deUint32                                                     destBinding;
+                               0u,                                                                                     // deUint32                                                     destArrayElement;
+                               2u,                                                                                     // deUint32                                                     count;
+                               VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,                      // VkDescriptorType                                     descriptorType;
+                               DE_NULL,                                                                        // const VkDescriptorImageInfo*         pImageInfo;
+                               descriptorBufferInfo,                                           // const VkDescriptorBufferInfo*        pBufferInfo;
+                               DE_NULL                                                                         // const VkBufferView*                          pTexelBufferView;
+                       }
+               };
+
+               vk.updateDescriptorSets(vkDevice, 1, writeDescritporSets, 0u, DE_NULL);
+       }
+
+       // Create pipeline layout
+       {
+               const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,          // VkStructureType                              sType;
+                       DE_NULL,                                                                                        // const void*                                  pNext;
+                       (VkPipelineLayoutCreateFlags)0,                                         // VkPipelineLayoutCreateFlags  flags;
+                       1u,                                                                                                     // deUint32                                             descriptorSetCount;
+                       &*descriptorSetLayout,                                                          // const VkDescriptorSetLayout* pSetLayouts;
+                       0u,                                                                                                     // deUint32                                             pushConstantRangeCount;
+                       DE_NULL                                                                                         // const VkPushConstantRange*   pPushConstantRanges;
+               };
+
+               pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
+       }
+
+       // Create shader modules
+       {
+               vertexShaderModule              = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("vert"), 0);
+               tessControlShaderModule = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("tess_control"), 0);
+               tessEvalShaderModule    = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("tess_eval"), 0);
+               fragmentShaderModule    = createShaderModule(vk, vkDevice, ctx.getBinaryCollection().get("frag"), 0);
+       }
+
+       // Create pipeline
+       {
+               const VkPipelineShaderStageCreateInfo shaderStageParams[4] =
+               {
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
+                               VK_SHADER_STAGE_VERTEX_BIT,                                                                     // VkShaderStageFlagBit                                 stage;
+                               *vertexShaderModule,                                                                            // VkShaderModule                                               shader;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       },
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
+                               VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,                                       // VkShaderStageFlagBit                                 stage;
+                               *tessControlShaderModule,                                                                       // VkShaderModule                                               shader;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       },
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
+                               VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,                            // VkShaderStageFlagBit                                 stage;
+                               *tessEvalShaderModule,                                                                          // VkShaderModule                                               shader;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       },
+                       {
+                               VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,            // VkStructureType                                              sType;
+                               DE_NULL,                                                                                                        // const void*                                                  pNext;
+                               (VkPipelineShaderStageCreateFlags)0,                                            // VkPipelineShaderStageCreateFlags             flags;
+                               VK_SHADER_STAGE_FRAGMENT_BIT,                                                           // VkShaderStageFlagBit                                 stage;
+                               *fragmentShaderModule,                                                                          // VkShaderModule                                               shader;
+                               "main",                                                                                                         // const char*                                                  pName;
+                               DE_NULL                                                                                                         // const VkSpecializationInfo*                  pSpecializationInfo;
+                       }
+               };
+
+               const VkPipelineVertexInputStateCreateInfo vertexInputStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,              // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       (VkPipelineVertexInputStateCreateFlags)0,                                               // VkPipelineVertexInputStateCreateFlags        flags;
+                       0u,                                                                                                                             // deUint32                                                                     bindingCount;
+                       DE_NULL,                                                                                                                // const VkVertexInputBindingDescription*       pVertexBindingDescriptions;
+                       0u,                                                                                                                             // deUint32                                                                     attributeCount;
+                       DE_NULL,                                                                                                                // const VkVertexInputAttributeDescription*     pvertexAttributeDescriptions;
+               };
+
+               const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,    // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                                // const void*                                                  pNext;
+                       (VkPipelineShaderStageCreateFlags)0,                                                    // VkPipelineShaderStageCreateFlags     flags;
+                       VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,                                                               // VkPrimitiveTopology                                  topology;
+                       DE_FALSE                                                                                                                // VkBool32                                                             primitiveRestartEnable;
+               };
+
+               struct VkPipelineTessellationStateCreateInfo tessellationStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,              // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       (VkPipelineTesselationStateCreateFlags)0,                                               // VkPipelineTessellationStateCreateFlags       flags;
+                       vertexCount                                                                                                             // uint32_t                                                                     patchControlPoints;
+               };
+
+               const VkViewport viewport =
+               {
+                       0.0f,                                           // float        originX;
+                       0.0f,                                           // float        originY;
+                       (float)renderSize.x(),          // float        width;
+                       (float)renderSize.y(),          // float        height;
+                       0.0f,                                           // float        minDepth;
+                       1.0f                                            // float        maxDepth;
+               };
+
+               const VkRect2D scissor =
+               {
+                       {
+                               0u,                                             // deUint32     x;
+                               0u,                                             // deUint32     y;
+                       },                                                      // VkOffset2D   offset;
+                       {
+                               renderSize.x(),                 // deUint32     width;
+                               renderSize.y(),                 // deUint32     height;
+                       },                                                      // VkExtent2D   extent;
+               };
+
+               const VkPipelineViewportStateCreateInfo viewportStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,  // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                // const void*                                                  pNext;
+                       (VkPipelineViewportStateCreateFlags)0,                                  // VkPipelineViewPortStateCreateFlags   flags;
+                       1u,                                                                                                             // deUint32                                                             viewportCount;
+                       &viewport,                                                                                              // const VkViewport*                                    pViewports;
+                       1u,                                                                                                             // deUint32                                                             scissorsCount;
+                       &scissor                                                                                                // const VkRect2D*                                              pScissors;
+               };
+
+               const VkPipelineRasterizationStateCreateInfo rasterStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,             // VkStructureType                                                      sType;
+                       DE_NULL,                                                                                                                // const void*                                                          pNext;
+                       (VkPipelineRasterizationStateCreateFlags)0,                                             // VkPipelineRasterizationStageCreateFlags      flags;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     depthClipEnable;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     rasterizerDiscardEnable;
+                       VK_POLYGON_MODE_FILL,                                                                                   // VkPolygonMode                                                        polygonMode;
+                       VK_CULL_MODE_NONE,                                                                                              // VkCullMode                                                           cullMode;
+                       VK_FRONT_FACE_COUNTER_CLOCKWISE,                                                                // VkFrontFace                                                          frontFace;
+                       VK_FALSE,                                                                                                               // VkBool32                                                                     depthBiasEnable;
+                       0.0f,                                                                                                                   // float                                                                        depthBias;
+                       0.0f,                                                                                                                   // float                                                                        depthBiasClamp;
+                       0.0f,                                                                                                                   // float                                                                        slopeScaledDepthBias;
+                       1.0f                                                                                                                    // float                                                                        lineWidth;
+               };
+
+               const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+               {
+                       VK_FALSE,                                               // VkBool32                                     blendEnable;
+                       VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcBlendColor;
+                       VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        destBlendColor;
+                       VK_BLEND_OP_ADD,                                // VkBlendOp                            blendOpColor;
+                       VK_BLEND_FACTOR_ONE,                    // VkBlendFactor                        srcBlendAlpha;
+                       VK_BLEND_FACTOR_ZERO,                   // VkBlendFactor                        destBlendAlpha;
+                       VK_BLEND_OP_ADD,                                // VkBlendOp                            blendOpAlpha;
+                       (VK_COLOR_COMPONENT_R_BIT |
+                        VK_COLOR_COMPONENT_G_BIT |
+                        VK_COLOR_COMPONENT_B_BIT |
+                        VK_COLOR_COMPONENT_A_BIT)              // VkColorComponentFlags        colorWriteMask;
+               };
+
+               const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,       // VkStructureType                                                              sType;
+                       DE_NULL,                                                                                                        // const void*                                                                  pNext;
+                       (VkPipelineColorBlendStateCreateFlags)0,                                        // VkPipelineColorBlendStateCreateFlags                 flags
+                       VK_FALSE,                                                                                                       // VkBool32                                                                             logicOpEnable;
+                       VK_LOGIC_OP_COPY,                                                                                       // VkLogicOp                                                                    logicOp;
+                       1u,                                                                                                                     // deUint32                                                                             attachmentCount;
+                       &colorBlendAttachmentState,                                                                     // const VkPipelineColorBlendAttachmentState*   pAttachments;
+                       { 0.0f, 0.0f, 0.0f, 0.0f }                                                                      // float                                                                                blendConst[4];
+               };
+
+               const VkPipelineDynamicStateCreateInfo dynamicStateInfo =
+               {
+                       VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,           // VkStructureType                                              sType;
+                       DE_NULL,                                                                                                        // const void*                                                  pNext;
+                       (VkPipelineDynamicStateCreateFlags)0,                                           // VkPipelineDynamicStateCreateFlags    flags;
+                       0u,                                                                                                                     // deUint32                                                             dynamicStateCount;
+                       DE_NULL                                                                                                         // const VkDynamicState*                                pDynamicStates;
+               };
+
+               const VkGraphicsPipelineCreateInfo graphicsPipelineParams =
+               {
+                       VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,        // VkStructureType                                                                      sType;
+                       DE_NULL,                                                                                        // const void*                                                                          pNext;
+                       0u,                                                                                                     // VkPipelineCreateFlags                                                        flags;
+                       4u,                                                                                                     // deUint32                                                                                     stageCount;
+                       shaderStageParams,                                                                      // const VkPipelineShaderStageCreateInfo*                       pStages;
+                       &vertexInputStateParams,                                                        // const VkPipelineVertexInputStateCreateInfo*          pVertexInputState;
+                       &inputAssemblyStateParams,                                                      // const VkPipelineInputAssemblyStateCreateInfo*        pInputAssemblyState;
+                       &tessellationStateParams,                                                       // const VkPipelineTessellationStateCreateInfo*         pTessellationState;
+                       &viewportStateParams,                                                           // const VkPipelineViewportStateCreateInfo*                     pViewportState;
+                       &rasterStateParams,                                                                     // const VkPipelineRasterStateCreateInfo*                       pRasterState;
+                       DE_NULL,                                                                                        // const VkPipelineMultisampleStateCreateInfo*          pMultisampleState;
+                       DE_NULL,                                                                                        // const VkPipelineDepthStencilStateCreateInfo*         pDepthStencilState;
+                       &colorBlendStateParams,                                                         // const VkPipelineColorBlendStateCreateInfo*           pColorBlendState;
+                       &dynamicStateInfo,                                                                      // const VkPipelineDynamicStateCreateInfo*                      pDynamicState;
+                       *pipelineLayout,                                                                        // VkPipelineLayout                                                                     layout;
+                       *renderPass,                                                                            // VkRenderPass                                                                         renderPass;
+                       0u,                                                                                                     // deUint32                                                                                     subpass;
+                       0u,                                                                                                     // VkPipeline                                                                           basePipelineHandle;
+                       0u                                                                                                      // deInt32                                                                                      basePipelineIndex;
+               };
+
+               graphicsPipeline = createGraphicsPipeline(vk, vkDevice, DE_NULL, &graphicsPipelineParams);
+       }
+
+       // Create command pool
+       {
+               const VkCommandPoolCreateInfo cmdPoolParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,             // VkStructureType              sType;
+                       DE_NULL,                                                                                // const void*                  pNext;
+                       VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,                   // VkCmdPoolCreateFlags flags;
+                       queueFamilyIndex,                                                               // deUint32                             queueFamilyIndex;
+               };
+
+               cmdPool = createCommandPool(vk, vkDevice, &cmdPoolParams);
+       }
+
+       // Create command buffer
+       {
+               const VkCommandBufferAllocateInfo cmdBufferParams =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, // VkStructureType                      sType;
+                       DE_NULL,                                                                                // const void*                          pNext;
+                       *cmdPool,                                                                               // VkCmdPool                            cmdPool;
+                       VK_COMMAND_BUFFER_LEVEL_PRIMARY,                                // VkCmdBufferLevel                     level;
+                       0u                                                                                              // VkCmdBufferCreateFlags       flags;
+               };
+
+               const VkCommandBufferBeginInfo cmdBufferBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,    // VkStructureType                                      sType;
+                       DE_NULL,                                                                                // const void*                                          pNext;
+                       0u,                                                                                             // VkCmdBufferOptimizeFlags                     flags;
+                       DE_NULL,                                                                                // VkRenderPass                                         renderPass;
+                       0u,                                                                                             // deUint32                                                     subpass;
+                       DE_NULL,                                                                                // VkFramebuffer                                        framebuffer;
+                       VK_FALSE,                                                                               //VkBool32                                                      occlusionQueryEnable;
+                       (VkQueryControlFlags)0u,                                                // VkQueryControlFlags                          queryFlags;
+                       (VkQueryPipelineStatisticFlags)0u                               // VkQueryPipelineStatisticFlags        pipelineStatistics;
+
+               };
+
+               const VkClearValue clearValues[1] =
+               {
+                       getDefaultClearColor()
+               };
+
+               const VkRenderPassBeginInfo renderPassBeginInfo =
+               {
+                       VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,                               // VkStructureType              sType;
+                       DE_NULL,                                                                                                // const void*                  pNext;
+                       *renderPass,                                                                                    // VkRenderPass                 renderPass;
+                       *framebuffer,                                                                                   // VkFramebuffer                framebuffer;
+                       { { 0, 0 }, { renderSize.x(), renderSize.y() } },               // VkRect2D                             renderArea;
+                       1,                                                                                                              // deUint32                             attachmentCount;
+                       clearValues                                                                                             // const VkClearValue*  pClearValues;
+               };
+
+               cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
+
+               VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
+
+               vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+               vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
+
+               vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &*descriptorSet, 0u, DE_NULL);
+
+               vk.cmdDraw(*cmdBuffer, vertexCount, 1, 0, 0);
+
+               vk.cmdEndRenderPass(*cmdBuffer);
+               VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
+       }
+
+       // Create fence
+       {
+               const VkFenceCreateInfo fenceParams =
+               {
+                       VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,    // VkStructureType              sType;
+                       DE_NULL,                                                                // const void*                  pNext;
+                       0u                                                                              // VkFenceCreateFlags   flags;
+               };
+               fence = createFence(vk, vkDevice, &fenceParams);
+       }
+
+       // Execute Draw
+       {
+               VK_CHECK(vk.resetFences(vkDevice, 1, &fence.get()));
+               const VkSubmitInfo submitInfo =
+               {
+                       VK_STRUCTURE_TYPE_SUBMIT_INFO,
+                       DE_NULL,
+                       0u,
+                       (const VkSemaphore*)0,
+                       1u,
+                       &cmdBuffer.get(),
+                       0u,
+                       (const VkSemaphore*)0,
+               };
+               VK_CHECK(vk.queueSubmit(queue, 1, &submitInfo, *fence));
+               VK_CHECK(vk.waitForFences(vkDevice, 1, &fence.get(), true, ~(0ull) /* infinity*/));
+       }
+}
+
+// TessControlExecutor
+
+class TessControlExecutor : public TessellationExecutor
+{
+public:
+                                               TessControlExecutor                     (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                         ~TessControlExecutor            (void);
+
+       virtual void            setShaderSources                        (SourceCollections& programCollection) const;
+
+       virtual void            execute                                         (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs);
+
+protected:
+       static std::string      generateTessControlShader       (const ShaderSpec& shaderSpec);
+};
+
+TessControlExecutor::TessControlExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : TessellationExecutor (shaderSpec, shaderType)
+{
+}
+
+TessControlExecutor::~TessControlExecutor (void)
+{
+}
+
+std::string TessControlExecutor::generateTessControlShader (const ShaderSpec& shaderSpec)
+{
+       std::ostringstream src;
+       src <<  "#version 310 es\n"
+                       "#extension GL_EXT_tessellation_shader : require\n\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       src << "\nlayout(vertices = 1) out;\n\n";
+
+       declareBufferBlocks(src, shaderSpec);
+
+       src << "void main (void)\n{\n";
+
+       for (int ndx = 0; ndx < 2; ndx++)
+               src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
+
+       for (int ndx = 0; ndx < 4; ndx++)
+               src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
+
+       src << "\n"
+               << "\thighp uint invocationId = uint(gl_PrimitiveID);\n";
+
+       generateExecBufferIo(src, shaderSpec, "invocationId");
+
+       src << "}\n";
+
+       return src.str();
+}
+
+static std::string generateEmptyTessEvalShader ()
+{
+       std::ostringstream src;
+
+       src <<  "#version 310 es\n"
+                       "#extension GL_EXT_tessellation_shader : require\n\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       src << "layout(triangles, ccw) in;\n";
+
+       src << "\nvoid main (void)\n{\n"
+               << "\tgl_Position = vec4(gl_TessCoord.xy, 0.0, 1.0);\n"
+               << "}\n";
+
+       return src.str();
+}
+
+void TessControlExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("vert") << glu::VertexSource(generateVertexShaderForTess());
+       programCollection.glslSources.add("tess_control") << glu::TessellationControlSource(generateTessControlShader(m_shaderSpec));
+       programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(generateEmptyTessEvalShader());
+       programCollection.glslSources.add("frag") << glu::FragmentSource(generateEmptyFragmentSource());
+}
+
+void TessControlExecutor::execute (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs)
+{
+       checkSupported(ctx, m_shaderType);
+
+       initBuffers(ctx, numValues);
+
+       // Setup input buffer & copy data
+       uploadInputBuffer(ctx, inputs, numValues);
+
+       renderTess(ctx, 3 * numValues);
+
+       // Read back data
+       readOutputBuffer(ctx, outputs, numValues);
+}
+
+// TessEvaluationExecutor
+
+class TessEvaluationExecutor : public TessellationExecutor
+{
+public:
+                                               TessEvaluationExecutor  (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+       virtual                         ~TessEvaluationExecutor (void);
+
+       virtual void            setShaderSources                (SourceCollections& programCollection) const;
+
+       virtual void            execute                                 (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs);
+
+protected:
+       static std::string      generateTessEvalShader  (const ShaderSpec& shaderSpec);
+};
+
+TessEvaluationExecutor::TessEvaluationExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : TessellationExecutor (shaderSpec, shaderType)
+{
+}
+
+TessEvaluationExecutor::~TessEvaluationExecutor (void)
+{
+}
+
+static std::string generatePassthroughTessControlShader (void)
+{
+       std::ostringstream src;
+
+       src <<  "#version 310 es\n"
+                       "#extension GL_EXT_tessellation_shader : require\n\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       src << "layout(vertices = 1) out;\n\n";
+
+       src << "void main (void)\n{\n";
+
+       for (int ndx = 0; ndx < 2; ndx++)
+               src << "\tgl_TessLevelInner[" << ndx << "] = 1.0;\n";
+
+       for (int ndx = 0; ndx < 4; ndx++)
+               src << "\tgl_TessLevelOuter[" << ndx << "] = 1.0;\n";
+
+       src << "}\n";
+
+       return src.str();
+}
+
+std::string TessEvaluationExecutor::generateTessEvalShader (const ShaderSpec& shaderSpec)
+{
+       std::ostringstream src;
+
+       src <<  "#version 310 es\n"
+                       "#extension GL_EXT_tessellation_shader : require\n\n"
+                       "#extension GL_ARB_separate_shader_objects : enable\n"
+                       "#extension GL_ARB_shading_language_420pack : enable\n";
+
+       if (!shaderSpec.globalDeclarations.empty())
+               src << shaderSpec.globalDeclarations << "\n";
+
+       src << "\n";
+
+       src << "layout(isolines, equal_spacing) in;\n\n";
+
+       declareBufferBlocks(src, shaderSpec);
+
+       src << "void main (void)\n{\n"
+               << "\tgl_Position = vec4(gl_TessCoord.x, 0.0, 0.0, 1.0);\n"
+               << "\thighp uint invocationId = uint(gl_PrimitiveID) + (gl_TessCoord.x > 0.5 ? 1u : 0u);\n";
+
+       generateExecBufferIo(src, shaderSpec, "invocationId");
+
+       src     << "}\n";
+
+       return src.str();
+}
+
+void TessEvaluationExecutor::setShaderSources (SourceCollections& programCollection) const
+{
+       programCollection.glslSources.add("vert") << glu::VertexSource(generateVertexShaderForTess());
+       programCollection.glslSources.add("tess_control") << glu::TessellationControlSource(generatePassthroughTessControlShader());
+       programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(generateTessEvalShader(m_shaderSpec));
+       programCollection.glslSources.add("frag") << glu::FragmentSource(generateEmptyFragmentSource());
+}
+
+void TessEvaluationExecutor::execute (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs)
+{
+       checkSupported(ctx, m_shaderType);
+
+       const int       alignedValues   = deAlign32(numValues, 2);
+
+       // Initialize buffers with aligned value count to make room for padding
+       initBuffers(ctx, alignedValues);
+
+       // Setup input buffer & copy data
+       uploadInputBuffer(ctx, inputs, numValues);
+
+       renderTess(ctx, 2 * numValues);
+
+       // Read back data
+       readOutputBuffer(ctx, outputs, numValues);
+}
+
+} // anonymous
+
+// ShaderExecutor
+
+ShaderExecutor::ShaderExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType)
+       : m_shaderSpec  (shaderSpec)
+       , m_shaderType  (shaderType)
+{
+}
+
+ShaderExecutor::~ShaderExecutor (void)
+{
+}
+
+// Utilities
+
+ShaderExecutor* createExecutor (glu::ShaderType shaderType, const ShaderSpec& shaderSpec)
+{
+       switch (shaderType)
+       {
+               case glu::SHADERTYPE_VERTEX:                                    return new VertexShaderExecutor         (shaderSpec, shaderType);
+               case glu::SHADERTYPE_TESSELLATION_CONTROL:              return new TessControlExecutor          (shaderSpec, shaderType);
+               case glu::SHADERTYPE_TESSELLATION_EVALUATION:   return new TessEvaluationExecutor       (shaderSpec, shaderType);
+               case glu::SHADERTYPE_GEOMETRY:                                  return new GeometryShaderExecutor       (shaderSpec, shaderType);
+               case glu::SHADERTYPE_FRAGMENT:                                  return new FragmentShaderExecutor       (shaderSpec, shaderType);
+               case glu::SHADERTYPE_COMPUTE:                                   return new ComputeShaderExecutor        (shaderSpec, shaderType);
+               default:
+                       throw tcu::InternalError("Unsupported shader type");
+       }
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp
new file mode 100644 (file)
index 0000000..6f6d523
--- /dev/null
@@ -0,0 +1,101 @@
+#ifndef _VKTSHADEREXECUTOR_HPP
+#define _VKTSHADEREXECUTOR_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan ShaderExecutor
+ *//*--------------------------------------------------------------------*/
+
+#include "vktTestCase.hpp"
+#include "vkPrograms.hpp"
+
+#include "gluVarType.hpp"
+
+#include <vector>
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+//! Shader input / output variable declaration.
+struct Symbol
+{
+       std::string                             name;           //!< Symbol name.
+       glu::VarType                    varType;        //!< Symbol type.
+
+
+       Symbol (void) {}
+       Symbol (const std::string& name_, const glu::VarType& varType_) : name(name_), varType(varType_) {}
+};
+
+//! Complete shader specification.
+struct ShaderSpec
+{
+       std::vector<Symbol>             inputs;
+       std::vector<Symbol>             outputs;
+       std::string                             globalDeclarations;     //!< These are placed into global scope. Can contain uniform declarations for example.
+       std::string                             source;                         //!< Source snippet to be executed.
+
+       ShaderSpec (void) {}
+};
+
+//! Base class for shader executor.
+class ShaderExecutor
+{
+public:
+       virtual                                 ~ShaderExecutor         (void);
+
+       //! Log executor details (program etc.).
+       virtual void                    log                                     (tcu::TestLog& log) const = 0;
+
+       //! Execute
+       virtual void                    execute                         (const Context& ctx, int numValues, const void* const* inputs, void* const* outputs) = 0;
+
+       virtual void                    setShaderSources        (vk::SourceCollections& programCollection) const = 0;
+
+protected:
+                                                       ShaderExecutor          (const ShaderSpec& shaderSpec, glu::ShaderType shaderType);
+
+       const ShaderSpec                m_shaderSpec;
+       const glu::ShaderType   m_shaderType;
+};
+
+inline tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderExecutor* executor) { executor->log(log); return log; }
+inline tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderExecutor& executor) { executor.log(log); return log; }
+
+ShaderExecutor* createExecutor(glu::ShaderType shaderType, const ShaderSpec& shaderSpec);
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTSHADEREXECUTOR_HPP
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp
new file mode 100644 (file)
index 0000000..a6fd155
--- /dev/null
@@ -0,0 +1,61 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan shader render test cases
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderExecutorTests.hpp"
+
+#include "deUniquePtr.hpp"
+
+#include "vktShaderCommonFunctionTests.hpp"
+#include "vktShaderIntegerFunctionTests.hpp"
+#include "vktShaderPackingFunctionTests.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> shaderExecutorTests (new tcu::TestCaseGroup(testCtx, "ShaderExecutor", "shaderExecutor Tests"));
+
+       shaderExecutorTests->addChild(new ShaderCommonFunctionTests(testCtx));
+       shaderExecutorTests->addChild(new ShaderIntegerFunctionTests(testCtx));
+       shaderExecutorTests->addChild(new ShaderPackingFunctionTests(testCtx));
+
+       return shaderExecutorTests.release();
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.hpp
new file mode 100644 (file)
index 0000000..08cd649
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _VKTSHADEREXECUTORTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Vulkan shader render test cases
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+tcu::TestCaseGroup*            createTests                     (tcu::TestContext& testCtx);
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTSHADEREXECUTORTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.cpp
new file mode 100644 (file)
index 0000000..ef0119b
--- /dev/null
@@ -0,0 +1,1358 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Integer built-in function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderIntegerFunctionTests.hpp"
+#include "vktShaderExecutor.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuFloat.hpp"
+#include "deRandom.hpp"
+#include "deMath.h"
+#include "deString.h"
+#include "deInt32.h"
+#include "deSharedPtr.hpp"
+
+#include <iostream>
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+using std::vector;
+using std::string;
+using tcu::TestLog;
+
+using tcu::IVec2;
+using tcu::IVec3;
+using tcu::IVec4;
+using tcu::UVec2;
+using tcu::UVec3;
+using tcu::UVec4;
+
+// Utilities
+
+namespace
+{
+
+struct HexFloat
+{
+       const float value;
+       HexFloat (const float value_) : value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const HexFloat& v)
+{
+       return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
+}
+
+struct VarValue
+{
+       const glu::VarType&     type;
+       const void*                     value;
+
+       VarValue (const glu::VarType& type_, const void* value_) : type(type_), value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const VarValue& varValue)
+{
+       DE_ASSERT(varValue.type.isBasicType());
+
+       const glu::DataType             basicType               = varValue.type.getBasicType();
+       const glu::DataType             scalarType              = glu::getDataTypeScalarType(basicType);
+       const int                               numComponents   = glu::getDataTypeScalarSize(basicType);
+
+       if (numComponents > 1)
+               str << glu::getDataTypeName(basicType) << "(";
+
+       for (int compNdx = 0; compNdx < numComponents; compNdx++)
+       {
+               if (compNdx != 0)
+                       str << ", ";
+
+               switch (scalarType)
+               {
+                       case glu::TYPE_FLOAT:   str << HexFloat(((const float*)varValue.value)[compNdx]);                                               break;
+                       case glu::TYPE_INT:             str << ((const deInt32*)varValue.value)[compNdx];                                                               break;
+                       case glu::TYPE_UINT:    str << tcu::toHex(((const deUint32*)varValue.value)[compNdx]);                                  break;
+                       case glu::TYPE_BOOL:    str << (((const deUint32*)varValue.value)[compNdx] != 0 ? "true" : "false");    break;
+
+                       default:
+                               DE_ASSERT(false);
+               }
+       }
+
+       if (numComponents > 1)
+               str << ")";
+
+       return str;
+}
+
+inline int getShaderUintBitCount (glu::ShaderType shaderType, glu::Precision precision)
+{
+       // \todo [2013-10-31 pyry] Query from GL for vertex and fragment shaders.
+       DE_UNREF(shaderType);
+       const int bitCounts[] = { 9, 16, 32 };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(bitCounts) == glu::PRECISION_LAST);
+       return bitCounts[precision];
+}
+
+static inline deUint32 extendSignTo32 (deUint32 integer, deUint32 integerLength)
+{
+       DE_ASSERT(integerLength > 0 && integerLength <= 32);
+
+       return deUint32(0 - deInt32((integer & (1 << (integerLength - 1))) << 1)) | integer;
+}
+
+static inline deUint32 getLowBitMask (int integerLength)
+{
+       DE_ASSERT(integerLength >= 0 && integerLength <= 32);
+
+       // \note: shifting more or equal to 32 => undefined behavior. Avoid it by shifting in two parts (1 << (num-1) << 1)
+       if (integerLength == 0u)
+               return 0u;
+       return ((1u << ((deUint32)integerLength - 1u)) << 1u) - 1u;
+}
+
+static void generateRandomInputData (de::Random& rnd, glu::ShaderType shaderType, glu::DataType dataType, glu::Precision precision, deUint32* dst, int numValues)
+{
+       const int                               scalarSize              = glu::getDataTypeScalarSize(dataType);
+       const deUint32                  integerLength   = (deUint32)getShaderUintBitCount(shaderType, precision);
+       const deUint32                  integerMask             = getLowBitMask(integerLength);
+       const bool                              isUnsigned              = glu::isDataTypeUintOrUVec(dataType);
+
+       if (isUnsigned)
+       {
+               for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               dst[valueNdx*scalarSize + compNdx] = rnd.getUint32() & integerMask;
+       }
+       else
+       {
+               for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               dst[valueNdx*scalarSize + compNdx] = extendSignTo32(rnd.getUint32() & integerMask, integerLength);
+       }
+}
+
+static vector<int> getScalarSizes (const vector<Symbol>& symbols)
+{
+       vector<int> sizes(symbols.size());
+       for (int ndx = 0; ndx < (int)symbols.size(); ++ndx)
+               sizes[ndx] = symbols[ndx].varType.getScalarSize();
+       return sizes;
+}
+
+static int computeTotalScalarSize (const vector<Symbol>& symbols)
+{
+       int totalSize = 0;
+       for (vector<Symbol>::const_iterator sym = symbols.begin(); sym != symbols.end(); ++sym)
+               totalSize += sym->varType.getScalarSize();
+       return totalSize;
+}
+
+static vector<void*> getInputOutputPointers (const vector<Symbol>& symbols, vector<deUint32>& data, const int numValues)
+{
+       vector<void*>   pointers                (symbols.size());
+       int                             curScalarOffset = 0;
+
+       for (int varNdx = 0; varNdx < (int)symbols.size(); ++varNdx)
+       {
+               const Symbol&   var                             = symbols[varNdx];
+               const int               scalarSize              = var.varType.getScalarSize();
+
+               // Uses planar layout as input/output specs do not support strides.
+               pointers[varNdx] = &data[curScalarOffset];
+               curScalarOffset += scalarSize*numValues;
+       }
+
+       DE_ASSERT(curScalarOffset == (int)data.size());
+
+       return pointers;
+}
+
+static const char* getPrecisionPostfix (glu::Precision precision)
+{
+       static const char* s_postfix[] =
+       {
+               "_lowp",
+               "_mediump",
+               "_highp"
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[precision];
+}
+
+static const char* getShaderTypePostfix (glu::ShaderType shaderType)
+{
+       static const char* s_postfix[] =
+       {
+               "_vertex",
+               "_fragment",
+               "_geometry",
+               "_tess_control",
+               "_tess_eval",
+               "_compute"
+       };
+       DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[shaderType];
+}
+
+static std::string getIntegerFuncCaseName (glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+{
+       return string(glu::getDataTypeName(baseType)) + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType);
+}
+
+static inline deUint32 reverseBits (deUint32 v)
+{
+       v = (((v & 0xaaaaaaaa) >> 1) | ((v & 0x55555555) << 1));
+       v = (((v & 0xcccccccc) >> 2) | ((v & 0x33333333) << 2));
+       v = (((v & 0xf0f0f0f0) >> 4) | ((v & 0x0f0f0f0f) << 4));
+       v = (((v & 0xff00ff00) >> 8) | ((v & 0x00ff00ff) << 8));
+       return((v >> 16) | (v << 16));
+}
+
+static int findLSB (deUint32 value)
+{
+       for (int i = 0; i < 32; i++)
+       {
+               if (value & (1u<<i))
+                       return i;
+       }
+       return -1;
+}
+
+static int findMSB (deInt32 value)
+{
+       if (value > 0)
+               return 31 - deClz32((deUint32)value);
+       else if (value < 0)
+               return 31 - deClz32(~(deUint32)value);
+       else
+               return -1;
+}
+
+static int findMSB (deUint32 value)
+{
+       if (value > 0)
+               return 31 - deClz32(value);
+       else
+               return -1;
+}
+
+static deUint32 toPrecision (deUint32 value, int numIntegerBits)
+{
+       return value & getLowBitMask(numIntegerBits);
+}
+
+static deInt32 toPrecision (deInt32 value, int numIntegerBits)
+{
+       return (deInt32)extendSignTo32((deUint32)value & getLowBitMask(numIntegerBits), numIntegerBits);
+}
+
+template<class TestClass>
+static void addFunctionCases (tcu::TestCaseGroup* parent, const char* functionName, bool intTypes, bool uintTypes, bool allPrec, deUint32 shaderBits)
+{
+       tcu::TestCaseGroup* group = new tcu::TestCaseGroup(parent->getTestContext(), functionName, functionName);
+
+       parent->addChild(group);
+       const glu::DataType scalarTypes[] =
+       {
+               glu::TYPE_INT,
+               glu::TYPE_UINT
+       };
+
+       for (int scalarTypeNdx = 0; scalarTypeNdx < DE_LENGTH_OF_ARRAY(scalarTypes); scalarTypeNdx++)
+       {
+               const glu::DataType scalarType = scalarTypes[scalarTypeNdx];
+
+               if ((!intTypes && scalarType == glu::TYPE_INT) || (!uintTypes && scalarType == glu::TYPE_UINT))
+                       continue;
+
+               for (int vecSize = 1; vecSize <= 4; vecSize++)
+               {
+                       for (int prec = glu::PRECISION_LOWP; prec <= glu::PRECISION_HIGHP; prec++)
+                       {
+                               if (prec != glu::PRECISION_HIGHP && !allPrec)
+                                       continue;
+
+                               for (int shaderTypeNdx = 0; shaderTypeNdx < glu::SHADERTYPE_LAST; shaderTypeNdx++)
+                               {
+                                       if (shaderBits & (1<<shaderTypeNdx))
+                                               group->addChild(new TestClass(parent->getTestContext(), glu::DataType(scalarType + vecSize - 1), glu::Precision(prec), glu::ShaderType(shaderTypeNdx)));
+                               }
+                       }
+               }
+       }
+}
+
+} // anonymous
+
+// IntegerFunctionCase
+
+class IntegerFunctionCase : public TestCase
+{
+public:
+                                                                               IntegerFunctionCase             (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
+                                                                               ~IntegerFunctionCase    (void);
+
+       virtual void                                            initPrograms                    (vk::SourceCollections& programCollection) const
+                                                                               {
+                                                                                       m_executor->setShaderSources(programCollection);
+                                                                               }
+
+       virtual TestInstance*                           createInstance                  (Context& context) const = 0;
+       virtual void                                            init                                    (void);
+
+protected:
+                                                                               IntegerFunctionCase             (const IntegerFunctionCase& other);
+       IntegerFunctionCase&                            operator=                               (const IntegerFunctionCase& other);
+
+       const glu::ShaderType                           m_shaderType;
+
+       ShaderSpec                                                      m_spec;
+
+       de::MovePtr<ShaderExecutor>                     m_executor;
+
+       const int                                                       m_numValues;
+};
+
+IntegerFunctionCase::IntegerFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
+       : TestCase              (testCtx, name, description)
+       , m_shaderType  (shaderType)
+       , m_executor    (DE_NULL)
+       , m_numValues   (100)
+{
+}
+
+IntegerFunctionCase::~IntegerFunctionCase (void)
+{
+}
+
+void IntegerFunctionCase::init (void)
+{
+       DE_ASSERT(!m_executor);
+
+       m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_spec));
+       m_testCtx.getLog() << *m_executor;
+}
+
+// IntegerFunctionTestInstance
+
+class IntegerFunctionTestInstance : public TestInstance
+{
+public:
+                                                               IntegerFunctionTestInstance             (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+                                                                       : TestInstance  (context)
+                                                                       , m_shaderType  (shaderType)
+                                                                       , m_spec                (spec)
+                                                                       , m_numValues   (numValues)
+                                                                       , m_name                (name)
+                                                                       , m_executor    (executor)
+                                                               {
+                                                               }
+       virtual tcu::TestStatus         iterate                                                 (void);
+protected:
+       virtual bool                                            compare                                 (const void* const* inputs, const void* const* outputs) = 0;
+
+       virtual void                                            getInputValues                  (int numValues, void* const* values) const = 0;
+
+       const glu::ShaderType                           m_shaderType;
+
+       ShaderSpec                                                      m_spec;
+
+       const int                                                       m_numValues;
+
+       const char*                                             m_name;
+
+       std::ostringstream                                      m_failMsg;                              //!< Comparison failure help message.
+
+       ShaderExecutor&                                         m_executor;
+};
+
+tcu::TestStatus IntegerFunctionTestInstance::iterate (void)
+{
+       const int                               numInputScalars                 = computeTotalScalarSize(m_spec.inputs);
+       const int                               numOutputScalars                = computeTotalScalarSize(m_spec.outputs);
+       vector<deUint32>                inputData                               (numInputScalars * m_numValues);
+       vector<deUint32>                outputData                              (numOutputScalars * m_numValues);
+       const vector<void*>             inputPointers                   = getInputOutputPointers(m_spec.inputs, inputData, m_numValues);
+       const vector<void*>             outputPointers                  = getInputOutputPointers(m_spec.outputs, outputData, m_numValues);
+
+       // Initialize input data.
+       getInputValues(m_numValues, &inputPointers[0]);
+
+       // Execute shader.
+       m_executor.execute(m_context, m_numValues, &inputPointers[0], &outputPointers[0]);
+
+       // Compare results.
+       {
+               const vector<int>               inScalarSizes           = getScalarSizes(m_spec.inputs);
+               const vector<int>               outScalarSizes          = getScalarSizes(m_spec.outputs);
+               vector<void*>                   curInputPtr                     (inputPointers.size());
+               vector<void*>                   curOutputPtr            (outputPointers.size());
+               int                                             numFailed                       = 0;
+               tcu::TestContext&               testCtx                         = m_context.getTestContext();
+               for (int valNdx = 0; valNdx < m_numValues; valNdx++)
+               {
+                       // Set up pointers for comparison.
+                       for (int inNdx = 0; inNdx < (int)curInputPtr.size(); ++inNdx)
+                               curInputPtr[inNdx] = (deUint32*)inputPointers[inNdx] + inScalarSizes[inNdx]*valNdx;
+
+                       for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); ++outNdx)
+                               curOutputPtr[outNdx] = (deUint32*)outputPointers[outNdx] + outScalarSizes[outNdx]*valNdx;
+
+                       if (!compare(&curInputPtr[0], &curOutputPtr[0]))
+                       {
+                               // \todo [2013-08-08 pyry] We probably want to log reference value as well?
+
+                               testCtx.getLog() << TestLog::Message << "ERROR: comparison failed for value " << valNdx << ":\n  " << m_failMsg.str() << TestLog::EndMessage;
+
+                               testCtx.getLog() << TestLog::Message << "  inputs:" << TestLog::EndMessage;
+                               for (int inNdx = 0; inNdx < (int)curInputPtr.size(); inNdx++)
+                                       testCtx.getLog() << TestLog::Message << "    " << m_spec.inputs[inNdx].name << " = "
+                                                                                                                  << VarValue(m_spec.inputs[inNdx].varType, curInputPtr[inNdx])
+                                                                          << TestLog::EndMessage;
+
+                               testCtx.getLog() << TestLog::Message << "  outputs:" << TestLog::EndMessage;
+                               for (int outNdx = 0; outNdx < (int)curOutputPtr.size(); outNdx++)
+                                       testCtx.getLog() << TestLog::Message << "    " << m_spec.outputs[outNdx].name << " = "
+                                                                                                                  << VarValue(m_spec.outputs[outNdx].varType, curOutputPtr[outNdx])
+                                                                          << TestLog::EndMessage;
+
+                               m_failMsg.str("");
+                               m_failMsg.clear();
+                               numFailed += 1;
+                       }
+               }
+
+               testCtx.getLog() << TestLog::Message << (m_numValues - numFailed) << " / " << m_numValues << " values passed" << TestLog::EndMessage;
+
+               if (numFailed == 0)
+                       return tcu::TestStatus::pass("Pass");
+               else
+                       return tcu::TestStatus::fail("Result comparison failed");
+       }
+}
+
+// Test cases
+
+class UaddCarryCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       UaddCarryCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0x235facu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  integerMask             = getLowBitMask(integerLength);
+               const bool                              isSigned                = glu::isDataTypeIntOrIVec(type);
+               deUint32*                               in0                             = (deUint32*)values[0];
+               deUint32*                               in1                             = (deUint32*)values[1];
+
+               const struct
+               {
+                       deUint32        x;
+                       deUint32        y;
+               } easyCases[] =
+               {
+                       { 0x00000000u,  0x00000000u },
+                       { 0xfffffffeu,  0x00000001u },
+                       { 0x00000001u,  0xfffffffeu },
+                       { 0xffffffffu,  0x00000001u },
+                       { 0x00000001u,  0xffffffffu },
+                       { 0xfffffffeu,  0x00000002u },
+                       { 0x00000002u,  0xfffffffeu },
+                       { 0xffffffffu,  0xffffffffu }
+               };
+
+               // generate integers with proper bit count
+               for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
+                               in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
+                       }
+               }
+
+               // convert to signed
+               if (isSigned)
+               {
+                       for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+                       {
+                               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               {
+                                       in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
+                                       in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
+                               }
+                       }
+               }
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
+               generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  mask0                   = getLowBitMask(integerLength);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  in0             = ((const deUint32*)inputs[0])[compNdx];
+                       const deUint32  in1             = ((const deUint32*)inputs[1])[compNdx];
+                       const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  out1    = ((const deUint32*)outputs[1])[compNdx];
+                       const deUint32  ref0    = in0+in1;
+                       const deUint32  ref1    = (deUint64(in0)+deUint64(in1)) > 0xffffffffu ? 1u : 0u;
+
+                       if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class UaddCarryCase : public IntegerFunctionCase
+{
+public:
+       UaddCarryCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "uaddCarry", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("sum", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
+               m_spec.source = "sum = uaddCarry(x, y, carry);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UaddCarryCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class UsubBorrowCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       UsubBorrowCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                             (deStringHash(m_name) ^ 0x235facu);
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  integerMask             = getLowBitMask(integerLength);
+               const bool                              isSigned                = glu::isDataTypeIntOrIVec(type);
+               deUint32*                               in0                             = (deUint32*)values[0];
+               deUint32*                               in1                             = (deUint32*)values[1];
+
+               const struct
+               {
+                       deUint32        x;
+                       deUint32        y;
+               } easyCases[] =
+               {
+                       { 0x00000000u,  0x00000000u },
+                       { 0x00000001u,  0x00000001u },
+                       { 0x00000001u,  0x00000002u },
+                       { 0x00000001u,  0xffffffffu },
+                       { 0xfffffffeu,  0xffffffffu },
+                       { 0xffffffffu,  0xffffffffu },
+               };
+
+               // generate integers with proper bit count
+               for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               in0[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x & integerMask;
+                               in1[easyCaseNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y & integerMask;
+                       }
+               }
+
+               // convert to signed
+               if (isSigned)
+               {
+                       for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+                       {
+                               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                               {
+                                       in0[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in0[easyCaseNdx*scalarSize + compNdx], integerLength);
+                                       in1[easyCaseNdx*scalarSize + compNdx] = extendSignTo32(in1[easyCaseNdx*scalarSize + compNdx], integerLength);
+                               }
+                       }
+               }
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, in0, numValues - DE_LENGTH_OF_ARRAY(easyCases));
+               generateRandomInputData(rnd, m_shaderType, type, precision, in1, numValues - DE_LENGTH_OF_ARRAY(easyCases));
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  mask0                   = getLowBitMask(integerLength);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  in0             = ((const deUint32*)inputs[0])[compNdx];
+                       const deUint32  in1             = ((const deUint32*)inputs[1])[compNdx];
+                       const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  out1    = ((const deUint32*)outputs[1])[compNdx];
+                       const deUint32  ref0    = in0-in1;
+                       const deUint32  ref1    = in0 >= in1 ? 0u : 1u;
+
+                       if (((out0&mask0) != (ref0&mask0)) || out1 != ref1)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class UsubBorrowCase : public IntegerFunctionCase
+{
+public:
+       UsubBorrowCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "usubBorrow", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("diff", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("carry", glu::VarType(baseType, glu::PRECISION_LOWP)));
+               m_spec.source = "diff = usubBorrow(x, y, carry);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UsubBorrowCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class UmulExtendedCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       UmulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x235facu);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+//             const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+               deUint32*                               in0                     = (deUint32*)values[0];
+               deUint32*                               in1                     = (deUint32*)values[1];
+               int                                             valueNdx        = 0;
+
+               const struct
+               {
+                       deUint32        x;
+                       deUint32        y;
+               } easyCases[] =
+               {
+                       { 0x00000000u,  0x00000000u },
+                       { 0xffffffffu,  0x00000001u },
+                       { 0xffffffffu,  0x00000002u },
+                       { 0x00000001u,  0xffffffffu },
+                       { 0x00000002u,  0xffffffffu },
+                       { 0xffffffffu,  0xffffffffu },
+               };
+
+               for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               in0[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].x;
+                               in1[valueNdx*scalarSize + compNdx] = easyCases[easyCaseNdx].y;
+                       }
+
+                       valueNdx += 1;
+               }
+
+               while (valueNdx < numValues)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const deUint32  base0   = rnd.getUint32();
+                               const deUint32  base1   = rnd.getUint32();
+                               const int               adj0    = rnd.getInt(0, 20);
+                               const int               adj1    = rnd.getInt(0, 20);
+                               in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
+                               in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
+                       }
+
+                       valueNdx += 1;
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  in0             = ((const deUint32*)inputs[0])[compNdx];
+                       const deUint32  in1             = ((const deUint32*)inputs[1])[compNdx];
+                       const deUint32  out0    = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  out1    = ((const deUint32*)outputs[1])[compNdx];
+                       const deUint64  mul64   = deUint64(in0)*deUint64(in1);
+                       const deUint32  ref0    = deUint32(mul64 >> 32);
+                       const deUint32  ref1    = deUint32(mul64 & 0xffffffffu);
+
+                       if (out0 != ref0 || out1 != ref1)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class UmulExtendedCase : public IntegerFunctionCase
+{
+public:
+       UmulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "umulExtended", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
+               m_spec.source = "umulExtended(x, y, msb, lsb);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UmulExtendedCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class ImulExtendedCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       ImulExtendedCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x224fa1u);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+//             const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize      = glu::getDataTypeScalarSize(type);
+               deUint32*                               in0                     = (deUint32*)values[0];
+               deUint32*                               in1                     = (deUint32*)values[1];
+               int                                             valueNdx        = 0;
+
+               const struct
+               {
+                       deUint32        x;
+                       deUint32        y;
+               } easyCases[] =
+               {
+                       { 0x00000000u,  0x00000000u },
+                       { 0xffffffffu,  0x00000002u },
+                       { 0x7fffffffu,  0x00000001u },
+                       { 0x7fffffffu,  0x00000002u },
+                       { 0x7fffffffu,  0x7fffffffu },
+                       { 0xffffffffu,  0xffffffffu },
+                       { 0x7fffffffu,  0xfffffffeu },
+               };
+
+               for (int easyCaseNdx = 0; easyCaseNdx < DE_LENGTH_OF_ARRAY(easyCases); easyCaseNdx++)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               in0[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].x;
+                               in1[valueNdx*scalarSize + compNdx] = (deInt32)easyCases[easyCaseNdx].y;
+                       }
+
+                       valueNdx += 1;
+               }
+
+               while (valueNdx < numValues)
+               {
+                       for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+                       {
+                               const deInt32   base0   = (deInt32)rnd.getUint32();
+                               const deInt32   base1   = (deInt32)rnd.getUint32();
+                               const int               adj0    = rnd.getInt(0, 20);
+                               const int               adj1    = rnd.getInt(0, 20);
+                               in0[valueNdx*scalarSize + compNdx] = base0 >> adj0;
+                               in1[valueNdx*scalarSize + compNdx] = base1 >> adj1;
+                       }
+
+                       valueNdx += 1;
+               }
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deInt32   in0             = ((const deInt32*)inputs[0])[compNdx];
+                       const deInt32   in1             = ((const deInt32*)inputs[1])[compNdx];
+                       const deInt32   out0    = ((const deInt32*)outputs[0])[compNdx];
+                       const deInt32   out1    = ((const deInt32*)outputs[1])[compNdx];
+                       const deInt64   mul64   = deInt64(in0)*deInt64(in1);
+                       const deInt32   ref0    = deInt32(mul64 >> 32);
+                       const deInt32   ref1    = deInt32(mul64 & 0xffffffffu);
+
+                       if (out0 != ref0 || out1 != ref1)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref0) << ", " << tcu::toHex(ref1);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class ImulExtendedCase : public IntegerFunctionCase
+{
+public:
+       ImulExtendedCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "imulExtended", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("x", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("y", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("msb", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("lsb", glu::VarType(baseType, precision)));
+               m_spec.source = "imulExtended(x, y, msb, lsb);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new ImulExtendedCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class BitfieldExtractCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       BitfieldExtractCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xa113fca2u);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const bool                              ignoreSign      = precision != glu::PRECISION_HIGHP && glu::isDataTypeIntOrIVec(type);
+               const int                               numBits         = getShaderUintBitCount(m_shaderType, precision) - (ignoreSign ? 1 : 0);
+               deUint32*                               inValue         = (deUint32*)values[0];
+               int*                                    inOffset        = (int*)values[1];
+               int*                                    inBits          = (int*)values[2];
+
+               for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
+               {
+                       const int               bits    = rnd.getInt(0, numBits);
+                       const int               offset  = rnd.getInt(0, numBits-bits);
+
+                       inOffset[valueNdx]      = offset;
+                       inBits[valueNdx]        = bits;
+               }
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const bool                              isSigned                = glu::isDataTypeIntOrIVec(type);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               offset                  = *((const int*)inputs[1]);
+               const int                               bits                    = *((const int*)inputs[2]);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
+                       const deUint32  out             = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  valMask = (bits == 32 ? ~0u : ((1u<<bits)-1u));
+                       const deUint32  baseVal = (offset == 32) ? (0) : ((value >> offset) & valMask);
+                       const deUint32  ref             = baseVal | ((isSigned && (baseVal & (1<<(bits-1)))) ? ~valMask : 0u);
+
+                       if (out != ref)
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class BitfieldExtractCase : public IntegerFunctionCase
+{
+public:
+       BitfieldExtractCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldExtract", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
+               m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
+               m_spec.outputs.push_back(Symbol("extracted", glu::VarType(baseType, precision)));
+               m_spec.source = "extracted = bitfieldExtract(value, offset, bits);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new BitfieldExtractCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class BitfieldInsertCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       BitfieldInsertCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x12c2acff);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               const int                               numBits         = getShaderUintBitCount(m_shaderType, precision);
+               deUint32*                               inBase          = (deUint32*)values[0];
+               deUint32*                               inInsert        = (deUint32*)values[1];
+               int*                                    inOffset        = (int*)values[2];
+               int*                                    inBits          = (int*)values[3];
+
+               for (int valueNdx = 0; valueNdx < numValues; ++valueNdx)
+               {
+                       const int bits          = rnd.getInt(0, numBits);
+                       const int offset        = rnd.getInt(0, numBits-bits);
+
+                       inOffset[valueNdx]      = offset;
+                       inBits[valueNdx]        = bits;
+               }
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inBase, numValues);
+               generateRandomInputData(rnd, m_shaderType, type, precision, inInsert, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  cmpMask                 = getLowBitMask(integerLength);
+               const int                               offset                  = *((const int*)inputs[2]);
+               const int                               bits                    = *((const int*)inputs[3]);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  base    = ((const deUint32*)inputs[0])[compNdx];
+                       const deUint32  insert  = ((const deUint32*)inputs[1])[compNdx];
+                       const deInt32   out             = ((const deUint32*)outputs[0])[compNdx];
+
+                       const deUint32  mask    = bits == 32 ? ~0u : (1u<<bits)-1;
+                       const deUint32  ref             = (base & ~(mask<<offset)) | ((insert & mask)<<offset);
+
+                       if ((out&cmpMask) != (ref&cmpMask))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class BitfieldInsertCase : public IntegerFunctionCase
+{
+public:
+       BitfieldInsertCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldInsert", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("base", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("insert", glu::VarType(baseType, precision)));
+               m_spec.inputs.push_back(Symbol("offset", glu::VarType(glu::TYPE_INT, precision)));
+               m_spec.inputs.push_back(Symbol("bits", glu::VarType(glu::TYPE_INT, precision)));
+               m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, precision)));
+               m_spec.source = "result = bitfieldInsert(base, insert, offset, bits);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new BitfieldInsertCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class BitfieldReverseCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       BitfieldReverseCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xff23a4);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               deUint32*                               inValue         = (deUint32*)values[0];
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const deUint32                  cmpMask                 = reverseBits(getLowBitMask(integerLength));
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
+                       const deInt32   out             = ((const deUint32*)outputs[0])[compNdx];
+                       const deUint32  ref             = reverseBits(value);
+
+                       if ((out&cmpMask) != (ref&cmpMask))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] = " << tcu::toHex(ref);
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class BitfieldReverseCase : public IntegerFunctionCase
+{
+public:
+       BitfieldReverseCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitfieldReverse", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("result", glu::VarType(baseType, glu::PRECISION_HIGHP)));
+               m_spec.source = "result = bitfieldReverse(value);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new BitfieldReverseCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class BitCountCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       BitCountCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0xab2cca4);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               deUint32*                               inValue         = (deUint32*)values[0];
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const deUint32                  countMask               = getLowBitMask(integerLength);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
+                       const int               out             = ((const int*)outputs[0])[compNdx];
+                       const int               minRef  = dePop32(value&countMask);
+                       const int               maxRef  = dePop32(value);
+
+                       if (!de::inRange(out, minRef, maxRef))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class BitCountCase : public IntegerFunctionCase
+{
+public:
+       BitCountCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "bitCount", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
+
+               m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("count", glu::VarType(intType, glu::PRECISION_LOWP)));
+               m_spec.source = "count = bitCount(value);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new BitCountCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class FindLSBCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       FindLSBCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x9923c2af);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               deUint32*                               inValue         = (deUint32*)values[0];
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+               const deUint32                  mask                    = getLowBitMask(integerLength);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
+                       const int               out             = ((const int*)outputs[0])[compNdx];
+                       const int               minRef  = findLSB(value&mask);
+                       const int               maxRef  = findLSB(value);
+
+                       if (!de::inRange(out, minRef, maxRef))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class FindLSBCase : public IntegerFunctionCase
+{
+public:
+       FindLSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findLSB", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
+
+               m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("lsb", glu::VarType(intType, glu::PRECISION_LOWP)));
+               m_spec.source = "lsb = findLSB(value);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new FindLSBCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+class findMSBCaseInstance : public IntegerFunctionTestInstance
+{
+public:
+       findMSBCaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, ShaderExecutor& executor, int numValues, const char* name)
+               : IntegerFunctionTestInstance   (context, shaderType, spec, executor, numValues, name)
+       {
+       }
+
+       void getInputValues (int numValues, void* const* values) const
+       {
+               de::Random                              rnd                     (deStringHash(m_name) ^ 0x742ac4e);
+               const glu::DataType             type            = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision       = m_spec.inputs[0].varType.getPrecision();
+               deUint32*                               inValue         = (deUint32*)values[0];
+
+               generateRandomInputData(rnd, m_shaderType, type, precision, inValue, numValues);
+       }
+
+       bool compare (const void* const* inputs, const void* const* outputs)
+       {
+               const glu::DataType             type                    = m_spec.inputs[0].varType.getBasicType();
+               const glu::Precision    precision               = m_spec.inputs[0].varType.getPrecision();
+               const bool                              isSigned                = glu::isDataTypeIntOrIVec(type);
+               const int                               scalarSize              = glu::getDataTypeScalarSize(type);
+               const int                               integerLength   = getShaderUintBitCount(m_shaderType, precision);
+
+               for (int compNdx = 0; compNdx < scalarSize; compNdx++)
+               {
+                       const deUint32  value   = ((const deUint32*)inputs[0])[compNdx];
+                       const int               out             = ((const deInt32*)outputs[0])[compNdx];
+                       const int               minRef  = isSigned ? findMSB(toPrecision(deInt32(value), integerLength))        : findMSB(toPrecision(value, integerLength));
+                       const int               maxRef  = isSigned ? findMSB(deInt32(value))                                                            : findMSB(value);
+
+                       if (!de::inRange(out, minRef, maxRef))
+                       {
+                               m_failMsg << "Expected [" << compNdx << "] in range [" << minRef << ", " << maxRef << "]";
+                               return false;
+                       }
+               }
+
+               return true;
+       }
+};
+
+class findMSBCase : public IntegerFunctionCase
+{
+public:
+       findMSBCase (tcu::TestContext& testCtx, glu::DataType baseType, glu::Precision precision, glu::ShaderType shaderType)
+               : IntegerFunctionCase   (testCtx, getIntegerFuncCaseName(baseType, precision, shaderType).c_str(), "findMSB", shaderType)
+       {
+               const int                       vecSize         = glu::getDataTypeScalarSize(baseType);
+               const glu::DataType     intType         = vecSize == 1 ? glu::TYPE_INT : glu::getDataTypeIntVec(vecSize);
+
+               m_spec.inputs.push_back(Symbol("value", glu::VarType(baseType, precision)));
+               m_spec.outputs.push_back(Symbol("msb", glu::VarType(intType, glu::PRECISION_LOWP)));
+               m_spec.source = "msb = findMSB(value);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new findMSBCaseInstance(ctx, m_shaderType, m_spec, *m_executor, m_numValues, getName());
+       }
+};
+
+ShaderIntegerFunctionTests::ShaderIntegerFunctionTests (tcu::TestContext& testCtx)
+       : tcu::TestCaseGroup    (testCtx, "integer", "Integer function tests")
+{
+}
+
+ShaderIntegerFunctionTests::~ShaderIntegerFunctionTests (void)
+{
+}
+
+void ShaderIntegerFunctionTests::init (void)
+{
+       enum
+       {
+               VS = (1<<glu::SHADERTYPE_VERTEX),
+               FS = (1<<glu::SHADERTYPE_FRAGMENT),
+               CS = (1<<glu::SHADERTYPE_COMPUTE),
+               GS = (1<<glu::SHADERTYPE_GEOMETRY),
+               TC = (1<<glu::SHADERTYPE_TESSELLATION_CONTROL),
+               TE = (1<<glu::SHADERTYPE_TESSELLATION_EVALUATION),
+
+               ALL_SHADERS = VS|TC|TE|GS|FS|CS
+       };
+
+       //                                                                                                                                              Int?    Uint?   AllPrec?        Shaders
+       addFunctionCases<UaddCarryCase>                         (this,  "uaddcarry",            false,  true,   true,           ALL_SHADERS);
+       addFunctionCases<UsubBorrowCase>                        (this,  "usubborrow",           false,  true,   true,           ALL_SHADERS);
+       addFunctionCases<UmulExtendedCase>                      (this,  "umulextended",         false,  true,   false,          ALL_SHADERS);
+       addFunctionCases<ImulExtendedCase>                      (this,  "imulextended",         true,   false,  false,          ALL_SHADERS);
+       addFunctionCases<BitfieldExtractCase>           (this,  "bitfieldextract",      true,   true,   true,           ALL_SHADERS);
+       addFunctionCases<BitfieldInsertCase>            (this,  "bitfieldinsert",       true,   true,   true,           ALL_SHADERS);
+       addFunctionCases<BitfieldReverseCase>           (this,  "bitfieldreverse",      true,   true,   true,           ALL_SHADERS);
+       addFunctionCases<BitCountCase>                          (this,  "bitcount",                     true,   true,   true,           ALL_SHADERS);
+       addFunctionCases<FindLSBCase>                           (this,  "findlsb",                      true,   true,   true,           ALL_SHADERS);
+       addFunctionCases<findMSBCase>                           (this,  "findMSB",                      true,   true,   true,           ALL_SHADERS);
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderIntegerFunctionTests.hpp
new file mode 100644 (file)
index 0000000..b59fa6d
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef _VKTSHADERINTEGERFUNCTIONTESTS_HPP
+#define _VKTSHADERINTEGERFUNCTIONTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Integer built-in function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+// ShaderIntegerFunctionTests
+
+class ShaderIntegerFunctionTests : public tcu::TestCaseGroup
+{
+public:
+                                                                               ShaderIntegerFunctionTests              (tcu::TestContext& testCtx);
+       virtual                                                         ~ShaderIntegerFunctionTests             (void);
+
+       virtual void                                            init                                                    (void);
+
+private:
+                                                                               ShaderIntegerFunctionTests              (const ShaderIntegerFunctionTests&);            // not allowed!
+       ShaderIntegerFunctionTests&                     operator=                                               (const ShaderIntegerFunctionTests&);            // not allowed!
+};
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTSHADERINTEGERFUNCTIONTESTS_HPP
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.cpp
new file mode 100644 (file)
index 0000000..fd27efd
--- /dev/null
@@ -0,0 +1,1452 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Floating-point packing and unpacking function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktShaderPackingFunctionTests.hpp"
+#include "vktShaderExecutor.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuFormatUtil.hpp"
+#include "tcuFloat.hpp"
+#include "deRandom.hpp"
+#include "deMath.h"
+#include "deString.h"
+#include "deSharedPtr.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+using namespace shaderexecutor;
+
+using std::string;
+using tcu::TestLog;
+
+namespace
+{
+
+inline deUint32 getUlpDiff (float a, float b)
+{
+       const deUint32  aBits   = tcu::Float32(a).bits();
+       const deUint32  bBits   = tcu::Float32(b).bits();
+       return aBits > bBits ? aBits - bBits : bBits - aBits;
+}
+
+struct HexFloat
+{
+       const float value;
+       HexFloat (const float value_) : value(value_) {}
+};
+
+std::ostream& operator<< (std::ostream& str, const HexFloat& v)
+{
+       return str << v.value << " / " << tcu::toHex(tcu::Float32(v.value).bits());
+}
+
+static const char* getPrecisionPostfix (glu::Precision precision)
+{
+       static const char* s_postfix[] =
+       {
+               "_lowp",
+               "_mediump",
+               "_highp"
+       };
+       DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_postfix) == glu::PRECISION_LAST);
+       DE_ASSERT(de::inBounds<int>(precision, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[precision];
+}
+
+static const char* getShaderTypePostfix (glu::ShaderType shaderType)
+{
+       static const char* s_postfix[] =
+       {
+               "_vertex",
+               "_fragment",
+               "_geometry",
+               "_tess_control",
+               "_tess_eval",
+               "_compute"
+       };
+       DE_ASSERT(de::inBounds<int>(shaderType, 0, DE_LENGTH_OF_ARRAY(s_postfix)));
+       return s_postfix[shaderType];
+}
+
+} // anonymous
+
+// ShaderPackingFunctionCase
+
+class ShaderPackingFunctionCase : public TestCase
+{
+public:
+                                                                               ShaderPackingFunctionCase                       (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType);
+                                                                               ~ShaderPackingFunctionCase                      (void);
+
+       virtual void                                            initPrograms                                            (vk::SourceCollections& programCollection) const
+                                                                               {
+                                                                                       m_executor->setShaderSources(programCollection);
+                                                                               }
+       virtual TestInstance*                           createInstance                                          (Context& context) const = 0;
+       void                                                            init                                                            (void);
+
+protected:
+       const glu::ShaderType                           m_shaderType;
+       ShaderSpec                                                      m_spec;
+       de::SharedPtr<ShaderExecutor>           m_executor;
+
+private:
+                                                                               ShaderPackingFunctionCase                       (const ShaderPackingFunctionCase& other);
+       ShaderPackingFunctionCase&                      operator=                                                       (const ShaderPackingFunctionCase& other);
+};
+
+ShaderPackingFunctionCase::ShaderPackingFunctionCase (tcu::TestContext& testCtx, const char* name, const char* description, glu::ShaderType shaderType)
+       : TestCase              (testCtx, name, description)
+       , m_shaderType  (shaderType)
+       , m_executor    (DE_NULL)
+{
+}
+
+ShaderPackingFunctionCase::~ShaderPackingFunctionCase (void)
+{
+}
+
+void ShaderPackingFunctionCase::init (void)
+{
+       DE_ASSERT(!m_executor);
+
+       m_executor = de::SharedPtr<ShaderExecutor>(createExecutor(m_shaderType, m_spec));
+       m_testCtx.getLog() << *m_executor;
+}
+
+// ShaderPackingFunctionTestInstance
+
+class ShaderPackingFunctionTestInstance : public TestInstance
+{
+public:
+                                                                               ShaderPackingFunctionTestInstance       (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+                                                                                       : TestInstance  (context)
+                                                                                       , m_testCtx             (context.getTestContext())
+                                                                                       , m_shaderType  (shaderType)
+                                                                                       , m_spec                (spec)
+                                                                                       , m_name                (name)
+                                                                                       , m_executor    (executor)
+                                                                               {
+                                                                               }
+       virtual tcu::TestStatus                         iterate                                                         (void) = 0;
+protected:
+       tcu::TestContext&                                       m_testCtx;
+       const glu::ShaderType                           m_shaderType;
+       ShaderSpec                                                      m_spec;
+       const char*                                             m_name;
+       de::SharedPtr<ShaderExecutor>           m_executor;
+};
+
+// Test cases
+
+class PackSnorm2x16CaseInstance: public ShaderPackingFunctionTestInstance
+{
+public:
+       PackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+               , m_precision                                           (precision)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<tcu::Vec2>          inputs;
+               std::vector<deUint32>           outputs;
+               const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
+                                                                                                 m_precision == glu::PRECISION_MEDIUMP ? 33    :               // (2^-10) * (2^15) + 1
+                                                                                                 m_precision == glu::PRECISION_LOWP    ? 129   : 0;    // (2^-8) * (2^15) + 1
+
+               // Special values to check.
+               inputs.push_back(tcu::Vec2(0.0f, 0.0f));
+               inputs.push_back(tcu::Vec2(-1.0f, 1.0f));
+               inputs.push_back(tcu::Vec2(0.5f, -0.5f));
+               inputs.push_back(tcu::Vec2(-1.5f, 1.5f));
+               inputs.push_back(tcu::Vec2(0.25f, -0.75f));
+
+               // Random values, mostly in range.
+               for (int ndx = 0; ndx < 15; ndx++)
+               {
+                       const float x = rnd.getFloat()*2.5f - 1.25f;
+                       const float y = rnd.getFloat()*2.5f - 1.25f;
+                       inputs.push_back(tcu::Vec2(x, y));
+               }
+
+               // Large random values.
+               for (int ndx = 0; ndx < 80; ndx++)
+               {
+                       const float x = rnd.getFloat()*1e6f - 0.5e6f;
+                       const float y = rnd.getFloat()*1e6f - 0.5e6f;
+                       inputs.push_back(tcu::Vec2(x, y));
+               }
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < numValues; valNdx++)
+                       {
+                               const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
+                               const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 32767.0f), -(1<<15), (1<<15)-1);
+                               const deUint32  ref             = (ref1 << 16) | ref0;
+                               const deUint32  res             = outputs[valNdx];
+                               const deUint16  res0    = (deUint16)(res & 0xffff);
+                               const deUint16  res1    = (deUint16)(res >> 16);
+                               const int               diff0   = de::abs((int)ref0 - (int)res0);
+                               const int               diff1   = de::abs((int)ref1 - (int)res1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
+                                                                                                                          << ", expected packSnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
+                                                                                                                          << ", got " << tcu::toHex(res)
+                                                                                                                          << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class PackSnorm2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       PackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
+               : ShaderPackingFunctionCase     (testCtx, (string("packsnorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm2x16", shaderType)
+               , m_precision                           (precision)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = packSnorm2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new PackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class UnpackSnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       UnpackSnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+       : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const deUint32                          maxDiff         = 1; // Rounding error.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<deUint32>           inputs;
+               std::vector<tcu::Vec2>          outputs;
+
+               inputs.push_back(0x00000000u);
+               inputs.push_back(0x7fff8000u);
+               inputs.push_back(0x80007fffu);
+               inputs.push_back(0xffffffffu);
+               inputs.push_back(0x0001fffeu);
+
+               // Random values.
+               for (int ndx = 0; ndx < 95; ndx++)
+                       inputs.push_back(rnd.getUint32());
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deInt16   in0                     = (deInt16)(deUint16)(inputs[valNdx] & 0xffff);
+                               const deInt16   in1                     = (deInt16)(deUint16)(inputs[valNdx] >> 16);
+                               const float             ref0            = de::clamp(float(in0) / 32767.f, -1.0f, 1.0f);
+                               const float             ref1            = de::clamp(float(in1) / 32767.f, -1.0f, 1.0f);
+                               const float             res0            = outputs[valNdx].x();
+                               const float             res1            = outputs[valNdx].y();
+
+                               const deUint32  diff0   = getUlpDiff(ref0, res0);
+                               const deUint32  diff1   = getUlpDiff(ref1, res1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
+                                                                                                                          << "  expected unpackSnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
+                                                                                                                          << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
+                                                                                                                          << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
+                                                                                                                          << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+class UnpackSnorm2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       UnpackSnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase     (testCtx, (string("unpacksnorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm2x16", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = unpackSnorm2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UnpackSnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+};
+
+class PackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       PackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
+       : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+       , m_precision                                           (precision)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<tcu::Vec2>          inputs;
+               std::vector<deUint32>           outputs;
+               const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1             :               // Rounding only.
+                                                                                                 m_precision == glu::PRECISION_MEDIUMP ? 65    :               // (2^-10) * (2^16) + 1
+                                                                                                 m_precision == glu::PRECISION_LOWP    ? 257   : 0;    // (2^-8) * (2^16) + 1
+
+               // Special values to check.
+               inputs.push_back(tcu::Vec2(0.0f, 0.0f));
+               inputs.push_back(tcu::Vec2(0.5f, 1.0f));
+               inputs.push_back(tcu::Vec2(1.0f, 0.5f));
+               inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
+               inputs.push_back(tcu::Vec2(0.25f, 0.75f));
+
+               // Random values, mostly in range.
+               for (int ndx = 0; ndx < 15; ndx++)
+               {
+                       const float x = rnd.getFloat()*1.25f;
+                       const float y = rnd.getFloat()*1.25f;
+                       inputs.push_back(tcu::Vec2(x, y));
+               }
+
+               // Large random values.
+               for (int ndx = 0; ndx < 80; ndx++)
+               {
+                       const float x = rnd.getFloat()*1e6f - 1e5f;
+                       const float y = rnd.getFloat()*1e6f - 1e5f;
+                       inputs.push_back(tcu::Vec2(x, y));
+               }
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint16  ref0    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
+                               const deUint16  ref1    = (deUint16)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 65535.0f), 0, (1<<16)-1);
+                               const deUint32  ref             = (ref1 << 16) | ref0;
+                               const deUint32  res             = outputs[valNdx];
+                               const deUint16  res0    = (deUint16)(res & 0xffff);
+                               const deUint16  res1    = (deUint16)(res >> 16);
+                               const int               diff0   = de::abs((int)ref0 - (int)res0);
+                               const int               diff1   = de::abs((int)ref1 - (int)res1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
+                                                                                                                          << ", expected packUnorm2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
+                                                                                                                          << ", got " << tcu::toHex(res)
+                                                                                                                          << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class PackUnorm2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       PackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
+               : ShaderPackingFunctionCase     (testCtx, (string("packunorm2x16") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm2x16", shaderType)
+               , m_precision                           (precision)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = packUnorm2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new PackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class UnpackUnorm2x16CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       UnpackUnorm2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const deUint32                          maxDiff         = 1; // Rounding error.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<deUint32>           inputs;
+               std::vector<tcu::Vec2>          outputs;
+
+               inputs.push_back(0x00000000u);
+               inputs.push_back(0x7fff8000u);
+               inputs.push_back(0x80007fffu);
+               inputs.push_back(0xffffffffu);
+               inputs.push_back(0x0001fffeu);
+
+               // Random values.
+               for (int ndx = 0; ndx < 95; ndx++)
+                       inputs.push_back(rnd.getUint32());
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
+                               const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
+                               const float             ref0            = float(in0) / 65535.0f;
+                               const float             ref1            = float(in1) / 65535.0f;
+                               const float             res0            = outputs[valNdx].x();
+                               const float             res1            = outputs[valNdx].y();
+
+                               const deUint32  diff0           = getUlpDiff(ref0, res0);
+                               const deUint32  diff1           = getUlpDiff(ref1, res1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
+                                                                                                                          << "  expected unpackUnorm2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
+                                                                                                                          << "vec2(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ")"
+                                                                                                                          << ", got vec2(" << HexFloat(res0) << ", " << HexFloat(res1) << ")"
+                                                                                                                          << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+
+class UnpackUnorm2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       UnpackUnorm2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase(testCtx, (string("unpackunorm2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm2x16", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = unpackUnorm2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UnpackUnorm2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+
+};
+
+class PackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       PackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+       : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const int                                       maxDiff         = 0; // Values can be represented exactly in mediump.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<tcu::Vec2>          inputs;
+               std::vector<deUint32>           outputs;
+
+               // Special values to check.
+               inputs.push_back(tcu::Vec2(0.0f, 0.0f));
+               inputs.push_back(tcu::Vec2(0.5f, 1.0f));
+               inputs.push_back(tcu::Vec2(1.0f, 0.5f));
+               inputs.push_back(tcu::Vec2(-0.5f, 1.5f));
+               inputs.push_back(tcu::Vec2(0.25f, 0.75f));
+
+               // Random values.
+               {
+                       const int       minExp  = -14;
+                       const int       maxExp  = 15;
+
+                       for (int ndx = 0; ndx < 95; ndx++)
+                       {
+                               tcu::Vec2 v;
+                               for (int c = 0; c < 2; c++)
+                               {
+                                       const int               s                       = rnd.getBool() ? 1 : -1;
+                                       const int               exp                     = rnd.getInt(minExp, maxExp);
+                                       const deUint32  mantissa        = rnd.getUint32() & ((1<<23)-1);
+
+                                       v[c] = tcu::Float32::construct(s, exp ? exp : 1 /* avoid denormals */, (1u<<23) | mantissa).asFloat();
+                               }
+                               inputs.push_back(v);
+                       }
+               }
+
+               // Convert input values to fp16 and back to make sure they can be represented exactly in mediump.
+               for (std::vector<tcu::Vec2>::iterator inVal = inputs.begin(); inVal != inputs.end(); ++inVal)
+                       *inVal = tcu::Vec2(tcu::Float16(inVal->x()).asFloat(), tcu::Float16(inVal->y()).asFloat());
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint16  ref0    = (deUint16)tcu::Float16(inputs[valNdx].x()).bits();
+                               const deUint16  ref1    = (deUint16)tcu::Float16(inputs[valNdx].y()).bits();
+                               const deUint32  ref             = (ref1 << 16) | ref0;
+                               const deUint32  res             = outputs[valNdx];
+                               const deUint16  res0    = (deUint16)(res & 0xffff);
+                               const deUint16  res1    = (deUint16)(res >> 16);
+                               const int               diff0   = de::abs((int)ref0 - (int)res0);
+                               const int               diff1   = de::abs((int)ref1 - (int)res1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
+                                                                                                                          << ", expected packHalf2x16(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
+                                                                                                                          << ", got " << tcu::toHex(res)
+                                                                                                                          << "\n  diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+class PackHalf2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       PackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase     (testCtx, (string("packhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "packHalf2x16", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = packHalf2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new PackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+
+};
+
+class UnpackHalf2x16CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       UnpackHalf2x16CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+       : ShaderPackingFunctionTestInstance (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const int                                       maxDiff         = 0; // All bits must be accurate.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<deUint32>           inputs;
+               std::vector<tcu::Vec2>          outputs;
+
+               // Special values.
+               inputs.push_back((tcu::Float16( 0.0f).bits() << 16) | tcu::Float16( 1.0f).bits());
+               inputs.push_back((tcu::Float16( 1.0f).bits() << 16) | tcu::Float16( 0.0f).bits());
+               inputs.push_back((tcu::Float16(-1.0f).bits() << 16) | tcu::Float16( 0.5f).bits());
+               inputs.push_back((tcu::Float16( 0.5f).bits() << 16) | tcu::Float16(-0.5f).bits());
+
+               // Construct random values.
+               {
+                       const int       minExp          = -14;
+                       const int       maxExp          = 15;
+                       const int       mantBits        = 10;
+
+                       for (int ndx = 0; ndx < 96; ndx++)
+                       {
+                               deUint32 inVal = 0;
+                               for (int c = 0; c < 2; c++)
+                               {
+                                       const int               s                       = rnd.getBool() ? 1 : -1;
+                                       const int               exp                     = rnd.getInt(minExp, maxExp);
+                                       const deUint32  mantissa        = rnd.getUint32() & ((1<<mantBits)-1);
+                                       const deUint16  value           = tcu::Float16::construct(s, exp ? exp : 1 /* avoid denorm */, (deUint16)((1u<<10) | mantissa)).bits();
+
+                                       inVal |= value << (16*c);
+                               }
+                               inputs.push_back(inVal);
+                       }
+               }
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint16  in0                     = (deUint16)(inputs[valNdx] & 0xffff);
+                               const deUint16  in1                     = (deUint16)(inputs[valNdx] >> 16);
+                               const float             ref0            = tcu::Float16(in0).asFloat();
+                               const float             ref1            = tcu::Float16(in1).asFloat();
+                               const float             res0            = outputs[valNdx].x();
+                               const float             res1            = outputs[valNdx].y();
+
+                               const deUint32  refBits0        = tcu::Float32(ref0).bits();
+                               const deUint32  refBits1        = tcu::Float32(ref1).bits();
+                               const deUint32  resBits0        = tcu::Float32(res0).bits();
+                               const deUint32  resBits1        = tcu::Float32(res1).bits();
+
+                               const int               diff0   = de::abs((int)refBits0 - (int)resBits0);
+                               const int               diff1   = de::abs((int)refBits1 - (int)resBits1);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
+                                                                                                                          << "  expected unpackHalf2x16(" << tcu::toHex(inputs[valNdx]) << ") = "
+                                                                                                                          << "vec2(" << ref0 << " / " << tcu::toHex(refBits0) << ", " << ref1 << " / " << tcu::toHex(refBits1) << ")"
+                                                                                                                          << ", got vec2(" << res0 << " / " << tcu::toHex(resBits0) << ", " << res1 << " / " << tcu::toHex(resBits1) << ")"
+                                                                                                                          << "\n  ULP diffs = (" << diff0 << ", " << diff1 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+class UnpackHalf2x16Case : public ShaderPackingFunctionCase
+{
+public:
+       UnpackHalf2x16Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase     (testCtx, (string("unpackhalf2x16") + getShaderTypePostfix(shaderType)).c_str(), "unpackHalf2x16", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC2, glu::PRECISION_MEDIUMP)));
+
+               m_spec.source = "out0 = unpackHalf2x16(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UnpackHalf2x16CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+
+};
+
+class PackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       PackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+               , m_precision                                           (precision)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x42f2c0);
+               std::vector<tcu::Vec4>          inputs;
+               std::vector<deUint32>           outputs;
+               const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1     :               // Rounding only.
+                                                                                                 m_precision == glu::PRECISION_MEDIUMP ? 1     :               // (2^-10) * (2^7) + 1
+                                                                                                 m_precision == glu::PRECISION_LOWP    ? 2     : 0;    // (2^-8) * (2^7) + 1
+
+               // Special values to check.
+               inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+               inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
+               inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
+               inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
+               inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
+
+               // Random values, mostly in range.
+               for (int ndx = 0; ndx < 15; ndx++)
+               {
+                       const float x = rnd.getFloat()*2.5f - 1.25f;
+                       const float y = rnd.getFloat()*2.5f - 1.25f;
+                       const float z = rnd.getFloat()*2.5f - 1.25f;
+                       const float w = rnd.getFloat()*2.5f - 1.25f;
+                       inputs.push_back(tcu::Vec4(x, y, z, w));
+               }
+
+               // Large random values.
+               for (int ndx = 0; ndx < 80; ndx++)
+               {
+                       const float x = rnd.getFloat()*1e6f - 0.5e6f;
+                       const float y = rnd.getFloat()*1e6f - 0.5e6f;
+                       const float z = rnd.getFloat()*1e6f - 0.5e6f;
+                       const float w = rnd.getFloat()*1e6f - 0.5e6f;
+                       inputs.push_back(tcu::Vec4(x, y, z, w));
+               }
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < numValues; valNdx++)
+                       {
+                               const deUint16  ref0    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
+                               const deUint16  ref1    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
+                               const deUint16  ref2    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
+                               const deUint16  ref3    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), -1.0f, 1.0f) * 127.0f), -(1<<7), (1<<7)-1);
+                               const deUint32  ref             = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
+                               const deUint32  res             = outputs[valNdx];
+                               const deUint16  res0    = (deUint8)(res & 0xff);
+                               const deUint16  res1    = (deUint8)((res >> 8) & 0xff);
+                               const deUint16  res2    = (deUint8)((res >> 16) & 0xff);
+                               const deUint16  res3    = (deUint8)((res >> 24) & 0xff);
+                               const int               diff0   = de::abs((int)ref0 - (int)res0);
+                               const int               diff1   = de::abs((int)ref1 - (int)res1);
+                               const int               diff2   = de::abs((int)ref2 - (int)res2);
+                               const int               diff3   = de::abs((int)ref3 - (int)res3);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
+                                                                                                                          << ", expected packSnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
+                                                                                                                          << ", got " << tcu::toHex(res)
+                                                                                                                          << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class PackSnorm4x8Case : public ShaderPackingFunctionCase
+{
+public:
+       PackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
+               : ShaderPackingFunctionCase     (testCtx, (string("packsnorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packSnorm4x8", shaderType)
+               , m_precision                           (precision)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = packSnorm4x8(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new PackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class UnpackSnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       UnpackSnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const deUint32                          maxDiff         = 1; // Rounding error.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<deUint32>           inputs;
+               std::vector<tcu::Vec4>          outputs;
+
+               inputs.push_back(0x00000000u);
+               inputs.push_back(0x7fff8000u);
+               inputs.push_back(0x80007fffu);
+               inputs.push_back(0xffffffffu);
+               inputs.push_back(0x0001fffeu);
+
+               // Random values.
+               for (int ndx = 0; ndx < 95; ndx++)
+                       inputs.push_back(rnd.getUint32());
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deInt8    in0             = (deInt8)(deUint8)(inputs[valNdx] & 0xff);
+                               const deInt8    in1             = (deInt8)(deUint8)((inputs[valNdx] >> 8) & 0xff);
+                               const deInt8    in2             = (deInt8)(deUint8)((inputs[valNdx] >> 16) & 0xff);
+                               const deInt8    in3             = (deInt8)(deUint8)(inputs[valNdx] >> 24);
+                               const float             ref0    = de::clamp(float(in0) / 127.f, -1.0f, 1.0f);
+                               const float             ref1    = de::clamp(float(in1) / 127.f, -1.0f, 1.0f);
+                               const float             ref2    = de::clamp(float(in2) / 127.f, -1.0f, 1.0f);
+                               const float             ref3    = de::clamp(float(in3) / 127.f, -1.0f, 1.0f);
+                               const float             res0    = outputs[valNdx].x();
+                               const float             res1    = outputs[valNdx].y();
+                               const float             res2    = outputs[valNdx].z();
+                               const float             res3    = outputs[valNdx].w();
+
+                               const deUint32  diff0   = getUlpDiff(ref0, res0);
+                               const deUint32  diff1   = getUlpDiff(ref1, res1);
+                               const deUint32  diff2   = getUlpDiff(ref2, res2);
+                               const deUint32  diff3   = getUlpDiff(ref3, res3);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
+                                                                                                                          << "  expected unpackSnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
+                                                                                                                          << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
+                                                                                                                          << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
+                                                                                                                          << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+
+class UnpackSnorm4x8Case : public ShaderPackingFunctionCase
+{
+public:
+       UnpackSnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase     (testCtx, (string("unpacksnorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackSnorm4x8", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = unpackSnorm4x8(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UnpackSnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+
+};
+
+class PackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       PackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, glu::Precision precision, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+               , m_precision                                           (precision)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<tcu::Vec4>          inputs;
+               std::vector<deUint32>           outputs;
+               const int                                       maxDiff         = m_precision == glu::PRECISION_HIGHP   ? 1     :               // Rounding only.
+                                                                                                 m_precision == glu::PRECISION_MEDIUMP ? 1     :               // (2^-10) * (2^8) + 1
+                                                                                                 m_precision == glu::PRECISION_LOWP    ? 2     : 0;    // (2^-8) * (2^8) + 1
+
+               // Special values to check.
+               inputs.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+               inputs.push_back(tcu::Vec4(-1.0f, 1.0f, -1.0f, 1.0f));
+               inputs.push_back(tcu::Vec4(0.5f, -0.5f, -0.5f, 0.5f));
+               inputs.push_back(tcu::Vec4(-1.5f, 1.5f, -1.5f, 1.5f));
+               inputs.push_back(tcu::Vec4(0.25f, -0.75f, -0.25f, 0.75f));
+
+               // Random values, mostly in range.
+               for (int ndx = 0; ndx < 15; ndx++)
+               {
+                       const float x = rnd.getFloat()*1.25f - 0.125f;
+                       const float y = rnd.getFloat()*1.25f - 0.125f;
+                       const float z = rnd.getFloat()*1.25f - 0.125f;
+                       const float w = rnd.getFloat()*1.25f - 0.125f;
+                       inputs.push_back(tcu::Vec4(x, y, z, w));
+               }
+
+               // Large random values.
+               for (int ndx = 0; ndx < 80; ndx++)
+               {
+                       const float x = rnd.getFloat()*1e6f - 1e5f;
+                       const float y = rnd.getFloat()*1e6f - 1e5f;
+                       const float z = rnd.getFloat()*1e6f - 1e5f;
+                       const float w = rnd.getFloat()*1e6f - 1e5f;
+                       inputs.push_back(tcu::Vec4(x, y, z, w));
+               }
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint16  ref0    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].x(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
+                               const deUint16  ref1    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].y(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
+                               const deUint16  ref2    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].z(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
+                               const deUint16  ref3    = (deUint8)de::clamp(deRoundFloatToInt32(de::clamp(inputs[valNdx].w(), 0.0f, 1.0f) * 255.0f), 0, (1<<8)-1);
+                               const deUint32  ref             = (deUint32(ref3) << 24) | (deUint32(ref2) << 16) | (deUint32(ref1) << 8) | deUint32(ref0);
+                               const deUint32  res             = outputs[valNdx];
+                               const deUint16  res0    = (deUint8)(res & 0xff);
+                               const deUint16  res1    = (deUint8)((res >> 8) & 0xff);
+                               const deUint16  res2    = (deUint8)((res >> 16) & 0xff);
+                               const deUint16  res3    = (deUint8)((res >> 24) & 0xff);
+                               const int               diff0   = de::abs((int)ref0 - (int)res0);
+                               const int               diff1   = de::abs((int)ref1 - (int)res1);
+                               const int               diff2   = de::abs((int)ref2 - (int)res2);
+                               const int               diff3   = de::abs((int)ref3 - (int)res3);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx
+                                                                                                                          << ", expected packUnorm4x8(" << inputs[valNdx] << ") = " << tcu::toHex(ref)
+                                                                                                                          << ", got " << tcu::toHex(res)
+                                                                                                                          << "\n  diffs = " << tcu::IVec4(diff0, diff1, diff2, diff3) << ", max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class PackUnorm4x8Case : public ShaderPackingFunctionCase
+{
+public:
+       PackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType, glu::Precision precision)
+               : ShaderPackingFunctionCase     (testCtx, (string("packunorm4x8") + getPrecisionPostfix(precision) + getShaderTypePostfix(shaderType)).c_str(), "packUnorm4x8", shaderType)
+               , m_precision                           (precision)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_FLOAT_VEC4, precision)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = packUnorm4x8(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new PackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_precision, m_executor, getName());
+       }
+
+private:
+       const glu::Precision m_precision;
+};
+
+class UnpackUnorm4x8CaseInstance : public ShaderPackingFunctionTestInstance
+{
+public:
+       UnpackUnorm4x8CaseInstance (Context& context, glu::ShaderType shaderType, ShaderSpec spec, de::SharedPtr<ShaderExecutor> executor, const char* name)
+               : ShaderPackingFunctionTestInstance     (context, shaderType, spec, executor, name)
+       {
+       }
+
+       tcu::TestStatus iterate (void)
+       {
+               const deUint32                          maxDiff         = 1; // Rounding error.
+               de::Random                                      rnd                     (deStringHash(m_name) ^ 0x776002);
+               std::vector<deUint32>           inputs;
+               std::vector<tcu::Vec4>          outputs;
+
+               inputs.push_back(0x00000000u);
+               inputs.push_back(0x7fff8000u);
+               inputs.push_back(0x80007fffu);
+               inputs.push_back(0xffffffffu);
+               inputs.push_back(0x0001fffeu);
+
+               // Random values.
+               for (int ndx = 0; ndx < 95; ndx++)
+                       inputs.push_back(rnd.getUint32());
+
+               outputs.resize(inputs.size());
+
+               m_testCtx.getLog() << TestLog::Message << "Executing shader for " << inputs.size() << " input values" << tcu::TestLog::EndMessage;
+
+               {
+                       const void*     in      = &inputs[0];
+                       void*           out     = &outputs[0];
+
+                       m_executor->execute(m_context, (int)inputs.size(), &in, &out);
+               }
+
+               // Verify
+               {
+                       const int       numValues       = (int)inputs.size();
+                       const int       maxPrints       = 10;
+                       int                     numFailed       = 0;
+
+                       for (int valNdx = 0; valNdx < (int)inputs.size(); valNdx++)
+                       {
+                               const deUint8   in0             = (deUint8)(inputs[valNdx] & 0xff);
+                               const deUint8   in1             = (deUint8)((inputs[valNdx] >> 8) & 0xff);
+                               const deUint8   in2             = (deUint8)((inputs[valNdx] >> 16) & 0xff);
+                               const deUint8   in3             = (deUint8)(inputs[valNdx] >> 24);
+                               const float             ref0    = de::clamp(float(in0) / 255.f, 0.0f, 1.0f);
+                               const float             ref1    = de::clamp(float(in1) / 255.f, 0.0f, 1.0f);
+                               const float             ref2    = de::clamp(float(in2) / 255.f, 0.0f, 1.0f);
+                               const float             ref3    = de::clamp(float(in3) / 255.f, 0.0f, 1.0f);
+                               const float             res0    = outputs[valNdx].x();
+                               const float             res1    = outputs[valNdx].y();
+                               const float             res2    = outputs[valNdx].z();
+                               const float             res3    = outputs[valNdx].w();
+
+                               const deUint32  diff0   = getUlpDiff(ref0, res0);
+                               const deUint32  diff1   = getUlpDiff(ref1, res1);
+                               const deUint32  diff2   = getUlpDiff(ref2, res2);
+                               const deUint32  diff3   = getUlpDiff(ref3, res3);
+
+                               if (diff0 > maxDiff || diff1 > maxDiff || diff2 > maxDiff || diff3 > maxDiff)
+                               {
+                                       if (numFailed < maxPrints)
+                                       {
+                                               m_testCtx.getLog() << TestLog::Message << "ERROR: Mismatch in value " << valNdx << ",\n"
+                                                                                                                          << "  expected unpackUnorm4x8(" << tcu::toHex(inputs[valNdx]) << ") = "
+                                                                                                                          << "vec4(" << HexFloat(ref0) << ", " << HexFloat(ref1) << ", " << HexFloat(ref2) << ", " << HexFloat(ref3) << ")"
+                                                                                                                          << ", got vec4(" << HexFloat(res0) << ", " << HexFloat(res1) << ", " << HexFloat(res2) << ", " << HexFloat(res3) << ")"
+                                                                                                                          << "\n  ULP diffs = (" << diff0 << ", " << diff1 << ", " << diff2 << ", " << diff3 << "), max diff = " << maxDiff
+                                                                                  << TestLog::EndMessage;
+                                       }
+                                       else if (numFailed == maxPrints)
+                                               m_testCtx.getLog() << TestLog::Message << "..." << TestLog::EndMessage;
+
+                                       numFailed += 1;
+                               }
+                       }
+
+                       m_testCtx.getLog() << TestLog::Message << (numValues - numFailed) << " / " << numValues << " values passed" << TestLog::EndMessage;
+
+                       if (numFailed == 0)
+                               return tcu::TestStatus::pass("Pass");
+                       else
+                               return tcu::TestStatus::fail("Result comparison failed");
+
+               }
+       }
+};
+
+class UnpackUnorm4x8Case : public ShaderPackingFunctionCase
+{
+public:
+       UnpackUnorm4x8Case (tcu::TestContext& testCtx, glu::ShaderType shaderType)
+               : ShaderPackingFunctionCase     (testCtx, (string("unpackunorm4x8") + getShaderTypePostfix(shaderType)).c_str(), "unpackUnorm4x8", shaderType)
+       {
+               m_spec.inputs.push_back(Symbol("in0", glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+               m_spec.outputs.push_back(Symbol("out0", glu::VarType(glu::TYPE_FLOAT_VEC4, glu::PRECISION_HIGHP)));
+
+               m_spec.source = "out0 = unpackUnorm4x8(in0);";
+               init();
+       }
+
+       TestInstance* createInstance (Context& ctx) const
+       {
+               return new UnpackUnorm4x8CaseInstance(ctx, m_shaderType, m_spec, m_executor, getName());
+       }
+
+};
+
+ShaderPackingFunctionTests::ShaderPackingFunctionTests (tcu::TestContext& testCtx)
+       : tcu::TestCaseGroup    (testCtx, "pack_unpack", "Floating-point pack and unpack function tests")
+{
+}
+
+ShaderPackingFunctionTests::~ShaderPackingFunctionTests (void)
+{
+}
+
+void ShaderPackingFunctionTests::init (void)
+{
+       // New built-in functions in GLES 3.1
+       {
+               const glu::ShaderType allShaderTypes[] =
+               {
+                       glu::SHADERTYPE_VERTEX,
+                       glu::SHADERTYPE_TESSELLATION_CONTROL,
+                       glu::SHADERTYPE_TESSELLATION_EVALUATION,
+                       glu::SHADERTYPE_GEOMETRY,
+                       glu::SHADERTYPE_FRAGMENT,
+                       glu::SHADERTYPE_COMPUTE
+               };
+
+               // packSnorm4x8
+               for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
+               {
+                       for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
+                               addChild(new PackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
+               }
+
+               // unpackSnorm4x8
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
+                       addChild(new UnpackSnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
+
+               // packUnorm4x8
+               for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
+               {
+                       for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
+                               addChild(new PackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx], glu::Precision(prec)));
+               }
+
+               // unpackUnorm4x8
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(allShaderTypes); shaderTypeNdx++)
+                       addChild(new UnpackUnorm4x8Case(m_testCtx, allShaderTypes[shaderTypeNdx]));
+       }
+
+       // GLES 3 functions in new shader types.
+       {
+               const glu::ShaderType newShaderTypes[] =
+               {
+                       glu::SHADERTYPE_GEOMETRY,
+                       glu::SHADERTYPE_COMPUTE
+               };
+
+               // packSnorm2x16
+               for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
+               {
+                       for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                               addChild(new PackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
+               }
+
+               // unpackSnorm2x16
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                       addChild(new UnpackSnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
+
+               // packUnorm2x16
+               for (int prec = 0; prec < glu::PRECISION_LAST; prec++)
+               {
+                       for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                               addChild(new PackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx], glu::Precision(prec)));
+               }
+
+               // unpackUnorm2x16
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                       addChild(new UnpackUnorm2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
+
+               // packHalf2x16
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                       addChild(new PackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
+
+               // unpackHalf2x16
+               for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(newShaderTypes); shaderTypeNdx++)
+                       addChild(new UnpackHalf2x16Case(m_testCtx, newShaderTypes[shaderTypeNdx]));
+       }
+}
+
+} // shaderexecutor
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderPackingFunctionTests.hpp
new file mode 100644 (file)
index 0000000..61afedb
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef _VKTSHADERPACKINGFUNCTIONTESTS_HPP
+#define _VKTSHADERPACKINGFUNCTIONTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2015 The Khronos Group Inc.
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice(s) and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * The Materials are Confidential Information as defined by the
+ * Khronos Membership Agreement until designated non-confidential by Khronos,
+ * at which point this condition clause shall be removed.
+ *
+ * THE MATERIALS ARE 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
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//*!
+ * \file
+ * \brief Floating-point packing and unpacking function tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuTestCase.hpp"
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+class ShaderPackingFunctionTests : public tcu::TestCaseGroup
+{
+public:
+                                                                       ShaderPackingFunctionTests                              (tcu::TestContext& testCtx);
+       virtual                                                 ~ShaderPackingFunctionTests                             (void);
+
+       virtual void                                    init                                                                    (void);
+
+private:
+                                                                       ShaderPackingFunctionTests                              (const ShaderPackingFunctionTests&);            // not allowed!
+       ShaderPackingFunctionTests&             operator=                                                               (const ShaderPackingFunctionTests&);            // not allowed!
+};
+
+} // shaderexecutor
+} // vkt
+
+#endif // _VKTSHADERPACKINGFUNCTIONTESTS_HPP
index 22547bc..0109cf7 100644 (file)
@@ -62,6 +62,7 @@
 #include "vktShaderRenderReturnTests.hpp"
 #include "vktShaderRenderStructTests.hpp"
 #include "vktShaderRenderSwitchTests.hpp"
+#include "vktShaderExecutorTests.hpp"
 
 #include <vector>
 #include <sstream>
@@ -278,6 +279,9 @@ tcu::TestCaseGroup* createGlslTests (tcu::TestContext& testCtx)
        glslTests->addChild(sr::createStructTests       (testCtx));
        glslTests->addChild(sr::createSwitchTests       (testCtx));
 
+       // ShaderExecutor-based tests
+       glslTests->addChild(shaderexecutor::createTests(testCtx));
+
        return glslTests.release();
 }