From 8bbf784b9515b34c9fa9bc931a68631bfb80a42c Mon Sep 17 00:00:00 2001 From: Akos Dirner Date: Wed, 16 Dec 2015 19:00:46 +0100 Subject: [PATCH] ShaderExecutor tests: Add Opaque type indexing tests and uniform support for shader executor --- .../vulkan/shaderexecutor/CMakeLists.txt | 2 + .../vktOpaqueTypeIndexingTests.cpp | 1385 +++++++++++++++++ .../vktOpaqueTypeIndexingTests.hpp | 61 + .../shaderexecutor/vktShaderExecutor.cpp | 424 ++++- .../shaderexecutor/vktShaderExecutor.hpp | 242 ++- .../shaderexecutor/vktShaderExecutorTests.cpp | 2 + 6 files changed, 2063 insertions(+), 53 deletions(-) create mode 100644 external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp create mode 100644 external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.hpp diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt b/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt index 63a1b22de..d49c8d699 100644 --- a/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt +++ b/external/vulkancts/modules/vulkan/shaderexecutor/CMakeLists.txt @@ -16,6 +16,8 @@ set(DEQP_VK_SHADEREXECUTOR_SRCS vktShaderPackingFunctionTests.hpp vktShaderBuiltinPrecisionTests.cpp vktShaderBuiltinPrecisionTests.hpp + vktOpaqueTypeIndexingTests.cpp + vktOpaqueTypeIndexingTests.hpp ) set(DEQP_VK_SHADEREXECUTOR_LIBS diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp new file mode 100644 index 000000000..fefc6b4f6 --- /dev/null +++ b/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.cpp @@ -0,0 +1,1385 @@ +/*------------------------------------------------------------------------ + * 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 + +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 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(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(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(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& lookupIndices); + virtual ~SamplerIndexingCaseInstance (void); + + virtual tcu::TestStatus iterate (void); + +protected: + const glu::DataType m_samplerType; + const std::vector& 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& 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 coords; + std::vector outData; + std::vector 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(DE_ARRAY_BEGIN(cmpValues), DE_ARRAY_END(cmpValues)); + } + + fillTextureData(refTexAccess, rnd); + + outData.resize(numLookups*outLookupStride); + + { + std::vector inputs; + std::vector outputs; + std::vector 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(resPtr), tcu::Format::HexIterator(resPtr+4)) + << " for lookup " << lookupNdx << " doesn't match result from first invocation " + << tcu::formatArray(tcu::Format::HexIterator(refPtr), tcu::Format::HexIterator(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 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& readIndices, + const std::vector& inValues); + virtual ~BlockArrayIndexingCaseInstance (void); + + virtual tcu::TestStatus iterate (void); + +private: + const BlockType m_blockType; + const std::vector& m_readIndices; + const std::vector& 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& readIndices, + const std::vector& 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 outValues (numInvocations*numReads); + + { + tcu::TestLog& log = m_context.getTestContext().getLog(); + tcu::TestStatus testResult = tcu::TestStatus::pass("Pass"); + std::vector expandedIndices; + std::vector inputs; + std::vector outputs; + deUint32 bindingLocation = getFirstFreeBindingLocation(m_shaderType, m_shaderSpec); + + for (size_t i = 0 ; i < m_inValues.size(); i++) + m_uniformSetup->addData(new UniformData(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 m_readIndices; + std::vector 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& opIndices, + const IndexExprType indexExprType); + virtual ~AtomicCounterIndexingCaseInstance (void); + + virtual tcu::TestStatus iterate (void); + +private: + const std::vector& m_opIndices; +}; + +AtomicCounterIndexingCaseInstance::AtomicCounterIndexingCaseInstance (Context& context, + const glu::ShaderType shaderType, + const ShaderSpec& shaderSpec, + ShaderExecutor& executor, + const char* name, + UniformSetup* uniformSetup, + const std::vector& 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 expandedIndices; + std::vector inputs; + std::vector outputs; + std::vector 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(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 numHits (numCounters, 0); // Number of hits per counter. + std::vector counterValues (numCounters); + std::vector > 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::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 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 diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.hpp new file mode 100644 index 000000000..0127f5b9a --- /dev/null +++ b/external/vulkancts/modules/vulkan/shaderexecutor/vktOpaqueTypeIndexingTests.hpp @@ -0,0 +1,61 @@ +#ifndef _VKTOPAQUETYPEINDEXINGTESTS_HPP +#define _VKTOPAQUETYPEINDEXINGTESTS_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 Opaque type (sampler, buffer, atomic counter, ...) indexing tests. + *//*--------------------------------------------------------------------*/ + +#include "tcuTestCase.hpp" + +namespace vkt +{ +namespace shaderexecutor +{ + +class OpaqueTypeIndexingTests : public tcu::TestCaseGroup +{ +public: + OpaqueTypeIndexingTests (tcu::TestContext& testCtx); + virtual ~OpaqueTypeIndexingTests (void); + + virtual void init (void); + +private: + OpaqueTypeIndexingTests (const OpaqueTypeIndexingTests&); + OpaqueTypeIndexingTests& operator= (const OpaqueTypeIndexingTests&); +}; + +} // shaderexecutor +} // vkt + +#endif // _VKTOPAQUETYPEINDEXINGTESTS_HPP diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp index 2d7249e2d..3adc3d417 100644 --- a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp +++ b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.cpp @@ -55,6 +55,7 @@ #include "vkTypeUtil.hpp" #include "vkQueryUtil.hpp" #include "vkDeviceUtil.hpp" +#include "vkImageUtil.hpp" #include "gluShaderUtil.hpp" @@ -754,6 +755,10 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void Move fence; + Move descriptorPool; + Move descriptorSetLayout; + Move descriptorSet; + clearRenderData(); // Compute positions - 1px points are used to drive fragment shading. @@ -922,6 +927,35 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void 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 = @@ -929,8 +963,8 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void 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; }; @@ -1165,6 +1199,7 @@ void FragmentOutExecutor::execute (const Context& ctx, int numValues, const void 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 offsets(numberOfVertexAttributes, 0); @@ -1868,6 +1903,7 @@ void ComputeShaderExecutor::execute (const Context& ctx, int numValues, const vo const DeviceInterface& vk = ctx.getDeviceInterface(); const VkQueue queue = ctx.getUniversalQueue(); const deUint32 queueFamilyIndex = ctx.getUniversalQueueFamilyIndex(); + Allocator& memAlloc = ctx.getDefaultAllocator(); Move computeShaderModule; Move computePipeline; @@ -1920,6 +1956,8 @@ void ComputeShaderExecutor::execute (const Context& ctx, int numValues, const vo }; + addUniforms(vkDevice, vk, queueFamilyIndex, memAlloc); + const VkDescriptorSetLayoutBinding layoutBindings[2] = { { @@ -2054,37 +2092,32 @@ void ComputeShaderExecutor::execute (const Context& ctx, int numValues, const vo Move 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)); @@ -2157,6 +2190,7 @@ TessellationExecutor::~TessellationExecutor (void) 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(); @@ -2349,6 +2383,7 @@ void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount) layoutBindings // const VkDescriptorSetLayoutBinding pBinding; }; + addUniforms(vkDevice, vk, queueFamilyIndex, memAlloc); descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorLayoutParams); const VkDescriptorPoolSize descriptorPoolSizes[] = @@ -2385,38 +2420,33 @@ void TessellationExecutor::renderTess (const Context& ctx, deUint32 vertexCount) }; 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 @@ -2959,5 +2989,301 @@ ShaderExecutor* createExecutor (glu::ShaderType shaderType, const ShaderSpec& sh } } +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 buffer = createBuffer(vk, vkDevice, &uniformBufferParams); + de::MovePtr 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 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(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))); +} + +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 vkSamplers; + de::MovePtr 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 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(uniform))); + //samplers->uniforms.push_back(UniformInfoSp(new de::UniquePtr(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(samplers))); +} + + +void ShaderExecutor::addUniforms (const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc) +{ + if (!m_uniformSetup) + return; + + for (std::vector::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::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(uniformInfo); + std::vector descriptors; + + for (std::vector::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(uniformInfo); + descriptorSetUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(bufferUniform->location), bufferUniform->type, &bufferUniform->descriptor); + } + else if (uniformInfo->isSamplerUniform()) { + const SamplerUniform* samplerUniform = static_cast(uniformInfo); + descriptorSetUpdateBuilder.writeSingle(descriptorSet, DescriptorSetUpdateBuilder::Location::binding(samplerUniform->location), samplerUniform->type, &samplerUniform->descriptor); + } + } +} + +Move 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 vkTexture = createImage(vk, vkDevice, &imageCreateInfo); + return vkTexture; +} + +de::MovePtr 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 = 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::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 vkTexture; + de::MovePtr 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 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 imageView = createImageView(vk, vkDevice, &viewParams); + + const VkDescriptorImageInfo descriptor = + { + sampler.get(), // VkSampler sampler; + imageView.get(), // VkImageView imageView; + VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout imageLayout; + }; + + de::MovePtr uniform(new SamplerUniform()); + uniform->type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + uniform->descriptor = descriptor; + uniform->location = bindingLocation; + uniform->image = VkImageSp(new Unique(vkTexture)); + uniform->imageView = VkImageViewSp(new Unique(imageView)); + uniform->sampler = VkSamplerSp(new Unique(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 diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp index 6f6d523ce..1195fa5eb 100644 --- a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp +++ b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutor.hpp @@ -35,11 +35,16 @@ * \brief Vulkan ShaderExecutor *//*--------------------------------------------------------------------*/ +#include "deSharedPtr.hpp" + #include "vktTestCase.hpp" -#include "vkPrograms.hpp" +#include "vkMemUtil.hpp" +#include "vkBuilderUtil.hpp" #include "gluVarType.hpp" +#include "tcuTexture.hpp" + #include namespace vkt @@ -47,6 +52,8 @@ namespace vkt namespace shaderexecutor { +using namespace vk; + //! Shader input / output variable declaration. struct Symbol { @@ -69,6 +76,36 @@ struct ShaderSpec ShaderSpec (void) {} }; +// UniformSetup + +class UniformDataBase; +class ShaderExecutor; + +typedef de::SharedPtr > UniformDataSp; + +class UniformSetup +{ +public: + UniformSetup (void) {} + virtual ~UniformSetup (void) {} + + void addData (UniformDataBase* uniformData) + { + m_uniforms.push_back(UniformDataSp(new de::UniquePtr(uniformData))); + } + + const std::vector& uniforms (void) const + { + return m_uniforms; + } + +private: + UniformSetup (const UniformSetup&); // not allowed! + UniformSetup& operator= (const UniformSetup&); // not allowed! + + std::vector m_uniforms; +}; + //! Base class for shader executor. class ShaderExecutor { @@ -81,13 +118,141 @@ public: //! 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; + virtual void setShaderSources (SourceCollections& programCollection) const = 0; + + void setUniforms (const UniformSetup* uniformSetup) + { + m_uniformSetup = de::MovePtr(uniformSetup); + }; + + void setupUniformData (const VkDevice& vkDevice, + const DeviceInterface& vk, + const deUint32 queueFamilyIndex, + Allocator& memAlloc, + deUint32 bindingLocation, + deUint32 size, + const void* dataPtr); + + void 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); + protected: ShaderExecutor (const ShaderSpec& shaderSpec, glu::ShaderType shaderType); - const ShaderSpec m_shaderSpec; - const glu::ShaderType m_shaderType; + void addUniforms (const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc); + + void uploadUniforms (DescriptorSetUpdateBuilder& descriptorSetUpdateBuilder, VkDescriptorSet descriptorSet); + + class UniformInfo; + typedef de::SharedPtr > UniformInfoSp; + + class SamplerUniform; + typedef de::SharedPtr > SamplerUniformSp; + + + typedef de::SharedPtr > VkBufferSp; + typedef de::SharedPtr > VkImageSp; + typedef de::SharedPtr > VkImageViewSp; + typedef de::SharedPtr > VkSamplerSp; + typedef de::SharedPtr AllocationSp; + + + class UniformInfo + { + public: + UniformInfo (void) {} + virtual ~UniformInfo (void) {} + virtual bool isSamplerArray (void) const { return false; } + virtual bool isBufferUniform (void) const { return false; } + virtual bool isSamplerUniform (void) const { return false; } + + VkDescriptorType type; + deUint32 location; + }; + + class BufferUniform : public UniformInfo + { + public: + BufferUniform (void) {} + virtual ~BufferUniform (void) {} + virtual bool isBufferUniform (void) const { return true; } + + VkBufferSp buffer; + AllocationSp alloc; + VkDescriptorBufferInfo descriptor; + }; + + class SamplerUniform : public UniformInfo + { + public: + SamplerUniform (void) {} + virtual ~SamplerUniform (void) {} + virtual bool isSamplerUniform (void) const { return true; } + VkImageSp image; + VkImageViewSp imageView; + VkSamplerSp sampler; + AllocationSp alloc; + VkDescriptorImageInfo descriptor; + }; + + class SamplerArrayUniform : public UniformInfo + { + public: + SamplerArrayUniform (void) {} + virtual ~SamplerArrayUniform (void) {} + virtual bool isSamplerArray (void) const { return true; } + + std::vector uniforms; + }; + + Move 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); + + de::MovePtr 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 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 ShaderSpec m_shaderSpec; + const glu::ShaderType m_shaderType; + + std::vector m_uniformInfos; + de::MovePtr m_uniformSetup; + DescriptorSetLayoutBuilder m_descriptorSetLayoutBuilder; + DescriptorPoolBuilder m_descriptorPoolBuilder; + }; inline tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderExecutor* executor) { executor->log(log); return log; } @@ -95,6 +260,75 @@ inline tcu::TestLog& operator<< (tcu::TestLog& log, const ShaderExecutor& execut ShaderExecutor* createExecutor(glu::ShaderType shaderType, const ShaderSpec& shaderSpec); + +class UniformDataBase +{ +public: + UniformDataBase (deUint32 bindingLocation) + : m_bindingLocation (bindingLocation) + { + } + virtual ~UniformDataBase (void) {} + virtual void setup (ShaderExecutor&, const VkDevice&, const DeviceInterface&, const deUint32, Allocator&) const = 0; + +protected: + const deUint32 m_bindingLocation; +}; + +template +class UniformData : public UniformDataBase +{ +public: + UniformData (deUint32 bindingLocation, const T data); + virtual ~UniformData (void); + virtual void setup (ShaderExecutor& executor, const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc) const; + +private: + T m_data; +}; + +template +UniformData::UniformData (deUint32 bindingLocation, const T data) + : UniformDataBase (bindingLocation) + , m_data (data) +{ +} + +template +UniformData::~UniformData (void) +{ +} + +template +void UniformData::setup (ShaderExecutor& executor, const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc) const +{ + executor.setupUniformData(vkDevice, vk, queueFamilyIndex, memAlloc, m_bindingLocation, sizeof(T), &m_data); +} + +class SamplerUniformData : public UniformDataBase +{ +public: + SamplerUniformData (deUint32 bindingLocation, + deUint32 numSamplers, + const tcu::Sampler& refSampler, + const tcu::TextureFormat& texFormat, + const tcu::IVec3& texSize, + VkImageType imageType, + VkImageViewType imageViewType, + const void* data); + virtual ~SamplerUniformData (void); + virtual void setup (ShaderExecutor& executor, const VkDevice& vkDevice, const DeviceInterface& vk, const deUint32 queueFamilyIndex, Allocator& memAlloc) const; + +private: + deUint32 m_numSamplers; + const tcu::Sampler m_refSampler; + const tcu::TextureFormat m_texFormat; + const tcu::IVec3 m_texSize; + VkImageType m_imageType; + VkImageViewType m_imageViewType; + const void* m_data; +}; + } // shaderexecutor } // vkt diff --git a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp index a855f0090..6d0f02cd9 100644 --- a/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp +++ b/external/vulkancts/modules/vulkan/shaderexecutor/vktShaderExecutorTests.cpp @@ -42,6 +42,7 @@ #include "vktShaderCommonFunctionTests.hpp" #include "vktShaderIntegerFunctionTests.hpp" #include "vktShaderPackingFunctionTests.hpp" +#include "vktOpaqueTypeIndexingTests.hpp" namespace vkt { @@ -57,6 +58,7 @@ tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx) shaderExecutorTests->addChild(new ShaderCommonFunctionTests(testCtx)); shaderExecutorTests->addChild(new ShaderIntegerFunctionTests(testCtx)); shaderExecutorTests->addChild(new ShaderPackingFunctionTests(testCtx)); + shaderExecutorTests->addChild(new OpaqueTypeIndexingTests(testCtx)); return shaderExecutorTests.release(); } -- 2.34.1