--- /dev/null
+/*------------------------------------------------------------------------
+ * 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 Opaque type (sampler, buffer, atomic counter, ...) indexing tests.
+ *//*--------------------------------------------------------------------*/
+
+#include "vktOpaqueTypeIndexingTests.hpp"
+
+#include "tcuTexture.hpp"
+#include "tcuTestLog.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "deStringUtil.hpp"
+#include "deRandom.hpp"
+
+#include "vktShaderExecutor.hpp"
+
+#include <sstream>
+
+namespace vkt
+{
+namespace shaderexecutor
+{
+
+namespace
+{
+
+enum IndexExprType
+{
+ INDEX_EXPR_TYPE_CONST_LITERAL = 0,
+ INDEX_EXPR_TYPE_CONST_EXPRESSION,
+ INDEX_EXPR_TYPE_UNIFORM,
+ INDEX_EXPR_TYPE_DYNAMIC_UNIFORM,
+
+ INDEX_EXPR_TYPE_LAST
+};
+
+enum TextureType
+{
+ TEXTURE_TYPE_1D = 0,
+ TEXTURE_TYPE_2D,
+ TEXTURE_TYPE_CUBE,
+ TEXTURE_TYPE_2D_ARRAY,
+ TEXTURE_TYPE_3D,
+
+ TEXTURE_TYPE_LAST
+};
+
+class OpaqueTypeIndexingCase : public TestCase
+{
+public:
+ OpaqueTypeIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ const glu::ShaderType shaderType,
+ const IndexExprType indexExprType);
+ virtual ~OpaqueTypeIndexingCase (void);
+ virtual void initPrograms (vk::SourceCollections& programCollection) const
+ {
+ m_executor->setShaderSources(programCollection);
+ }
+ virtual TestInstance* createInstance (Context& context) const = 0;
+ void init (void);
+
+protected:
+ const char* m_name;
+ const glu::ShaderType m_shaderType;
+ const IndexExprType m_indexExprType;
+ ShaderSpec m_shaderSpec;
+ de::MovePtr<ShaderExecutor> m_executor;
+ UniformSetup* m_uniformSetup;
+};
+
+class OpaqueTypeIndexingTestInstance : public TestInstance
+{
+public:
+ OpaqueTypeIndexingTestInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ UniformSetup* uniformSetup,
+ const IndexExprType indexExprType);
+ virtual ~OpaqueTypeIndexingTestInstance (void);
+
+ virtual tcu::TestStatus iterate (void) = 0;
+
+protected:
+ tcu::TestContext& m_testCtx;
+ const glu::ShaderType m_shaderType;
+ const ShaderSpec& m_shaderSpec;
+ const char* m_name;
+ const IndexExprType m_indexExprType;
+ ShaderExecutor& m_executor;
+ UniformSetup* m_uniformSetup;
+};
+
+OpaqueTypeIndexingCase::OpaqueTypeIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ const glu::ShaderType shaderType,
+ const IndexExprType indexExprType)
+ : TestCase (testCtx, name, description)
+ , m_name (name)
+ , m_shaderType (shaderType)
+ , m_indexExprType (indexExprType)
+ , m_executor (DE_NULL)
+ , m_uniformSetup (new UniformSetup())
+{
+}
+
+OpaqueTypeIndexingCase::~OpaqueTypeIndexingCase (void)
+{
+}
+
+void OpaqueTypeIndexingCase::init (void)
+{
+ DE_ASSERT(!m_executor);
+
+ m_executor = de::MovePtr<ShaderExecutor>(createExecutor(m_shaderType, m_shaderSpec));
+ m_testCtx.getLog() << *m_executor;
+}
+
+OpaqueTypeIndexingTestInstance::OpaqueTypeIndexingTestInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ UniformSetup* uniformSetup,
+ const IndexExprType indexExprType)
+ : TestInstance (context)
+ , m_testCtx (context.getTestContext())
+ , m_shaderType (shaderType)
+ , m_shaderSpec (shaderSpec)
+ , m_name (name)
+ , m_indexExprType (indexExprType)
+ , m_executor (executor)
+ , m_uniformSetup (uniformSetup)
+{
+}
+
+OpaqueTypeIndexingTestInstance::~OpaqueTypeIndexingTestInstance (void)
+{
+}
+
+static deUint32 getFirstFreeBindingLocation (const glu::ShaderType shaderType, const bool hasInputParam)
+{
+ deUint32 location;
+
+ switch (shaderType)
+ {
+ case glu::SHADERTYPE_TESSELLATION_CONTROL:
+ case glu::SHADERTYPE_TESSELLATION_EVALUATION:
+ case glu::SHADERTYPE_COMPUTE:
+ // 0 - output buffer
+ // 1 - input buffer (if any)
+ if (hasInputParam)
+ location = 2u;
+ else
+ location = 1u;
+ break;
+
+ default:
+ location = 0u;
+ break;
+ }
+
+ return location;
+}
+
+static deUint32 getFirstFreeBindingLocation (const glu::ShaderType shaderType, const ShaderSpec& shaderSpec)
+{
+ return getFirstFreeBindingLocation(shaderType, !shaderSpec.inputs.empty());
+}
+
+static void declareUniformIndexVars (std::ostream& str, const char* varPrefix, int numVars, deUint32& bindingLocation)
+{
+ for (int varNdx = 0; varNdx < numVars; varNdx++)
+ str << "layout(set = 0, binding = " << bindingLocation++ << ") uniform buf" << varNdx << " { highp int " << varPrefix << varNdx << "; }" << ";\n";
+}
+
+static void uploadUniformIndices (UniformSetup* uniformSetup, int numIndices, const int* indices, deUint32& bindingLocation)
+{
+ for (int varNdx = 0; varNdx < numIndices; varNdx++)
+ uniformSetup->addData(new UniformData<int>(bindingLocation++, indices[varNdx]));
+}
+
+static TextureType getTextureType (glu::DataType samplerType)
+{
+ switch (samplerType)
+ {
+ case glu::TYPE_SAMPLER_1D:
+ case glu::TYPE_INT_SAMPLER_1D:
+ case glu::TYPE_UINT_SAMPLER_1D:
+ case glu::TYPE_SAMPLER_1D_SHADOW:
+ return TEXTURE_TYPE_1D;
+
+ case glu::TYPE_SAMPLER_2D:
+ case glu::TYPE_INT_SAMPLER_2D:
+ case glu::TYPE_UINT_SAMPLER_2D:
+ case glu::TYPE_SAMPLER_2D_SHADOW:
+ return TEXTURE_TYPE_2D;
+
+ case glu::TYPE_SAMPLER_CUBE:
+ case glu::TYPE_INT_SAMPLER_CUBE:
+ case glu::TYPE_UINT_SAMPLER_CUBE:
+ case glu::TYPE_SAMPLER_CUBE_SHADOW:
+ return TEXTURE_TYPE_CUBE;
+
+ case glu::TYPE_SAMPLER_2D_ARRAY:
+ case glu::TYPE_INT_SAMPLER_2D_ARRAY:
+ case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
+ case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
+ return TEXTURE_TYPE_2D_ARRAY;
+
+ case glu::TYPE_SAMPLER_3D:
+ case glu::TYPE_INT_SAMPLER_3D:
+ case glu::TYPE_UINT_SAMPLER_3D:
+ return TEXTURE_TYPE_3D;
+
+ default:
+ throw tcu::InternalError("Invalid sampler type");
+ }
+}
+
+static bool isShadowSampler (glu::DataType samplerType)
+{
+ return samplerType == glu::TYPE_SAMPLER_1D_SHADOW ||
+ samplerType == glu::TYPE_SAMPLER_2D_SHADOW ||
+ samplerType == glu::TYPE_SAMPLER_2D_ARRAY_SHADOW ||
+ samplerType == glu::TYPE_SAMPLER_CUBE_SHADOW;
+}
+
+static glu::DataType getSamplerOutputType (glu::DataType samplerType)
+{
+ switch (samplerType)
+ {
+ case glu::TYPE_SAMPLER_1D:
+ case glu::TYPE_SAMPLER_2D:
+ case glu::TYPE_SAMPLER_CUBE:
+ case glu::TYPE_SAMPLER_2D_ARRAY:
+ case glu::TYPE_SAMPLER_3D:
+ return glu::TYPE_FLOAT_VEC4;
+
+ case glu::TYPE_SAMPLER_1D_SHADOW:
+ case glu::TYPE_SAMPLER_2D_SHADOW:
+ case glu::TYPE_SAMPLER_CUBE_SHADOW:
+ case glu::TYPE_SAMPLER_2D_ARRAY_SHADOW:
+ return glu::TYPE_FLOAT;
+
+ case glu::TYPE_INT_SAMPLER_1D:
+ case glu::TYPE_INT_SAMPLER_2D:
+ case glu::TYPE_INT_SAMPLER_CUBE:
+ case glu::TYPE_INT_SAMPLER_2D_ARRAY:
+ case glu::TYPE_INT_SAMPLER_3D:
+ return glu::TYPE_INT_VEC4;
+
+ case glu::TYPE_UINT_SAMPLER_1D:
+ case glu::TYPE_UINT_SAMPLER_2D:
+ case glu::TYPE_UINT_SAMPLER_CUBE:
+ case glu::TYPE_UINT_SAMPLER_2D_ARRAY:
+ case glu::TYPE_UINT_SAMPLER_3D:
+ return glu::TYPE_UINT_VEC4;
+
+ default:
+ throw tcu::InternalError("Invalid sampler type");
+ }
+}
+
+static tcu::TextureFormat getSamplerTextureFormat (glu::DataType samplerType)
+{
+ const glu::DataType outType = getSamplerOutputType(samplerType);
+ const glu::DataType outScalarType = glu::getDataTypeScalarType(outType);
+
+ switch (outScalarType)
+ {
+ case glu::TYPE_FLOAT:
+ if (isShadowSampler(samplerType))
+ return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16);
+ else
+ return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
+
+ case glu::TYPE_INT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::SIGNED_INT8);
+ case glu::TYPE_UINT: return tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNSIGNED_INT8);
+
+ default:
+ throw tcu::InternalError("Invalid sampler type");
+ }
+}
+
+static glu::DataType getSamplerCoordType (glu::DataType samplerType)
+{
+ const TextureType texType = getTextureType(samplerType);
+ int numCoords = 0;
+
+ switch (texType)
+ {
+ case TEXTURE_TYPE_1D: numCoords = 1; break;
+ case TEXTURE_TYPE_2D: numCoords = 2; break;
+ case TEXTURE_TYPE_2D_ARRAY: numCoords = 3; break;
+ case TEXTURE_TYPE_CUBE: numCoords = 3; break;
+ case TEXTURE_TYPE_3D: numCoords = 3; break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ if (isShadowSampler(samplerType))
+ numCoords += 1;
+
+ DE_ASSERT(de::inRange(numCoords, 1, 4));
+
+ return numCoords == 1 ? glu::TYPE_FLOAT : glu::getDataTypeFloatVec(numCoords);
+}
+
+static void fillTextureData (const tcu::PixelBufferAccess& access, de::Random& rnd)
+{
+ DE_ASSERT(access.getHeight() == 1 && access.getDepth() == 1);
+
+ if (access.getFormat().order == tcu::TextureFormat::D)
+ {
+ // \note Texture uses odd values, lookup even values to avoid precision issues.
+ const float values[] = { 0.1f, 0.3f, 0.5f, 0.7f, 0.9f };
+
+ for (int ndx = 0; ndx < access.getWidth(); ndx++)
+ access.setPixDepth(rnd.choose<float>(DE_ARRAY_BEGIN(values), DE_ARRAY_END(values)), ndx, 0);
+ }
+ else
+ {
+ TCU_CHECK_INTERNAL(access.getFormat().order == tcu::TextureFormat::RGBA && access.getFormat().getPixelSize() == 4);
+
+ for (int ndx = 0; ndx < access.getWidth(); ndx++)
+ *((deUint32*)access.getDataPtr() + ndx) = rnd.getUint32();
+ }
+}
+
+static vk::VkImageType getVkImageType (TextureType texType)
+{
+ switch (texType)
+ {
+ case TEXTURE_TYPE_1D: return vk::VK_IMAGE_TYPE_1D;
+ case TEXTURE_TYPE_2D:
+ case TEXTURE_TYPE_2D_ARRAY: return vk::VK_IMAGE_TYPE_2D;
+ case TEXTURE_TYPE_CUBE: return vk::VK_IMAGE_TYPE_3D;
+ case TEXTURE_TYPE_3D: return vk::VK_IMAGE_TYPE_3D;
+ default:
+ DE_FATAL("Impossible");
+ return (vk::VkImageType)0;
+ }
+}
+
+static vk::VkImageViewType getVkImageViewType (TextureType texType)
+{
+ switch (texType)
+ {
+ case TEXTURE_TYPE_1D: return vk::VK_IMAGE_VIEW_TYPE_1D;
+ case TEXTURE_TYPE_2D: return vk::VK_IMAGE_VIEW_TYPE_2D;
+ case TEXTURE_TYPE_2D_ARRAY: return vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ case TEXTURE_TYPE_CUBE: return vk::VK_IMAGE_VIEW_TYPE_3D; // \todo vk::VK_IMAGE_VIEW_TYPE_CUBE ?
+ case TEXTURE_TYPE_3D: return vk::VK_IMAGE_VIEW_TYPE_3D;
+ default:
+ DE_FATAL("Impossible");
+ return (vk::VkImageViewType)0;
+ }
+}
+
+// SamplerIndexingCaseInstance
+
+class SamplerIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
+{
+public:
+ enum
+ {
+ NUM_INVOCATIONS = 64,
+ NUM_SAMPLERS = 8,
+ NUM_LOOKUPS = 4
+ };
+
+ SamplerIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ glu::DataType samplerType,
+ const IndexExprType indexExprType,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& lookupIndices);
+ virtual ~SamplerIndexingCaseInstance (void);
+
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ const glu::DataType m_samplerType;
+ const std::vector<int>& m_lookupIndices;
+};
+
+SamplerIndexingCaseInstance::SamplerIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ glu::DataType samplerType,
+ const IndexExprType indexExprType,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& lookupIndices)
+ : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
+ , m_samplerType (samplerType)
+ , m_lookupIndices (lookupIndices)
+{
+}
+
+SamplerIndexingCaseInstance::~SamplerIndexingCaseInstance (void)
+{
+}
+
+tcu::TestStatus SamplerIndexingCaseInstance::iterate (void)
+{
+ const int numInvocations = SamplerIndexingCaseInstance::NUM_INVOCATIONS;
+ const int numSamplers = SamplerIndexingCaseInstance::NUM_SAMPLERS;
+ const int numLookups = SamplerIndexingCaseInstance::NUM_LOOKUPS;
+ const glu::DataType coordType = getSamplerCoordType(m_samplerType);
+ const glu::DataType outputType = getSamplerOutputType(m_samplerType);
+ const tcu::TextureFormat texFormat = getSamplerTextureFormat(m_samplerType);
+ const int outLookupStride = numInvocations*getDataTypeScalarSize(outputType);
+ std::vector<float> coords;
+ std::vector<deUint32> outData;
+ std::vector<deUint8> texData (numSamplers * texFormat.getPixelSize());
+ const tcu::PixelBufferAccess refTexAccess (texFormat, numSamplers, 1, 1, &texData[0]);
+ de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
+ const TextureType texType = getTextureType(m_samplerType);
+ const vk::VkImageType imageType = getVkImageType(texType);
+ const vk::VkImageViewType imageViewType = getVkImageViewType(texType);
+ const tcu::Sampler refSampler = isShadowSampler(m_samplerType)
+ ? tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
+ tcu::Sampler::NEAREST, tcu::Sampler::NEAREST, 0.0f, false /* non-normalized */,
+ tcu::Sampler::COMPAREMODE_LESS)
+ : tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
+ tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
+
+ coords.resize(numInvocations * getDataTypeScalarSize(coordType));
+
+ if (isShadowSampler(m_samplerType))
+ {
+ // Use different comparison value per invocation.
+ // \note Texture uses odd values, comparison even values.
+ const int numCoordComps = getDataTypeScalarSize(coordType);
+ const float cmpValues[] = { 0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f };
+
+ for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
+ coords[invocationNdx*numCoordComps + (numCoordComps-1)] = rnd.choose<float>(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues));
+ }
+
+ fillTextureData(refTexAccess, rnd);
+
+ outData.resize(numLookups*outLookupStride);
+
+ {
+ std::vector<void*> inputs;
+ std::vector<void*> outputs;
+ std::vector<int> expandedIndices;
+ deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType, m_shaderSpec);
+
+ inputs.push_back(&coords[0]);
+
+ m_uniformSetup->addData(new SamplerUniformData(bindingLocation++, (deUint32)numSamplers, refSampler, texFormat, tcu::IVec3(1, 1, 1), imageType, imageViewType, &texData[0]));
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ expandedIndices.resize(numInvocations * m_lookupIndices.size());
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ {
+ for (int invNdx = 0; invNdx < numInvocations; invNdx++)
+ expandedIndices[lookupNdx*numInvocations + invNdx] = m_lookupIndices[lookupNdx];
+ }
+
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ inputs.push_back(&expandedIndices[lookupNdx*numInvocations]);
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ uploadUniformIndices(m_uniformSetup, numLookups, &m_lookupIndices[0], bindingLocation);
+
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ outputs.push_back(&outData[outLookupStride*lookupNdx]);
+
+ m_executor.setUniforms(m_uniformSetup);
+
+ m_executor.execute(m_context, numInvocations, &inputs[0], &outputs[0]);
+ }
+
+ {
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+ tcu::TestStatus testResult = tcu::TestStatus::pass("Pass");
+
+ if (isShadowSampler(m_samplerType))
+ {
+ const int numCoordComps = getDataTypeScalarSize(coordType);
+
+ TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 1);
+
+ // Each invocation may have different results.
+ for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
+ {
+ const float coord = coords[invocationNdx*numCoordComps + (numCoordComps-1)];
+
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ {
+ const int texNdx = m_lookupIndices[lookupNdx];
+ const float result = *((const float*)(const deUint8*)&outData[lookupNdx*outLookupStride + invocationNdx]);
+ const float reference = refTexAccess.sample2DCompare(refSampler, tcu::Sampler::NEAREST, coord, (float)texNdx, 0.0f, tcu::IVec3(0));
+
+ if (de::abs(result-reference) > 0.005f)
+ {
+ log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx << ", lookup " << lookupNdx << ": expected "
+ << reference << ", got " << result
+ << tcu::TestLog::EndMessage;
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Got invalid lookup result");
+ }
+ }
+ }
+ }
+ else
+ {
+ TCU_CHECK_INTERNAL(getDataTypeScalarSize(outputType) == 4);
+
+ // Validate results from first invocation
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ {
+ const int texNdx = m_lookupIndices[lookupNdx];
+ const deUint8* resPtr = (const deUint8*)&outData[lookupNdx*outLookupStride];
+ bool isOk;
+
+ if (outputType == glu::TYPE_FLOAT_VEC4)
+ {
+ const float threshold = 1.0f / 256.0f;
+ const tcu::Vec4 reference = refTexAccess.getPixel(texNdx, 0);
+ const float* floatPtr = (const float*)resPtr;
+ const tcu::Vec4 result (floatPtr[0], floatPtr[1], floatPtr[2], floatPtr[3]);
+
+ isOk = boolAll(lessThanEqual(abs(reference-result), tcu::Vec4(threshold)));
+
+ if (!isOk)
+ {
+ log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
+ << reference << ", got " << result
+ << tcu::TestLog::EndMessage;
+ }
+ }
+ else
+ {
+ const tcu::UVec4 reference = refTexAccess.getPixelUint(texNdx, 0);
+ const deUint32* uintPtr = (const deUint32*)resPtr;
+ const tcu::UVec4 result (uintPtr[0], uintPtr[1], uintPtr[2], uintPtr[3]);
+
+ isOk = boolAll(equal(reference, result));
+
+ if (!isOk)
+ {
+ log << tcu::TestLog::Message << "ERROR: at lookup " << lookupNdx << ": expected "
+ << reference << ", got " << result
+ << tcu::TestLog::EndMessage;
+ }
+ }
+
+ if (!isOk && testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Got invalid lookup result");
+ }
+
+ // Check results of other invocations against first one
+ for (int invocationNdx = 1; invocationNdx < numInvocations; invocationNdx++)
+ {
+ for (int lookupNdx = 0; lookupNdx < numLookups; lookupNdx++)
+ {
+ const deUint32* refPtr = &outData[lookupNdx*outLookupStride];
+ const deUint32* resPtr = refPtr + invocationNdx*4;
+ bool isOk = true;
+
+ for (int ndx = 0; ndx < 4; ndx++)
+ isOk = isOk && (refPtr[ndx] == resPtr[ndx]);
+
+ if (!isOk)
+ {
+ log << tcu::TestLog::Message << "ERROR: invocation " << invocationNdx << " result "
+ << tcu::formatArray(tcu::Format::HexIterator<deUint32>(resPtr), tcu::Format::HexIterator<deUint32>(resPtr+4))
+ << " for lookup " << lookupNdx << " doesn't match result from first invocation "
+ << tcu::formatArray(tcu::Format::HexIterator<deUint32>(refPtr), tcu::Format::HexIterator<deUint32>(refPtr+4))
+ << tcu::TestLog::EndMessage;
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Inconsistent lookup results");
+ }
+ }
+ }
+ }
+
+ return testResult;
+ }
+}
+
+class SamplerIndexingCase : public OpaqueTypeIndexingCase
+{
+public:
+ SamplerIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ const glu::ShaderType shaderType,
+ glu::DataType samplerType,
+ IndexExprType indexExprType);
+ virtual ~SamplerIndexingCase (void);
+
+ virtual TestInstance* createInstance (Context& ctx) const;
+
+private:
+ SamplerIndexingCase (const SamplerIndexingCase&);
+ SamplerIndexingCase& operator= (const SamplerIndexingCase&);
+
+ void createShaderSpec (void);
+
+ const glu::DataType m_samplerType;
+ const int m_numSamplers;
+ const int m_numLookups;
+ std::vector<int> m_lookupIndices;
+};
+
+SamplerIndexingCase::SamplerIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ const glu::ShaderType shaderType,
+ glu::DataType samplerType,
+ IndexExprType indexExprType)
+ : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType)
+ , m_samplerType (samplerType)
+ , m_numSamplers (SamplerIndexingCaseInstance::NUM_SAMPLERS)
+ , m_numLookups (SamplerIndexingCaseInstance::NUM_LOOKUPS)
+ , m_lookupIndices (m_numLookups)
+{
+ createShaderSpec();
+ init();
+}
+
+SamplerIndexingCase::~SamplerIndexingCase (void)
+{
+}
+
+TestInstance* SamplerIndexingCase::createInstance (Context& ctx) const
+{
+ return new SamplerIndexingCaseInstance(ctx,
+ m_shaderType,
+ m_shaderSpec,
+ *m_executor,
+ m_name,
+ m_samplerType,
+ m_indexExprType,
+ m_uniformSetup,
+ m_lookupIndices);
+}
+
+void SamplerIndexingCase::createShaderSpec (void)
+{
+ de::Random rnd (deInt32Hash(m_samplerType) ^ deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
+ deUint32 binding = getFirstFreeBindingLocation(m_shaderType, true);
+ const char* samplersName = "texSampler";
+ const char* coordsName = "coords";
+ const char* indicesPrefix = "index";
+ const char* resultPrefix = "result";
+ const glu::DataType coordType = getSamplerCoordType(m_samplerType);
+ const glu::DataType outType = getSamplerOutputType(m_samplerType);
+ std::ostringstream global, code;
+
+ for (int ndx = 0; ndx < m_numLookups; ndx++)
+ m_lookupIndices[ndx] = rnd.getInt(0, m_numSamplers-1);
+
+ m_shaderSpec.inputs.push_back(Symbol(coordsName, glu::VarType(coordType, glu::PRECISION_HIGHP)));
+
+ if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
+ global << "#extension GL_EXT_gpu_shader5 : require\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ global << "const highp int indexBase = 1;\n";
+
+ global <<
+ "layout(set = 0, binding = " << binding++ << ") uniform highp " << getDataTypeName(m_samplerType) << " " << samplersName << "[" << m_numSamplers << "];\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
+ {
+ const std::string varName = indicesPrefix + de::toString(lookupNdx);
+ m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
+ }
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ declareUniformIndexVars(global, indicesPrefix, m_numLookups, binding);
+
+ for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
+ {
+ const std::string varName = resultPrefix + de::toString(lookupNdx);
+ m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(outType, glu::PRECISION_HIGHP)));
+ }
+
+ for (int lookupNdx = 0; lookupNdx < m_numLookups; lookupNdx++)
+ {
+ code << resultPrefix << "" << lookupNdx << " = texture(" << samplersName << "[";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
+ code << m_lookupIndices[lookupNdx];
+ else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ code << "indexBase + " << (m_lookupIndices[lookupNdx]-1);
+ else
+ code << indicesPrefix << lookupNdx;
+
+ code << "], " << coordsName << ");\n";
+ }
+
+ m_shaderSpec.globalDeclarations = global.str();
+ m_shaderSpec.source = code.str();
+}
+
+enum BlockType
+{
+ BLOCKTYPE_UNIFORM = 0,
+ BLOCKTYPE_BUFFER,
+
+ BLOCKTYPE_LAST
+};
+
+class BlockArrayIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
+{
+public:
+ enum
+ {
+ NUM_INVOCATIONS = 32,
+ NUM_INSTANCES = 4,
+ NUM_READS = 4
+ };
+
+ BlockArrayIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ BlockType blockType,
+ const IndexExprType indexExprType,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& readIndices,
+ const std::vector<deUint32>& inValues);
+ virtual ~BlockArrayIndexingCaseInstance (void);
+
+ virtual tcu::TestStatus iterate (void);
+
+private:
+ const BlockType m_blockType;
+ const std::vector<int>& m_readIndices;
+ const std::vector<deUint32>& m_inValues;
+};
+
+BlockArrayIndexingCaseInstance::BlockArrayIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ BlockType blockType,
+ const IndexExprType indexExprType,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& readIndices,
+ const std::vector<deUint32>& inValues)
+ : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
+ , m_blockType (blockType)
+ , m_readIndices (readIndices)
+ , m_inValues (inValues)
+{
+}
+
+BlockArrayIndexingCaseInstance::~BlockArrayIndexingCaseInstance (void)
+{
+}
+
+tcu::TestStatus BlockArrayIndexingCaseInstance::iterate (void)
+{
+ const int numInvocations = NUM_INVOCATIONS;
+ const int numReads = NUM_READS;
+ std::vector<deUint32> outValues (numInvocations*numReads);
+
+ {
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+ tcu::TestStatus testResult = tcu::TestStatus::pass("Pass");
+ std::vector<int> expandedIndices;
+ std::vector<void*> inputs;
+ std::vector<void*> outputs;
+ deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType, m_shaderSpec);
+
+ for (size_t i = 0 ; i < m_inValues.size(); i++)
+ m_uniformSetup->addData(new UniformData<deUint32>(bindingLocation++, m_inValues[i]));
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ expandedIndices.resize(numInvocations * m_readIndices.size());
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ {
+ int* dst = &expandedIndices[numInvocations*readNdx];
+ std::fill(dst, dst+numInvocations, m_readIndices[readNdx]);
+ }
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ inputs.push_back(&expandedIndices[readNdx*numInvocations]);
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ uploadUniformIndices(m_uniformSetup, numReads, &m_readIndices[0], bindingLocation);
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ outputs.push_back(&outValues[readNdx*numInvocations]);
+
+ m_executor.setUniforms(m_uniformSetup);
+
+ m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
+
+ for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
+ {
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ {
+ const deUint32 refValue = m_inValues[m_readIndices[readNdx]];
+ const deUint32 resValue = outValues[readNdx*numInvocations + invocationNdx];
+
+ if (refValue != resValue)
+ {
+ log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx
+ << ", read " << readNdx << ": expected "
+ << tcu::toHex(refValue) << ", got " << tcu::toHex(resValue)
+ << tcu::TestLog::EndMessage;
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Invalid result value");
+ }
+ }
+ }
+
+ return testResult;
+ }
+}
+
+class BlockArrayIndexingCase : public OpaqueTypeIndexingCase
+{
+public:
+ BlockArrayIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ BlockType blockType,
+ IndexExprType indexExprType,
+ const glu::ShaderType shaderType);
+ virtual ~BlockArrayIndexingCase (void);
+
+ virtual TestInstance* createInstance (Context& ctx) const;
+
+private:
+ BlockArrayIndexingCase (const BlockArrayIndexingCase&);
+ BlockArrayIndexingCase& operator= (const BlockArrayIndexingCase&);
+
+ void createShaderSpec (void);
+
+ const BlockType m_blockType;
+ std::vector<int> m_readIndices;
+ std::vector<deUint32> m_inValues;
+};
+
+BlockArrayIndexingCase::BlockArrayIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ BlockType blockType,
+ IndexExprType indexExprType,
+ const glu::ShaderType shaderType)
+ : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType)
+ , m_blockType (blockType)
+ , m_readIndices (BlockArrayIndexingCaseInstance::NUM_READS)
+ , m_inValues (BlockArrayIndexingCaseInstance::NUM_INSTANCES)
+{
+ createShaderSpec();
+ init();
+}
+
+BlockArrayIndexingCase::~BlockArrayIndexingCase (void)
+{
+}
+
+TestInstance* BlockArrayIndexingCase::createInstance (Context& ctx) const
+{
+ return new BlockArrayIndexingCaseInstance(ctx,
+ m_shaderType,
+ m_shaderSpec,
+ *m_executor,
+ m_name,
+ m_blockType,
+ m_indexExprType,
+ m_uniformSetup,
+ m_readIndices,
+ m_inValues);
+}
+
+void BlockArrayIndexingCase::createShaderSpec (void)
+{
+ const int numInstances = BlockArrayIndexingCaseInstance::NUM_INSTANCES;
+ const int numReads = BlockArrayIndexingCaseInstance::NUM_READS;
+ de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_blockType) ^ deInt32Hash(m_indexExprType));
+ deUint32 binding = getFirstFreeBindingLocation(m_shaderType, m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM && numReads > 0);
+ const char* blockName = "Block";
+ const char* instanceName = "block";
+ const char* indicesPrefix = "index";
+ const char* resultPrefix = "result";
+ const char* interfaceName = m_blockType == BLOCKTYPE_UNIFORM ? "uniform" : "buffer";
+ std::ostringstream global, code;
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ m_readIndices[readNdx] = rnd.getInt(0, numInstances-1);
+
+ for (int instanceNdx = 0; instanceNdx < numInstances; instanceNdx++)
+ m_inValues[instanceNdx] = rnd.getUint32();
+
+ if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
+ global << "#extension GL_EXT_gpu_shader5 : require\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ global << "const highp int indexBase = 1;\n";
+
+ global <<
+ "layout(set = 0, binding = " << binding++ << ") " << interfaceName << " " << blockName << "\n"
+ "{\n"
+ " highp uint value;\n"
+ "} " << instanceName << "[" << numInstances << "];\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ {
+ const std::string varName = indicesPrefix + de::toString(readNdx);
+ m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
+ }
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ declareUniformIndexVars(global, indicesPrefix, numReads, binding);
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ {
+ const std::string varName = resultPrefix + de::toString(readNdx);
+ m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+ }
+
+ for (int readNdx = 0; readNdx < numReads; readNdx++)
+ {
+ code << resultPrefix << readNdx << " = " << instanceName << "[";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
+ code << m_readIndices[readNdx];
+ else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ code << "indexBase + " << (m_readIndices[readNdx]-1);
+ else
+ code << indicesPrefix << readNdx;
+
+ code << "].value;\n";
+ }
+
+ m_shaderSpec.globalDeclarations = global.str();
+ m_shaderSpec.source = code.str();
+}
+
+class AtomicCounterIndexingCaseInstance : public OpaqueTypeIndexingTestInstance
+{
+public:
+ enum
+ {
+ NUM_INVOCATIONS = 32,
+ NUM_COUNTERS = 4,
+ NUM_OPS = 4
+ };
+
+ AtomicCounterIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& opIndices,
+ const IndexExprType indexExprType);
+ virtual ~AtomicCounterIndexingCaseInstance (void);
+
+ virtual tcu::TestStatus iterate (void);
+
+private:
+ const std::vector<int>& m_opIndices;
+};
+
+AtomicCounterIndexingCaseInstance::AtomicCounterIndexingCaseInstance (Context& context,
+ const glu::ShaderType shaderType,
+ const ShaderSpec& shaderSpec,
+ ShaderExecutor& executor,
+ const char* name,
+ UniformSetup* uniformSetup,
+ const std::vector<int>& opIndices,
+ const IndexExprType indexExprType)
+ : OpaqueTypeIndexingTestInstance (context, shaderType, shaderSpec, executor, name, uniformSetup, indexExprType)
+ , m_opIndices (opIndices)
+{
+}
+
+AtomicCounterIndexingCaseInstance::~AtomicCounterIndexingCaseInstance (void)
+{
+}
+
+tcu::TestStatus AtomicCounterIndexingCaseInstance::iterate (void)
+{
+ // \todo [2015-12-02 elecro] Add vertexPipelineStoresAndAtomics feature check.
+ const int numInvocations = NUM_INVOCATIONS;
+ const int numCounters = NUM_COUNTERS;
+ const int numOps = NUM_OPS;
+ std::vector<int> expandedIndices;
+ std::vector<void*> inputs;
+ std::vector<void*> outputs;
+ std::vector<deUint32> outValues (numInvocations*numOps);
+ deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType, m_shaderSpec);
+
+ {
+ DE_ASSERT(numCounters <= 4);
+ // Add the atomic counters' base value, all zero.
+ m_uniformSetup->addData(new UniformData<tcu::Mat4>(bindingLocation++, tcu::Mat4(0.0)));
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ expandedIndices.resize(numInvocations * m_opIndices.size());
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ {
+ int* dst = &expandedIndices[numInvocations*opNdx];
+ std::fill(dst, dst+numInvocations, m_opIndices[opNdx]);
+ }
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ inputs.push_back(&expandedIndices[opNdx*numInvocations]);
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ uploadUniformIndices(m_uniformSetup, numOps, &m_opIndices[0], bindingLocation);
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ outputs.push_back(&outValues[opNdx*numInvocations]);
+
+ m_executor.setUniforms(m_uniformSetup);
+
+ m_executor.execute(m_context, numInvocations, inputs.empty() ? DE_NULL : &inputs[0], &outputs[0]);
+ }
+
+ {
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+ tcu::TestStatus testResult = tcu::TestStatus::pass("Pass");
+ std::vector<int> numHits (numCounters, 0); // Number of hits per counter.
+ std::vector<deUint32> counterValues (numCounters);
+ std::vector<std::vector<bool> > counterMasks (numCounters);
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ numHits[m_opIndices[opNdx]] += 1;
+
+ // Verify counter values
+ for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
+ {
+ const deUint32 refCount = (deUint32)(numHits[counterNdx]*numInvocations);
+ const deUint32 resCount = counterValues[counterNdx];
+
+ if (refCount != resCount)
+ {
+ log << tcu::TestLog::Message << "ERROR: atomic counter " << counterNdx << " has value " << resCount
+ << ", expected " << refCount
+ << tcu::TestLog::EndMessage;
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Invalid atomic counter value");
+ }
+ }
+
+ // Allocate bitmasks - one bit per each valid result value
+ for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
+ {
+ const int counterValue = numHits[counterNdx]*numInvocations;
+ counterMasks[counterNdx].resize(counterValue, false);
+ }
+
+ // Verify result values from shaders
+ for (int invocationNdx = 0; invocationNdx < numInvocations; invocationNdx++)
+ {
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ {
+ const int counterNdx = m_opIndices[opNdx];
+ const deUint32 resValue = outValues[opNdx*numInvocations + invocationNdx];
+ const bool rangeOk = de::inBounds(resValue, 0u, (deUint32)counterMasks[counterNdx].size());
+ const bool notSeen = rangeOk && !counterMasks[counterNdx][resValue];
+ const bool isOk = rangeOk && notSeen;
+
+ if (!isOk)
+ {
+ log << tcu::TestLog::Message << "ERROR: at invocation " << invocationNdx
+ << ", op " << opNdx << ": got invalid result value "
+ << resValue
+ << tcu::TestLog::EndMessage;
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ testResult = tcu::TestStatus::fail("Invalid result value");
+ }
+ else
+ {
+ // Mark as used - no other invocation should see this value from same counter.
+ counterMasks[counterNdx][resValue] = true;
+ }
+ }
+ }
+
+ if (testResult.getCode() == QP_TEST_RESULT_PASS)
+ {
+ // Consistency check - all masks should be 1 now
+ for (int counterNdx = 0; counterNdx < numCounters; counterNdx++)
+ {
+ for (std::vector<bool>::const_iterator i = counterMasks[counterNdx].begin(); i != counterMasks[counterNdx].end(); i++)
+ TCU_CHECK_INTERNAL(*i);
+ }
+ }
+
+ return testResult;
+ }
+}
+
+class AtomicCounterIndexingCase : public OpaqueTypeIndexingCase
+{
+public:
+ AtomicCounterIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ IndexExprType indexExprType,
+ const glu::ShaderType shaderType);
+ virtual ~AtomicCounterIndexingCase (void);
+
+ virtual TestInstance* createInstance (Context& ctx) const;
+
+private:
+ AtomicCounterIndexingCase (const BlockArrayIndexingCase&);
+ AtomicCounterIndexingCase& operator= (const BlockArrayIndexingCase&);
+
+ void createShaderSpec (void);
+
+ std::vector<int> m_opIndices;
+};
+
+AtomicCounterIndexingCase::AtomicCounterIndexingCase (tcu::TestContext& testCtx,
+ const char* name,
+ const char* description,
+ IndexExprType indexExprType,
+ const glu::ShaderType shaderType)
+ : OpaqueTypeIndexingCase (testCtx, name, description, shaderType, indexExprType)
+ , m_opIndices (AtomicCounterIndexingCaseInstance::NUM_OPS)
+{
+ createShaderSpec();
+ init();
+}
+
+AtomicCounterIndexingCase::~AtomicCounterIndexingCase (void)
+{
+}
+
+TestInstance* AtomicCounterIndexingCase::createInstance (Context& ctx) const
+{
+ return new AtomicCounterIndexingCaseInstance(ctx,
+ m_shaderType,
+ m_shaderSpec,
+ *m_executor,
+ m_name,
+ m_uniformSetup,
+ m_opIndices,
+ m_indexExprType);
+}
+
+void AtomicCounterIndexingCase::createShaderSpec (void)
+{
+ const int numCounters = AtomicCounterIndexingCaseInstance::NUM_COUNTERS;
+ const int numOps = AtomicCounterIndexingCaseInstance::NUM_OPS;
+ deUint32 binding = getFirstFreeBindingLocation(m_shaderType, m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM && numOps > 0);
+ de::Random rnd (deInt32Hash(m_shaderType) ^ deInt32Hash(m_indexExprType));
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ m_opIndices[opNdx] = rnd.getInt(0, numOps-1);
+
+ {
+ const char* indicesPrefix = "index";
+ const char* resultPrefix = "result";
+ std::ostringstream global, code;
+
+ if (m_indexExprType != INDEX_EXPR_TYPE_CONST_LITERAL)
+ global << "#extension GL_EXT_gpu_shader5 : require\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ global << "const highp int indexBase = 1;\n";
+
+ global <<
+ "layout(set = 0, binding = " << binding++ << ") buffer AtomicBuffer { highp uint counter[" << numCounters << "]; };\n";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_DYNAMIC_UNIFORM)
+ {
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ {
+ const std::string varName = indicesPrefix + de::toString(opNdx);
+ m_shaderSpec.inputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_INT, glu::PRECISION_HIGHP)));
+ }
+ }
+ else if (m_indexExprType == INDEX_EXPR_TYPE_UNIFORM)
+ declareUniformIndexVars(global, indicesPrefix, numOps, binding);
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ {
+ const std::string varName = resultPrefix + de::toString(opNdx);
+ m_shaderSpec.outputs.push_back(Symbol(varName, glu::VarType(glu::TYPE_UINT, glu::PRECISION_HIGHP)));
+ }
+
+ for (int opNdx = 0; opNdx < numOps; opNdx++)
+ {
+ code << resultPrefix << opNdx << " = atomicAdd(counter[";
+
+ if (m_indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL)
+ code << m_opIndices[opNdx];
+ else if (m_indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ code << "indexBase + " << (m_opIndices[opNdx]-1);
+ else
+ code << indicesPrefix << opNdx;
+
+ code << "], uint(1));\n";
+ }
+
+ m_shaderSpec.globalDeclarations = global.str();
+ m_shaderSpec.source = code.str();
+ }
+}
+
+} // anonymous
+
+OpaqueTypeIndexingTests::OpaqueTypeIndexingTests (tcu::TestContext& testCtx)
+ : tcu::TestCaseGroup(testCtx, "opaque_type_indexing", "Opaque Type Indexing Tests")
+{
+}
+
+OpaqueTypeIndexingTests::~OpaqueTypeIndexingTests (void)
+{
+}
+
+void OpaqueTypeIndexingTests::init (void)
+{
+ static const struct
+ {
+ IndexExprType type;
+ const char* name;
+ const char* description;
+ } indexingTypes[] =
+ {
+ { INDEX_EXPR_TYPE_CONST_LITERAL, "const_literal", "Indexing by constant literal" },
+ { INDEX_EXPR_TYPE_CONST_EXPRESSION, "const_expression", "Indexing by constant expression" },
+ { INDEX_EXPR_TYPE_UNIFORM, "uniform", "Indexing by uniform value" },
+ { INDEX_EXPR_TYPE_DYNAMIC_UNIFORM, "dynamically_uniform", "Indexing by dynamically uniform expression" }
+ };
+
+ static const struct
+ {
+ glu::ShaderType type;
+ const char* name;
+ } shaderTypes[] =
+ {
+ { glu::SHADERTYPE_VERTEX, "vertex" },
+ { glu::SHADERTYPE_FRAGMENT, "fragment" },
+ { glu::SHADERTYPE_COMPUTE, "compute" }
+ };
+
+ // .sampler
+ {
+ static const glu::DataType samplerTypes[] =
+ {
+ // \note 1D images will be added by a later extension.
+// glu::TYPE_SAMPLER_1D,
+ glu::TYPE_SAMPLER_2D,
+ glu::TYPE_SAMPLER_CUBE,
+ glu::TYPE_SAMPLER_2D_ARRAY,
+ glu::TYPE_SAMPLER_3D,
+// glu::TYPE_SAMPLER_1D_SHADOW,
+ glu::TYPE_SAMPLER_2D_SHADOW,
+ glu::TYPE_SAMPLER_CUBE_SHADOW,
+ glu::TYPE_SAMPLER_2D_ARRAY_SHADOW,
+// glu::TYPE_INT_SAMPLER_1D,
+ glu::TYPE_INT_SAMPLER_2D,
+ glu::TYPE_INT_SAMPLER_CUBE,
+ glu::TYPE_INT_SAMPLER_2D_ARRAY,
+ glu::TYPE_INT_SAMPLER_3D,
+// glu::TYPE_UINT_SAMPLER_1D,
+ glu::TYPE_UINT_SAMPLER_2D,
+ glu::TYPE_UINT_SAMPLER_CUBE,
+ glu::TYPE_UINT_SAMPLER_2D_ARRAY,
+ glu::TYPE_UINT_SAMPLER_3D,
+ };
+
+ tcu::TestCaseGroup* const samplerGroup = new tcu::TestCaseGroup(m_testCtx, "sampler", "Sampler Array Indexing Tests");
+ addChild(samplerGroup);
+
+ for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
+ {
+ const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type;
+ tcu::TestCaseGroup* const indexGroup = new tcu::TestCaseGroup(m_testCtx, indexingTypes[indexTypeNdx].name, indexingTypes[indexTypeNdx].description);
+ samplerGroup->addChild(indexGroup);
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
+ {
+ const glu::ShaderType shaderType = shaderTypes[shaderTypeNdx].type;
+ tcu::TestCaseGroup* const shaderGroup = new tcu::TestCaseGroup(m_testCtx, shaderTypes[shaderTypeNdx].name, "");
+ indexGroup->addChild(shaderGroup);
+
+ for (int samplerTypeNdx = 0; samplerTypeNdx < DE_LENGTH_OF_ARRAY(samplerTypes); samplerTypeNdx++)
+ {
+ const glu::DataType samplerType = samplerTypes[samplerTypeNdx];
+ const char* samplerName = getDataTypeName(samplerType);
+ const std::string caseName = de::toLower(samplerName);
+
+ shaderGroup->addChild(new SamplerIndexingCase(m_testCtx, caseName.c_str(), "", shaderType, samplerType, indexExprType));
+ }
+ }
+ }
+ }
+
+ // .ubo / .ssbo / .atomic_counter
+ {
+ tcu::TestCaseGroup* const uboGroup = new tcu::TestCaseGroup(m_testCtx, "ubo", "Uniform Block Instance Array Indexing Tests");
+ tcu::TestCaseGroup* const ssboGroup = new tcu::TestCaseGroup(m_testCtx, "ssbo", "Buffer Block Instance Array Indexing Tests");
+ tcu::TestCaseGroup* const acGroup = new tcu::TestCaseGroup(m_testCtx, "atomic_counter", "Atomic Counter Array Indexing Tests");
+ addChild(uboGroup);
+ addChild(ssboGroup);
+ addChild(acGroup);
+
+ for (int indexTypeNdx = 0; indexTypeNdx < DE_LENGTH_OF_ARRAY(indexingTypes); indexTypeNdx++)
+ {
+ const IndexExprType indexExprType = indexingTypes[indexTypeNdx].type;
+ const char* indexExprName = indexingTypes[indexTypeNdx].name;
+ const char* indexExprDesc = indexingTypes[indexTypeNdx].description;
+
+ for (int shaderTypeNdx = 0; shaderTypeNdx < DE_LENGTH_OF_ARRAY(shaderTypes); shaderTypeNdx++)
+ {
+ const glu::ShaderType shaderType = shaderTypes[shaderTypeNdx].type;
+ const std::string name = std::string(indexExprName) + "_" + shaderTypes[shaderTypeNdx].name;
+
+ uboGroup->addChild (new BlockArrayIndexingCase (m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_UNIFORM, indexExprType, shaderType));
+ acGroup->addChild (new AtomicCounterIndexingCase (m_testCtx, name.c_str(), indexExprDesc, indexExprType, shaderType));
+
+ if (indexExprType == INDEX_EXPR_TYPE_CONST_LITERAL || indexExprType == INDEX_EXPR_TYPE_CONST_EXPRESSION)
+ ssboGroup->addChild (new BlockArrayIndexingCase (m_testCtx, name.c_str(), indexExprDesc, BLOCKTYPE_BUFFER, indexExprType, shaderType));
+ }
+ }
+ }
+}
+
+} // shaderexecutor
+} // vkt
#include "vkTypeUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkDeviceUtil.hpp"
+#include "vkImageUtil.hpp"
#include "gluShaderUtil.hpp"
Move<VkFence> fence;
+ Move<VkDescriptorPool> descriptorPool;
+ Move<VkDescriptorSetLayout> descriptorSetLayout;
+ Move<VkDescriptorSet> descriptorSet;
+
clearRenderData();
// Compute positions - 1px points are used to drive fragment shading.
framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams);
}
+ // Create descriptors
+ {
+ addUniforms(vkDevice, vk, queueFamilyIndex, memAlloc);
+
+ descriptorSetLayout = m_descriptorSetLayoutBuilder.build(vk, vkDevice);
+ descriptorPool = m_descriptorPoolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+
+ const VkDescriptorSetAllocateInfo allocInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
+ DE_NULL,
+ *descriptorPool,
+ 1u,
+ &*descriptorSetLayout
+ };
+
+ descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
+
+ // Update descriptors
+ {
+ vk::DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
+
+ uploadUniforms(descriptorSetUpdateBuilder, *descriptorSet);
+
+ descriptorSetUpdateBuilder.update(vk, vkDevice);
+ }
+ }
+
+
// 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;
+ 1, // deUint32 descriptorSetCount;
+ &*descriptorSetLayout, // const VkDescriptorSetLayout* pSetLayouts;
0u, // deUint32 pushConstantRangeCount;
DE_NULL // const VkPushConstantRange* pPushConstantRanges;
};
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);
const deUint32 numberOfVertexAttributes = (deUint32)m_vertexBuffers.size();
std::vector<VkDeviceSize> offsets(numberOfVertexAttributes, 0);
const DeviceInterface& vk = ctx.getDeviceInterface();
const VkQueue queue = ctx.getUniversalQueue();
const deUint32 queueFamilyIndex = ctx.getUniversalQueueFamilyIndex();
+ Allocator& memAlloc = ctx.getDefaultAllocator();
Move<VkShaderModule> computeShaderModule;
Move<VkPipeline> computePipeline;
};
+ addUniforms(vkDevice, vk, queueFamilyIndex, memAlloc);
+
const VkDescriptorSetLayoutBinding layoutBindings[2] =
{
{
Move<VkCommandBuffer> cmdBuffer;
const int numToExec = de::min(maxValuesPerInvocation, numValues-curOffset);
- const VkDescriptorBufferInfo descriptorBufferInfo[] =
+ // Update descriptors
{
- {
- *m_inputBuffer, // VkBuffer buffer;
- curOffset * inputStride, // VkDeviceSize offset;
- numToExec * inputStride // VkDeviceSize range;
- },
+ DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
+
+ const VkDescriptorBufferInfo outputDescriptorBufferInfo =
{
*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;
+ descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)OUTPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputDescriptorBufferInfo);
+
+ if (inputStride) {
+ const VkDescriptorBufferInfo inputDescriptorBufferInfo =
+ {
+ *m_inputBuffer, // VkBuffer buffer;
+ curOffset * inputStride, // VkDeviceSize offset;
+ numToExec * inputStride // VkDeviceSize range;
+ };
+ descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)INPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputDescriptorBufferInfo);
}
- };
+ uploadUniforms(descriptorSetUpdateBuilder, *descriptorSet);
- vk.updateDescriptorSets(vkDevice, 1, writeDescritporSets, 0u, DE_NULL);
+ descriptorSetUpdateBuilder.update(vk, vkDevice);
+ }
cmdBuffer = allocateCommandBuffer(vk, vkDevice, &cmdBufferParams);
VK_CHECK(vk.beginCommandBuffer(*cmdBuffer, &cmdBufferBeginInfo));
void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount)
{
+ const size_t inputBufferSize = (vertexCount/2) * getInputStride();
const VkDevice vkDevice = ctx.getDevice();
const DeviceInterface& vk = ctx.getDeviceInterface();
const VkQueue queue = ctx.getUniversalQueue();
layoutBindings // const VkDescriptorSetLayoutBinding pBinding;
};
+ addUniforms(vkDevice, vk, queueFamilyIndex, memAlloc);
descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams);
const VkDescriptorPoolSize descriptorPoolSizes[] =
};
descriptorSet = allocateDescriptorSet(vk, vkDevice, &allocInfo);
-
- const VkDescriptorBufferInfo descriptorBufferInfo[] =
+ // Update descriptors
{
- {
- *m_inputBuffer, // VkBuffer buffer;
- 0u, // VkDeviceSize offset;
- VK_WHOLE_SIZE // VkDeviceSize range;
- },
+ DescriptorSetUpdateBuilder descriptorSetUpdateBuilder;
+ const VkDescriptorBufferInfo outputDescriptorBufferInfo =
{
*m_outputBuffer, // VkBuffer buffer;
0u, // VkDeviceSize offset;
VK_WHOLE_SIZE // VkDeviceSize range;
- },
- };
+ };
+
+ descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)OUTPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outputDescriptorBufferInfo);
+
+ if (inputBufferSize) {
+ const VkDescriptorBufferInfo inputDescriptorBufferInfo =
+ {
+ *m_inputBuffer, // VkBuffer buffer;
+ 0u, // VkDeviceSize offset;
+ VK_WHOLE_SIZE // VkDeviceSize range;
+ };
+
+ descriptorSetUpdateBuilder.writeSingle(*descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding((deUint32)INPUT_BUFFER_BINDING), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &inputDescriptorBufferInfo);
- 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;
}
- };
+ uploadUniforms(descriptorSetUpdateBuilder, *descriptorSet);
- vk.updateDescriptorSets(vkDevice, 1, writeDescritporSets, 0u, DE_NULL);
+ descriptorSetUpdateBuilder.update(vk, vkDevice);
+ }
}
// Create pipeline layout
}
}
+void ShaderExecutor::setupUniformData (const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc, deUint32 bindingLocation, deUint32 size, const void* dataPtr)
+{
+ const VkBufferCreateInfo uniformBufferParams =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ size, // VkDeviceSize size;
+ VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage;
+ 0u, // VkBufferCreateFlags flags;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1u, // deUint32 queueFamilyCount;
+ &queueFamilyIndex // const deUint32* pQueueFamilyIndices;
+ };
+
+ Move<VkBuffer> buffer = createBuffer(vk, vkDevice, &uniformBufferParams);
+ 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, size);
+ flushMappedMemoryRange(vk, vkDevice, alloc->getMemory(), alloc->getOffset(), size);
+
+ de::MovePtr<BufferUniform> uniformInfo(new BufferUniform());
+ //? storage vagy uniform shaderben mi van???? storage v unuiform
+ uniformInfo->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
+ uniformInfo->descriptor = makeDescriptorBufferInfo(*buffer, 0u, size);
+ uniformInfo->location = bindingLocation;
+ uniformInfo->buffer = VkBufferSp(new Unique<VkBuffer>(buffer));
+ uniformInfo->alloc = AllocationSp(alloc.release());
+
+ m_descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
+ m_descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
+
+ m_uniformInfos.push_back(UniformInfoSp(new de::UniquePtr<UniformInfo>(uniformInfo)));
+}
+
+void ShaderExecutor::setupSamplerData (const VkDevice& vkDevice,
+ const DeviceInterface& vk,
+ const deUint32 queueFamilyIndex,
+ Allocator& memAlloc,
+ deUint32 bindingLocation,
+ deUint32 numSamplers,
+ const tcu::Sampler& refSampler,
+ const tcu::TextureFormat& texFormat,
+ const tcu::IVec3& texSize,
+ VkImageType imageType,
+ VkImageViewType imageViewType,
+ const void* data)
+{
+ DE_ASSERT(numSamplers > 0);
+
+ std::vector<VkSampler> vkSamplers;
+ de::MovePtr<SamplerArrayUniform> samplers (new SamplerArrayUniform());
+
+ samplers->type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ samplers->location = bindingLocation;
+
+ for (deUint32 ndx = 0; ndx < numSamplers; ++ndx)
+ {
+ const int offset = ndx * texSize.x() * texSize.y() * texSize.z() * texFormat.getPixelSize();
+ const void* samplerData = ((deUint32*)data) + offset;
+ de::MovePtr<SamplerUniform> uniform = createSamplerUniform(vkDevice, vk, queueFamilyIndex, memAlloc, bindingLocation, refSampler, texFormat, texSize, imageType, imageViewType, samplerData);
+
+ vkSamplers.push_back(uniform->sampler.get()->get());
+
+ samplers->uniforms.push_back(SamplerUniformSp(new de::UniquePtr<SamplerUniform>(uniform)));
+ //samplers->uniforms.push_back(UniformInfoSp(new de::UniquePtr<UniformInfo>(uniform)));
+ }
+
+ m_descriptorSetLayoutBuilder.addArraySamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numSamplers, VK_SHADER_STAGE_ALL, &vkSamplers[0]);
+ m_descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, numSamplers);
+
+ m_uniformInfos.push_back(UniformInfoSp(new de::UniquePtr<UniformInfo>(samplers)));
+}
+
+
+void ShaderExecutor::addUniforms (const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc)
+{
+ if (!m_uniformSetup)
+ return;
+
+ for (std::vector<UniformDataSp>::const_iterator it = m_uniformSetup->uniforms().begin(); it != m_uniformSetup->uniforms().end(); ++it)
+ {
+ const UniformDataBase* uniformData = it->get()->get();
+ uniformData->setup(*this, vkDevice, vk, queueFamilyIndex, memAlloc);
+ }
+}
+
+void ShaderExecutor::uploadUniforms (DescriptorSetUpdateBuilder& descriptorSetUpdateBuilder, VkDescriptorSet descriptorSet)
+{
+ for (std::vector<UniformInfoSp>::const_iterator it = m_uniformInfos.begin(); it != m_uniformInfos.end(); ++it)
+ {
+ const UniformInfo* uniformInfo = it->get()->get();
+
+ if (uniformInfo->isSamplerArray())
+ {
+ const SamplerArrayUniform* arrayInfo = static_cast<const SamplerArrayUniform*>(uniformInfo);
+ std::vector<VkDescriptorImageInfo> descriptors;
+
+ for (std::vector<SamplerUniformSp>::const_iterator ait = arrayInfo->uniforms.begin(); ait != arrayInfo->uniforms.end(); ++ait)
+ {
+ descriptors.push_back(ait->get()->get()->descriptor);
+ }
+
+ descriptorSetUpdateBuilder.writeArray(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(uniformInfo->location), uniformInfo->type, (deUint32)descriptors.size(), &descriptors[0]);
+ }
+ else if (uniformInfo->isBufferUniform()) {
+ const BufferUniform* bufferUniform = static_cast<const BufferUniform*>(uniformInfo);
+ descriptorSetUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferUniform->location), bufferUniform->type, &bufferUniform->descriptor);
+ }
+ else if (uniformInfo->isSamplerUniform()) {
+ const SamplerUniform* samplerUniform = static_cast<const SamplerUniform*>(uniformInfo);
+ descriptorSetUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(samplerUniform->location), samplerUniform->type, &samplerUniform->descriptor);
+ }
+ }
+}
+
+Move<VkImage> ShaderExecutor::createCombinedImage (const VkDevice& vkDevice,
+ const DeviceInterface& vk,
+ const deUint32 queueFamilyIndex,
+ const tcu::IVec3& texSize,
+ const VkFormat format,
+ const VkImageType imageType,
+ const VkImageUsageFlags usage,
+ const VkImageTiling tiling)
+{
+ const VkImageCreateInfo imageCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pnext;
+ 0, // VkImageCreateFlags flags;
+ imageType, // VkImageType imageType;
+ format, // VkFormat format;
+ { texSize.x(), texSize.y(), texSize.z() }, // VkExtend3D extent;
+ 1u, // deUint32 mipLevels;
+ 1u, // deUint32 arraySize;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ tiling, // VkImageTiling tiling;
+ usage, // VkImageUsageFlags usage;
+ VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
+ 1, // deuint32 queueFamilyCount;
+ &queueFamilyIndex, // const deUint32* pQueueFamilyIndices;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ };
+
+ Move<VkImage> vkTexture = createImage(vk, vkDevice, &imageCreateInfo);
+ return vkTexture;
+}
+
+de::MovePtr<Allocation> ShaderExecutor::uploadImage (const VkDevice& vkDevice,
+ const DeviceInterface& vk,
+ Allocator& memAlloc,
+ const tcu::TextureFormat& texFormat,
+ const tcu::IVec3& texSize,
+ const void* data,
+ const VkImage& vkTexture)
+{
+ de::MovePtr<Allocation> allocation = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, vkTexture), MemoryRequirement::HostVisible);
+ VK_CHECK(vk.bindImageMemory(vkDevice, vkTexture, allocation->getMemory(), allocation->getOffset()));
+
+ const VkImageSubresource subres =
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, // VkImageAspectFlags aspectMask;
+ 0u, // deUint32 mipLevel;
+ 0u // deUint32 arraySlice
+ };
+
+ VkSubresourceLayout layout;
+ vk.getImageSubresourceLayout(vkDevice, vkTexture, &subres, &layout);
+
+ tcu::ConstPixelBufferAccess access (texFormat, texSize, data);
+ tcu::PixelBufferAccess destAccess (texFormat, texSize, allocation->getHostPtr());
+
+ tcu::copy(destAccess, access);
+
+ flushMappedMemoryRange(vk, vkDevice, allocation->getMemory(), allocation, layout.size);
+
+ return allocation;
+}
+
+
+de::MovePtr<ShaderExecutor::SamplerUniform> ShaderExecutor::createSamplerUniform (const VkDevice& vkDevice,
+ const DeviceInterface& vk,
+ const deUint32 queueFamilyIndex,
+ Allocator& memAlloc,
+ deUint32 bindingLocation,
+ const tcu::Sampler& refSampler,
+ const tcu::TextureFormat& texFormat,
+ const tcu::IVec3& texSize,
+ VkImageType imageType,
+ VkImageViewType imageViewType,
+ const void* data)
+{
+ const VkFormat format = mapTextureFormat(texFormat);
+ Move<VkImage> vkTexture;
+ de::MovePtr<Allocation> allocation;
+
+ vkTexture = createCombinedImage(vkDevice, vk, queueFamilyIndex, texSize, format, imageType, VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_TILING_LINEAR);
+ allocation = uploadImage(vkDevice, vk, memAlloc, texFormat, texSize, data, *vkTexture);
+
+ // Create sampler
+ const bool compareEnabled = (refSampler.compare != tcu::Sampler::COMPAREMODE_NONE);
+ const VkSamplerCreateInfo samplerParams =
+ {
+ VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ VkSamplerCreateFlags(0u), // VkSamplerCreateFlags flags;
+ mapFilterMode(refSampler.magFilter), // VkTexFilter magFilter;
+ mapFilterMode(refSampler.minFilter), // VkTexFilter minFilter;
+ mapMipmapMode(refSampler.minFilter), // VkTexMipmapMode mipMode;
+ mapWrapMode(refSampler.wrapS), // VkTexAddressMode addressModeU;
+ mapWrapMode(refSampler.wrapT), // VkTexAddressMode addressModeV;
+ mapWrapMode(refSampler.wrapR), // VkTexAddressMode addressModeW;
+ refSampler.lodThreshold, // float mipLodBias;
+ 1, // float maxAnisotropy;
+ compareEnabled, // VkBool32 compareEnable;
+ mapCompareMode(refSampler.compare), // VkCompareOp compareOp;
+ 0.0f, // float minLod;
+ 0.0f, // float maxLod;
+ VK_BORDER_COLOR_INT_OPAQUE_WHITE, // VkBorderColor boderColor;
+ VK_FALSE, // VkBool32 unnormalizerdCoordinates;
+ };
+
+ Move<VkSampler> sampler = createSampler(vk, vkDevice, &samplerParams);
+
+ const VkImageViewCreateInfo viewParams =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
+ NULL, // const voide* pNexŧ;
+ 0u, // VkImageViewCreateFlags flags;
+ *vkTexture, // VkImage image;
+ imageViewType, // VkImageViewType viewType;
+ format, // 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;
+ 0, // deUint32 baseMipLevel;
+ 1, // deUint32 mipLevels;
+ 0, // deUint32 baseArraySlice;
+ 1 // deUint32 arraySize;
+ } // VkImageSubresourceRange subresourceRange;
+ };
+
+ Move<VkImageView> imageView = createImageView(vk, vkDevice, &viewParams);
+
+ const VkDescriptorImageInfo descriptor =
+ {
+ sampler.get(), // VkSampler sampler;
+ imageView.get(), // VkImageView imageView;
+ VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout;
+ };
+
+ de::MovePtr<SamplerUniform> uniform(new SamplerUniform());
+ uniform->type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ uniform->descriptor = descriptor;
+ uniform->location = bindingLocation;
+ uniform->image = VkImageSp(new Unique<VkImage>(vkTexture));
+ uniform->imageView = VkImageViewSp(new Unique<VkImageView>(imageView));
+ uniform->sampler = VkSamplerSp(new Unique<VkSampler>(sampler));
+ uniform->alloc = AllocationSp(allocation.release());
+
+ return uniform;
+}
+
+SamplerUniformData::SamplerUniformData (deUint32 bindingLocation,
+ deUint32 numSamplers,
+ const tcu::Sampler& refSampler,
+ const tcu::TextureFormat& texFormat,
+ const tcu::IVec3& texSize,
+ VkImageType imageType,
+ VkImageViewType imageViewType,
+ const void* data)
+ : UniformDataBase (bindingLocation)
+ , m_numSamplers (numSamplers)
+ , m_refSampler (refSampler)
+ , m_texFormat (texFormat)
+ , m_texSize (texSize)
+ , m_imageType (imageType)
+ , m_imageViewType (imageViewType)
+ , m_data (data)
+{
+}
+
+SamplerUniformData::~SamplerUniformData (void)
+{
+}
+
+void SamplerUniformData::setup (ShaderExecutor& executor, const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc) const
+{
+ executor.setupSamplerData(vkDevice, vk, queueFamilyIndex, memAlloc, m_bindingLocation, m_numSamplers, m_refSampler, m_texFormat, m_texSize, m_imageType, m_imageViewType, m_data);
+}
+
} // shaderexecutor
} // vkt