--- /dev/null
+/*------------------------------------------------------------------------
+* Vulkan Conformance Tests
+* ------------------------
+*
+* Copyright (c) 2019 The Khronos Group Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*//*!
+* \file
+* \brief Vulkan Decriptor Indexing Tests
+*//*--------------------------------------------------------------------*/
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <functional>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "vktDescriptorSetsIndexingTests.hpp"
+
+#include "vkBuilderUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "vkDefs.hpp"
+#include "vkObjUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuResource.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuCommandLine.hpp"
+#include "tcuStringTemplate.hpp"
+#include "tcuSurface.hpp"
+#include "tcuVectorUtil.hpp"
+
+#include "deRandom.hpp"
+#include "deMath.h"
+#include "deStringUtil.hpp"
+
+namespace vkt
+{
+namespace DescriptorIndexing
+{
+namespace
+{
+using namespace vk;
+using tcu::UVec2;
+using tcu::Vec4;
+using tcu::TestStatus;
+using tcu::PixelBufferAccess;
+using tcu::Texture2D;
+
+#define RESOLUTION_width 64
+#define RESOLUTION_height 64
+static const VkExtent3D RESOLUTION = { RESOLUTION_width, RESOLUTION_height, 1 };
+
+#define MAX_DESCRIPTORS 4200
+#define FUZZY_COMPARE DE_FALSE
+#define CMP_THRESHOLD 0.02f
+
+#define BINDING_Undefined 0
+#define BINDING_UniformBuffer 1
+#define BINDING_StorageBuffer 2
+#define BINDING_UniformTexelBuffer 3
+#define BINDING_StorageTexelBuffer 4
+#define BINDING_Sampler 5
+#define BINDING_SampledImage 6
+#define BINDING_CombinedImageSampler 7
+#define BINDING_UniformBufferDynamic 8
+#define BINDING_StorageBufferDynamic 9
+#define BINDING_InputAttachment 10
+#define BINDING_StorageImage 11
+#define BINDING_DescriptorEnumerator 12
+
+static const VkExtent3D smallImageExtent = { 4, 4, 1 };
+static const VkExtent3D bigImageExtent = { 32, 32, 1 };
+static const VkDescriptorType VK_DESCRIPTOR_TYPE_UNDEFINED = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT;
+
+template<deUint32 BindingNumber>
+struct Binding
+{
+ static const deUint32 binding = BindingNumber;
+};
+
+struct BindingUniformBuffer : Binding<BINDING_UniformBuffer>
+{
+ typedef struct
+ {
+ tcu::Vec4 c;
+ } Data;
+};
+
+struct BindingStorageBuffer : Binding<BINDING_StorageBuffer>
+{
+ typedef struct
+ {
+ tcu::Vec4 cnew;
+ tcu::Vec4 cold;
+ } Data;
+};
+
+struct TestCaseParams
+{
+ VkDescriptorType descriptorType; // used only to distinguish test class instance
+ VkShaderStageFlags stageFlags; // used only to build a proper program
+ VkExtent3D frameResolution; // target frame buffer resolution
+ bool updateAfterBind; // whether a test will use update after bind feature
+ bool calculateInLoop; // perform calculation in a loop
+ bool usesMipMaps; // this makes a sense and affects in image test cases only
+ deBool fuzzyComparison; // if true then a test will use fuzzy comparison, otherwise float threshold
+ float thresholdValue; // a threshold that will be used for both, float and fuzzy comparisons
+};
+
+struct TestParams
+{
+ VkShaderStageFlags stageFlags;
+ VkDescriptorType descriptorType;
+ deUint32 descriptorBinding;
+ VkDescriptorType additionalDescriptorType;
+ deUint32 additionalDescriptorBinding;
+ bool copyBuffersToImages;
+ bool allowVertexStoring;
+ VkExtent3D frameResolution;
+ bool updateAfterBind;
+ bool calculateInLoop;
+ bool usesMipMaps;
+ deBool fuzzyComparison;
+ float thresholdValue;
+
+ TestParams (VkShaderStageFlags stageFlags_,
+ VkDescriptorType descriptorType_,
+ deUint32 descriptorBinding_,
+ VkDescriptorType additionalDescriptorType_,
+ deUint32 additionalDescriptorBinding_,
+ bool copyBuffersToImages_,
+ bool allowVertexStoring_,
+ const TestCaseParams& caseParams)
+ : stageFlags (stageFlags_)
+ , descriptorType (descriptorType_)
+ , descriptorBinding (descriptorBinding_)
+ , additionalDescriptorType (additionalDescriptorType_)
+ , additionalDescriptorBinding (additionalDescriptorBinding_)
+ , copyBuffersToImages (copyBuffersToImages_)
+ , allowVertexStoring (allowVertexStoring_)
+ , frameResolution (caseParams.frameResolution)
+ , updateAfterBind (caseParams.updateAfterBind)
+ , calculateInLoop (caseParams.calculateInLoop)
+ , usesMipMaps (caseParams.usesMipMaps)
+ , fuzzyComparison (caseParams.fuzzyComparison ? true : false)
+ , thresholdValue (caseParams.thresholdValue)
+ {
+ }
+};
+
+struct DescriptorEnumerator
+{
+ ut::BufferHandleAllocSp buffer;
+ ut::BufferViewSp bufferView;
+ VkDeviceSize bufferSize;
+
+ Move<VkDescriptorSetLayout> descriptorSetLayout;
+ Move<VkDescriptorPool> descriptorPool;
+ Move<VkDescriptorSet> descriptorSet;
+
+ void init(const vkt::Context& context, deUint32 vertexCount, deUint32 availableDescriptorCount);
+ void update(const vkt::Context& context);
+};
+
+struct IterateCommonVariables
+{
+ // An amount of descriptors of a given type available on the platform
+ deUint32 availableDescriptorCount;
+ // An amount of valid descriptors that have connected a buffers to them
+ deUint32 validDescriptorCount;
+ // As the name suggests, sometimes it is used as invocationCount
+ deUint32 vertexCount;
+ VkRect2D renderArea;
+ VkDeviceSize dataAlignment;
+ deUint32 lowerBound;
+ deUint32 upperBound;
+
+ DescriptorEnumerator descriptorEnumerator;
+
+ ut::BufferHandleAllocSp vertexAttributesBuffer;
+ ut::BufferHandleAllocSp descriptorsBuffer;
+ std::vector<VkDescriptorBufferInfo> descriptorsBufferInfos;
+ std::vector<ut::BufferViewSp> descriptorsBufferViews;
+ std::vector<ut::ImageViewSp> descriptorImageViews;
+ std::vector<ut::SamplerSp> descriptorSamplers;
+ std::vector<ut::ImageHandleAllocSp> descriptorsImages;
+ ut::FrameBufferSp frameBuffer;
+
+ Move<VkDescriptorSetLayout> descriptorSetLayout;
+ Move<VkDescriptorPool> descriptorPool;
+ Move<VkDescriptorSet> descriptorSet;
+ Move<VkPipelineLayout> pipelineLayout;
+ Move<VkRenderPass> renderPass;
+ Move<VkPipeline> pipeline;
+ Move<VkCommandBuffer> commandBuffer;
+};
+
+class CommonDescriptorInstance : public TestInstance
+{
+public:
+ CommonDescriptorInstance (Context& context,
+ const TestParams& testParams);
+
+ void checkIndexingAvailable (const ut::DeviceProperties& devProps) const;
+
+ deUint32 computeAvailableDescriptorCount (VkDescriptorType descriptorType) const;
+
+ Move<VkDescriptorSetLayout> createDescriptorSetLayout (deUint32& descriptorCount) const;
+
+ Move<VkDescriptorPool> createDescriptorPool (deUint32 descriptorCount) const;
+
+ Move<VkDescriptorSet> createDescriptorSet (VkDescriptorPool dsPool,
+ VkDescriptorSetLayout dsLayout) const;
+
+ struct attributes
+ {
+ typedef tcu::Vec4 vec4;
+ typedef tcu::Vec2 vec2;
+ typedef tcu::IVec4 ivec4;
+ vec4 position;
+ vec2 normalpos;
+ ivec4 index;
+ attributes& operator()(const vec4& pos)
+ {
+ position = pos;
+
+ normalpos.x() = (pos.x() + 1.0f) / 2.0f;
+ normalpos.y() = (pos.y() + 1.0f) / 2.0f;
+
+ return *this;
+ }
+ };
+ void createVertexAttributeBuffer (ut::BufferHandleAllocSp& buffer,
+ deUint32 availableDescriptorCount) const;
+
+ static std::string substBinding (deUint32 binding,
+ const char* str,
+ deUint32 count = 0,
+ const char* name = DE_NULL);
+
+ static const char* getVertexShaderProlog (void);
+
+ static const char* getFragmentShaderProlog (void);
+
+ static const char* getShaderEpilog (void);
+
+ static bool performWritesInVertex (VkDescriptorType descriptorType);
+
+ static std::string getShaderSource (VkShaderStageFlagBits shaderType,
+ const TestCaseParams& testCaseParams,
+ bool allowVertexStoring);
+
+ static std::string getColorAccess (VkDescriptorType descriptorType,
+ const char* indexVariableName,
+ bool usesMipMaps);
+
+ static std::string getFragmentReturnSource (const std::string& colorAccess);
+
+ static std::string getFragmentLoopSource (const std::string& colorAccess1,
+ const std::string& colorAccess2);
+
+ virtual Move<VkRenderPass> createRenderPass (const IterateCommonVariables& variables);
+
+ struct push_constant
+ {
+ deInt32 lowerBound;
+ deInt32 upperBound;
+ };
+ VkPushConstantRange makePushConstantRange (void) const;
+
+ Move<VkPipelineLayout> createPipelineLayout (const std::vector<VkDescriptorSetLayout>& descriptorSetLayouts) const;
+
+ // Creates graphics or compute pipeline and appropriate shaders' modules according the testCaseParams.stageFlags
+ // In the case of compute pipeline renderPass parameter is ignored.
+ // Viewport will be created with a width and a height taken from testCaseParam.fragResolution.
+ Move<VkPipeline> createPipeline (VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass);
+
+ virtual void createFramebuffer (ut::FrameBufferSp& frameBuffer,
+ VkRenderPass renderPass,
+ const IterateCommonVariables& variables);
+
+ // Creates one big stagging buffer cutted out on chunks that can accomodate an element of elementSize size
+ VkDeviceSize createBuffers (std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ ut::BufferHandleAllocSp& buffer,
+ deUint32 elementCount,
+ deUint32 elementSize,
+ VkDeviceSize alignment,
+ VkBufferUsageFlags bufferUsage);
+
+ // Creates and binds an imagesCount of images with given parameters.
+ // Additionally creates stagging buffer for their data and PixelBufferAccess for particular images.
+ VkDeviceSize createImages (std::vector<ut::ImageHandleAllocSp>& images,
+ std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ ut::BufferHandleAllocSp& buffer,
+ VkBufferUsageFlags bufferUsage,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ VkImageLayout imageLayout,
+ deUint32 imageCount,
+ bool withMipMaps = false);
+
+ void createBuffersViews (std::vector<ut::BufferViewSp>& views,
+ const std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ VkFormat format);
+
+ void createImagesViews (std::vector<ut::ImageViewSp>& views,
+ const std::vector<ut::ImageHandleAllocSp>& images,
+ VkFormat format);
+
+ virtual void copyBuffersToImages (IterateCommonVariables& variables);
+
+ virtual void copyImagesToBuffers (IterateCommonVariables& variables);
+
+ PixelBufferAccess getPixelAccess (deUint32 imageIndex,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ const std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ const ut::BufferHandleAllocSp& buffer,
+ deUint32 mipLevel = 0u) const;
+
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables) = 0;
+
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+
+ virtual void iterateCollectResults (ut::UpdatablePixelBufferAccessPtr& result,
+ const IterateCommonVariables& variables,
+ bool fromTest);
+
+
+ void iterateCommandBegin (IterateCommonVariables& variables);
+
+ bool iterateCommandEnd (IterateCommonVariables& variables,
+ bool collectBeforeSubmit = true);
+
+ Move<VkCommandBuffer> createCmdBuffer (void);
+
+ void commandBindPipeline (VkCommandBuffer commandBuffer,
+ VkPipeline pipeline);
+
+ void commandBindVertexAttributes (VkCommandBuffer commandBuffer,
+ const ut::BufferHandleAllocSp& vertexAttributesBuffer);
+
+ void commandBindDescriptorSets (VkCommandBuffer commandBuffer,
+ VkPipelineLayout pipelineLayout,
+ VkDescriptorSet descriptorSet,
+ deUint32 descriptorSetIndex);
+
+ void commandReadFrameBuffer (ut::BufferHandleAllocSp& content,
+ VkCommandBuffer commandBuffer,
+ const ut::FrameBufferSp& frameBuffer);
+ ut::UpdatablePixelBufferAccessPtr
+ commandReadFrameBuffer (VkCommandBuffer commandBuffer,
+ const ut::FrameBufferSp& frameBuffer);
+
+ Move<VkFence> commandSubmit (VkCommandBuffer commandBuffer);
+
+ virtual bool verifyVertexWriteResults (IterateCommonVariables& variables);
+
+protected:
+ virtual tcu::TestStatus iterate (void);
+
+protected:
+ const VkDevice m_vkd;
+ const DeviceInterface& m_vki;
+ Allocator& m_allocator;
+ const VkQueue m_queue;
+ const deUint32 m_queueFamilyIndex;
+ const Move<VkCommandPool> m_commandPool;
+ const VkFormat m_colorFormat;
+ const TestParams m_testParams;
+ static const tcu::Vec4 m_clearColor;
+ const std::vector<float> m_colorScheme;
+ const deUint32 m_schemeSize;
+
+private:
+
+ Move<VkPipeline> createGraphicsPipeline (VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass);
+
+ Move<VkPipeline> createComputePipeline (VkPipelineLayout pipelineLayout);
+
+ int constructShaderModules (void);
+
+ static std::vector<float> createColorScheme();
+
+ Move<VkShaderModule> m_vertexModule;
+ Move<VkShaderModule> m_fragmentModule;
+ Move<VkShaderModule> m_computeModule;
+};
+const tcu::Vec4 CommonDescriptorInstance::m_clearColor = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
+
+void DescriptorEnumerator::init (const vkt::Context& context, deUint32 vertexCount, deUint32 availableDescriptorCount)
+{
+ const VkDevice device = context.getDevice();
+ const DeviceInterface& deviceInterface = context.getDeviceInterface();
+
+ const VkFormat imageFormat = VK_FORMAT_R32G32B32A32_SINT;
+ typedef ut::mapVkFormat2Type<imageFormat>::type pixelType;
+ const VkDeviceSize dataSize = vertexCount * sizeof(pixelType);
+ const std::vector<deUint32> primes = ut::generatePrimes(availableDescriptorCount);
+ const deUint32 primeCount = static_cast<deUint32>(primes.size());
+
+ std::vector<pixelType> data(vertexCount);
+ // e.g. 2,3,5,7,11,13,2,3,5,7,...
+ for (deUint32 idx = 0; idx < vertexCount; ++idx)
+ {
+ data[idx].x() = static_cast<pixelType::Element>(primes[idx % primeCount]);
+ data[idx].y() = static_cast<pixelType::Element>(idx);
+ }
+
+ bufferSize = ut::createBufferAndBind(buffer, context, VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, dataSize);
+ deMemcpy(buffer->alloc->getHostPtr(), data.data(), static_cast<size_t>(dataSize));
+
+ const VkBufferViewCreateInfo bufferViewCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ 0u, // flags
+ *(buffer.get()->buffer), // buffer
+ imageFormat, // format
+ 0u, // offset
+ bufferSize, // range
+ };
+
+ bufferView = ut::BufferViewSp(new Move<VkBufferView>(vk::createBufferView(deviceInterface, device, &bufferViewCreateInfo)));
+
+ const VkDescriptorSetLayoutBinding binding =
+ {
+ BINDING_DescriptorEnumerator, // binding
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, // descriptorType
+ 1u, // descriptorCount
+ VK_SHADER_STAGE_ALL, // stageFlags
+ DE_NULL, // pImmutableSamplers
+ };
+
+ const VkDescriptorSetLayoutCreateInfo layoutCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ DE_NULL, // pNext
+ 0u, // flags
+ 1u, // bindingCount
+ &binding, // pBindings
+ };
+
+ descriptorSetLayout = vk::createDescriptorSetLayout(deviceInterface, device, &layoutCreateInfo);
+ descriptorPool = DescriptorPoolBuilder().addType(binding.descriptorType)
+ .build(deviceInterface, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
+
+ const VkDescriptorSetAllocateInfo dsAllocInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType
+ DE_NULL, // pNext
+ *descriptorPool, // descriptorPool
+ 1u, // descriptorSetCount
+ &(*descriptorSetLayout) // pSetLayouts
+ };
+
+ descriptorSet = vk::allocateDescriptorSet(deviceInterface, device, &dsAllocInfo);
+}
+
+void DescriptorEnumerator::update (const vkt::Context& context)
+{
+ const VkDescriptorBufferInfo bufferInfo =
+ {
+ *(buffer.get()->buffer), // buffer
+ 0u, // offset
+ bufferSize, // range
+ };
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
+ DE_NULL, // pNext
+ *descriptorSet, // dstSet
+ BINDING_DescriptorEnumerator, // dstBinding
+ 0u, // dstArrayElement
+ 1u, // descriptorCount
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, // descriptorType
+ DE_NULL, // pImageInfo
+ &bufferInfo, // pBufferInfo
+ &(**bufferView), // pTexelBufferView
+ };
+
+ context.getDeviceInterface().updateDescriptorSets(context.getDevice(), 1u, &writeInfo, 0u, DE_NULL);
+}
+
+CommonDescriptorInstance::CommonDescriptorInstance (Context& context,
+ const TestParams& testParams)
+ : TestInstance (context)
+ , m_vkd (context.getDevice())
+ , m_vki (context.getDeviceInterface())
+ , m_allocator (context.getDefaultAllocator())
+ , m_queue (context.getUniversalQueue())
+ , m_queueFamilyIndex(context.getUniversalQueueFamilyIndex())
+ , m_commandPool (vk::createCommandPool(m_vki, m_vkd, (VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT), m_queueFamilyIndex))
+ , m_colorFormat (VK_FORMAT_R32G32B32A32_SFLOAT)
+ , m_testParams (testParams)
+ , m_colorScheme (createColorScheme())
+ , m_schemeSize (static_cast<deUint32>(m_colorScheme.size()))
+{
+}
+
+void CommonDescriptorInstance::checkIndexingAvailable (const ut::DeviceProperties& devProps) const
+{
+ DE_UNREF(devProps);
+ m_context.requireDeviceExtension("VK_EXT_descriptor_indexing");
+}
+
+deUint32 CommonDescriptorInstance::computeAvailableDescriptorCount (VkDescriptorType descriptorType) const
+{
+ DE_UNREF(descriptorType);
+ const deUint32 vertexCount = m_testParams.frameResolution.width * m_testParams.frameResolution.height;
+ const deUint32 availableDescriptorsOnDevice = ut::DeviceProperties(m_context).computeMaxPerStageDescriptorCount(m_testParams.descriptorType, m_testParams.updateAfterBind);
+ return deMinu32(deMinu32(vertexCount, availableDescriptorsOnDevice), MAX_DESCRIPTORS);
+}
+
+Move<VkDescriptorSetLayout> CommonDescriptorInstance::createDescriptorSetLayout (deUint32& descriptorCount) const
+{
+ descriptorCount = computeAvailableDescriptorCount(m_testParams.descriptorType);
+
+ bool optional = (m_testParams.additionalDescriptorBinding != BINDING_Undefined) && (m_testParams.additionalDescriptorType != VK_DESCRIPTOR_TYPE_UNDEFINED);
+
+ const VkDescriptorSetLayoutBinding bindings[] =
+ {
+ {
+ m_testParams.descriptorBinding, // binding
+ m_testParams.descriptorType, // descriptorType
+ descriptorCount, // descriptorCount
+ m_testParams.stageFlags, // stageFlags
+ DE_NULL, // pImmutableSamplers
+ },
+ {
+ m_testParams.additionalDescriptorBinding, // binding
+ m_testParams.additionalDescriptorType, // descriptorType
+ 1, // descriptorCount
+ m_testParams.stageFlags, // stageFlags
+ DE_NULL, // pImmutableSamplers
+ }
+ };
+
+ const VkDescriptorBindingFlagsEXT bindingFlagUpdateAfterBind =
+ m_testParams.updateAfterBind ? VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT : 0;
+
+ const VkDescriptorBindingFlagsEXT bindingFlagsExt[] =
+ {
+ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | bindingFlagUpdateAfterBind,
+ VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | bindingFlagUpdateAfterBind
+ };
+
+ const VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingCreateInfoExt =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
+ DE_NULL,
+ optional ? 2u : 1u, // bindingCount
+ bindingFlagsExt, // pBindingFlags
+ };
+
+ const VkDescriptorSetLayoutCreateFlags layoutCreateFlags =
+ m_testParams.updateAfterBind ? VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT : 0;
+
+ const VkDescriptorSetLayoutCreateInfo layoutCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
+ &bindingCreateInfoExt, // pNext
+ layoutCreateFlags, // flags
+ optional ? 2u : 1u, // bindingCount
+ bindings, // pBindings
+ };
+
+ return vk::createDescriptorSetLayout(m_vki, m_vkd, &layoutCreateInfo);
+}
+
+Move<VkDescriptorPool> CommonDescriptorInstance::createDescriptorPool (deUint32 descriptorCount) const
+{
+ const VkDescriptorPoolCreateFlags pcf = m_testParams.updateAfterBind ? VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT : 0;
+
+ DescriptorPoolBuilder builder;
+
+ builder.addType(m_testParams.descriptorType, descriptorCount);
+
+ if (m_testParams.additionalDescriptorType != VK_DESCRIPTOR_TYPE_UNDEFINED && m_testParams.additionalDescriptorBinding != BINDING_Undefined)
+ {
+ builder.addType(m_testParams.additionalDescriptorType, 1);
+ }
+
+ return builder.build(m_vki, m_vkd, (VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT | pcf), 1u);
+}
+
+Move<VkDescriptorSet> CommonDescriptorInstance::createDescriptorSet (VkDescriptorPool dsPool,
+ VkDescriptorSetLayout dsLayout) const
+{
+ const VkDescriptorSetAllocateInfo dsAllocInfo =
+ {
+ VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // sType;
+ DE_NULL, // pNext;
+ dsPool, // descriptorPool;
+ 1u, // descriptorSetCount
+ &dsLayout // pSetLayouts
+ };
+
+ return vk::allocateDescriptorSet(m_vki, m_vkd, &dsAllocInfo);
+}
+
+void CommonDescriptorInstance::createVertexAttributeBuffer (ut::BufferHandleAllocSp& buffer,
+ deUint32 availableDescriptorCount) const
+{
+ float xSize = 0.0f;
+ float ySize = 0.0f;
+
+ const deUint32 invocationCount = m_testParams.frameResolution.width * m_testParams.frameResolution.height;
+ const std::vector<Vec4> vertices = ut::createVertices(m_testParams.frameResolution.width, m_testParams.frameResolution.height, xSize, ySize);
+ const std::vector<deUint32> primes = ut::generatePrimes(availableDescriptorCount);
+ const deUint32 primeCount = static_cast<deUint32>(primes.size());
+
+ std::vector<attributes> data(vertices.size());
+ std::transform(vertices.begin(), vertices.end(), data.begin(), attributes());
+
+ for (deUint32 invIdx = 0; invIdx < invocationCount; ++invIdx)
+ {
+ // r: 2,3,5,7,11,13,2,3,5,7,...
+ data[invIdx].index.x() = primes[invIdx % primeCount];
+
+ // b: x index in texel coordinate
+ data[invIdx].index.z() = invIdx % m_testParams.frameResolution.width;
+
+ //a: y index in texel coordinate
+ data[invIdx].index.w() = invIdx / m_testParams.frameResolution.width;
+ }
+
+ // g: 0,0,2,3,0,5,0,7,0,0,0,11,0,13,...
+ for (deUint32 primeIdx = 0; primeIdx < primeCount; ++primeIdx)
+ {
+ const deUint32 prime = primes[primeIdx];
+ DE_ASSERT(prime < invocationCount);
+ data[prime].index.y() = prime;
+ }
+
+ const VkDeviceSize dataSize = data.size() * sizeof(attributes);
+
+ VkDeviceSize deviceSize = ut::createBufferAndBind(buffer, m_context, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, dataSize);
+
+ deMemcpy(buffer->alloc->getHostPtr(), data.data(), static_cast<size_t>(deviceSize));
+
+ vk::flushAlloc(m_vki, m_vkd, *buffer->alloc);
+}
+
+std::string CommonDescriptorInstance::substBinding (deUint32 binding,
+ const char* str,
+ deUint32 count,
+ const char* name)
+{
+ std::map<std::string, std::string> vars;
+ vars["?"] = de::toString(binding);
+ vars["*"] = (0 == count) ? "" : de::toString(count);
+ vars["VAR"] = (DE_NULL == name) ? "data" : name;
+ return tcu::StringTemplate(str).specialize(vars);
+}
+
+const char* CommonDescriptorInstance::getVertexShaderProlog (void)
+{
+ return
+ "layout(location = 0) in vec4 in_position; \n"
+ "layout(location = 1) in vec2 in_normalpos; \n"
+ "layout(location = 2) in ivec4 index; \n"
+ "layout(location = 0) out vec4 position; \n"
+ "layout(location = 1) out vec2 normalpos; \n"
+ "layout(location = 2) out int vIndex; \n"
+ "layout(location = 3) out int rIndex; \n"
+ "layout(location = 4) out int gIndex; \n"
+ "layout(location = 5) out int bIndex; \n"
+ "layout(location = 6) out int aIndex; \n"
+ "void main() \n"
+ "{ \n"
+ " gl_PointSize = 0.2f; \n"
+ " position = in_position; \n"
+ " normalpos = in_normalpos; \n"
+ " gl_Position = position; \n"
+ " vIndex = gl_VertexIndex; \n"
+ " rIndex = index.x; \n"
+ " gIndex = index.y; \n"
+ " bIndex = index.z; \n"
+ " aIndex = index.w; \n";
+}
+
+const char* CommonDescriptorInstance::getFragmentShaderProlog (void)
+{
+ return
+ "layout(location = 0) out vec4 FragColor; \n"
+ "layout(location = 0) in flat vec4 position; \n"
+ "layout(location = 1) in flat vec2 normalpos; \n"
+ "layout(location = 2) in flat int vIndex; \n"
+ "layout(location = 3) in flat int rIndex; \n"
+ "layout(location = 4) in flat int gIndex; \n"
+ "layout(location = 5) in flat int bIndex; \n"
+ "layout(location = 6) in flat int aIndex; \n"
+ "void main() \n"
+ "{ \n";
+}
+
+const char* CommonDescriptorInstance::getShaderEpilog (void)
+{
+ return "} \n";
+}
+
+int CommonDescriptorInstance::constructShaderModules (void)
+{
+ int result = 0;
+ ut::DeviceProperties dp (m_context);
+ const VkPhysicalDeviceFeatures& feats = dp.physicalDeviceFeatures();
+ tcu::TestLog& log = m_context.getTestContext().getLog();
+
+ if (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
+ {
+ ++result;
+ const std::string name = ut::buildShaderName(VK_SHADER_STAGE_COMPUTE_BIT, m_testParams.descriptorType, m_testParams.updateAfterBind, m_testParams.calculateInLoop, false);
+ m_computeModule = vk::createShaderModule(m_vki, m_vkd, m_context.getBinaryCollection().get(name), (VkShaderModuleCreateFlags)0);
+ }
+ if (m_testParams.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT)
+ {
+ ++result;
+ const std::string name = ut::buildShaderName(VK_SHADER_STAGE_FRAGMENT_BIT, m_testParams.descriptorType, m_testParams.updateAfterBind, m_testParams.calculateInLoop, (feats.vertexPipelineStoresAndAtomics != DE_FALSE && m_testParams.allowVertexStoring));
+ m_fragmentModule = vk::createShaderModule(m_vki, m_vkd, m_context.getBinaryCollection().get(name), (VkShaderModuleCreateFlags)0);
+ log << tcu::TestLog::Message << "Finally used fragment shader: " << name << '\n' << tcu::TestLog::EndMessage;
+ }
+ if (m_testParams.stageFlags & VK_SHADER_STAGE_VERTEX_BIT)
+ {
+ ++result;
+ const std::string name = ut::buildShaderName(VK_SHADER_STAGE_VERTEX_BIT, m_testParams.descriptorType, m_testParams.updateAfterBind, m_testParams.calculateInLoop, (feats.vertexPipelineStoresAndAtomics != DE_FALSE && m_testParams.allowVertexStoring));
+ m_vertexModule = vk::createShaderModule(m_vki, m_vkd, m_context.getBinaryCollection().get(name), (VkShaderModuleCreateFlags)0);
+ log << tcu::TestLog::Message << "Finally used vertex shader: " << name << '\n' << tcu::TestLog::EndMessage;
+ }
+
+ DE_ASSERT(result > 0);
+
+ return result;
+}
+
+Move<VkRenderPass> CommonDescriptorInstance::createRenderPass (const IterateCommonVariables& variables)
+{
+ DE_UNREF(variables);
+ if ((m_testParams.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) || (m_testParams.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT))
+ {
+ return vk::makeRenderPass(m_vki, m_vkd, m_colorFormat);
+ }
+ return Move<VkRenderPass>();
+}
+
+VkPushConstantRange CommonDescriptorInstance::makePushConstantRange (void) const
+{
+ const VkPushConstantRange pcr =
+ {
+ m_testParams.stageFlags, // stageFlags
+ 0u, // offset
+ static_cast<deUint32>(sizeof(push_constant)) // size
+ };
+ return pcr;
+}
+
+Move<VkPipelineLayout> CommonDescriptorInstance::createPipelineLayout (const std::vector<VkDescriptorSetLayout>& descriptorSetLayouts) const
+{
+ const VkPushConstantRange pcr = makePushConstantRange();
+
+ const VkPipelineLayoutCreateInfo createInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkPipelineLayoutCreateFlags)0, // flags
+ static_cast<deUint32>(descriptorSetLayouts.size()), // setLayoutCount
+ descriptorSetLayouts.data(), // pSetLayouts;
+ m_testParams.calculateInLoop ? 1u : 0u, // pushConstantRangeCount
+ m_testParams.calculateInLoop ? &pcr : DE_NULL, // pPushConstantRanges
+ };
+
+ return vk::createPipelineLayout(m_vki, m_vkd, &createInfo);
+}
+
+void CommonDescriptorInstance::createFramebuffer (ut::FrameBufferSp& frameBuffer,
+ VkRenderPass renderPass,
+ const IterateCommonVariables& variables)
+{
+ DE_UNREF(variables);
+ ut::createFrameBuffer(frameBuffer, m_context, m_testParams.frameResolution, m_colorFormat, renderPass);
+}
+
+Move<VkPipeline> CommonDescriptorInstance::createPipeline (VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass)
+{ DE_ASSERT(VK_SHADER_STAGE_ALL != m_testParams.stageFlags);
+
+ constructShaderModules();
+
+ return (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
+ ? createComputePipeline(pipelineLayout)
+ : createGraphicsPipeline(pipelineLayout, renderPass);
+}
+
+Move<VkPipeline> CommonDescriptorInstance::createComputePipeline (VkPipelineLayout pipelineLayout)
+{
+ const VkPipelineShaderStageCreateInfo shaderStaegCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
+ DE_NULL, // pNext
+ (VkPipelineShaderStageCreateFlags)0, // flags
+ VK_SHADER_STAGE_COMPUTE_BIT, // stage
+ *m_computeModule, // module
+ "main", // pName
+ (VkSpecializationInfo*)DE_NULL // pSpecializationInfo
+ };
+
+ const VkComputePipelineCreateInfo pipelineCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
+ DE_NULL, // pNext
+ 0u, // flags
+ shaderStaegCreateInfo, // stage
+ pipelineLayout, // layout
+ (VkPipeline)0, // basePipelineHandle
+ 0u, // basePipelineIndex
+ };
+ return vk::createComputePipeline(m_vki, m_vkd, (VkPipelineCache)0u, &pipelineCreateInfo);
+}
+
+Move<VkPipeline> CommonDescriptorInstance::createGraphicsPipeline (VkPipelineLayout pipelineLayout,
+ VkRenderPass renderPass)
+{
+ const VkVertexInputBindingDescription bindingDescriptions[] =
+ {
+ {
+ 0u, // binding
+ sizeof(attributes), // stride
+ VK_VERTEX_INPUT_RATE_VERTEX, // inputRate
+ },
+ };
+
+ const VkVertexInputAttributeDescription attributeDescriptions[] =
+ {
+ {
+ 0u, // location
+ 0u, // binding
+ ut::mapType2vkFormat<attributes::vec4>::value, // format
+ 0u // offset
+ }, // @in_position
+ {
+ 1u, // location
+ 0u, // binding
+ ut::mapType2vkFormat<attributes::vec2>::value, // format
+ static_cast<deUint32>(sizeof(attributes::vec4)) // offset
+ }, // @normalpos
+ {
+ 2u, // location
+ 0u, // binding
+ ut::mapType2vkFormat<attributes::ivec4>::value, // format
+ static_cast<deUint32>(sizeof(attributes::vec2)
+ + sizeof(attributes::vec4)) // offset
+ }, // @index
+ };
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
+ DE_NULL,
+ (VkPipelineVertexInputStateCreateFlags)0, // flags
+ DE_LENGTH_OF_ARRAY(bindingDescriptions), // vertexBindingDescriptionCount
+ bindingDescriptions, // pVertexBindingDescriptions
+ DE_LENGTH_OF_ARRAY(attributeDescriptions), // vertexAttributeDescriptionCount
+ attributeDescriptions // pVertexAttributeDescriptions
+ };
+
+ const std::vector<VkViewport> viewports (1, makeViewport(m_testParams.frameResolution.width, m_testParams.frameResolution.height));
+ const std::vector<VkRect2D> scissors (1, makeRect2D(m_testParams.frameResolution.width, m_testParams.frameResolution.height));
+
+ DE_ASSERT(m_vertexModule && m_fragmentModule);
+
+ return vk::makeGraphicsPipeline(
+ m_vki, // vk
+ m_vkd, // device
+ pipelineLayout, // pipelineLayout
+ *m_vertexModule, // vertexShaderModule
+ DE_NULL, // tessellationControlModule
+ DE_NULL, // tessellationEvalModule
+ DE_NULL, // geometryShaderModule
+ *m_fragmentModule, // fragmentShaderModule
+ renderPass, // renderPass
+ viewports, // viewports
+ scissors, // scissors
+ VK_PRIMITIVE_TOPOLOGY_POINT_LIST, // topology
+ 0U, // subpass
+ 0U, // patchControlPoints
+ &vertexInputStateCreateInfo); // vertexInputStateCreateInfo
+}
+
+VkDeviceSize CommonDescriptorInstance::createBuffers (std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ ut::BufferHandleAllocSp& buffer,
+ deUint32 elementCount,
+ deUint32 elementSize,
+ VkDeviceSize alignment,
+ VkBufferUsageFlags bufferUsage)
+{
+ const VkDeviceSize roundedSize = deAlign64(elementSize, alignment);
+ VkDeviceSize bufferSize = ut::createBufferAndBind(buffer, m_context, bufferUsage, (roundedSize * elementCount));
+
+ for (deUint32 elementIdx = 0; elementIdx < elementCount; ++elementIdx)
+ {
+ const VkDescriptorBufferInfo bufferInfo =
+ {
+ *buffer.get()->buffer, //buffer;
+ elementIdx * roundedSize, //offset;
+ elementSize, // range;
+
+ };
+ bufferInfos.push_back(bufferInfo);
+ }
+
+ return bufferSize;
+}
+
+VkDeviceSize CommonDescriptorInstance::createImages (std::vector<ut::ImageHandleAllocSp>& images,
+ std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ ut::BufferHandleAllocSp& buffer,
+ VkBufferUsageFlags bufferUsage,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ VkImageLayout imageLayout,
+ deUint32 imageCount,
+ bool withMipMaps)
+
+{
+ const deUint32 imageSize = ut::computeImageSize(imageExtent, imageFormat, withMipMaps);
+
+ const VkDeviceSize bufferSize = createBuffers(bufferInfos, buffer, imageCount, imageSize, sizeof(tcu::Vec4), bufferUsage);
+
+ for (deUint32 imageIdx = 0; imageIdx < imageCount; ++imageIdx)
+ {
+ ut::ImageHandleAllocSp image;
+ ut::createImageAndBind(image, m_context, imageFormat, imageExtent, imageLayout, withMipMaps);
+ images.push_back(image);
+ }
+
+ return bufferSize;
+}
+
+void CommonDescriptorInstance::createBuffersViews (std::vector<ut::BufferViewSp>& views,
+ const std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ VkFormat format)
+{
+ const deUint32 infoCount = static_cast<deUint32>(bufferInfos.size());
+ for (deUint32 infoIdx = 0; infoIdx < infoCount; ++infoIdx)
+ {
+ const VkDescriptorBufferInfo& bufferInfo = bufferInfos[infoIdx];
+ const VkBufferViewCreateInfo bufferViewInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkBufferViewCreateFlags)0, // flags
+ bufferInfo.buffer, // buffer
+ format, // format
+ bufferInfo.offset, // offset
+ bufferInfo.range // range;
+ };
+ views.push_back(ut::BufferViewSp(new Move<VkBufferView>(vk::createBufferView(m_vki, m_vkd, &bufferViewInfo))));
+ }
+}
+
+void CommonDescriptorInstance::createImagesViews (std::vector<ut::ImageViewSp>& views,
+ const std::vector<ut::ImageHandleAllocSp>& images,
+ VkFormat format)
+{
+ const deUint32 imageCount = static_cast<deUint32>(images.size());
+ for (deUint32 imageIdx = 0; imageIdx < imageCount; ++imageIdx)
+ {
+ const VkImageViewCreateInfo createInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkImageViewCreateFlags)0, // flags
+ *images[imageIdx]->image, // image
+ VK_IMAGE_VIEW_TYPE_2D, // viewType
+ format, // format
+ vk::makeComponentMappingRGBA(), // components
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
+ (deUint32)0, // baseMipLevel
+ images[imageIdx]->levels, // mipLevels
+ (deUint32)0, // baseArrayLayer
+ (deUint32)1u, // arraySize
+ },
+ };
+ views.push_back(ut::ImageViewSp(new Move<VkImageView>(vk::createImageView(m_vki, m_vkd, &createInfo))));
+ }
+}
+
+void CommonDescriptorInstance::copyBuffersToImages (IterateCommonVariables& variables)
+{
+ const deUint32 infoCount = static_cast<deUint32>(variables.descriptorsBufferInfos.size());
+ DE_ASSERT(variables.descriptorsImages.size() == infoCount);
+ const VkPipelineStageFlagBits dstStageMask = (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
+ ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ : VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
+ for (deUint32 infoIdx = 0; infoIdx < infoCount; ++infoIdx)
+ {
+ ut::recordCopyBufferToImage(
+ *variables.commandBuffer, // commandBuffer
+ m_vki, // interface
+ VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // srcStageMask
+ dstStageMask, // dstStageMask
+ variables.descriptorsBufferInfos[infoIdx], // bufferInfo
+ *(variables.descriptorsImages[infoIdx]->image), // image
+ variables.descriptorsImages[infoIdx]->extent, // imageExtent
+ variables.descriptorsImages[infoIdx]->format, // imageFormat
+ variables.descriptorsImages[infoIdx]->layout, // oldImageLayout
+ VK_IMAGE_LAYOUT_GENERAL, // newImageLayout
+ variables.descriptorsImages[infoIdx]->levels); // mipLevelCount
+
+ variables.descriptorsImages[infoIdx]->layout = VK_IMAGE_LAYOUT_GENERAL;
+ }
+}
+
+void CommonDescriptorInstance::copyImagesToBuffers (IterateCommonVariables& variables)
+{
+ const deUint32 infoCount = static_cast<deUint32>(variables.descriptorsBufferInfos.size());
+ DE_ASSERT(variables.descriptorsImages.size() == infoCount);
+ const VkPipelineStageFlagBits srcStageMask = (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT)
+ ? VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT
+ : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+
+ for (deUint32 infoIdx = 0; infoIdx < infoCount; ++infoIdx)
+ {
+ ut::recordCopyImageToBuffer(
+ *variables.commandBuffer, // commandBuffer
+ m_vki, // interface
+ srcStageMask, // srcStageMask
+ VK_PIPELINE_STAGE_HOST_BIT, // dstStageMask
+ *(variables.descriptorsImages[infoIdx]->image), // image
+ variables.descriptorsImages[infoIdx]->extent, // imageExtent
+ variables.descriptorsImages[infoIdx]->format, // imageFormat
+ variables.descriptorsImages[infoIdx]->layout, // oldImageLayout
+ VK_IMAGE_LAYOUT_GENERAL, // newImageLayout
+ variables.descriptorsBufferInfos[infoIdx]); // bufferInfo
+ }
+}
+
+PixelBufferAccess CommonDescriptorInstance::getPixelAccess (deUint32 imageIndex,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ const std::vector<VkDescriptorBufferInfo>& bufferInfos,
+ const ut::BufferHandleAllocSp& buffer,
+ deUint32 mipLevel) const
+{
+ DE_ASSERT(bufferInfos[imageIndex].buffer == *buffer.get()->buffer);
+ DE_ASSERT(ut::computeImageSize(imageExtent, imageFormat, true, (mipLevel ? ut::maxDeUint32 : 0)) <= bufferInfos[imageIndex].range);
+ DE_ASSERT(imageExtent.width >> mipLevel);
+ DE_ASSERT(imageExtent.height >> mipLevel);
+
+ deUint32 mipOffset = 0;
+
+ for (deUint32 level = 0; mipLevel && level < mipLevel; ++level)
+ {
+ mipOffset += ut::computeImageSize(imageExtent, imageFormat, true, level);
+ }
+
+ unsigned char* hostPtr = static_cast<unsigned char*>(buffer->alloc->getHostPtr());
+ unsigned char* data = hostPtr + bufferInfos[imageIndex].offset + mipOffset;
+ return tcu::PixelBufferAccess(vk::mapVkFormat(imageFormat), (imageExtent.width >> mipLevel), (imageExtent.height >> mipLevel), imageExtent.depth, data);
+}
+
+
+void CommonDescriptorInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+ const deUint32 primeCount = static_cast<deUint32>(primes.size());
+
+ for (deUint32 primeIdx = 0; primeIdx < primeCount; ++primeIdx)
+ {
+ const VkDescriptorBufferInfo* pBufferInfo = DE_NULL;
+ const VkDescriptorImageInfo* pImageInfo = DE_NULL;
+ const VkBufferView* pTexelBufferView = DE_NULL;
+
+
+ VkDescriptorImageInfo imageInfo =
+ {
+ static_cast<VkSampler>(0),
+ static_cast<VkImageView>(0),
+ VK_IMAGE_LAYOUT_GENERAL
+ };
+
+ switch (m_testParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ {
+ pBufferInfo = &variables.descriptorsBufferInfos[primeIdx];
+ switch (m_testParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ pTexelBufferView = &(**variables.descriptorsBufferViews[primeIdx]);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ imageInfo.sampler = **variables.descriptorSamplers[primeIdx];
+ pImageInfo = &imageInfo;
+ break;
+
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ imageInfo.imageView = **variables.descriptorImageViews[primeIdx];
+ pImageInfo = &imageInfo;
+ break;
+
+ default: break;
+ }
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ m_testParams.descriptorBinding, // descriptorBinding;
+ primes[primeIdx], // elementIndex
+ 1u, // descriptorCount
+ m_testParams.descriptorType, // descriptorType
+ pImageInfo, // pImageInfo
+ pBufferInfo, // pBufferInfo
+ pTexelBufferView // pTexelBufferView
+ };
+
+ m_vki.updateDescriptorSets(m_vkd, 1u, &writeInfo, 0u, DE_NULL);
+ }
+}
+
+void CommonDescriptorInstance::iterateCommandBegin (IterateCommonVariables& variables)
+{
+ variables.dataAlignment = 0;
+
+ variables.renderArea.offset.x = 0;
+ variables.renderArea.offset.y = 0;
+ variables.renderArea.extent.width = m_testParams.frameResolution.width;
+ variables.renderArea.extent.height = m_testParams.frameResolution.height;
+
+ variables.vertexCount = m_testParams.frameResolution.width * m_testParams.frameResolution.height;
+
+ variables.lowerBound = 0;
+ variables.upperBound = variables.vertexCount;
+
+ variables.descriptorSetLayout = createDescriptorSetLayout(variables.availableDescriptorCount);
+ variables.validDescriptorCount = ut::computePrimeCount(variables.availableDescriptorCount);
+ variables.descriptorPool = createDescriptorPool(variables.availableDescriptorCount);
+ variables.descriptorSet = createDescriptorSet(*variables.descriptorPool, *variables.descriptorSetLayout);
+
+ std::vector<VkDescriptorSetLayout> descriptorSetLayouts;
+ descriptorSetLayouts.push_back(*variables.descriptorSetLayout);
+ if (m_testParams.calculateInLoop)
+ {
+ variables.descriptorEnumerator.init(m_context, variables.vertexCount, variables.availableDescriptorCount);
+ descriptorSetLayouts.push_back(*variables.descriptorEnumerator.descriptorSetLayout);
+ }
+
+ variables.pipelineLayout = createPipelineLayout(descriptorSetLayouts);
+
+ createAndPopulateDescriptors (variables);
+
+ variables.renderPass = createRenderPass(variables);
+ variables.pipeline = createPipeline(*variables.pipelineLayout, *variables.renderPass);
+
+ variables.commandBuffer = createCmdBuffer();
+
+ if ((m_testParams.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) || (m_testParams.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT))
+ {
+ createVertexAttributeBuffer (variables.vertexAttributesBuffer, variables.availableDescriptorCount);
+ createFramebuffer (variables.frameBuffer, *variables.renderPass, variables);
+ }
+
+ if (m_testParams.calculateInLoop)
+ {
+ variables.descriptorEnumerator.update(m_context);
+ }
+
+ if (!m_testParams.updateAfterBind)
+ {
+ updateDescriptors (variables);
+ }
+
+ vk::beginCommandBuffer (m_vki, *variables.commandBuffer);
+
+ if (m_testParams.calculateInLoop)
+ {
+ deRandom rnd;
+ deRandom_init(&rnd, static_cast<deUint32>(m_testParams.descriptorType));
+ const deUint32 quarter = variables.vertexCount / 4;
+
+ variables.lowerBound = deRandom_getUint32(&rnd) % quarter;
+ variables.upperBound = (deRandom_getUint32(&rnd) % quarter) + (3 * quarter);
+
+ const push_constant pc =
+ {
+ static_cast<deInt32>(variables.lowerBound),
+ static_cast<deInt32>(variables.upperBound)
+ };
+
+ m_vki.cmdPushConstants(*variables.commandBuffer, *variables.pipelineLayout, m_testParams.stageFlags, 0u, static_cast<deUint32>(sizeof(pc)), &pc);
+ }
+
+ if ((m_testParams.stageFlags & VK_SHADER_STAGE_VERTEX_BIT) || (m_testParams.stageFlags & VK_SHADER_STAGE_FRAGMENT_BIT))
+ {
+ commandBindVertexAttributes (*variables.commandBuffer, variables.vertexAttributesBuffer);
+ }
+
+ if (m_testParams.calculateInLoop)
+ {
+ commandBindDescriptorSets(*variables.commandBuffer, *variables.pipelineLayout, *variables.descriptorEnumerator.descriptorSet, 1);
+ }
+
+ if (!ut::isDynamicDescriptor(m_testParams.descriptorType))
+ {
+ commandBindDescriptorSets (*variables.commandBuffer, *variables.pipelineLayout, *variables.descriptorSet, 0);
+ }
+
+ commandBindPipeline (*variables.commandBuffer, *variables.pipeline);
+}
+
+tcu::TestStatus CommonDescriptorInstance::iterate (void)
+{
+ IterateCommonVariables v;
+ iterateCommandBegin (v);
+
+ if (true == m_testParams.copyBuffersToImages)
+ {
+ copyBuffersToImages (v);
+ }
+
+ if (true == m_testParams.updateAfterBind)
+ {
+ updateDescriptors (v);
+ }
+
+ vk::beginRenderPass (m_vki, *v.commandBuffer, *v.renderPass, *v.frameBuffer->buffer, v.renderArea, m_clearColor);
+ m_vki.cmdDraw (*v.commandBuffer, v.vertexCount, 1u, 0u, 0u);
+ vk::endRenderPass (m_vki, *v.commandBuffer);
+
+ return (iterateCommandEnd(v) ? tcu::TestStatus::pass : tcu::TestStatus::fail)("");
+}
+
+std::vector<float> CommonDescriptorInstance::createColorScheme (void)
+{
+ std::vector<float> cs;
+ int divider = 2;
+ for (int i = 0; i < 10; ++i)
+ {
+ cs.push_back(1.0f / float(divider));
+ divider *= 2;
+ }
+ return cs;
+}
+
+bool CommonDescriptorInstance::iterateCommandEnd (IterateCommonVariables& variables,
+ bool collectBeforeSubmit)
+{
+ ut::UpdatablePixelBufferAccessPtr programResult;
+ ut::UpdatablePixelBufferAccessPtr referenceResult;
+
+ if (collectBeforeSubmit)
+ {
+ iterateCollectResults(programResult, variables, true);
+ iterateCollectResults(referenceResult, variables, false);
+ }
+
+ VK_CHECK(m_vki.endCommandBuffer(*variables.commandBuffer));
+ Move<VkFence> fence = commandSubmit(*variables.commandBuffer);
+ m_vki.waitForFences(m_vkd, 1, &(*fence), DE_TRUE, ~0ull);
+
+ if (false == collectBeforeSubmit)
+ {
+ iterateCollectResults(programResult, variables, true);
+ iterateCollectResults(referenceResult, variables, false);
+ }
+
+ bool result = false;
+ if (m_testParams.fuzzyComparison)
+ {
+ result = tcu::fuzzyCompare(m_context.getTestContext().getLog(),
+ "Fuzzy Compare", "Comparison result", *referenceResult.get(), *programResult.get(), 0.02f, tcu::COMPARE_LOG_EVERYTHING);
+ }
+ else
+ {
+ result = tcu::floatThresholdCompare(m_context.getTestContext().getLog(),
+ "Float Threshold Compare", "Comparison result", *referenceResult.get(), *programResult.get(), tcu::Vec4(0.02f, 0.02f, 0.02f, 0.02f), tcu::COMPARE_LOG_EVERYTHING);
+ }
+
+ if (m_testParams.allowVertexStoring)
+ {
+ result = verifyVertexWriteResults(variables);
+ }
+
+ return result;
+}
+
+void CommonDescriptorInstance::iterateCollectResults (ut::UpdatablePixelBufferAccessPtr& result,
+ const IterateCommonVariables& variables,
+ bool fromTest)
+{
+ if (fromTest)
+ {
+ result = commandReadFrameBuffer(*variables.commandBuffer, variables.frameBuffer);
+ }
+ else
+ {
+ result = ut::UpdatablePixelBufferAccessPtr(new ut::PixelBufferAccessAllocation(vk::mapVkFormat(m_colorFormat), m_testParams.frameResolution));
+
+ for (deUint32 y = 0, pixelNum = 0; y < m_testParams.frameResolution.height; ++y)
+ {
+ for (deUint32 x = 0; x < m_testParams.frameResolution.width; ++x, ++pixelNum)
+ {
+ const float component = m_colorScheme[(pixelNum % variables.validDescriptorCount) % m_schemeSize];
+ result->setPixel(tcu::Vec4(component, component, component, 1.0f), x, y);
+ }
+ }
+ }
+}
+
+Move<VkCommandBuffer> CommonDescriptorInstance::createCmdBuffer (void)
+{
+ return vk::allocateCommandBuffer(m_vki, m_vkd, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+}
+
+Move<VkFence> CommonDescriptorInstance::commandSubmit (VkCommandBuffer cmd)
+{
+ Move<VkFence> fence(vk::createFence(m_vki, m_vkd));
+
+ const VkSubmitInfo submitInfo =
+ {
+ VK_STRUCTURE_TYPE_SUBMIT_INFO, // sType
+ DE_NULL, // pNext
+ 0u, // waitSemaphoreCount
+ static_cast<VkSemaphore*>(DE_NULL), // pWaitSemaphores
+ static_cast<const VkPipelineStageFlags*>(DE_NULL), // pWaitDstStageMask
+ 1u, // commandBufferCount
+ &cmd, // pCommandBuffers
+ 0u, // signalSemaphoreCount
+ static_cast<VkSemaphore*>(DE_NULL) // pSignalSemaphores
+ };
+
+ VK_CHECK(m_vki.queueSubmit(m_queue, 1u, &submitInfo, *fence));
+
+ return fence;
+}
+
+bool CommonDescriptorInstance::verifyVertexWriteResults(IterateCommonVariables& variables)
+{
+ DE_UNREF(variables);
+ return true;
+}
+
+void CommonDescriptorInstance::commandBindPipeline (VkCommandBuffer commandBuffer,
+ VkPipeline pipeline)
+{
+ const VkPipelineBindPoint pipelineBindingPoint = (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
+ m_vki.cmdBindPipeline(commandBuffer, pipelineBindingPoint, pipeline);
+}
+
+void CommonDescriptorInstance::commandBindVertexAttributes (VkCommandBuffer commandBuffer,
+ const ut::BufferHandleAllocSp& vertexAttributesBuffer)
+{
+ const VkDeviceSize offsets[] = { 0u };
+ const VkBuffer buffers[] = { *vertexAttributesBuffer->buffer };
+ m_vki.cmdBindVertexBuffers(commandBuffer, 0u, 1u, buffers, offsets);
+}
+
+void CommonDescriptorInstance::commandBindDescriptorSets (VkCommandBuffer commandBuffer,
+ VkPipelineLayout pipelineLayout,
+ VkDescriptorSet descriptorSet,
+ deUint32 descriptorSetIndex)
+{
+ const VkPipelineBindPoint pipelineBindingPoint = (m_testParams.stageFlags & VK_SHADER_STAGE_COMPUTE_BIT) ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS;
+ m_vki.cmdBindDescriptorSets(commandBuffer, pipelineBindingPoint, pipelineLayout, descriptorSetIndex, 1u, &descriptorSet, 0u, static_cast<deUint32*>(DE_NULL));
+}
+
+ut::UpdatablePixelBufferAccessPtr
+CommonDescriptorInstance::commandReadFrameBuffer (VkCommandBuffer commandBuffer,
+ const ut::FrameBufferSp& frameBuffer)
+{
+ ut::BufferHandleAllocSp frameBufferContent;
+ commandReadFrameBuffer(frameBufferContent, commandBuffer, frameBuffer);
+ return ut::UpdatablePixelBufferAccessPtr(new ut::PixelBufferAccessBuffer(
+ m_vkd, m_vki, vk::mapVkFormat(m_colorFormat), m_testParams.frameResolution,
+ de::SharedPtr< Move<VkBuffer> >(new Move<VkBuffer>(frameBufferContent->buffer)),
+ de::SharedPtr< de::MovePtr<Allocation> >(new de::MovePtr<Allocation>(frameBufferContent->alloc))));
+}
+
+void CommonDescriptorInstance::commandReadFrameBuffer (ut::BufferHandleAllocSp& content,
+ VkCommandBuffer commandBuffer,
+ const ut::FrameBufferSp& frameBuffer)
+{
+ Move<VkBuffer> buffer;
+ de::MovePtr<Allocation> allocation;
+
+ const VkDeviceSize bufferSize = ut::computeImageSize(frameBuffer->image);
+
+ // create a buffer and an host allocation for it
+ {
+ const VkBufferCreateInfo bufferCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ 0u, // flags
+ bufferSize, // size
+ VK_BUFFER_USAGE_TRANSFER_DST_BIT, // usage
+ VK_SHARING_MODE_EXCLUSIVE, // sharingMode
+ 1u, // queueFamilyIndexCoun
+ &m_queueFamilyIndex // pQueueFamilyIndices
+ };
+
+ buffer = vk::createBuffer(m_vki, m_vkd, &bufferCreateInfo);
+ const VkMemoryRequirements memRequirements(vk::getBufferMemoryRequirements(m_vki, m_vkd, *buffer));
+ allocation = m_allocator.allocate(memRequirements, MemoryRequirement::HostVisible);
+
+ VK_CHECK(m_vki.bindBufferMemory(m_vkd, *buffer, allocation->getMemory(), allocation->getOffset()));
+ }
+
+ const VkImage& image = *frameBuffer->image->image;
+
+ VkImageSubresourceRange subresourceRange =
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
+ 0u, // baseMipLevel
+ 1u, // levelCount
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ };
+
+ const VkImageMemoryBarrier imageBarrier =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask;
+ VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask;
+ VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ image, // image;
+ subresourceRange, // subresourceRange;
+ };
+
+ const VkBufferImageCopy copyRegion =
+ {
+ 0u, // bufferOffset
+ frameBuffer->image->extent.width, // bufferRowLength
+ frameBuffer->image->extent.height, // bufferImageHeight
+ { // VkImageSubresourceLayers
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspect
+ 0u, // mipLevel
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ },
+ { 0, 0, 0 }, // imageOffset
+ frameBuffer->image->extent // imageExtent
+ };
+
+ const VkBufferMemoryBarrier bufferBarrier =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask;
+ VK_ACCESS_HOST_READ_BIT, // dstAccessMask;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ *buffer, // buffer;
+ 0u, // offset;
+ bufferSize // size;
+ };
+
+ m_vki.cmdPipelineBarrier(commandBuffer, // commandBuffer
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask, dstStageMask
+ (VkDependencyFlags)0, // dependencyFlags
+ 0u, (const VkMemoryBarrier*)DE_NULL, // memoryBarrierCount, pMemoryBarriers
+ 0u, (const VkBufferMemoryBarrier*)DE_NULL, // bufferBarrierCount, pBufferBarriers
+ 1u, &imageBarrier); // imageBarrierCount, pImageBarriers
+
+ m_vki.cmdCopyImageToBuffer(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *buffer, 1u, ©Region);
+
+ m_vki.cmdPipelineBarrier(commandBuffer,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT,
+ (VkDependencyFlags)0,
+ 0, DE_NULL,
+ 1, &bufferBarrier,
+ 0u, DE_NULL);
+
+ content = ut::BufferHandleAllocSp(new ut::BufferHandleAlloc(buffer, allocation));
+}
+
+std::string CommonDescriptorInstance::getColorAccess (VkDescriptorType descriptorType,
+ const char* indexVariableName,
+ bool usesMipMaps)
+{
+ std::string text;
+ std::map<std::string, std::string> vars;
+ vars["INDEX"] = indexVariableName;
+
+ switch (descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ text = "data[nonuniformEXT(${INDEX})].c";
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ text = "data[nonuniformEXT(${INDEX})].cold";
+ break;
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ text = "subpassLoad(data[nonuniformEXT(${INDEX})]).rgba";
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ text = "texelFetch(data[nonuniformEXT(${INDEX})], 0)";
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ text = "imageLoad(data[nonuniformEXT(${INDEX})], 0)";
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ text = usesMipMaps
+ ? "textureLod(sampler2D(tex[0], data[nonuniformEXT(${INDEX})]), normalpos, 1)"
+ : "texture( sampler2D(tex[0], data[nonuniformEXT(${INDEX})]), normalpos )";
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ text = usesMipMaps
+ ? "textureLod( sampler2D(data[nonuniformEXT(${INDEX})], samp[0]), vec2(0,0), textureQueryLevels(sampler2D(data[nonuniformEXT(${INDEX})], samp[0]))-1)"
+ : "texture( sampler2D(data[nonuniformEXT(${INDEX})], samp[0]), vec2(0,0) )";
+ break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ text = usesMipMaps
+ ? "textureLod( data[nonuniformEXT(${INDEX})], uvec2(0,0), textureQueryLevels(data[nonuniformEXT(${INDEX})])-1)"
+ : "texture( data[nonuniformEXT(${INDEX})], uvec2(0,0) )";
+ break;
+ default:
+ TCU_THROW(InternalError, "Not implemented descriptor type");
+ }
+
+ return tcu::StringTemplate(text).specialize(vars);
+}
+
+std::string CommonDescriptorInstance::getFragmentReturnSource (const std::string& colorAccess)
+{
+ return " FragColor = " + colorAccess + ";\n";
+}
+
+std::string CommonDescriptorInstance::getFragmentLoopSource (const std::string& colorAccess1,
+ const std::string& colorAccess2)
+{
+ std::map < std::string, std::string > vars;
+ vars["COLOR_ACCESS_1"] = colorAccess1;
+ vars["COLOR_ACCESS_2"] = colorAccess2;
+
+ const char* s =
+ " vec4 sumClr1 = vec4(0,0,0,0); \n"
+ " vec4 sumClr2 = vec4(0,0,0,0); \n"
+ " for (int i = pc.lowerBound; i < pc.upperBound; ++i) \n"
+ " {\n"
+ " int loopIdx = texelFetch(iter, i).x; \n"
+ " sumClr1 += ${COLOR_ACCESS_2} + ${COLOR_ACCESS_1}; \n"
+ " sumClr2 += ${COLOR_ACCESS_2}; \n"
+ " }\n"
+ " FragColor = vec4(((sumClr1 - sumClr2) / float(pc.upperBound - pc.lowerBound)).rgb, 1); \n";
+
+ return tcu::StringTemplate(s).specialize(vars);
+}
+
+bool CommonDescriptorInstance::performWritesInVertex (VkDescriptorType descriptorType)
+{
+ bool result = false;
+
+ switch (descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ result = true;
+ break;
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
+std::string CommonDescriptorInstance::getShaderSource (VkShaderStageFlagBits shaderType,
+ const TestCaseParams& testCaseParams,
+ bool allowVertexStoring)
+{
+ std::stringstream s;
+
+ s << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << '\n';
+ s << "#extension GL_EXT_nonuniform_qualifier : require \n";
+
+ if (testCaseParams.calculateInLoop)
+ {
+ s << "layout(push_constant) uniform Block { int lowerBound, upperBound; } pc;\n";
+ s << substBinding(BINDING_DescriptorEnumerator,
+ "layout(set=1,binding=${?}) uniform isamplerBuffer iter; \n");
+ }
+
+ switch (testCaseParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ s << substBinding(BINDING_StorageBuffer,
+ "layout(set=0,binding=${?}) buffer Data { vec4 cnew, cold; } data[]; \n");
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ s << substBinding(BINDING_StorageBufferDynamic,
+ "layout(set=0,binding=${?}) buffer Data { vec4 cnew, cold; } data[]; \n");
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ s << substBinding(BINDING_UniformBuffer,
+ "layout(set=0,binding=${?}) uniform Data { vec4 c; } data[]; \n");
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ s << substBinding(BINDING_UniformBufferDynamic,
+ "layout(set=0,binding=${?}) uniform Data { vec4 c; } data[]; \n");
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ s << substBinding(BINDING_StorageTexelBuffer,
+ "layout(set=0,binding=${?},rgba32f) uniform imageBuffer data[];\n");
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ s << "#extension GL_EXT_texture_buffer : require \n";
+ s << substBinding(BINDING_UniformTexelBuffer,
+ "layout(set=0,binding=${?}) uniform samplerBuffer data[];\n");
+ break;
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ // Left for the consistent of code.
+ // Header is set one swicth below
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ s << "#extension GL_EXT_texture_buffer : require \n";
+ s << substBinding(BINDING_SampledImage,
+ "layout(set=0,binding=${?}) uniform texture2D ${VAR}[${*}];\n", 1, "tex");
+ s << substBinding(BINDING_Sampler,
+ "layout(set=0,binding=${?}) uniform sampler ${VAR}[${*}];\n");
+ break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ s << "#extension GL_EXT_texture_buffer : require \n";
+ s << substBinding(BINDING_Sampler,
+ "layout(set=0,binding=${?}) uniform sampler ${VAR}[${*}];\n", 1, "samp");
+ s << substBinding(BINDING_SampledImage,
+ "layout(set=0,binding=${?}) uniform texture2D ${VAR}[${*}];\n");
+ break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ s << "#extension GL_EXT_texture_buffer : require \n";
+ s << substBinding(BINDING_CombinedImageSampler,
+ "layout(set=0,binding=${?}) uniform sampler2D data[];\n");
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ s << "layout(local_size_x=1,local_size_y=1,local_size_z=1) in; \n";
+ s << substBinding(BINDING_StorageImage + 1,
+ "layout(r32ui,set=0,binding=${?}) uniform uimage2D idxs; \n");
+ s << substBinding(BINDING_StorageImage,
+ "layout(r32ui,set=0,binding=${?}) uniform uimage2D data[]; \n");
+ break;
+ default:
+ TCU_THROW(InternalError, "Not implemented descriptor type");
+ }
+
+ switch (shaderType)
+ {
+ case VK_SHADER_STAGE_VERTEX_BIT: s << getVertexShaderProlog(); break;
+ case VK_SHADER_STAGE_FRAGMENT_BIT:
+ {
+ if (testCaseParams.descriptorType == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
+ {
+ s << substBinding(BINDING_InputAttachment,
+ "layout(input_attachment_index=1,set=0,binding=${?}) uniform subpassInput data[]; \n");
+ }
+ s << getFragmentShaderProlog();
+ }
+ break;
+ case VK_SHADER_STAGE_COMPUTE_BIT:
+ break;
+ default:
+ TCU_THROW(InternalError, "Not implemented shader stage");
+ }
+
+ switch (shaderType)
+ {
+ case VK_SHADER_STAGE_VERTEX_BIT:
+ {
+ switch (testCaseParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ if (allowVertexStoring)
+ s << " if (gIndex != 0) data[nonuniformEXT(gIndex)].cnew = data[nonuniformEXT(rIndex)].cold; \n";
+ break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ if (allowVertexStoring)
+ s << " if (gIndex != 0) imageStore(data[nonuniformEXT(gIndex)], 1, imageLoad(data[nonuniformEXT(rIndex)], 0)); \n";
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ break;
+
+ default:
+ TCU_THROW(InternalError, "Not implemented descriptor type");
+ }
+ }
+ break;
+
+ case VK_SHADER_STAGE_FRAGMENT_BIT:
+ {
+ switch (testCaseParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ {
+ if (testCaseParams.calculateInLoop)
+ s << getFragmentLoopSource(
+ getColorAccess(testCaseParams.descriptorType, "rIndex", false),
+ getColorAccess(testCaseParams.descriptorType, "loopIdx", false));
+ else
+ s << getFragmentReturnSource(getColorAccess(testCaseParams.descriptorType, "rIndex", false));
+ }
+ break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ if (testCaseParams.calculateInLoop)
+ s << getFragmentLoopSource(
+ getColorAccess(testCaseParams.descriptorType, "rIndex", testCaseParams.usesMipMaps),
+ getColorAccess(testCaseParams.descriptorType, "loopIdx", testCaseParams.usesMipMaps));
+ else
+ s << getFragmentReturnSource(getColorAccess(testCaseParams.descriptorType, "rIndex", testCaseParams.usesMipMaps));
+ break;
+ default: TCU_THROW(InternalError, "Not implemented descriptor type");
+ }
+ }
+ break;
+
+ case VK_SHADER_STAGE_COMPUTE_BIT: // VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
+ s << "void main(void)\n{\n";
+ if (testCaseParams.calculateInLoop)
+ s << " for (int i = pc.lowerBound; i < pc.upperBound; ++i) \n"
+ " imageAtomicAdd(data[nonuniformEXT(texelFetch(iter, i).x)], ivec2(0, 0), 1); \n";
+ else
+ s << " uvec4 c = imageLoad(idxs, ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y)); \n"
+ " imageAtomicAdd( data[nonuniformEXT(c.r)], ivec2(0, 0), 1); \n";
+ break;
+
+ default: TCU_THROW(InternalError, "Not implemented shader stage");
+ }
+
+ s << getShaderEpilog();
+
+ return s.str();
+}
+
+class StorageBufferInstance : virtual public CommonDescriptorInstance
+{
+public:
+ StorageBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+protected:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+
+ virtual bool verifyVertexWriteResults (IterateCommonVariables& variables);
+};
+
+StorageBufferInstance::StorageBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ BINDING_StorageBuffer,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const vk::VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderStorageBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over storage buffer descriptor arrays is not supported.");
+
+ if (m_testParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingStorageBufferUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for storage buffer descriptors is not supported.");
+ }
+}
+
+void StorageBufferInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ BindingStorageBuffer::Data data;
+
+ bool vertexStores = false;
+ {
+ ut::DeviceProperties dp(m_context);
+ vertexStores = dp.physicalDeviceFeatures().vertexPipelineStoresAndAtomics != DE_FALSE;
+ }
+ const deUint32 alignment = static_cast<deUint32>(ut::DeviceProperties(m_context).physicalDeviceProperties().limits.minStorageBufferOffsetAlignment);
+ createBuffers(variables.descriptorsBufferInfos, variables.descriptorsBuffer, variables.validDescriptorCount, sizeof(data), alignment, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
+
+ unsigned char* buffer = static_cast<unsigned char*>(variables.descriptorsBuffer->alloc->getHostPtr());
+ for (deUint32 infoIdx = 0; infoIdx < variables.validDescriptorCount; ++infoIdx)
+ {
+ const float component = m_colorScheme[infoIdx % m_schemeSize];
+ const tcu::Vec4 color (component, component, component, 1.0f);
+ VkDescriptorBufferInfo& info = variables.descriptorsBufferInfos[infoIdx];
+ data.cnew = vertexStores ? m_clearColor : color;
+ data.cold = color;
+
+ deMemcpy(buffer + info.offset, &data, sizeof(data));
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+
+ variables.dataAlignment = deAlign64(sizeof(data), alignment);
+}
+
+bool StorageBufferInstance::verifyVertexWriteResults (IterateCommonVariables& variables)
+{
+ const tcu::Vec4 threshold (0.002f, 0.002f, 0.002f, 0.002f);
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+
+ unsigned char* buffer = static_cast<unsigned char*>(variables.descriptorsBuffer->alloc->getHostPtr());
+ BindingStorageBuffer::Data data;
+ for (deUint32 primeIdx = 0; primeIdx < variables.validDescriptorCount; ++primeIdx)
+ {
+ const deUint32 prime = primes[primeIdx];
+ const float component = m_colorScheme[(prime % variables.validDescriptorCount) % m_schemeSize];
+ const tcu::Vec4 referenceValue(component, component, component, 1.0f);
+
+ VkDescriptorBufferInfo& info = variables.descriptorsBufferInfos[primeIdx];
+ deMemcpy(&data, buffer + info.offset, sizeof(data));
+ const tcu::Vec4 realValue = data.cnew;
+
+ const tcu::Vec4 diff = tcu::absDiff(referenceValue, realValue);
+ if (!tcu::boolAll(tcu::lessThanEqual(diff, threshold)))
+ return false;
+ }
+ return true;
+}
+
+class UniformBufferInstance : virtual public CommonDescriptorInstance
+{
+public:
+ UniformBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+protected:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+};
+
+UniformBufferInstance::UniformBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ BINDING_UniformBuffer,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderUniformBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing for uniform buffer descriptor arrays is not supported.");
+
+ if (m_testParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingUniformBufferUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for uniform buffer descriptors is not supported.");
+ }
+}
+
+void UniformBufferInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ BindingUniformBuffer::Data data;
+
+ const deUint32 alignment = static_cast<deUint32>(ut::DeviceProperties(m_context).physicalDeviceProperties().limits.minUniformBufferOffsetAlignment);
+ createBuffers(variables.descriptorsBufferInfos, variables.descriptorsBuffer, variables.validDescriptorCount, sizeof(data), alignment, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
+
+ unsigned char* buffer = static_cast<unsigned char*>(variables.descriptorsBuffer->alloc->getHostPtr());
+ for (deUint32 infoIdx = 0; infoIdx < variables.validDescriptorCount; ++infoIdx)
+ {
+ const float component = m_colorScheme[infoIdx % m_schemeSize];
+ VkDescriptorBufferInfo& info = variables.descriptorsBufferInfos[infoIdx];
+ data.c = tcu::Vec4(component, component, component, 1.0f);
+ deMemcpy(buffer + info.offset, &data, sizeof(data));
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+
+ variables.dataAlignment = deAlign64(sizeof(data), alignment);
+}
+
+class StorageTexelInstance : public CommonDescriptorInstance
+{
+public:
+ StorageTexelInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+
+ virtual bool verifyVertexWriteResults (IterateCommonVariables& variables);
+};
+
+StorageTexelInstance::StorageTexelInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+ BINDING_StorageTexelBuffer,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderStorageTexelBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing for storage texel buffer descriptor arrays is not supported.");
+
+ if (m_testParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingStorageTexelBufferUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for storage texel buffer descriptors is not supported.");
+ }
+}
+
+void StorageTexelInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ const VkExtent3D imageExtent = { 4, 4, 1 };
+ const deUint32 imageSize = ut::computeImageSize(imageExtent, m_colorFormat);
+
+ createBuffers(variables.descriptorsBufferInfos, variables.descriptorsBuffer, variables.validDescriptorCount, imageSize, sizeof(tcu::Vec4), VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
+ createBuffersViews(variables.descriptorsBufferViews, variables.descriptorsBufferInfos, m_colorFormat);
+
+ for (deUint32 imageIdx = 0; imageIdx < variables.validDescriptorCount; ++imageIdx)
+ {
+ const float component = m_colorScheme[imageIdx % m_schemeSize];
+ const PixelBufferAccess pa = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+
+ tcu::clear(pa, m_clearColor);
+ pa.setPixel(tcu::Vec4(component, component, component, 1.0f), 0, 0);
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+}
+
+bool StorageTexelInstance::verifyVertexWriteResults(IterateCommonVariables& variables)
+{
+ const VkExtent3D imageExtent = { 4, 4, 1 };
+ const tcu::Vec4 threshold (0.002f, 0.002f, 0.002f, 0.002f);
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+
+ for (deUint32 primeIdx = 0; primeIdx < variables.validDescriptorCount; ++primeIdx)
+ {
+ const deUint32 prime = primes[primeIdx];
+ const float component = m_colorScheme[( prime % variables.validDescriptorCount ) % m_schemeSize];
+ const tcu::Vec4 referenceValue(component, component, component, 1.0f);
+
+ const PixelBufferAccess pa = getPixelAccess(primeIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+ const tcu::Vec4 realValue = pa.getPixel(1, 0);
+
+ const tcu::Vec4 diff = tcu::absDiff(referenceValue, realValue);
+ if (!tcu::boolAll(tcu::lessThanEqual(diff, threshold)))
+ return false;
+ }
+ return true;
+}
+
+class UniformTexelInstance : public CommonDescriptorInstance
+{
+public:
+ UniformTexelInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+};
+
+UniformTexelInstance::UniformTexelInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+ BINDING_UniformTexelBuffer,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderUniformTexelBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing for uniform texel buffer descriptor arrays is not supported.");
+
+ if (m_testParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingUniformTexelBufferUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for uniform texel buffer descriptors is not supported.");
+ }
+}
+
+void UniformTexelInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ const VkExtent3D imageExtent = { 4, 4, 1 };
+ const deUint32 imageSize = ut::computeImageSize(imageExtent, m_colorFormat);
+
+ createBuffers(variables.descriptorsBufferInfos, variables.descriptorsBuffer, variables.validDescriptorCount, imageSize, sizeof(tcu::Vec4), VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT);
+ createBuffersViews(variables.descriptorsBufferViews, variables.descriptorsBufferInfos, m_colorFormat);
+
+ for (deUint32 imageIdx = 0; imageIdx < variables.validDescriptorCount; ++imageIdx)
+ {
+ const float component = m_colorScheme[imageIdx % m_schemeSize];
+ const PixelBufferAccess pa = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+
+ tcu::clear(pa, tcu::Vec4(component, component, component, 1.0f));
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+}
+
+class DynamicBuffersInstance : virtual public CommonDescriptorInstance
+{
+public:
+ DynamicBuffersInstance (Context& context,
+ const TestParams& testParams)
+ : CommonDescriptorInstance(context, testParams) {}
+
+protected:
+ virtual tcu::TestStatus iterate (void);
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+};
+
+void DynamicBuffersInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.dataAlignment);
+
+ VkDescriptorBufferInfo bufferInfo =
+ {
+ *variables.descriptorsBuffer.get()->buffer,
+ 0, // always 0, it will be taken from pDynamicOffsets
+ variables.dataAlignment
+ };
+
+ VkWriteDescriptorSet updateInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ m_testParams.descriptorBinding, // descriptorBinding;
+ 0, // to be set in below loop // dstArrayElement
+ 1u, // descriptorCount
+ m_testParams.descriptorType, // descriptorType
+ DE_NULL, // pImageInfo
+ &bufferInfo, // pBufferInfo
+ DE_NULL // pTexelBufferView
+ };
+
+ deUint32 descIdx = 0;
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+ for (deUint32 validIdx = 0; validIdx < variables.validDescriptorCount; ++validIdx)
+ {
+ for (; descIdx < primes[validIdx]; ++descIdx)
+ {
+ updateInfo.dstArrayElement = descIdx;
+ m_vki.updateDescriptorSets (m_vkd, 1u, &updateInfo, 0u, DE_NULL);
+ }
+
+ updateInfo.dstArrayElement = primes[validIdx];
+ m_vki.updateDescriptorSets (m_vkd, 1u, &updateInfo, 0u, DE_NULL);
+
+ ++descIdx;
+ }
+ for (; descIdx < variables.availableDescriptorCount; ++descIdx)
+ {
+ updateInfo.dstArrayElement = descIdx;
+ m_vki.updateDescriptorSets(m_vkd, 1u, &updateInfo, 0u, DE_NULL);
+ }
+}
+
+tcu::TestStatus DynamicBuffersInstance::iterate (void)
+{
+ IterateCommonVariables v;
+ iterateCommandBegin (v);
+
+ DE_ASSERT(v.dataAlignment);
+
+ std::vector<deUint32> dynamicOffsets;
+
+ deUint32 descIdx = 0;
+ const std::vector<deUint32> primes = ut::generatePrimes(v.availableDescriptorCount);
+ for (deUint32 validIdx = 0; validIdx < v.validDescriptorCount; ++validIdx)
+ {
+ for (; descIdx < primes[validIdx]; ++descIdx)
+ {
+ dynamicOffsets.push_back(0);
+ }
+
+ dynamicOffsets.push_back(static_cast<deUint32>(validIdx * v.dataAlignment));
+
+ ++descIdx;
+ }
+ for (; descIdx < v.availableDescriptorCount; ++descIdx)
+ {
+ dynamicOffsets.push_back(0);
+ }
+
+ // Unfortunatelly not lees and not more, only exactly
+ DE_ASSERT(dynamicOffsets.size() == v.availableDescriptorCount);
+
+ const VkDescriptorSet descriptorSets[] = { *v.descriptorSet };
+
+ m_vki.cmdBindDescriptorSets(
+ *v.commandBuffer, // commandBuffer
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // pipelineBindPoint
+ *v.pipelineLayout, // layout
+ 0u, // firstSet
+ DE_LENGTH_OF_ARRAY(descriptorSets), // descriptorSetCount
+ descriptorSets, // pDescriptorSets
+ v.availableDescriptorCount, // dynamicOffsetCount
+ dynamicOffsets.data()); // pDynamicOffsets
+
+ vk::beginRenderPass (m_vki, *v.commandBuffer, *v.renderPass, *v.frameBuffer->buffer, v.renderArea, m_clearColor);
+ m_vki.cmdDraw (*v.commandBuffer, v.vertexCount, 1, 0, 0);
+ vk::endRenderPass (m_vki, *v.commandBuffer);
+
+ return (iterateCommandEnd(v) ? tcu::TestStatus::pass : tcu::TestStatus::fail)("");
+}
+
+class DynamicStorageBufferInstance : public DynamicBuffersInstance, public StorageBufferInstance
+{
+public:
+ DynamicStorageBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+ tcu::TestStatus iterate (void);
+ void createAndPopulateDescriptors (IterateCommonVariables& variables);
+ void updateDescriptors (IterateCommonVariables& variables);
+ bool verifyVertexWriteResults (IterateCommonVariables& variables);
+};
+
+DynamicStorageBufferInstance::DynamicStorageBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+ BINDING_StorageBufferDynamic,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams)),
+ DynamicBuffersInstance(context, m_testParams), StorageBufferInstance(context, testCaseParams)
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderStorageBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over storage buffer dynamic descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ TCU_THROW(NotSupportedError, "Update after bind for storage buffer dynamic descriptors is not supported.");
+ }
+}
+
+tcu::TestStatus DynamicStorageBufferInstance::iterate(void)
+{
+ return DynamicBuffersInstance::iterate();
+}
+
+void DynamicStorageBufferInstance::createAndPopulateDescriptors(IterateCommonVariables& variables)
+{
+ StorageBufferInstance::createAndPopulateDescriptors(variables);
+}
+
+void DynamicStorageBufferInstance::updateDescriptors(IterateCommonVariables& variables)
+{
+ DynamicBuffersInstance::updateDescriptors(variables);
+}
+
+bool DynamicStorageBufferInstance::verifyVertexWriteResults(IterateCommonVariables& variables)
+{
+ return StorageBufferInstance::verifyVertexWriteResults(variables);
+}
+
+class DynamicUniformBufferInstance : public DynamicBuffersInstance, public UniformBufferInstance
+{
+public:
+ DynamicUniformBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+ tcu::TestStatus iterate(void);
+ void createAndPopulateDescriptors(IterateCommonVariables& variables);
+ void updateDescriptors(IterateCommonVariables& variables);
+};
+
+DynamicUniformBufferInstance::DynamicUniformBufferInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ BINDING_UniformBufferDynamic,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ false,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams)),
+ DynamicBuffersInstance(context, m_testParams), UniformBufferInstance(context, testCaseParams)
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderUniformBufferArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over uniform buffer dynamic descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ TCU_THROW(NotSupportedError, "Update after bind for uniform buffer dynamic descriptors is not supported.");
+ }
+}
+
+tcu::TestStatus DynamicUniformBufferInstance::iterate(void)
+{
+ return DynamicBuffersInstance::iterate();
+}
+
+void DynamicUniformBufferInstance::createAndPopulateDescriptors(IterateCommonVariables& variables)
+{
+ UniformBufferInstance::createAndPopulateDescriptors(variables);
+}
+
+void DynamicUniformBufferInstance::updateDescriptors(IterateCommonVariables& variables)
+{
+ DynamicBuffersInstance::updateDescriptors(variables);
+}
+
+class InputAttachmentInstance : public CommonDescriptorInstance
+{
+public:
+ InputAttachmentInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual Move<VkRenderPass> createRenderPass (const IterateCommonVariables& variables);
+ virtual void createFramebuffer (ut::FrameBufferSp& frameBuffer,
+ VkRenderPass renderPass,
+ const IterateCommonVariables& variables);
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+};
+
+InputAttachmentInstance::InputAttachmentInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+ BINDING_InputAttachment,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ true,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+
+ if (!(feats.shaderInputAttachmentArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over input attachment descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ TCU_THROW(NotSupportedError, "Update after bind for input attachment descriptors is not supported.");
+ }
+}
+
+void InputAttachmentInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, variables.descriptorsBuffer,
+ (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT), m_testParams.frameResolution, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, variables.validDescriptorCount);
+ createImagesViews(variables.descriptorImageViews, variables.descriptorsImages, m_colorFormat);
+
+ for (deUint32 descriptorIdx = 0; descriptorIdx < variables.validDescriptorCount; ++descriptorIdx)
+ {
+ const float component = m_colorScheme[descriptorIdx % m_schemeSize];
+ const tcu::PixelBufferAccess pa = getPixelAccess(descriptorIdx, m_testParams.frameResolution, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+ tcu::clear(pa, tcu::Vec4(component, component, component, 1.0f));
+ }
+}
+
+Move<VkRenderPass> InputAttachmentInstance::createRenderPass (const IterateCommonVariables& variables)
+{
+ std::vector<VkAttachmentDescription> attachmentDescriptions;
+ std::vector<VkAttachmentReference> inputAttachmentRefs;
+
+ const VkAttachmentDescription colorAttachmentDescription =
+ {
+ (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags;
+ m_colorFormat, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
+ };
+ const VkAttachmentReference colorAttachmentRef =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+ attachmentDescriptions.push_back(colorAttachmentDescription);
+
+ // build input atachments
+ {
+ const deUint32 inputCount = static_cast<deUint32>(variables.descriptorImageViews.size());
+ for (deUint32 inputIdx = 0; inputIdx < inputCount; ++inputIdx)
+ {
+ const VkAttachmentDescription inputAttachmentDescription =
+ {
+ VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT, // VkAttachmentDescriptionFlags flags;
+ variables.descriptorsImages[inputIdx]->format, // VkFormat format;
+ VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ variables.descriptorsImages[inputIdx]->layout, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_GENERAL, // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentReference inputAttachmentRef =
+ {
+ inputIdx + 1, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_GENERAL // VkImageLayout layout;
+ };
+
+ inputAttachmentRefs.push_back(inputAttachmentRef);
+ attachmentDescriptions.push_back(inputAttachmentDescription);
+ }
+ }
+
+ const VkSubpassDescription subpassDescription =
+ {
+ (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ static_cast<deUint32>(inputAttachmentRefs.size()), // deUint32 inputAttachmentCount;
+ inputAttachmentRefs.data(), // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments;
+ DE_NULL, // const VkAttachmentReference* pResolveAttachments;
+ DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const deUint32* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags;
+ static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
+ attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ return vk::createRenderPass(m_vki, m_vkd, &renderPassInfo);
+}
+
+void InputAttachmentInstance::createFramebuffer (ut::FrameBufferSp& frameBuffer,
+ VkRenderPass renderPass,
+ const IterateCommonVariables& variables)
+{
+ std::vector<VkImageView> inputAttachments;
+ const deUint32 viewCount = static_cast<deUint32>(variables.descriptorImageViews.size());
+ inputAttachments.resize(viewCount);
+ for (deUint32 viewIdx = 0; viewIdx < viewCount; ++viewIdx)
+ {
+ inputAttachments[viewIdx] = **variables.descriptorImageViews[viewIdx];
+ }
+ ut::createFrameBuffer(frameBuffer, m_context, m_testParams.frameResolution, m_colorFormat, renderPass, viewCount, inputAttachments.data());
+}
+
+class SamplerInstance : public CommonDescriptorInstance
+{
+public:
+ SamplerInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+};
+
+SamplerInstance::SamplerInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_SAMPLER,
+ BINDING_Sampler,
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ BINDING_SampledImage,
+ true,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+ // Note: common flags for SAMPLER, SAMPLED_IMAGE, COMBINED_IMAGE_SAMPLER
+
+ if (!(feats.shaderSampledImageArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over sampler descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingSampledImageUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for sampler descriptors is not supported.");
+ }
+}
+
+void SamplerInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.descriptorsImages.size() == 1);
+ DE_ASSERT(variables.descriptorImageViews.size() == 1);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == 1);
+ DE_ASSERT(m_testParams.additionalDescriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
+ DE_ASSERT(variables.descriptorSamplers.size() == variables.validDescriptorCount);
+
+ // update an image
+ {
+ const VkDescriptorImageInfo imageInfo =
+ {
+ static_cast<VkSampler>(0),
+ **variables.descriptorImageViews[0],
+ VK_IMAGE_LAYOUT_GENERAL
+ };
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ BINDING_SampledImage, // descriptorBinding;
+ 0, // elementIndex
+ 1u, // descriptorCount
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, // descriptorType
+ &imageInfo, // pImageInfo
+ DE_NULL, // pBufferInfo
+ DE_NULL // pTexelBufferView
+ };
+
+ m_vki.updateDescriptorSets(m_vkd, 1u, &writeInfo, 0u, DE_NULL);
+ }
+
+ // update samplers
+ CommonDescriptorInstance::updateDescriptors(variables);
+}
+
+void SamplerInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.descriptorsImages.size() == 0);
+ DE_ASSERT(variables.descriptorImageViews.size() == 0);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == 0);
+ DE_ASSERT(variables.descriptorSamplers.size() == 0);
+
+ // create and populate an image
+ {
+ VkExtent3D imageExtent = m_testParams.frameResolution;
+ if (m_testParams.usesMipMaps)
+ {
+ imageExtent.width *= 2;
+ imageExtent.height *= 2;
+ };
+
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, variables.descriptorsBuffer,
+ (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT), imageExtent, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, 1, m_testParams.usesMipMaps);
+ createImagesViews(variables.descriptorImageViews, variables.descriptorsImages, m_colorFormat);
+
+ PixelBufferAccess pa = getPixelAccess(0, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, m_testParams.usesMipMaps ? 1 : 0);
+
+ for (deUint32 y = 0, pixelNum = 0; y < m_testParams.frameResolution.height; ++y)
+ {
+ for (deUint32 x = 0; x < m_testParams.frameResolution.width; ++x, ++pixelNum)
+ {
+ const float component = m_colorScheme[(pixelNum % variables.validDescriptorCount) % m_schemeSize];
+ pa.setPixel(tcu::Vec4(component, component, component, 1.0f), x, y);
+ }
+ }
+
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+ }
+
+ const tcu::Sampler sampler(
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapS
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapT
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapR
+ m_testParams.usesMipMaps ? tcu::Sampler::LINEAR_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // minFilter
+ m_testParams.usesMipMaps ? tcu::Sampler::LINEAR_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // magFilter
+ 0.0f, // lodTreshold
+ true); // normalizeCoords
+ const VkSamplerCreateInfo createInfo = vk::mapSampler(sampler, vk::mapVkFormat(m_colorFormat));
+ variables.descriptorSamplers.resize(variables.validDescriptorCount);
+
+ for (deUint32 samplerIdx = 0; samplerIdx < variables.validDescriptorCount; ++samplerIdx)
+ {
+ variables.descriptorSamplers[samplerIdx] = ut::SamplerSp(new Move<VkSampler>(vk::createSampler(m_vki, m_vkd, &createInfo)));
+ }
+}
+
+class SampledImageInstance : public CommonDescriptorInstance
+{
+public:
+ SampledImageInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+};
+
+SampledImageInstance::SampledImageInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ BINDING_SampledImage,
+ VK_DESCRIPTOR_TYPE_SAMPLER,
+ BINDING_Sampler,
+ true,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+ // Note: common flags for SAMPLER, SAMPLED_IMAGE, COMBINED_IMAGE_SAMPLER
+
+ if (!(feats.shaderSampledImageArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over sampled image descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingSampledImageUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for sampled image descriptors is not supported.");
+ }
+}
+
+void SampledImageInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.descriptorSamplers.size() == 1);
+ DE_ASSERT(variables.descriptorsImages.size() == variables.validDescriptorCount);
+ DE_ASSERT(variables.descriptorImageViews.size() == variables.validDescriptorCount);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == variables.validDescriptorCount);
+
+ // update a sampler
+ {
+ const VkDescriptorImageInfo samplerInfo =
+ {
+ **variables.descriptorSamplers[0],
+ static_cast<VkImageView>(0),
+ static_cast<VkImageLayout>(0)
+ };
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ BINDING_Sampler, // descriptorBinding;
+ 0, // elementIndex
+ 1u, // descriptorCount
+ VK_DESCRIPTOR_TYPE_SAMPLER, // descriptorType
+ &samplerInfo, // pImageInfo
+ DE_NULL, // pBufferInfo
+ DE_NULL // pTexelBufferView
+ };
+
+ m_vki.updateDescriptorSets(m_vkd, 1u, &writeInfo, 0u, DE_NULL);
+ }
+
+ // update images
+ CommonDescriptorInstance::updateDescriptors(variables);
+}
+
+void SampledImageInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.descriptorSamplers.size() == 0);
+ DE_ASSERT(variables.descriptorsImages.size() == 0);
+ DE_ASSERT(variables.descriptorImageViews.size() == 0);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == 0);
+
+ // create an only one sampler for all images
+ {
+ const tcu::Sampler sampler(
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapS
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapT
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapR
+ m_testParams.usesMipMaps ? tcu::Sampler::NEAREST_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // minFilter
+ m_testParams.usesMipMaps ? tcu::Sampler::NEAREST_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // magFilter
+ 0.0f, // lodTreshold
+ true); // normalizeCoords
+ const VkSamplerCreateInfo createInfo = vk::mapSampler(sampler, vk::mapVkFormat(m_colorFormat));
+ variables.descriptorSamplers.push_back(ut::SamplerSp(new Move<VkSampler>(vk::createSampler(m_vki, m_vkd, &createInfo))));
+ }
+
+ const VkExtent3D& imageExtent = m_testParams.usesMipMaps ? bigImageExtent : smallImageExtent;
+
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, variables.descriptorsBuffer,
+ (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT), imageExtent, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, variables.validDescriptorCount, m_testParams.usesMipMaps);
+ createImagesViews(variables.descriptorImageViews, variables.descriptorsImages, m_colorFormat);
+
+ PixelBufferAccess pixelAccess;
+ for (deUint32 imageIdx = 0; imageIdx < variables.validDescriptorCount; ++imageIdx)
+ {
+ const float component = m_colorScheme[imageIdx % m_schemeSize];
+
+ if (m_testParams.usesMipMaps)
+ {
+ const deUint32 mipCount = ut::computeMipMapCount(imageExtent);
+ DE_ASSERT(mipCount >= 2);
+ for (deUint32 mipIdx = 0; mipIdx < mipCount; ++mipIdx)
+ {
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, mipIdx);
+ tcu::clear(pixelAccess, m_clearColor);
+ }
+
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, mipCount-1);
+ pixelAccess.setPixel(tcu::Vec4(component, component, component, 1.0f), 0, 0);
+ }
+ else
+ {
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, 0);
+ pixelAccess.setPixel(tcu::Vec4(component, component, component, 1.0f), 0, 0);
+ }
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+}
+
+class CombinedImageInstance : public CommonDescriptorInstance
+{
+public:
+ CombinedImageInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+};
+
+CombinedImageInstance::CombinedImageInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams(VK_SHADER_STAGE_ALL_GRAPHICS,
+ testCaseParams.descriptorType,
+ BINDING_CombinedImageSampler,
+ VK_DESCRIPTOR_TYPE_UNDEFINED,
+ BINDING_Undefined,
+ true,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& feats = dp.descriptorIndexingFeatures();
+ // Note: common flags for SAMPLER, SAMPLED_IMAGE, COMBINED_IMAGE_SAMPLER
+
+ if (!(feats.shaderSampledImageArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over combined image sampler descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ if (!(feats.descriptorBindingSampledImageUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for combined image sampler descriptors is not supported.");
+ }
+}
+
+void CombinedImageInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+ const deUint32 primeCount = static_cast<deUint32>(primes.size());
+
+ DE_ASSERT(variables.descriptorSamplers.size() == 1);
+ DE_ASSERT(variables.descriptorsImages.size() == primeCount);
+ DE_ASSERT(variables.descriptorImageViews.size() == primeCount);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == primeCount);
+
+ for (deUint32 primeIdx = 0; primeIdx < primeCount; ++primeIdx)
+ {
+ const VkDescriptorImageInfo imageInfo =
+ {
+ **variables.descriptorSamplers[0],
+ **variables.descriptorImageViews[primeIdx],
+ VK_IMAGE_LAYOUT_GENERAL
+ };
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ BINDING_CombinedImageSampler, // descriptorBinding;
+ primes[primeIdx], // elementIndex
+ 1u, // descriptorCount
+ m_testParams.descriptorType, // descriptorType
+ &imageInfo, // pImageInfo
+ DE_NULL, // pBufferInfo
+ DE_NULL // pTexelBufferView
+ };
+
+ m_vki.updateDescriptorSets(m_vkd, 1u, &writeInfo, 0u, DE_NULL);
+ }
+}
+
+void CombinedImageInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ DE_ASSERT(variables.descriptorSamplers.size() == 0);
+ DE_ASSERT(variables.descriptorsImages.size() == 0);
+ DE_ASSERT(variables.descriptorImageViews.size() == 0);
+ DE_ASSERT(variables.descriptorsBufferInfos.size() == 0);
+ DE_ASSERT(variables.descriptorSamplers.size() == 0);
+
+ const tcu::Sampler sampler(
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapS
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapT
+ tcu::Sampler::CLAMP_TO_BORDER, // wrapR
+ m_testParams.usesMipMaps ? tcu::Sampler::NEAREST_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // minFilter
+ m_testParams.usesMipMaps ? tcu::Sampler::NEAREST_MIPMAP_NEAREST : tcu::Sampler::NEAREST, // magFilter
+ 0.0f, // lodTreshold
+ true); // normalizeCoords
+ const VkSamplerCreateInfo createInfo = vk::mapSampler(sampler, vk::mapVkFormat(m_colorFormat));
+ variables.descriptorSamplers.push_back(ut::SamplerSp(new Move<VkSampler>(vk::createSampler(m_vki, m_vkd, &createInfo))));
+
+ const VkExtent3D& imageExtent = m_testParams.usesMipMaps ? bigImageExtent : smallImageExtent;
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, variables.descriptorsBuffer, (VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT),
+ imageExtent, m_colorFormat, VK_IMAGE_LAYOUT_UNDEFINED, variables.validDescriptorCount, m_testParams.usesMipMaps);
+ createImagesViews(variables.descriptorImageViews, variables.descriptorsImages, m_colorFormat);
+
+ PixelBufferAccess pixelAccess;
+ for (deUint32 imageIdx = 0; imageIdx < variables.validDescriptorCount; ++imageIdx)
+ {
+ const float component = m_colorScheme[imageIdx % m_schemeSize];
+
+ if (m_testParams.usesMipMaps)
+ {
+ const deUint32 mipCount = ut::computeMipMapCount(imageExtent);
+ DE_ASSERT(mipCount >= 2);
+ for (deUint32 mipIdx = 0; mipIdx < mipCount; ++mipIdx)
+ {
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, mipIdx);
+ tcu::clear(pixelAccess, m_clearColor);
+ }
+
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, mipCount-1);
+ pixelAccess.setPixel(tcu::Vec4(component, component, component, 1.0f), 0, 0);
+ }
+ else
+ {
+ pixelAccess = getPixelAccess(imageIdx, imageExtent, m_colorFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer, 0);
+ pixelAccess.setPixel(tcu::Vec4(component, component, component, 1.0f), 0, 0);
+ }
+ }
+
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+}
+
+class StorageImageInstance : public CommonDescriptorInstance
+{
+public:
+ StorageImageInstance (Context& context,
+ const TestCaseParams& testCaseParams);
+private:
+ virtual tcu::TestStatus iterate (void);
+ virtual void createAndPopulateDescriptors (IterateCommonVariables& variables);
+ virtual void updateDescriptors (IterateCommonVariables& variables);
+ virtual void iterateCollectResults (ut::UpdatablePixelBufferAccessPtr& result,
+ const IterateCommonVariables& variables,
+ bool fromTest);
+ ut::BufferHandleAllocSp m_buffer;
+ const deUint32 m_fillColor;
+ typedef deUint32 m_imageFormat_t;
+};
+
+StorageImageInstance::StorageImageInstance (Context& context,
+ const TestCaseParams& testCaseParams)
+ : CommonDescriptorInstance(context,
+ TestParams (VK_SHADER_STAGE_COMPUTE_BIT,
+ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ BINDING_StorageImage,
+ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ (BINDING_StorageImage + 1),
+ true,
+ performWritesInVertex(testCaseParams.descriptorType),
+ testCaseParams))
+ , m_buffer ()
+ , m_fillColor (10)
+{
+ ut::DeviceProperties dp(context);
+
+ checkIndexingAvailable(dp);
+
+ const VkPhysicalDeviceDescriptorIndexingFeaturesEXT& features = dp.descriptorIndexingFeatures();
+
+ if (!(features.shaderStorageImageArrayNonUniformIndexing))
+ TCU_THROW(NotSupportedError, "Non-uniform indexing over storage image descriptor arrays is not supported.");
+
+ if (testCaseParams.updateAfterBind)
+ {
+ if (!(features.descriptorBindingStorageImageUpdateAfterBind))
+ TCU_THROW(NotSupportedError, "Update after bind for storage image descriptors is not supported.");
+ }
+}
+
+void StorageImageInstance::updateDescriptors (IterateCommonVariables& variables)
+{
+ // update image at last index
+ {
+ VkDescriptorImageInfo imageInfo =
+ {
+ static_cast<VkSampler>(0),
+ **variables.descriptorImageViews[variables.validDescriptorCount],
+ VK_IMAGE_LAYOUT_GENERAL
+ };
+
+ const VkWriteDescriptorSet writeInfo =
+ {
+ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // sType
+ DE_NULL, // pNext
+ *variables.descriptorSet, // descriptorSet
+ m_testParams.additionalDescriptorBinding, // descriptorBinding;
+ 0, // elementIndex
+ 1u, // descriptorCount
+ m_testParams.additionalDescriptorType, // descriptorType
+ &imageInfo, // pImageInfo
+ DE_NULL, // pBufferInfo
+ DE_NULL // pTexelBufferView
+ };
+
+ m_vki.updateDescriptorSets(m_vkd, 1u, &writeInfo, 0u, DE_NULL);
+ }
+
+ // update rest images
+ CommonDescriptorInstance::updateDescriptors(variables);
+}
+
+void StorageImageInstance::createAndPopulateDescriptors (IterateCommonVariables& variables)
+{
+ const VkFormat imageFormat = ut::mapType2vkFormat<m_imageFormat_t>::value;
+ const VkBufferUsageFlags bufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
+
+ // create descriptor buffer, images and views
+ {
+ const VkExtent3D imageExtent = { 4, 4, 1 };
+
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, variables.descriptorsBuffer,
+ bufferUsage, imageExtent, imageFormat, VK_IMAGE_LAYOUT_UNDEFINED, variables.validDescriptorCount);
+
+ for (deUint32 imageIdx = 0; imageIdx < variables.validDescriptorCount; ++imageIdx)
+ {
+ const PixelBufferAccess pa = getPixelAccess(imageIdx, imageExtent, imageFormat, variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+ tcu::clear(pa, tcu::UVec4(m_fillColor));
+ }
+ vk::flushAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+ }
+
+ // create additional image that will be used as index container
+ {
+ createImages(variables.descriptorsImages, variables.descriptorsBufferInfos, m_buffer,
+ bufferUsage, m_testParams.frameResolution, imageFormat, VK_IMAGE_LAYOUT_UNDEFINED, 1);
+
+ // populate buffer
+ const std::vector<deUint32> primes = ut::generatePrimes(variables.availableDescriptorCount);
+ const PixelBufferAccess pa = getPixelAccess(variables.validDescriptorCount, m_testParams.frameResolution, imageFormat, variables.descriptorsBufferInfos, m_buffer);
+ for (deUint32 y = 0, pixel = 0; y < m_testParams.frameResolution.height; ++y)
+ {
+ for (deUint32 x = 0; x < m_testParams.frameResolution.width; ++x, ++pixel)
+ {
+ const deUint32 component = primes[pixel % variables.validDescriptorCount];
+ pa.setPixel(tcu::UVec4(component), x, y);
+ }
+ }
+
+ // save changes
+ vk::flushAlloc(m_vki, m_vkd, *m_buffer->alloc);
+ }
+
+ // create views for all previously created images
+ createImagesViews(variables.descriptorImageViews, variables.descriptorsImages, imageFormat);
+}
+
+tcu::TestStatus StorageImageInstance::iterate (void)
+{
+ IterateCommonVariables v;
+ iterateCommandBegin (v);
+
+ if (m_testParams.updateAfterBind)
+ {
+ updateDescriptors (v);
+ }
+
+ copyBuffersToImages (v);
+
+ m_vki.cmdDispatch (*v.commandBuffer,
+ m_testParams.calculateInLoop ? 1 : v.renderArea.extent.width,
+ m_testParams.calculateInLoop ? 1 : v.renderArea.extent.height,
+ 1);
+
+ copyImagesToBuffers (v);
+
+ return (iterateCommandEnd(v, false) ? tcu::TestStatus::pass : tcu::TestStatus::fail)("");
+}
+
+void StorageImageInstance::iterateCollectResults (ut::UpdatablePixelBufferAccessPtr& result,
+ const IterateCommonVariables& variables,
+ bool fromTest)
+{
+ result = ut::UpdatablePixelBufferAccessPtr(new ut::PixelBufferAccessAllocation(
+ vk::mapVkFormat(ut::mapType2vkFormat<m_imageFormat_t>::value), m_testParams.frameResolution));
+ const PixelBufferAccess& dst = *result.get();
+
+ if (fromTest)
+ {
+ vk::invalidateAlloc(m_vki, m_vkd, *variables.descriptorsBuffer->alloc);
+ for (deUint32 y = 0, pixelNum = 0; y < m_testParams.frameResolution.height; ++y)
+ {
+ for (deUint32 x = 0; x < m_testParams.frameResolution.width; ++x, ++pixelNum)
+ {
+ const deUint32 imageIdx = pixelNum % variables.validDescriptorCount;
+ const PixelBufferAccess src = getPixelAccess(imageIdx,
+ variables.descriptorsImages[imageIdx]->extent, variables.descriptorsImages[imageIdx]->format,
+ variables.descriptorsBufferInfos, variables.descriptorsBuffer);
+ dst.setPixel(tcu::Vector<m_imageFormat_t, 4>(src.getPixelT<m_imageFormat_t>(0, 0).x()), x, y);
+ }
+ }
+ }
+ else
+ {
+ std::vector<m_imageFormat_t> inc(variables.validDescriptorCount, m_fillColor);
+
+ for (deUint32 invIdx = variables.lowerBound; invIdx < variables.upperBound; ++invIdx)
+ {
+ ++inc[invIdx % variables.validDescriptorCount];
+ }
+
+ for (deUint32 invIdx = 0; invIdx < variables.vertexCount; ++invIdx)
+ {
+ const deUint32 row = invIdx / m_testParams.frameResolution.width;
+ const deUint32 col = invIdx % m_testParams.frameResolution.width;
+ const m_imageFormat_t color = inc[invIdx % variables.validDescriptorCount];
+ dst.setPixel(tcu::Vector<m_imageFormat_t, 4>(color), col, row);
+ }
+ }
+}
+
+class DescriptorIndexingTestCase : public TestCase
+{
+ const TestCaseParams m_testCaseParams;
+public:
+ DescriptorIndexingTestCase(tcu::TestContext &context, const char *name, const char *description, const TestCaseParams& testCaseParams)
+ : TestCase(context, name, description)
+ , m_testCaseParams(testCaseParams)
+ {
+ }
+
+ vkt::TestInstance* createInstance(vkt::Context& context) const // override
+ {
+ switch (m_testCaseParams.descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+ return new StorageBufferInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+ return new UniformBufferInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+ return new StorageTexelInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+ return new UniformTexelInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+ return new DynamicStorageBufferInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+ return new DynamicUniformBufferInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+ return new InputAttachmentInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_SAMPLER:
+ return new SamplerInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+ return new SampledImageInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+ return new CombinedImageInstance (context, m_testCaseParams);
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+ return new StorageImageInstance (context, m_testCaseParams);
+ default:
+ TCU_THROW(InternalError, "Unknown Descriptor Type");
+ }
+ return DE_NULL;
+ }
+
+ virtual void initPrograms(SourceCollections& programCollection) const
+ {
+ std::string(*genShaderSource)(VkShaderStageFlagBits, const TestCaseParams&, bool) = &CommonDescriptorInstance::getShaderSource;
+
+ if (VK_SHADER_STAGE_VERTEX_BIT & m_testCaseParams.stageFlags)
+ {
+ programCollection.glslSources.add(
+ ut::buildShaderName(VK_SHADER_STAGE_VERTEX_BIT, m_testCaseParams.descriptorType, m_testCaseParams.updateAfterBind, m_testCaseParams.calculateInLoop, false))
+ << glu::VertexSource((*genShaderSource)(VK_SHADER_STAGE_VERTEX_BIT, m_testCaseParams, false));
+
+ if (CommonDescriptorInstance::performWritesInVertex(m_testCaseParams.descriptorType))
+ {
+ programCollection.glslSources.add(
+ ut::buildShaderName(VK_SHADER_STAGE_VERTEX_BIT, m_testCaseParams.descriptorType, m_testCaseParams.updateAfterBind, m_testCaseParams.calculateInLoop, true))
+ << glu::VertexSource((*genShaderSource)(VK_SHADER_STAGE_VERTEX_BIT, m_testCaseParams, true));
+ }
+ }
+ if (VK_SHADER_STAGE_FRAGMENT_BIT & m_testCaseParams.stageFlags)
+ {
+ programCollection.glslSources.add(
+ ut::buildShaderName(VK_SHADER_STAGE_FRAGMENT_BIT, m_testCaseParams.descriptorType, m_testCaseParams.updateAfterBind, m_testCaseParams.calculateInLoop, false))
+ << glu::FragmentSource((*genShaderSource)(VK_SHADER_STAGE_FRAGMENT_BIT, m_testCaseParams, false));
+
+ if (CommonDescriptorInstance::performWritesInVertex(m_testCaseParams.descriptorType))
+ {
+ programCollection.glslSources.add(
+ ut::buildShaderName(VK_SHADER_STAGE_FRAGMENT_BIT, m_testCaseParams.descriptorType, m_testCaseParams.updateAfterBind, m_testCaseParams.calculateInLoop, true))
+ << glu::FragmentSource((*genShaderSource)(VK_SHADER_STAGE_FRAGMENT_BIT, m_testCaseParams, true));
+ }
+ }
+ if (VK_SHADER_STAGE_COMPUTE_BIT & m_testCaseParams.stageFlags)
+ {
+ programCollection.glslSources.add(
+ ut::buildShaderName(VK_SHADER_STAGE_COMPUTE_BIT, m_testCaseParams.descriptorType, m_testCaseParams.updateAfterBind, m_testCaseParams.calculateInLoop, false))
+ << glu::ComputeSource((*genShaderSource)(VK_SHADER_STAGE_COMPUTE_BIT, m_testCaseParams, false));
+ }
+ }
+};
+
+} // - unnamed namespace
+
+void descriptorIndexingDescriptorSetsCreateTests (tcu::TestCaseGroup* group)
+{
+ struct TestCaseInfo
+ {
+ const char* name;
+ const char* description;
+ TestCaseParams params;
+ };
+
+ tcu::TestContext& context(group->getTestContext());
+
+ TestCaseInfo casesAfterBindAndLoop[] =
+ {
+ {
+ "storage_buffer", "Regular Storage Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "storage_texel_buffer", "Storage Texel Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "uniform_texel_buffer", "Uniform Texel Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind,
+ false, // calculateInLoop
+ false, // usesMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "storage_image", "Storage Image Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
+ VK_SHADER_STAGE_COMPUTE_BIT,
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ };
+
+ for (int updateAfterBind = 0; updateAfterBind < 2; ++updateAfterBind)
+ {
+ for (int calculateInLoop = 0; calculateInLoop < 2; ++calculateInLoop)
+ {
+ for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(casesAfterBindAndLoop); ++caseIdx)
+ {
+ TestCaseInfo& info (casesAfterBindAndLoop[caseIdx]);
+ std::string caseName (info.name);
+ std::string caseDescription (info.description);
+ TestCaseParams params (info.params);
+
+ caseName += (updateAfterBind ? "_after_bind" : "");
+ caseName += (calculateInLoop ? "_in_loop" : "");
+
+ caseDescription += (updateAfterBind ? " After Bind" : "");
+ caseDescription += (calculateInLoop ? " In Loop" : "");
+
+ params.updateAfterBind = updateAfterBind ? true : false;
+ params.calculateInLoop = calculateInLoop ? true : false;
+
+ group->addChild(new DescriptorIndexingTestCase(context, caseName.c_str(), caseDescription.c_str(), params));
+ }
+ }
+ }
+
+ TestCaseInfo casesAfterBindAndLoopAndLOD[] =
+ {
+ {
+ "sampler", "Sampler Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_SAMPLER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // usesMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "sampled_image", "Sampled Image Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // usesMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "combined_image_sampler", "Combined Image Sampler Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // usesMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ };
+
+ for (int updateAfterBind = 0; updateAfterBind < 2; ++updateAfterBind)
+ {
+ for (int calculateInLoop = 0; calculateInLoop < 2; ++calculateInLoop)
+ {
+ for (int usesMipMaps = 0; usesMipMaps < 2; ++usesMipMaps)
+ {
+ for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(casesAfterBindAndLoopAndLOD); ++caseIdx)
+ {
+ TestCaseInfo& info (casesAfterBindAndLoopAndLOD[caseIdx]);
+ std::string caseName (info.name);
+ std::string caseDescription (info.description);
+ TestCaseParams params (info.params);
+
+ caseName += (updateAfterBind ? "_after_bind" : "");
+ caseName += (calculateInLoop ? "_in_loop" : "");
+ caseName += (usesMipMaps ? "_with_lod" : "");
+
+ caseDescription += (updateAfterBind ? " After Bind" : "");
+ caseDescription += (calculateInLoop ? " In Loop" : "");
+ caseDescription += (usesMipMaps ? " Use LOD" : "");
+
+ params.updateAfterBind = updateAfterBind ? true : false;
+ params.calculateInLoop = calculateInLoop ? true : false;
+ params.usesMipMaps = usesMipMaps ? true : false;
+
+ group->addChild(new DescriptorIndexingTestCase(context, caseName.c_str(), caseDescription.c_str(), params));
+ }
+ }
+ }
+ }
+
+ TestCaseInfo casesNonAfterBindAndLoop[] =
+ {
+ {
+ "uniform_buffer", "Regular Uniform Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // usesMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "storage_buffer_dynamic", "Dynamic Storage Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "uniform_buffer_dynamic", "Dynamic Uniform Buffer Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ {
+ "input_attachment", "Input Attachment Descriptors",
+ {
+ VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
+ (VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT),
+ RESOLUTION,
+ false, // updateAfterBind
+ false, // calculateInLoop
+ false, // useMipMaps
+ FUZZY_COMPARE, CMP_THRESHOLD
+ }
+ },
+ };
+
+ for (int calculateInLoop = 0; calculateInLoop < 2; ++calculateInLoop)
+ {
+ for (deUint32 caseIdx = 0; caseIdx < DE_LENGTH_OF_ARRAY(casesNonAfterBindAndLoop); ++caseIdx)
+ {
+ TestCaseInfo& info(casesNonAfterBindAndLoop[caseIdx]);
+ std::string caseName(info.name);
+ std::string caseDescription(info.description);
+ TestCaseParams params(info.params);
+
+ caseName += (calculateInLoop ? "_in_loop" : "");
+
+ caseDescription += (calculateInLoop ? " In Loop" : "");
+
+ params.calculateInLoop = calculateInLoop ? true : false;
+
+ group->addChild(new DescriptorIndexingTestCase(context, caseName.c_str(), caseDescription.c_str(), params));
+ }
+ }
+}
+
+} // - DescriptorIndexing
+} // - vkt
--- /dev/null
+/*------------------------------------------------------------------------
+* Vulkan Conformance Tests
+* ------------------------
+*
+* Copyright (c) 2019 The Khronos Group Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*//*!
+* \file
+* \brief Vulkan Decriptor Indexing Tests
+*//*--------------------------------------------------------------------*/
+
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <functional>
+#include <sstream>
+#include <utility>
+#include <vector>
+
+#include "vktDescriptorSetsIndexingTests.hpp"
+
+#include "vkBuilderUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "vkDefs.hpp"
+#include "vkObjUtil.hpp"
+#include "vkPlatform.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkTypeUtil.hpp"
+
+#include "tcuTestLog.hpp"
+#include "tcuResource.hpp"
+#include "tcuImageCompare.hpp"
+#include "tcuCommandLine.hpp"
+#include "tcuStringTemplate.hpp"
+
+#include "deRandom.hpp"
+#include "deMath.h"
+#include "deStringUtil.hpp"
+
+namespace vkt
+{
+namespace DescriptorIndexing
+{
+using namespace vk;
+namespace ut
+{
+
+ImageHandleAlloc::ImageHandleAlloc (Move<VkImage>& image_,
+ AllocMv& alloc_,
+ const VkExtent3D& extent_,
+ VkFormat format_,
+ VkImageLayout layout_,
+ bool usesMipMaps_)
+ : image (image_)
+ , alloc (alloc_)
+ , extent (extent_)
+ , format (format_)
+ , layout (layout_)
+ , levels (usesMipMaps_ ? computeMipMapCount(extent_) : 1)
+{
+}
+
+std::string buildShaderName (VkShaderStageFlagBits stage,
+ VkDescriptorType descriptorType,
+ deBool updateAfterBind,
+ bool calculateInLoop,
+ bool performWritesInVertex)
+{
+ const char* stageName = DE_NULL;
+ switch (stage)
+ {
+ case VK_SHADER_STAGE_VERTEX_BIT: stageName = "vert"; break;
+ case VK_SHADER_STAGE_FRAGMENT_BIT: stageName = "frag"; break;
+ case VK_SHADER_STAGE_COMPUTE_BIT: stageName = "comp"; break;
+ case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: stageName = "tesc"; break;
+ case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: stageName = "tese"; break;
+ case VK_SHADER_STAGE_GEOMETRY_BIT: stageName = "geom"; break;
+ default: stageName = "any"; break;
+ }
+ DE_ASSERT(stageName);
+
+ std::map<std::string, std::string> m;
+ m["STAGE"] = stageName;
+ m["DESC"] = de::toString(deUint32(descriptorType));
+ m["ABIND"] = updateAfterBind ? "_afterBind" : "";
+ m["LOOP"] = calculateInLoop ? "_inLoop" : "";
+ m["SHWR"] = performWritesInVertex ? "_shaderWrites" : "";
+
+ return tcu::StringTemplate("descriptorIndexing_${STAGE}${DESC}${ABIND}${LOOP}${SHWR}").specialize(m);
+}
+
+std::vector<deUint32> generatePrimes (deUint32 limit)
+{
+ deUint32 i, j, *data;
+ std::vector<deUint32> v(limit);
+
+ data = v.data();
+
+ for (i = 0; i < limit; ++i)
+ data[i] = i;
+
+ for (i = 2; i < limit; ++i)
+ {
+ if (data[i])
+ {
+ for (j = i*2; j < limit; j += i)
+ data[j] = 0;
+ }
+ }
+
+ std::vector<deUint32>::iterator x = std::stable_partition(v.begin(), v.end(), std::bind2nd(std::greater_equal<deUint32>(), 2));
+
+ return std::vector<deUint32>(v.begin(), x);
+}
+
+deUint32 computePrimeCount (deUint32 limit)
+{
+ deUint32 i, j, k, *data;
+ std::vector<deUint32> v(limit);
+
+ data = v.data();
+
+ for (i = 0; i < limit; ++i)
+ data[i] = i;
+
+ k = 0;
+ for (i = 2; i < limit; ++i)
+ {
+ if (data[i])
+ {
+ ++k;
+ for (j = i*2; j < limit; j += i)
+ data[j] = 0;
+ }
+ }
+ return k;
+}
+
+deUint32 computeMipMapCount (const VkExtent3D& extent)
+{
+ return deUint32(floor(log2(std::max(extent.width, extent.height)))) + 1;
+}
+
+deUint32 computeImageSize (const VkExtent3D& extent,
+ VkFormat format,
+ bool withMipMaps,
+ deUint32 level)
+{
+ deUint32 mipSize = extent.width * extent.height * extent.depth * vk::mapVkFormat(format).getPixelSize();
+ if (withMipMaps)
+ {
+ deUint32 mipIdx = 0u;
+ deUint32 width = extent.width;
+ deUint32 height = extent.height;
+ const deUint32 mipCount = computeMipMapCount(extent) - 1;
+ do
+ {
+ width /= 2;
+ height /= 2;
+ deUint32 tmpSize = width * height * extent.depth * vk::mapVkFormat(format).getPixelSize();
+
+ if (level == mipIdx)
+ {
+ break;
+ }
+ else if (level == maxDeUint32)
+ {
+ mipSize += tmpSize;
+ }
+ else
+ {
+ mipSize = tmpSize;
+ }
+
+ } while (++mipIdx < mipCount);
+ }
+ return mipSize;
+}
+
+deUint32 computeImageSize (const ImageHandleAllocSp& image)
+{
+ return computeImageSize(image->extent, image->format);
+}
+
+void createImageAndBind (ut::ImageHandleAllocSp& output,
+ const vkt::Context& ctx,
+ VkFormat colorFormat,
+ const VkExtent3D& extent,
+ VkImageLayout initialLayout,
+ bool withMipMaps,
+ VkImageType imageType)
+{
+ const bool isDepthStencilFormat = vk::isDepthStencilFormat(colorFormat);
+
+ const VkImageUsageFlags imageUsageFlagsDependent = isDepthStencilFormat
+ ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
+ : VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+
+ const VkImageUsageFlags imageUsageFlags = imageUsageFlagsDependent
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT
+ | VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT
+ | VK_IMAGE_USAGE_STORAGE_BIT
+ | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
+
+ const deUint32 mipLevels = withMipMaps ? computeMipMapCount(extent) : 1;
+ const VkImageCreateInfo createInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkImageCreateFlags)0, // flags
+ imageType, // imageType
+ colorFormat, // format
+ extent, // extent
+ mipLevels, // mipLevels
+ (deUint32)1, // arrayLayers
+ VK_SAMPLE_COUNT_1_BIT, // samples
+ VK_IMAGE_TILING_OPTIMAL, // tiling
+ imageUsageFlags, // usage
+ VK_SHARING_MODE_EXCLUSIVE, // sharingMode
+ (deUint32)0, // queueFamilyCount
+ DE_NULL, // pQueueFamilyIndices
+ initialLayout // initialLayout
+ };
+
+ Allocator& allocator = ctx.getDefaultAllocator();
+ VkDevice device = ctx.getDevice();
+ const DeviceInterface& dinterface = ctx.getDeviceInterface();
+
+ Move<VkImage> image = vk::createImage(dinterface, device, &createInfo);
+
+ const VkMemoryRequirements memReqs = vk::getImageMemoryRequirements(dinterface, device, *image);
+ de::MovePtr<Allocation> allocation = allocator.allocate(memReqs, MemoryRequirement::Any);
+
+ VK_CHECK(dinterface.bindImageMemory(device, *image, allocation->getMemory(), allocation->getOffset()));
+
+ output = ImageHandleAllocSp(new ImageHandleAlloc(image, allocation, extent, colorFormat, initialLayout, withMipMaps));
+}
+
+void recordCopyBufferToImage (VkCommandBuffer cmd,
+ const DeviceInterface& interface,
+ VkPipelineStageFlagBits srcStageMask,
+ VkPipelineStageFlagBits dstStageMask,
+ const VkDescriptorBufferInfo& bufferInfo,
+ VkImage image,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ VkImageLayout oldImageLayout,
+ VkImageLayout newImageLayout,
+ deUint32 mipLevelCount)
+{
+ const VkImageAspectFlags imageAspect = vk::isDepthStencilFormat(imageFormat)
+ ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
+ : VK_IMAGE_ASPECT_COLOR_BIT;
+
+ std::vector<VkBufferImageCopy> copyRegions;
+ {
+ deUint32 width = imageExtent.width;
+ deUint32 height = imageExtent.height;
+ VkDeviceSize bufferOffset = bufferInfo.offset;
+
+ for (deUint32 mipIdx = 0; mipIdx < mipLevelCount; ++mipIdx)
+ {
+ VkDeviceSize imageSize = computeImageSize(imageExtent, imageFormat, true, mipIdx);
+
+ const VkBufferImageCopy copyRegion =
+ {
+ bufferOffset, // bufferOffset
+ width, // bufferRowLength
+ height, // bufferImageHeight
+ {
+ imageAspect, // aspect
+ mipIdx, // mipLevel
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ }, // VkImageSubresourceLayers imageSubresource
+ { 0,0,0 }, // VkOffset3D imageOffset
+ { width, height, 1 } // VkExtent3D imageExtent
+ };
+
+ copyRegions.push_back(copyRegion);
+
+ bufferOffset += imageSize;
+ width /= 2;
+ height /= 2;
+ }
+ }
+
+ const VkImageSubresourceRange subresourceRange =
+ {
+ imageAspect, // aspectMask
+ 0u, // baseMipLevel
+ mipLevelCount, // levelCount
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ };
+
+ const VkImageMemoryBarrier transitionBarrier =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ 0, // srcAccessMask;
+ VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessMask;
+ oldImageLayout, // oldLayout;
+ newImageLayout, // newLayout;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ image, // image
+ subresourceRange // subresourceRange
+ };
+
+ const VkBufferMemoryBarrier bufferBarrier =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ pipelineAcceesFromStage(srcStageMask, false), // srcAccessMask;
+ VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ bufferInfo.buffer, // buffer;
+ bufferInfo.offset, // offset;
+ bufferInfo.range // size;
+ };
+
+ const VkImageMemoryBarrier imageBarrier =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask;
+ pipelineAcceesFromStage(dstStageMask, true)
+ | pipelineAcceesFromStage(dstStageMask, false), // dstAccessMask;
+ oldImageLayout, // oldLayout;
+ newImageLayout, // newLayout;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ image, // image
+ subresourceRange // subresourceRange
+ };
+
+ interface.cmdPipelineBarrier(cmd,
+ srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask, dstStageMask
+ (VkDependencyFlags)0, // dependencyFlags
+ 0u, (const VkMemoryBarrier*)DE_NULL, // memoryBarrierCount, pMemoryBarriers
+ 1u, &bufferBarrier, // bufferBarrierCount, pBufferBarriers
+ 1u, &transitionBarrier); // imageBarrierCount, pImageBarriers
+
+ interface.cmdCopyBufferToImage(cmd, bufferInfo.buffer, image, newImageLayout, static_cast<deUint32>(copyRegions.size()), copyRegions.data());
+
+ interface.cmdPipelineBarrier(cmd,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, // srcStageMask, dstStageMask
+ (VkDependencyFlags)0, // dependencyFlags
+ 0u, (const VkMemoryBarrier*)DE_NULL, // memoryBarrierCount, pMemoryBarriers
+ 0u, (const VkBufferMemoryBarrier*)DE_NULL, // bufferBarrierCount, pBufferBarriers
+ 1u, &imageBarrier); // imageBarrierCount, pImageBarriers
+}
+
+void recordCopyImageToBuffer (VkCommandBuffer cmd,
+ const DeviceInterface& interface,
+ VkPipelineStageFlagBits srcStageMask,
+ VkPipelineStageFlagBits dstStageMask,
+ VkImage image,
+ const VkExtent3D& imageExtent,
+ VkFormat imageFormat,
+ VkImageLayout oldImageLayout,
+ VkImageLayout newImageLayout,
+ const VkDescriptorBufferInfo& bufferInfo)
+{
+ const VkImageAspectFlags imageAspect = vk::isDepthStencilFormat(imageFormat)
+ ? VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT
+ : VK_IMAGE_ASPECT_COLOR_BIT;
+
+ const VkBufferImageCopy copyRegion =
+ {
+ bufferInfo.offset, // bufferOffset
+ imageExtent.width, // bufferRowLength
+ imageExtent.height, // bufferImageHeight
+ {
+ imageAspect, // aspect
+ 0u, // mipLevel
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ }, // VkImageSubresourceLayers
+ { 0, 0, 0 }, // imageOffset
+ imageExtent // imageExtent
+ };
+
+ VkImageSubresourceRange subresourceRange =
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
+ 0u, // baseMipLevel
+ 1u, // levelCount
+ 0u, // baseArrayLayer
+ 1u, // layerCount
+ };
+
+ const VkImageMemoryBarrier imageBarrier =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ pipelineAcceesFromStage(srcStageMask, false), // srcAccessMask;
+ VK_ACCESS_TRANSFER_READ_BIT, // dstAccessMask;
+ oldImageLayout, // oldLayout
+ newImageLayout, // newLayout;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ image, // image;
+ subresourceRange, // subresourceRange;
+ };
+
+ const VkBufferMemoryBarrier bufferBarrier =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // sType;
+ DE_NULL, // pNext;
+ VK_ACCESS_TRANSFER_WRITE_BIT, // srcAccessMask;
+ pipelineAcceesFromStage(dstStageMask, true), // dstAccessMask;
+ VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex;
+ VK_QUEUE_FAMILY_IGNORED, // dstQueueFamilyIndex;
+ bufferInfo.buffer, // buffer;
+ bufferInfo.offset, // offset;
+ bufferInfo.range // size;
+ };
+
+ interface.cmdPipelineBarrier(cmd, // commandBuffer
+ srcStageMask, VK_PIPELINE_STAGE_TRANSFER_BIT, // srcStageMask, dstStageMask
+ (VkDependencyFlags)0, // dependencyFlags
+ 0u, (const VkMemoryBarrier*)DE_NULL, // memoryBarrierCount, pMemoryBarriers
+ 0u, (const VkBufferMemoryBarrier*)DE_NULL, // bufferBarrierCount, pBufferBarriers
+ 1u, &imageBarrier); // imageBarrierCount, pImageBarriers
+
+ interface.cmdCopyImageToBuffer(cmd, image, newImageLayout, bufferInfo.buffer, 1u, ©Region);
+
+ interface.cmdPipelineBarrier(cmd,
+ VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask,
+ (VkDependencyFlags)0,
+ 0, DE_NULL,
+ 1, &bufferBarrier,
+ 0u, DE_NULL);
+}
+
+VkAccessFlags pipelineAcceesFromStage (VkPipelineStageFlagBits stage, bool readORwrite)
+{
+ VkAccessFlags access[2];
+ VkAccessFlags& readAccess = access[1];
+ VkAccessFlags& writeAccess = access[0];
+ readAccess = writeAccess = static_cast<VkAccessFlagBits>(0);
+
+ switch (stage)
+ {
+ case VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT:
+ case VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT:
+ readAccess = VK_ACCESS_INDIRECT_COMMAND_READ_BIT;
+ break;
+
+ case VK_PIPELINE_STAGE_VERTEX_INPUT_BIT:
+ readAccess = static_cast<VkAccessFlagBits>(VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT);
+ break;
+
+ case VK_PIPELINE_STAGE_VERTEX_SHADER_BIT:
+ case VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT:
+ case VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT:
+ case VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT:
+ case VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT:
+ readAccess = VK_ACCESS_SHADER_READ_BIT;
+ writeAccess = VK_ACCESS_SHADER_WRITE_BIT;
+ break;
+
+ case VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT:
+ readAccess = static_cast<VkAccessFlagBits>(VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT);
+ writeAccess = VK_ACCESS_SHADER_READ_BIT;;
+ break;
+
+ case VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT:
+ readAccess = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
+ writeAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ break;
+
+ case VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT:
+ case VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT:
+ readAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
+ writeAccess = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
+ break;
+
+ case VK_PIPELINE_STAGE_TRANSFER_BIT:
+ readAccess = VK_ACCESS_TRANSFER_READ_BIT;
+ writeAccess = VK_ACCESS_TRANSFER_WRITE_BIT;
+ break;
+
+ case VK_PIPELINE_STAGE_HOST_BIT:
+ readAccess = VK_ACCESS_HOST_READ_BIT;
+ writeAccess = VK_ACCESS_HOST_WRITE_BIT;
+ break;
+
+ default:
+ if (stage == 0)
+ {
+ readAccess = VK_ACCESS_MEMORY_READ_BIT;
+ writeAccess = VK_ACCESS_MEMORY_WRITE_BIT;
+ break;
+ }
+
+ DE_ASSERT(DE_FALSE);
+ }
+ return access[readORwrite ? 1 : 0];
+}
+
+void createFrameBuffer (FrameBufferSp& outputFB,
+ const vkt::Context& context,
+ const VkExtent3D& extent,
+ VkFormat colorFormat,
+ VkRenderPass renderpass,
+ deUint32 additionalAttachmentCount,
+ const VkImageView additionalAttachments[])
+{
+ outputFB = FrameBufferSp(new ut::FrameBuffer);
+ VkDevice device = context.getDevice();
+ const DeviceInterface& interface = context.getDeviceInterface();
+ createImageAndBind(outputFB->image, context, colorFormat, extent, VK_IMAGE_LAYOUT_UNDEFINED);
+
+ // create and attachment0
+ {
+ const VkImageViewCreateInfo viewCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkImageViewCreateFlags)0, // flags
+ *outputFB->image->image, // image
+ VK_IMAGE_VIEW_TYPE_2D, // viewType
+ colorFormat, // format
+ vk::makeComponentMappingRGBA(), // components
+ {
+ VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
+ (deUint32)0, // baseMipLevel
+ (deUint32)1, // mipLevels
+ (deUint32)0, // baseArrayLayer
+ (deUint32)1u, // arraySize
+ },
+ };
+
+ outputFB->attachment0 = vk::createImageView(interface, device, &viewCreateInfo);
+
+ std::vector<VkImageView>& attachments(outputFB->attachments);
+ attachments.push_back(*outputFB->attachment0);
+ if (additionalAttachments && additionalAttachmentCount)
+ {
+ attachments.insert(attachments.end(), additionalAttachments, additionalAttachments + additionalAttachmentCount);
+ }
+ }
+
+ // create a frame buffer
+ {
+ std::vector<VkImageView>& attachments(outputFB->attachments);
+
+ const VkFramebufferCreateInfo framebufferCreateInfo =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkFramebufferCreateFlags)0, // flags
+ renderpass, // renderPass
+ static_cast<deUint32>(attachments.size()), // attachmentCount
+ attachments.data(), // pAttachments
+ extent.width, // width
+ extent.height, // height
+ (deUint32)1 // layers
+ };
+
+ outputFB->buffer = vk::createFramebuffer(interface, device, &framebufferCreateInfo);
+ }
+}
+
+VkDeviceSize createBufferAndBind (ut::BufferHandleAllocSp& output,
+ const vkt::Context& ctx,
+ VkBufferUsageFlags usage,
+ VkDeviceSize desiredSize)
+{
+ const size_t nonCoherentAtomSize (static_cast<size_t>(ctx.getDeviceProperties().limits.nonCoherentAtomSize));
+ const VkDeviceSize roundedSize (deAlignSize(static_cast<size_t>(desiredSize), nonCoherentAtomSize));
+ Allocator& allocator (ctx.getDefaultAllocator());
+ VkDevice device (ctx.getDevice());
+ const DeviceInterface& interface (ctx.getDeviceInterface());
+
+ const VkBufferCreateInfo createInfo =
+ {
+ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // sType
+ DE_NULL, // pNext
+ (VkBufferCreateFlags)0, // flags
+ roundedSize, // size
+ usage, // usage
+ VK_SHARING_MODE_EXCLUSIVE, // sharingMode
+ 0u, // queueFamilyIndexCount
+ DE_NULL, // pQueueFamilyIndices
+ };
+
+ Move<VkBuffer> buffer = vk::createBuffer(interface, device, &createInfo);
+
+ const VkMemoryRequirements memRequirements = vk::getBufferMemoryRequirements(interface, device, *buffer);
+ de::MovePtr<Allocation> allocation = allocator.allocate(memRequirements, MemoryRequirement::HostVisible);
+
+ VK_CHECK(interface.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
+
+ output = BufferHandleAllocSp(new BufferHandleAlloc(buffer, allocation));
+
+ return roundedSize;
+}
+
+std::vector<tcu::Vec4> createVertices (deUint32 width, deUint32 height, float& xSize, float& ySize)
+{
+ std::vector<tcu::Vec4> result;
+
+ const float xStep = 2.0f / static_cast<float>(width);
+ const float yStep = 2.0f / static_cast<float>(height);
+ const float xStart = -1.0f + xStep / 2.0f;
+ const float yStart = -1.0f + yStep / 2.0f;
+
+ xSize = xStep;
+ ySize = yStep;
+
+ float x = xStart;
+ float y = yStart;
+
+ result.reserve(width * height);
+
+ for (deUint32 row = 0u; row < height; ++row)
+ {
+ for (deUint32 col = 0u; col < width; ++col)
+ {
+ result.push_back(tcu::Vec4(x, y, 1.0f, 1.0f));
+ x += xStep;
+ }
+
+ y += yStep;
+ x = xStart;
+ }
+
+ return result;
+}
+
+bool isDynamicDescriptor (VkDescriptorType descriptorType)
+{
+ return descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+}
+
+DeviceProperties::DeviceProperties (const DeviceProperties& src)
+{
+ m_descriptorIndexingFeatures = src.m_descriptorIndexingFeatures;
+ m_features2 = src.m_features2;
+
+ m_descriptorIndexingProperties = src.m_descriptorIndexingProperties;
+ m_properties2 = src.m_properties2;
+}
+
+DeviceProperties::DeviceProperties (const vkt::Context& testContext)
+{
+ VkPhysicalDevice device = testContext.getPhysicalDevice();
+ const InstanceInterface& interface = testContext.getInstanceInterface();
+
+ deMemset(&m_descriptorIndexingFeatures, 0, sizeof(m_descriptorIndexingFeatures));
+ m_descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
+ m_descriptorIndexingFeatures.pNext = DE_NULL;
+
+ deMemset(&m_features2, 0, sizeof(m_features2));
+ m_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ m_features2.pNext = &m_descriptorIndexingFeatures;
+
+ interface.getPhysicalDeviceFeatures2(device, &m_features2);
+
+ deMemset(&m_descriptorIndexingProperties, 0, sizeof(m_descriptorIndexingProperties));
+ m_descriptorIndexingProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT;
+ m_descriptorIndexingProperties.pNext = DE_NULL;
+
+ deMemset(&m_properties2, 0, sizeof(m_properties2));
+ m_properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
+ m_properties2.pNext = &m_descriptorIndexingProperties;
+
+ interface.getPhysicalDeviceProperties2(device, &m_properties2);
+}
+
+deUint32 DeviceProperties::computeMaxPerStageDescriptorCount (VkDescriptorType descriptorType,
+ bool enableUpdateAfterBind) const
+{
+ const VkPhysicalDeviceDescriptorIndexingPropertiesEXT& descriptorProps = descriptorIndexingProperties();
+ const VkPhysicalDeviceProperties& deviceProps = physicalDeviceProperties();
+
+ deUint32 result = 0;
+ deUint32 samplers = 0;
+ deUint32 uniformBuffers = 0;
+ deUint32 uniformBuffersDynamic = 0;
+ deUint32 storageBuffers = 0;
+ deUint32 storageBuffersDynamic = 0;
+ deUint32 sampledImages = 0;
+ deUint32 storageImages = 0;
+ deUint32 inputAttachments = 0;
+ deUint32 inlineUniforms = 0;
+ const deUint32 resources = deviceProps.limits.maxPerStageResources;
+
+ if (enableUpdateAfterBind)
+ {
+ samplers = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindSamplers, descriptorProps.maxDescriptorSetUpdateAfterBindSamplers); // 1048576
+ uniformBuffers = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindUniformBuffers, descriptorProps.maxDescriptorSetUpdateAfterBindUniformBuffers); // 15
+ uniformBuffersDynamic = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindUniformBuffers, descriptorProps.maxDescriptorSetUpdateAfterBindUniformBuffersDynamic); // 8
+ storageBuffers = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindStorageBuffers, descriptorProps.maxDescriptorSetUpdateAfterBindStorageBuffers); // 1048576
+ storageBuffersDynamic = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindStorageBuffers, descriptorProps.maxDescriptorSetUpdateAfterBindStorageBuffersDynamic); // 8
+ sampledImages = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindSampledImages, descriptorProps.maxDescriptorSetUpdateAfterBindSampledImages); // 1048576
+ storageImages = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindStorageImages, descriptorProps.maxDescriptorSetUpdateAfterBindStorageImages); // 1048576
+ inputAttachments = deMinu32( descriptorProps.maxPerStageDescriptorUpdateAfterBindInputAttachments, descriptorProps.maxDescriptorSetUpdateAfterBindInputAttachments); // 1048576
+ }
+ else
+ {
+ samplers = deMinu32( deviceProps.limits.maxPerStageDescriptorSamplers, deviceProps.limits.maxDescriptorSetSamplers); // 1048576
+ uniformBuffers = deMinu32( deviceProps.limits.maxPerStageDescriptorUniformBuffers, deviceProps.limits.maxDescriptorSetUniformBuffers); // 15
+ uniformBuffersDynamic = deMinu32( deviceProps.limits.maxPerStageDescriptorUniformBuffers, deviceProps.limits.maxDescriptorSetUniformBuffersDynamic); // 8
+ storageBuffers = deMinu32( deviceProps.limits.maxPerStageDescriptorStorageBuffers, deviceProps.limits.maxDescriptorSetStorageBuffers); // 1048576
+ storageBuffersDynamic = deMinu32( deviceProps.limits.maxPerStageDescriptorStorageBuffers, deviceProps.limits.maxDescriptorSetStorageBuffersDynamic); // 8
+ sampledImages = deMinu32( deviceProps.limits.maxPerStageDescriptorSampledImages-1, deviceProps.limits.maxDescriptorSetSampledImages-1); // 1048576. -1 because during in_loop tests a single texel buffer is created and is calculated against this limit
+ storageImages = deMinu32( deviceProps.limits.maxPerStageDescriptorStorageImages, deviceProps.limits.maxDescriptorSetStorageImages); // 1048576
+ inputAttachments = deMinu32( deviceProps.limits.maxPerStageDescriptorInputAttachments, deviceProps.limits.maxDescriptorSetInputAttachments); // 1048576
+ }
+
+ // adding arbitrary upper bound limits to restrain the size of the test ( we are testing big arrays, not the maximum size arrays )
+ samplers = deMinu32( samplers, 4096);
+ uniformBuffers = deMinu32( uniformBuffers, 16);
+ uniformBuffersDynamic = deMinu32( uniformBuffersDynamic, 16);
+ storageBuffers = deMinu32( storageBuffers, 8192);
+ storageBuffersDynamic = deMinu32( storageBuffersDynamic, 8192);
+ sampledImages = deMinu32( sampledImages, 8192);
+ storageImages = deMinu32( storageImages, 8192);
+ inputAttachments = deMinu32( inputAttachments, 16);
+
+ switch (descriptorType)
+ {
+ case VK_DESCRIPTOR_TYPE_SAMPLER: result = samplers; break;
+ case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER: result = deMinu32(resources, deMinu32(samplers, sampledImages)); break;
+ case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: result = deMinu32(resources, sampledImages); break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: result = deMinu32(resources, storageImages); break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: result = deMinu32(resources, sampledImages); break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: result = deMinu32(resources, storageImages); break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: result = deMinu32(resources, uniformBuffers); break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: result = deMinu32(resources, storageBuffers); break;
+ case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: result = deMinu32(resources, uniformBuffersDynamic); break;
+ case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: result = deMinu32(resources, storageBuffersDynamic); break;
+ case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: result = deMinu32(resources, inputAttachments); break;
+ case VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT: result = deMinu32(resources, inlineUniforms); break;
+ default: DE_ASSERT(0);
+ }
+
+ DE_ASSERT(result);
+
+ return result;
+}
+
+} // - namespace ut
+} // - namespace DescriptorIndexing
+} // - namespace vkt