blob: e479adb6c49efcdc108be599a34d561ba35f1da5 [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2015 Google 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 Binding shader access tests
*//*--------------------------------------------------------------------*/
#include "vktBindingShaderAccessTests.hpp"
#include "vktTestCase.hpp"
#include "vkDefs.hpp"
#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkPlatform.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "tcuVector.hpp"
#include "tcuVectorUtil.hpp"
#include "tcuTexture.hpp"
#include "tcuTextureUtil.hpp"
#include "tcuResultCollector.hpp"
#include "tcuTestLog.hpp"
#include "tcuRGBA.hpp"
#include "tcuSurface.hpp"
#include "tcuImageCompare.hpp"
#include "deUniquePtr.hpp"
#include "deSharedPtr.hpp"
#include "deStringUtil.hpp"
#include "deArrayUtil.hpp"
#include "qpInfo.h"
#include <iostream>
namespace vkt
{
namespace BindingModel
{
namespace
{
enum ResourceFlag
{
RESOURCE_FLAG_IMMUTABLE_SAMPLER = (1u << 0u),
RESOURCE_FLAG_LAST = (1u << 1u)
};
enum DescriptorUpdateMethod
{
DESCRIPTOR_UPDATE_METHOD_NORMAL = 0, //!< use vkUpdateDescriptorSets
DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE, //!< use descriptor update templates
DESCRIPTOR_UPDATE_METHOD_WITH_PUSH, //!< use push descriptor updates
DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE, //!< use push descriptor update templates
DESCRIPTOR_UPDATE_METHOD_LAST
};
std::string stringifyDescriptorUpdateMethod(DescriptorUpdateMethod method)
{
switch (method)
{
case DESCRIPTOR_UPDATE_METHOD_NORMAL:
return "";
break;
case DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE:
return "with_template";
break;
case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH:
return "with_push";
break;
case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE:
return "with_push_template";
break;
default:
return "N/A";
break;
}
}
static const char* const s_quadrantGenVertexPosSource = " highp int quadPhase = gl_VertexIndex % 6;\n"
" highp int quadXcoord = int(quadPhase == 1 || quadPhase == 4 || quadPhase == 5);\n"
" highp int quadYcoord = int(quadPhase == 2 || quadPhase == 3 || quadPhase == 5);\n"
" highp int quadOriginX = (gl_VertexIndex / 6) % 2;\n"
" highp int quadOriginY = (gl_VertexIndex / 6) / 2;\n"
" quadrant_id = gl_VertexIndex / 6;\n"
" result_position = vec4(float(quadOriginX + quadXcoord - 1), float(quadOriginY + quadYcoord - 1), 0.0, 1.0);\n";
std::string genPerVertexBlock (const vk::VkShaderStageFlagBits stage, const glu::GLSLVersion version)
{
static const char* const block = "gl_PerVertex {\n"
" vec4 gl_Position;\n"
" float gl_PointSize;\n" // not used, but for compatibility with how implicit block is declared in ES
"}";
std::ostringstream str;
if (!glu::glslVersionIsES(version))
switch (stage)
{
case vk::VK_SHADER_STAGE_VERTEX_BIT:
str << "out " << block << ";\n";
break;
case vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
str << "in " << block << " gl_in[gl_MaxPatchVertices];\n"
<< "out " << block << " gl_out[];\n";
break;
case vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
str << "in " << block << " gl_in[gl_MaxPatchVertices];\n"
<< "out " << block << ";\n";
break;
case vk::VK_SHADER_STAGE_GEOMETRY_BIT:
str << "in " << block << " gl_in[];\n"
<< "out " << block << ";\n";
break;
default:
break;
}
return str.str();
}
bool isUniformDescriptorType (vk::VkDescriptorType type)
{
return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ||
type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
}
bool isDynamicDescriptorType (vk::VkDescriptorType type)
{
return type == vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC || type == vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
}
void verifyDriverSupport(const deUint32 apiVersion,
const vk::VkPhysicalDeviceFeatures& deviceFeatures,
const std::vector<std::string>& deviceExtensions,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descType,
vk::VkShaderStageFlags activeStages,
vk::VkImageViewType viewType = vk::VK_IMAGE_VIEW_TYPE_2D)
{
std::vector<std::string> extensionNames;
size_t numExtensionsNeeded = 0;
switch (updateMethod)
{
case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH:
extensionNames.push_back("VK_KHR_push_descriptor");
break;
case DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE:
extensionNames.push_back("VK_KHR_push_descriptor");
// Fallthrough
case DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE:
if (!vk::isCoreDeviceExtension(apiVersion, "VK_KHR_descriptor_update_template"))
extensionNames.push_back("VK_KHR_descriptor_update_template");
break;
case DESCRIPTOR_UPDATE_METHOD_NORMAL:
// no extensions needed
break;
default:
DE_FATAL("Impossible");
}
numExtensionsNeeded = extensionNames.size();
if (numExtensionsNeeded > 0)
{
for (size_t deviceExtNdx = 0; deviceExtNdx < deviceExtensions.size(); deviceExtNdx++)
{
for (size_t requiredExtNdx = 0; requiredExtNdx < extensionNames.size(); requiredExtNdx++)
{
if (deStringEqual(deviceExtensions[deviceExtNdx].c_str(), extensionNames[requiredExtNdx].c_str()))
{
--numExtensionsNeeded;
break;
}
}
if (numExtensionsNeeded == 0)
break;
}
if (numExtensionsNeeded > 0)
{
TCU_THROW(NotSupportedError, (stringifyDescriptorUpdateMethod(updateMethod) + " tests are not supported").c_str());
}
}
switch (descType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
// These are supported in all stages
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
if (activeStages & (vk::VK_SHADER_STAGE_VERTEX_BIT |
vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT |
vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT |
vk::VK_SHADER_STAGE_GEOMETRY_BIT))
{
if (!deviceFeatures.vertexPipelineStoresAndAtomics)
TCU_THROW(NotSupportedError, (de::toString(descType) + " is not supported in the vertex pipeline").c_str());
}
if (activeStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT)
{
if (!deviceFeatures.fragmentStoresAndAtomics)
TCU_THROW(NotSupportedError, (de::toString(descType) + " is not supported in fragment shaders").c_str());
}
break;
default:
DE_FATAL("Impossible");
}
if (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY && !deviceFeatures.imageCubeArray)
TCU_THROW(NotSupportedError, "imageCubeArray feature not supported");
}
vk::VkImageType viewTypeToImageType (vk::VkImageViewType type)
{
switch (type)
{
case vk::VK_IMAGE_VIEW_TYPE_1D:
case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY: return vk::VK_IMAGE_TYPE_1D;
case vk::VK_IMAGE_VIEW_TYPE_2D:
case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY: return vk::VK_IMAGE_TYPE_2D;
case vk::VK_IMAGE_VIEW_TYPE_3D: return vk::VK_IMAGE_TYPE_3D;
case vk::VK_IMAGE_VIEW_TYPE_CUBE:
case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return vk::VK_IMAGE_TYPE_2D;
default:
DE_FATAL("Impossible");
return (vk::VkImageType)0;
}
}
vk::VkImageLayout getImageLayoutForDescriptorType (vk::VkDescriptorType descType)
{
if (descType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)
return vk::VK_IMAGE_LAYOUT_GENERAL;
else
return vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
deUint32 getTextureLevelPyramidDataSize (const tcu::TextureLevelPyramid& srcImage)
{
deUint32 dataSize = 0;
for (int level = 0; level < srcImage.getNumLevels(); ++level)
{
const tcu::ConstPixelBufferAccess srcAccess = srcImage.getLevel(level);
// tightly packed
DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
dataSize += srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
}
return dataSize;
}
void writeTextureLevelPyramidData (void* dst, deUint32 dstLen, const tcu::TextureLevelPyramid& srcImage, vk::VkImageViewType viewType, std::vector<vk::VkBufferImageCopy>* copySlices)
{
// \note cube is copied face-by-face
const deUint32 arraySize = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (srcImage.getLevel(0).getHeight()) :
(viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? (srcImage.getLevel(0).getDepth()) :
(viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1) :
(viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (srcImage.getLevel(0).getDepth()) :
((deUint32)0);
deUint32 levelOffset = 0;
DE_ASSERT(arraySize != 0);
for (int level = 0; level < srcImage.getNumLevels(); ++level)
{
const tcu::ConstPixelBufferAccess srcAccess = srcImage.getLevel(level);
const tcu::PixelBufferAccess dstAccess (srcAccess.getFormat(), srcAccess.getSize(), srcAccess.getPitch(), (deUint8*)dst + levelOffset);
const deUint32 dataSize = srcAccess.getWidth() * srcAccess.getHeight() * srcAccess.getDepth() * srcAccess.getFormat().getPixelSize();
const deUint32 sliceDataSize = dataSize / arraySize;
const deInt32 sliceHeight = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1) : (srcAccess.getHeight());
const deInt32 sliceDepth = (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (srcAccess.getDepth()) : (1);
const tcu::IVec3 sliceSize (srcAccess.getWidth(), sliceHeight, sliceDepth);
// tightly packed
DE_ASSERT(srcAccess.getFormat().getPixelSize() == srcAccess.getPixelPitch());
for (int sliceNdx = 0; sliceNdx < (int)arraySize; ++sliceNdx)
{
const vk::VkBufferImageCopy copySlice =
{
(vk::VkDeviceSize)levelOffset + sliceNdx * sliceDataSize, // bufferOffset
(deUint32)sliceSize.x(), // bufferRowLength
(deUint32)sliceSize.y(), // bufferImageHeight
{
vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
(deUint32)level, // mipLevel
(deUint32)sliceNdx, // arrayLayer
1u, // arraySize
}, // imageSubresource
{
0,
0,
0,
}, // imageOffset
{
(deUint32)sliceSize.x(),
(deUint32)sliceSize.y(),
(deUint32)sliceSize.z(),
} // imageExtent
};
copySlices->push_back(copySlice);
}
DE_ASSERT(arraySize * sliceDataSize == dataSize);
tcu::copy(dstAccess, srcAccess);
levelOffset += dataSize;
}
DE_ASSERT(dstLen == levelOffset);
DE_UNREF(dstLen);
}
de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkBuffer buffer, vk::MemoryRequirement requirement)
{
const vk::VkMemoryRequirements requirements = vk::getBufferMemoryRequirements(vki, device, buffer);
de::MovePtr<vk::Allocation> allocation = allocator.allocate(requirements, requirement);
VK_CHECK(vki.bindBufferMemory(device, buffer, allocation->getMemory(), allocation->getOffset()));
return allocation;
}
de::MovePtr<vk::Allocation> allocateAndBindObjectMemory (const vk::DeviceInterface& vki, vk::VkDevice device, vk::Allocator& allocator, vk::VkImage image, vk::MemoryRequirement requirement)
{
const vk::VkMemoryRequirements requirements = vk::getImageMemoryRequirements(vki, device, image);
de::MovePtr<vk::Allocation> allocation = allocator.allocate(requirements, requirement);
VK_CHECK(vki.bindImageMemory(device, image, allocation->getMemory(), allocation->getOffset()));
return allocation;
}
vk::VkDescriptorImageInfo makeDescriptorImageInfo (vk::VkSampler sampler)
{
return vk::makeDescriptorImageInfo(sampler, (vk::VkImageView)0, (vk::VkImageLayout)0);
}
vk::VkDescriptorImageInfo makeDescriptorImageInfo (vk::VkImageView imageView, vk::VkImageLayout layout)
{
return vk::makeDescriptorImageInfo((vk::VkSampler)0, imageView, layout);
}
void drawQuadrantReferenceResult (const tcu::PixelBufferAccess& dst, const tcu::Vec4& c1, const tcu::Vec4& c2, const tcu::Vec4& c3, const tcu::Vec4& c4)
{
tcu::clear(tcu::getSubregion(dst, 0, 0, dst.getWidth() / 2, dst.getHeight() / 2), c1);
tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2, 0, dst.getWidth() - dst.getWidth() / 2, dst.getHeight() / 2), c2);
tcu::clear(tcu::getSubregion(dst, 0, dst.getHeight() / 2, dst.getWidth() / 2, dst.getHeight() - dst.getHeight() / 2), c3);
tcu::clear(tcu::getSubregion(dst, dst.getWidth() / 2, dst.getHeight() / 2, dst.getWidth() - dst.getWidth() / 2, dst.getHeight() - dst.getHeight() / 2), c4);
}
static const vk::VkDescriptorUpdateTemplateEntry createTemplateBinding (deUint32 binding, deUint32 arrayElement, deUint32 descriptorCount, vk::VkDescriptorType descriptorType, size_t offset, size_t stride)
{
const vk::VkDescriptorUpdateTemplateEntry updateBinding =
{
binding,
arrayElement,
descriptorCount,
descriptorType,
offset,
stride
};
return updateBinding;
}
class RawUpdateRegistry
{
public:
RawUpdateRegistry (void);
template<typename Type>
void addWriteObject (const Type& updateObject);
size_t getWriteObjectOffset (const deUint32 objectId);
const deUint8* getRawPointer () const;
private:
std::vector<deUint8> m_updateEntries;
std::vector<size_t> m_updateEntryOffsets;
size_t m_nextOffset;
};
RawUpdateRegistry::RawUpdateRegistry (void)
: m_updateEntries()
, m_updateEntryOffsets()
, m_nextOffset(0)
{
}
template<typename Type>
void RawUpdateRegistry::addWriteObject (const Type& updateObject)
{
m_updateEntryOffsets.push_back(m_nextOffset);
// in this case, elements <=> bytes
m_updateEntries.resize(m_nextOffset + sizeof(updateObject));
Type* t = reinterpret_cast<Type*>(m_updateEntries.data() + m_nextOffset);
*t = updateObject;
m_nextOffset += sizeof(updateObject);
}
size_t RawUpdateRegistry::getWriteObjectOffset (const deUint32 objectId)
{
return m_updateEntryOffsets[objectId];
}
const deUint8* RawUpdateRegistry::getRawPointer () const
{
return m_updateEntries.data();
}
class SingleTargetRenderInstance : public vkt::TestInstance
{
public:
SingleTargetRenderInstance (Context& context,
const tcu::UVec2& size);
private:
static vk::Move<vk::VkImage> createColorAttachment (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
const tcu::TextureFormat& format,
const tcu::UVec2& size,
de::MovePtr<vk::Allocation>* outAllocation);
static vk::Move<vk::VkImageView> createColorAttachmentView (const vk::DeviceInterface& vki,
vk::VkDevice device,
const tcu::TextureFormat& format,
vk::VkImage image);
static vk::Move<vk::VkFramebuffer> createFramebuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkRenderPass renderpass,
vk::VkImageView colorAttachmentView,
const tcu::UVec2& size);
static vk::Move<vk::VkCommandPool> createCommandPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex);
virtual void logTestPlan (void) const = 0;
virtual void renderToTarget (void) = 0;
virtual tcu::TestStatus verifyResultImage (const tcu::ConstPixelBufferAccess& result) const = 0;
void readRenderTarget (tcu::TextureLevel& dst);
tcu::TestStatus iterate (void);
protected:
const tcu::TextureFormat m_targetFormat;
const tcu::UVec2 m_targetSize;
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vk::Allocator& m_allocator;
de::MovePtr<vk::Allocation> m_colorAttachmentMemory;
const vk::Unique<vk::VkImage> m_colorAttachmentImage;
const vk::Unique<vk::VkImageView> m_colorAttachmentView;
const vk::Unique<vk::VkRenderPass> m_renderPass;
const vk::Unique<vk::VkFramebuffer> m_framebuffer;
const vk::Unique<vk::VkCommandPool> m_cmdPool;
bool m_firstIteration;
};
SingleTargetRenderInstance::SingleTargetRenderInstance (Context& context,
const tcu::UVec2& size)
: vkt::TestInstance (context)
, m_targetFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
, m_targetSize (size)
, m_vki (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_allocator (context.getDefaultAllocator())
, m_colorAttachmentMemory (DE_NULL)
, m_colorAttachmentImage (createColorAttachment(m_vki, m_device, m_allocator, m_targetFormat, m_targetSize, &m_colorAttachmentMemory))
, m_colorAttachmentView (createColorAttachmentView(m_vki, m_device, m_targetFormat, *m_colorAttachmentImage))
, m_renderPass (makeRenderPass(m_vki, m_device, vk::mapTextureFormat(m_targetFormat)))
, m_framebuffer (createFramebuffer(m_vki, m_device, *m_renderPass, *m_colorAttachmentView, m_targetSize))
, m_cmdPool (createCommandPool(m_vki, m_device, context.getUniversalQueueFamilyIndex()))
, m_firstIteration (true)
{
}
vk::Move<vk::VkImage> SingleTargetRenderInstance::createColorAttachment (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
const tcu::TextureFormat& format,
const tcu::UVec2& size,
de::MovePtr<vk::Allocation>* outAllocation)
{
const vk::VkImageCreateInfo imageInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
DE_NULL,
(vk::VkImageCreateFlags)0,
vk::VK_IMAGE_TYPE_2D, // imageType
vk::mapTextureFormat(format), // format
{ size.x(), size.y(), 1u }, // extent
1, // mipLevels
1, // arraySize
vk::VK_SAMPLE_COUNT_1_BIT, // samples
vk::VK_IMAGE_TILING_OPTIMAL, // tiling
vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
vk::VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
};
vk::Move<vk::VkImage> image (vk::createImage(vki, device, &imageInfo));
de::MovePtr<vk::Allocation> allocation (allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any));
*outAllocation = allocation;
return image;
}
vk::Move<vk::VkImageView> SingleTargetRenderInstance::createColorAttachmentView (const vk::DeviceInterface& vki,
vk::VkDevice device,
const tcu::TextureFormat& format,
vk::VkImage image)
{
const vk::VkImageViewCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
(vk::VkImageViewCreateFlags)0,
image, // image
vk::VK_IMAGE_VIEW_TYPE_2D, // viewType
vk::mapTextureFormat(format), // format
vk::makeComponentMappingRGBA(),
{
vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
0u, // baseMipLevel
1u, // mipLevels
0u, // baseArrayLayer
1u, // arraySize
},
};
return vk::createImageView(vki, device, &createInfo);
}
vk::Move<vk::VkFramebuffer> SingleTargetRenderInstance::createFramebuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkRenderPass renderpass,
vk::VkImageView colorAttachmentView,
const tcu::UVec2& size)
{
const vk::VkFramebufferCreateInfo framebufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
DE_NULL,
(vk::VkFramebufferCreateFlags)0,
renderpass, // renderPass
1u, // attachmentCount
&colorAttachmentView, // pAttachments
size.x(), // width
size.y(), // height
1, // layers
};
return vk::createFramebuffer(vki, device, &framebufferCreateInfo);
}
vk::Move<vk::VkCommandPool> SingleTargetRenderInstance::createCommandPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex)
{
return vk::createCommandPool(vki, device, vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
}
void SingleTargetRenderInstance::readRenderTarget (tcu::TextureLevel& dst)
{
const deUint64 pixelDataSize = (deUint64)(m_targetSize.x() * m_targetSize.y() * m_targetFormat.getPixelSize());
const vk::VkBufferCreateInfo bufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
pixelDataSize, // size
vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
const vk::Unique<vk::VkBuffer> buffer (vk::createBuffer(m_vki, m_device, &bufferCreateInfo));
const de::MovePtr<vk::Allocation> bufferMemory = allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible);
const vk::Unique<vk::VkCommandBuffer> cmd (vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
// copy content to buffer
beginCommandBuffer(m_vki, *cmd);
copyImageToBuffer(m_vki, *cmd, *m_colorAttachmentImage, *buffer, tcu::IVec2(m_targetSize.x(), m_targetSize.y()));
endCommandBuffer(m_vki, *cmd);
submitCommandsAndWait(m_vki, m_device, m_queue, cmd.get());
dst.setStorage(m_targetFormat, m_targetSize.x(), m_targetSize.y());
// copy data
invalidateAlloc(m_vki, m_device, *bufferMemory);
tcu::copy(dst, tcu::ConstPixelBufferAccess(dst.getFormat(), dst.getSize(), bufferMemory->getHostPtr()));
}
tcu::TestStatus SingleTargetRenderInstance::iterate (void)
{
tcu::TextureLevel resultImage;
// log
if (m_firstIteration)
{
logTestPlan();
m_firstIteration = false;
}
// render
{
// transition to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
const vk::VkImageSubresourceRange fullSubrange =
{
vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
0u, // baseMipLevel
1u, // mipLevels
0u, // baseArraySlice
1u, // arraySize
};
const vk::VkImageMemoryBarrier imageBarrier =
{
vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
DE_NULL,
0u, // srcAccessMask
vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask
vk::VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex
*m_colorAttachmentImage, // image
fullSubrange, // subresourceRange
};
const vk::Unique<vk::VkCommandBuffer> cmd (vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
beginCommandBuffer(m_vki, *cmd);
m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (vk::VkDependencyFlags)0,
0, (const vk::VkMemoryBarrier*)DE_NULL,
0, (const vk::VkBufferMemoryBarrier*)DE_NULL,
1, &imageBarrier);
endCommandBuffer(m_vki, *cmd);
submitCommandsAndWait(m_vki, m_device, m_queue, cmd.get());
renderToTarget();
}
// read and verify
readRenderTarget(resultImage);
return verifyResultImage(resultImage.getAccess());
}
class RenderInstanceShaders
{
public:
RenderInstanceShaders (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::VkPhysicalDeviceFeatures& deviceFeatures,
const vk::BinaryCollection& programCollection);
inline bool hasTessellationStage (void) const { return *m_tessCtrlShaderModule != 0 || *m_tessEvalShaderModule != 0; }
inline deUint32 getNumStages (void) const { return (deUint32)m_stageInfos.size(); }
inline const vk::VkPipelineShaderStageCreateInfo* getStages (void) const { return &m_stageInfos[0]; }
private:
void addStage (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::VkPhysicalDeviceFeatures& deviceFeatures,
const vk::BinaryCollection& programCollection,
const char* name,
vk::VkShaderStageFlagBits stage,
vk::Move<vk::VkShaderModule>* outModule);
vk::VkPipelineShaderStageCreateInfo getShaderStageCreateInfo (vk::VkShaderStageFlagBits stage, vk::VkShaderModule shader) const;
vk::Move<vk::VkShaderModule> m_vertexShaderModule;
vk::Move<vk::VkShaderModule> m_tessCtrlShaderModule;
vk::Move<vk::VkShaderModule> m_tessEvalShaderModule;
vk::Move<vk::VkShaderModule> m_geometryShaderModule;
vk::Move<vk::VkShaderModule> m_fragmentShaderModule;
std::vector<vk::VkPipelineShaderStageCreateInfo> m_stageInfos;
};
RenderInstanceShaders::RenderInstanceShaders (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::VkPhysicalDeviceFeatures& deviceFeatures,
const vk::BinaryCollection& programCollection)
{
addStage(vki, device, deviceFeatures, programCollection, "vertex", vk::VK_SHADER_STAGE_VERTEX_BIT, &m_vertexShaderModule);
addStage(vki, device, deviceFeatures, programCollection, "tess_ctrl", vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, &m_tessCtrlShaderModule);
addStage(vki, device, deviceFeatures, programCollection, "tess_eval", vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, &m_tessEvalShaderModule);
addStage(vki, device, deviceFeatures, programCollection, "geometry", vk::VK_SHADER_STAGE_GEOMETRY_BIT, &m_geometryShaderModule);
addStage(vki, device, deviceFeatures, programCollection, "fragment", vk::VK_SHADER_STAGE_FRAGMENT_BIT, &m_fragmentShaderModule);
DE_ASSERT(!m_stageInfos.empty());
}
void RenderInstanceShaders::addStage (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::VkPhysicalDeviceFeatures& deviceFeatures,
const vk::BinaryCollection& programCollection,
const char* name,
vk::VkShaderStageFlagBits stage,
vk::Move<vk::VkShaderModule>* outModule)
{
if (programCollection.contains(name))
{
if (vk::isShaderStageSupported(deviceFeatures, stage))
{
vk::Move<vk::VkShaderModule> module = createShaderModule(vki, device, programCollection.get(name), (vk::VkShaderModuleCreateFlags)0);
m_stageInfos.push_back(getShaderStageCreateInfo(stage, *module));
*outModule = module;
}
else
{
// Wait for the GPU to idle so that throwing the exception
// below doesn't free in-use GPU resource.
vki.deviceWaitIdle(device);
TCU_THROW(NotSupportedError, (de::toString(stage) + " is not supported").c_str());
}
}
}
vk::VkPipelineShaderStageCreateInfo RenderInstanceShaders::getShaderStageCreateInfo (vk::VkShaderStageFlagBits stage, vk::VkShaderModule shader) const
{
const vk::VkPipelineShaderStageCreateInfo stageCreateInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineShaderStageCreateFlags)0,
stage, // stage
shader, // shader
"main",
DE_NULL, // pSpecializationInfo
};
return stageCreateInfo;
}
class SingleCmdRenderInstance : public SingleTargetRenderInstance
{
public:
SingleCmdRenderInstance (Context& context,
bool isPrimaryCmdBuf,
const tcu::UVec2& renderSize);
private:
vk::Move<vk::VkPipeline> createPipeline (vk::VkPipelineLayout pipelineLayout);
virtual vk::VkPipelineLayout getPipelineLayout (void) const = 0;
virtual void writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const = 0;
void renderToTarget (void);
const bool m_isPrimaryCmdBuf;
};
SingleCmdRenderInstance::SingleCmdRenderInstance (Context& context,
bool isPrimaryCmdBuf,
const tcu::UVec2& renderSize)
: SingleTargetRenderInstance (context, renderSize)
, m_isPrimaryCmdBuf (isPrimaryCmdBuf)
{
}
vk::Move<vk::VkPipeline> SingleCmdRenderInstance::createPipeline (vk::VkPipelineLayout pipelineLayout)
{
const RenderInstanceShaders shaderStages (m_vki, m_device, m_context.getDeviceFeatures(), m_context.getBinaryCollection());
const vk::VkPrimitiveTopology topology = shaderStages.hasTessellationStage() ? vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
const vk::VkPipelineVertexInputStateCreateInfo vertexInputState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineVertexInputStateCreateFlags)0,
0u, // bindingCount
DE_NULL, // pVertexBindingDescriptions
0u, // attributeCount
DE_NULL, // pVertexAttributeDescriptions
};
const vk::VkPipelineInputAssemblyStateCreateInfo iaState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineInputAssemblyStateCreateFlags)0,
topology, // topology
VK_FALSE, // primitiveRestartEnable
};
const vk::VkPipelineTessellationStateCreateInfo tessState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineTessellationStateCreateFlags)0,
3u, // patchControlPoints
};
const vk::VkViewport viewport = vk::makeViewport(m_targetSize);
const vk::VkRect2D renderArea = vk::makeRect2D(m_targetSize);
const vk::VkPipelineViewportStateCreateInfo vpState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineViewportStateCreateFlags)0,
1u, // viewportCount
&viewport,
1u,
&renderArea,
};
const vk::VkPipelineRasterizationStateCreateInfo rsState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineRasterizationStateCreateFlags)0,
VK_FALSE, // depthClipEnable
VK_FALSE, // rasterizerDiscardEnable
vk::VK_POLYGON_MODE_FILL, // fillMode
vk::VK_CULL_MODE_NONE, // cullMode
vk::VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace
VK_FALSE, // depthBiasEnable
0.0f, // depthBias
0.0f, // depthBiasClamp
0.0f, // slopeScaledDepthBias
1.0f, // lineWidth
};
const vk::VkSampleMask sampleMask = 0x01u;
const vk::VkPipelineMultisampleStateCreateInfo msState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineMultisampleStateCreateFlags)0,
vk::VK_SAMPLE_COUNT_1_BIT, // rasterSamples
VK_FALSE, // sampleShadingEnable
0.0f, // minSampleShading
&sampleMask, // sampleMask
VK_FALSE, // alphaToCoverageEnable
VK_FALSE, // alphaToOneEnable
};
const vk::VkPipelineDepthStencilStateCreateInfo dsState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineDepthStencilStateCreateFlags)0,
VK_FALSE, // depthTestEnable
VK_FALSE, // depthWriteEnable
vk::VK_COMPARE_OP_ALWAYS, // depthCompareOp
VK_FALSE, // depthBoundsTestEnable
VK_FALSE, // stencilTestEnable
{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u }, // front
{ vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS, 0u, 0u, 0u }, // back
-1.0f, // minDepthBounds
+1.0f, // maxDepthBounds
};
const vk::VkPipelineColorBlendAttachmentState cbAttachment =
{
VK_FALSE, // blendEnable
vk::VK_BLEND_FACTOR_ZERO, // srcBlendColor
vk::VK_BLEND_FACTOR_ZERO, // destBlendColor
vk::VK_BLEND_OP_ADD, // blendOpColor
vk::VK_BLEND_FACTOR_ZERO, // srcBlendAlpha
vk::VK_BLEND_FACTOR_ZERO, // destBlendAlpha
vk::VK_BLEND_OP_ADD, // blendOpAlpha
(vk::VK_COLOR_COMPONENT_R_BIT |
vk::VK_COLOR_COMPONENT_G_BIT |
vk::VK_COLOR_COMPONENT_B_BIT |
vk::VK_COLOR_COMPONENT_A_BIT), // channelWriteMask
};
const vk::VkPipelineColorBlendStateCreateInfo cbState =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineColorBlendStateCreateFlags)0,
VK_FALSE, // logicOpEnable
vk::VK_LOGIC_OP_CLEAR, // logicOp
1u, // attachmentCount
&cbAttachment, // pAttachments
{ 0.0f, 0.0f, 0.0f, 0.0f }, // blendConst
};
const vk::VkGraphicsPipelineCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineCreateFlags)0,
shaderStages.getNumStages(), // stageCount
shaderStages.getStages(), // pStages
&vertexInputState, // pVertexInputState
&iaState, // pInputAssemblyState
(shaderStages.hasTessellationStage() ? &tessState : DE_NULL), // pTessellationState
&vpState, // pViewportState
&rsState, // pRasterState
&msState, // pMultisampleState
&dsState, // pDepthStencilState
&cbState, // pColorBlendState
(const vk::VkPipelineDynamicStateCreateInfo*)DE_NULL, // pDynamicState
pipelineLayout, // layout
*m_renderPass, // renderPass
0u, // subpass
(vk::VkPipeline)0, // basePipelineHandle
0u, // basePipelineIndex
};
return createGraphicsPipeline(m_vki, m_device, (vk::VkPipelineCache)0u, &createInfo);
}
void SingleCmdRenderInstance::renderToTarget (void)
{
const vk::VkRect2D renderArea =
{
{ 0, 0 }, // offset
{ m_targetSize.x(), m_targetSize.y() }, // extent
};
const vk::VkCommandBufferInheritanceInfo passCmdBufInheritInfo =
{
vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO,
DE_NULL,
(vk::VkRenderPass)*m_renderPass, // renderPass
0u, // subpass
(vk::VkFramebuffer)*m_framebuffer, // framebuffer
VK_FALSE, // occlusionQueryEnable
(vk::VkQueryControlFlags)0,
(vk::VkQueryPipelineStatisticFlags)0,
};
const vk::VkCommandBufferBeginInfo passCmdBufBeginInfo =
{
vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
DE_NULL,
vk::VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT |
vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, // flags
&passCmdBufInheritInfo,
};
const vk::VkPipelineLayout pipelineLayout (getPipelineLayout());
const vk::Unique<vk::VkPipeline> pipeline (createPipeline(pipelineLayout));
const vk::Unique<vk::VkCommandBuffer> mainCmd (vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
const vk::Unique<vk::VkCommandBuffer> passCmd ((m_isPrimaryCmdBuf) ? (vk::Move<vk::VkCommandBuffer>()) : (vk::allocateCommandBuffer(m_vki, m_device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_SECONDARY)));
const vk::Unique<vk::VkFence> fence (vk::createFence(m_vki, m_device));
const vk::VkSubpassContents passContents = (m_isPrimaryCmdBuf) ? (vk::VK_SUBPASS_CONTENTS_INLINE) : (vk::VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
beginCommandBuffer(m_vki, *mainCmd);
beginRenderPass(m_vki, *mainCmd, *m_renderPass, *m_framebuffer, renderArea, tcu::Vec4(0.0f), passContents);
if (m_isPrimaryCmdBuf)
{
m_vki.cmdBindPipeline(*mainCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
writeDrawCmdBuffer(*mainCmd);
}
else
{
VK_CHECK(m_vki.beginCommandBuffer(*passCmd, &passCmdBufBeginInfo));
m_vki.cmdBindPipeline(*passCmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
writeDrawCmdBuffer(*passCmd);
endCommandBuffer(m_vki, *passCmd);
m_vki.cmdExecuteCommands(*mainCmd, 1, &passCmd.get());
}
endRenderPass(m_vki, *mainCmd);
endCommandBuffer(m_vki, *mainCmd);
// submit and wait for them to finish before exiting scope. (Killing in-flight objects is a no-no).
submitCommandsAndWait(m_vki, m_device, m_queue, mainCmd.get());
}
enum DescriptorSetCount
{
DESCRIPTOR_SET_COUNT_SINGLE = 0, //!< single descriptor set
DESCRIPTOR_SET_COUNT_MULTIPLE, //!< multiple descriptor sets
DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS, //!< multiple discontiguous descriptor sets
DESCRIPTOR_SET_COUNT_LAST
};
deUint32 getDescriptorSetCount (DescriptorSetCount count)
{
switch (count)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
return 1u;
case DESCRIPTOR_SET_COUNT_MULTIPLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
return 2u;
default:
DE_FATAL("Impossible");
return 0u;
}
}
deUint32 getDescriptorSetNdx (DescriptorSetCount count, deUint32 setNdx)
{
DE_ASSERT(setNdx < getDescriptorSetCount(count));
const deUint32 contiguousNdx[] = { 0, 1 };
const deUint32 discontiguousNdx[] = { 0, 2 };
switch (count)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
return 0u;
case DESCRIPTOR_SET_COUNT_MULTIPLE:
return contiguousNdx[setNdx];
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
return discontiguousNdx[setNdx];
default:
DE_FATAL("Impossible");
return 0u;
}
}
enum ShaderInputInterface
{
SHADER_INPUT_SINGLE_DESCRIPTOR = 0, //!< one descriptor
SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS, //!< multiple descriptors with contiguous binding id's
SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS, //!< multiple descriptors with discontiguous binding id's
SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS, //!< multiple descriptors with large gaps between binding id's
SHADER_INPUT_DESCRIPTOR_ARRAY, //!< descriptor array
SHADER_INPUT_LAST
};
deUint32 getInterfaceNumResources (ShaderInputInterface shaderInterface)
{
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR: return 1u;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS: return 2u;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS: return 2u;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS: return 2u;
case SHADER_INPUT_DESCRIPTOR_ARRAY: return 2u;
default:
DE_FATAL("Impossible");
return 0u;
}
}
deUint32 getArbitraryBindingIndex (deUint32 ndx)
{
DE_ASSERT(ndx < 2);
// Binding decoration value can be any 32-bit unsigned integer value.
// 0xFFFE is the largest binding value accepted by glslang
const deUint32 bufferIndices[] =
{
0x7FFEu,
0xFFFEu
};
return bufferIndices[ndx];
}
typedef de::MovePtr<vk::Allocation> AllocationMp;
typedef de::SharedPtr<vk::Allocation> AllocationSp;
typedef vk::Unique<vk::VkBuffer> BufferHandleUp;
typedef de::SharedPtr<BufferHandleUp> BufferHandleSp;
typedef vk::Unique<vk::VkBufferView> BufferViewHandleUp;
typedef de::SharedPtr<BufferViewHandleUp> BufferViewHandleSp;
typedef vk::Unique<vk::VkSampler> SamplerHandleUp;
typedef de::SharedPtr<SamplerHandleUp> SamplerHandleSp;
typedef vk::Unique<vk::VkImage> ImageHandleUp;
typedef de::SharedPtr<ImageHandleUp> ImageHandleSp;
typedef vk::Unique<vk::VkImageView> ImageViewHandleUp;
typedef de::SharedPtr<ImageViewHandleUp> ImageViewHandleSp;
typedef vk::Unique<vk::VkDescriptorSet> DescriptorSetHandleUp;
typedef de::SharedPtr<DescriptorSetHandleUp> DescriptorSetHandleSp;
typedef vk::Unique<vk::VkDescriptorSetLayout> DescriptorSetLayoutHandleUp;
typedef de::SharedPtr<DescriptorSetLayoutHandleUp> DescriptorSetLayoutHandleSp;
typedef vk::Unique<vk::VkDescriptorUpdateTemplate> UpdateTemplateHandleUp;
typedef de::SharedPtr<UpdateTemplateHandleUp> UpdateTemplateHandleSp;
class BufferRenderInstance : public SingleCmdRenderInstance
{
public:
BufferRenderInstance (Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
bool viewOffset,
bool dynamicOffset,
bool dynamicOffsetNonZero);
static std::vector<deUint32> getViewOffsets (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool setViewOffset);
static std::vector<deUint32> getDynamicOffsets (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool dynamicOffsetNonZero);
static std::vector<BufferHandleSp> createSourceBuffers (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<deUint32>& viewOffset,
const std::vector<deUint32>& dynamicOffset,
std::vector<AllocationSp>& bufferMemory);
static vk::Move<vk::VkBuffer> createSourceBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
deUint32 setNdx,
deUint32 offset,
deUint32 bufferSize,
de::MovePtr<vk::Allocation>* outMemory);
static vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface);
static std::vector<DescriptorSetLayoutHandleSp> createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod);
static vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout);
static std::vector<DescriptorSetHandleSp> createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool descriptorPool,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<BufferHandleSp>& buffers,
const std::vector<deUint32>& offsets,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
vk::VkPipelineLayout pipelineLayout = DE_NULL);
static void writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkBuffer sourceBufferA,
const deUint32 viewOffsetA,
vk::VkBuffer sourceBufferB,
const deUint32 viewOffsetB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
static void writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorSetLayout descriptorSetLayout,
deUint32 setNdx,
vk::VkDescriptorPool descriptorPool,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkBuffer sourceBufferA,
const deUint32 viewOffsetA,
vk::VkBuffer sourceBufferB,
const deUint32 viewOffsetB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush = false,
vk::VkPipelineLayout pipelineLayout = 0);
void logTestPlan (void) const;
vk::VkPipelineLayout getPipelineLayout (void) const;
void writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const;
tcu::TestStatus verifyResultImage (const tcu::ConstPixelBufferAccess& result) const;
enum
{
RENDER_SIZE = 128,
BUFFER_DATA_SIZE = 8 * sizeof(float),
BUFFER_SIZE_A = 2048, //!< a lot more than required
BUFFER_SIZE_B = 2560, //!< a lot more than required
BUFFER_SIZE_C = 2128, //!< a lot more than required
BUFFER_SIZE_D = 2136, //!< a lot more than required
STATIC_OFFSET_VALUE_A = 256,
DYNAMIC_OFFSET_VALUE_A = 512,
STATIC_OFFSET_VALUE_B = 1024,
DYNAMIC_OFFSET_VALUE_B = 768,
STATIC_OFFSET_VALUE_C = 512,
DYNAMIC_OFFSET_VALUE_C = 512,
STATIC_OFFSET_VALUE_D = 768,
DYNAMIC_OFFSET_VALUE_D = 1024,
};
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const bool m_setViewOffset;
const bool m_setDynamicOffset;
const bool m_dynamicOffsetNonZero;
const vk::VkShaderStageFlags m_stageFlags;
const std::vector<deUint32> m_viewOffset;
const std::vector<deUint32> m_dynamicOffset;
std::vector<AllocationSp> m_bufferMemory;
const std::vector<BufferHandleSp> m_sourceBuffer;
const vk::Unique<vk::VkDescriptorPool> m_descriptorPool;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
const std::vector<DescriptorSetLayoutHandleSp> m_descriptorSetLayouts;
const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
std::vector<deUint32> m_descriptorsPerSet;
const std::vector<DescriptorSetHandleSp> m_descriptorSets;
};
BufferRenderInstance::BufferRenderInstance (Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
bool viewOffset,
bool dynamicOffset,
bool dynamicOffsetNonZero)
: SingleCmdRenderInstance (context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_setViewOffset (viewOffset)
, m_setDynamicOffset (dynamicOffset)
, m_dynamicOffsetNonZero (dynamicOffsetNonZero)
, m_stageFlags (stageFlags)
, m_viewOffset (getViewOffsets(m_descriptorSetCount, m_shaderInterface, m_setViewOffset))
, m_dynamicOffset (getDynamicOffsets(m_descriptorSetCount, m_shaderInterface, m_dynamicOffsetNonZero))
, m_bufferMemory ()
, m_sourceBuffer (createSourceBuffers(m_vki, m_device, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewOffset, m_dynamicOffset, m_bufferMemory))
, m_descriptorPool (createDescriptorPool(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface))
, m_updateTemplates ()
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorSetLayouts (createDescriptorSetLayouts(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_stageFlags, m_updateMethod))
, m_pipelineLayout (createPipelineLayout(m_vki, m_device, m_descriptorSetLayouts))
, m_descriptorsPerSet ()
, m_descriptorSets (createDescriptorSets(m_vki, m_updateMethod, m_device, m_descriptorSetLayouts, *m_descriptorPool, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_sourceBuffer, m_viewOffset, m_updateBuilder, m_descriptorsPerSet, m_updateTemplates, m_updateRegistry, *m_pipelineLayout))
{
if (m_setDynamicOffset)
DE_ASSERT(isDynamicDescriptorType(m_descriptorType));
if (m_dynamicOffsetNonZero)
DE_ASSERT(m_setDynamicOffset);
}
std::vector<deUint32> BufferRenderInstance::getViewOffsets (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool setViewOffset)
{
const int numBuffers = getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface);
std::vector<deUint32> viewOffset;
for (int bufferNdx = 0; bufferNdx < numBuffers; bufferNdx++)
{
const deUint32 staticOffsetValues[] =
{
STATIC_OFFSET_VALUE_A,
STATIC_OFFSET_VALUE_B,
STATIC_OFFSET_VALUE_C,
STATIC_OFFSET_VALUE_D
};
viewOffset.push_back(setViewOffset ? (staticOffsetValues[bufferNdx % getInterfaceNumResources(shaderInterface)]) : (0u));
}
return viewOffset;
}
std::vector<deUint32> BufferRenderInstance::getDynamicOffsets (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool dynamicOffsetNonZero)
{
const int numBuffers = getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface);
std::vector<deUint32> dynamicOffset;
for (int bufferNdx = 0; bufferNdx < numBuffers; bufferNdx++)
{
const deUint32 dynamicOffsetValues[] =
{
DYNAMIC_OFFSET_VALUE_A,
DYNAMIC_OFFSET_VALUE_B,
DYNAMIC_OFFSET_VALUE_C,
DYNAMIC_OFFSET_VALUE_D
};
dynamicOffset.push_back(dynamicOffsetNonZero ? (dynamicOffsetValues[bufferNdx % getInterfaceNumResources(shaderInterface)]) : (0u));
}
return dynamicOffset;
}
std::vector<BufferHandleSp> BufferRenderInstance::createSourceBuffers (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<deUint32>& viewOffset,
const std::vector<deUint32>& dynamicOffset,
std::vector<AllocationSp>& bufferMemory)
{
const int numBuffers = getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface);
std::vector<deUint32> effectiveOffset;
std::vector<deUint32> bufferSize;
std::vector<BufferHandleSp> sourceBuffers;
for (int bufferNdx = 0; bufferNdx < numBuffers; bufferNdx++)
{
const deUint32 bufferSizeValues[] =
{
BUFFER_SIZE_A,
BUFFER_SIZE_B,
BUFFER_SIZE_C,
BUFFER_SIZE_D
};
effectiveOffset.push_back(isDynamicDescriptorType(descriptorType) ? (viewOffset[bufferNdx] + dynamicOffset[bufferNdx]) : (viewOffset[bufferNdx]));
bufferSize.push_back(bufferSizeValues[bufferNdx % getInterfaceNumResources(shaderInterface)]);
}
// Create source buffers
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
for (deUint32 bufferNdx = 0; bufferNdx < getInterfaceNumResources(shaderInterface); bufferNdx++)
{
de::MovePtr<vk::Allocation> memory;
vk::Move<vk::VkBuffer> buffer = createSourceBuffer(vki, device, allocator, descriptorType, setNdx, effectiveOffset[bufferNdx], bufferSize[bufferNdx], &memory);
bufferMemory.push_back(AllocationSp(memory.release()));
sourceBuffers.push_back(BufferHandleSp(new BufferHandleUp(buffer)));
}
}
return sourceBuffers;
}
vk::Move<vk::VkBuffer> BufferRenderInstance::createSourceBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
deUint32 setNdx,
deUint32 offset,
deUint32 bufferSize,
de::MovePtr<vk::Allocation>* outMemory)
{
static const float s_colors[] =
{
0.0f, 1.0f, 0.0f, 1.0f, // green
1.0f, 1.0f, 0.0f, 1.0f, // yellow
0.0f, 0.0f, 1.0f, 1.0f, // blue
1.0f, 0.0f, 0.0f, 1.0f // red
};
DE_STATIC_ASSERT(sizeof(s_colors) / 2 == BUFFER_DATA_SIZE);
DE_ASSERT(offset + BUFFER_DATA_SIZE <= bufferSize);
DE_ASSERT(offset % sizeof(float) == 0);
DE_ASSERT(bufferSize % sizeof(float) == 0);
const bool isUniformBuffer = isUniformDescriptorType(descriptorType);
const vk::VkBufferUsageFlags usageFlags = (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
const float preGuardValue = 0.5f;
const float postGuardValue = 0.75f;
const vk::VkBufferCreateInfo bufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
bufferSize, // size
usageFlags, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
vk::Move<vk::VkBuffer> buffer (vk::createBuffer(vki, device, &bufferCreateInfo));
de::MovePtr<vk::Allocation> bufferMemory = allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible);
void* const mapPtr = bufferMemory->getHostPtr();
// guard with interesting values
for (size_t preGuardOffset = 0; preGuardOffset + sizeof(float) <= (size_t)offset; preGuardOffset += sizeof(float))
deMemcpy((deUint8*)mapPtr + preGuardOffset, &preGuardValue, sizeof(float));
deMemcpy((deUint8*)mapPtr + offset, &s_colors[8 * (setNdx % 2)], sizeof(s_colors) / 2);
for (size_t postGuardOffset = (size_t)offset + sizeof(s_colors) / 2; postGuardOffset + sizeof(float) <= (size_t)bufferSize; postGuardOffset += sizeof(float))
deMemcpy((deUint8*)mapPtr + postGuardOffset, &postGuardValue, sizeof(float));
deMemset((deUint8*)mapPtr + offset + sizeof(s_colors) / 2, 0x5A, (size_t)bufferSize - (size_t)offset - sizeof(s_colors) / 2); // fill with interesting pattern that produces valid floats
flushAlloc(vki, device, *bufferMemory);
// Flushed host-visible memory is automatically made available to the GPU, no barrier is needed.
*outMemory = bufferMemory;
return buffer;
}
vk::Move<vk::VkDescriptorPool> BufferRenderInstance::createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface)
{
return vk::DescriptorPoolBuilder()
.addType(descriptorType, getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface))
.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(descriptorSetCount));
}
std::vector<DescriptorSetLayoutHandleSp> BufferRenderInstance::createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod)
{
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::DescriptorSetLayoutBuilder builder;
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(descriptorType, stageFlags);
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, 0u);
builder.addSingleIndexedBinding(descriptorType, stageFlags, 2u);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(descriptorType, 2u, stageFlags);
break;
default:
DE_FATAL("Impossible");
}
vk::Move<vk::VkDescriptorSetLayout> layout = builder.build(vki, device, extraFlags);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
}
}
return descriptorSetLayouts;
}
vk::Move<vk::VkPipelineLayout> BufferRenderInstance::createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout)
{
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
for (size_t setNdx = 0; setNdx < descriptorSetLayout.size(); setNdx++)
layoutHandles.push_back(**descriptorSetLayout[setNdx]);
const vk::VkPipelineLayoutCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
(deUint32)layoutHandles.size(), // descriptorSetCount
&layoutHandles.front(), // pSetLayouts
0u, // pushConstantRangeCount
DE_NULL, // pPushConstantRanges
};
return vk::createPipelineLayout(vki, device, &createInfo);
}
std::vector<DescriptorSetHandleSp> BufferRenderInstance::createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool descriptorPool,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<BufferHandleSp>& buffers,
const std::vector<deUint32>& offsets,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
vk::VkPipelineLayout pipelineLayout)
{
std::vector<DescriptorSetHandleSp> descriptorSets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::VkDescriptorSetLayout layout = **descriptorSetLayouts[getDescriptorSetNdx(descriptorSetCount, setNdx)];
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
descriptorPool,
1u,
&layout
};
vk::VkBuffer bufferA = **buffers[(setNdx * getInterfaceNumResources(shaderInterface)) % buffers.size()];
vk::VkBuffer bufferB = **buffers[(setNdx * getInterfaceNumResources(shaderInterface) + 1) % buffers.size()];
deUint32 offsetA = offsets[(setNdx * getInterfaceNumResources(shaderInterface)) % offsets.size()];
deUint32 offsetB = offsets[(setNdx * getInterfaceNumResources(shaderInterface) + 1) % offsets.size()];
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, layout, setNdx, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateTemplates, updateRegistry);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, layout, setNdx, descriptorPool, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateTemplates, updateRegistry, true, pipelineLayout);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateBuilder, descriptorsPerSet, updateMethod);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, bufferA, offsetA, bufferB, offsetB, *descriptorSet, updateBuilder, descriptorsPerSet);
}
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(descriptorSet)));
}
return descriptorSets;
}
void BufferRenderInstance::writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkBuffer bufferA,
const deUint32 offsetA,
vk::VkBuffer bufferB,
const deUint32 offsetB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod)
{
const vk::VkDescriptorBufferInfo bufferInfos[2] =
{
vk::makeDescriptorBufferInfo(bufferA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
vk::makeDescriptorBufferInfo(bufferB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
};
deUint32 numDescriptors = 0u;
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &bufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), descriptorType, &bufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, bufferInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
descriptorsPerSet.push_back(numDescriptors);
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateBuilder.update(vki, device);
updateBuilder.clear();
}
}
void BufferRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorSetLayout layout,
deUint32 setNdx,
vk::VkDescriptorPool descriptorPool,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkBuffer bufferA,
const deUint32 offsetA,
vk::VkBuffer bufferB,
const deUint32 offsetB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush,
vk::VkPipelineLayout pipelineLayout)
{
DE_UNREF(descriptorPool);
const vk::VkDescriptorBufferInfo bufferInfos[2] =
{
vk::makeDescriptorBufferInfo(bufferA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
vk::makeDescriptorBufferInfo(bufferB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)BUFFER_DATA_SIZE),
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // descriptorUpdateEntryCount
DE_NULL, // pDescriptorUpdateEntries
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
setNdx
};
RawUpdateRegistry updateRegistry;
updateRegistry.addWriteObject(bufferInfos[0]);
updateRegistry.addWriteObject(bufferInfos[1]);
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(0u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(1u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(2u, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(0u, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(bufferInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
registry.push_back(updateRegistry);
if (!withPush)
{
vki.updateDescriptorSetWithTemplate(device, descriptorSet, **updateTemplates.back(), registry.back().getRawPointer());
}
}
void BufferRenderInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Rendering 2x2 yellow-green grid.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
<< "Buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
if (isDynamicDescriptorType(m_descriptorType))
{
if (m_setDynamicOffset)
{
msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
}
else
{
msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
}
}
if (m_stageFlags == 0u)
{
msg << "Descriptors are not accessed in any shader stage.\n";
}
else
{
msg << "Descriptors are accessed in {"
<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0) ? (" vertex") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? (" tess_control") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) ? (" tess_evaluation") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0) ? (" geometry") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0) ? (" fragment") : (""))
<< " } stages.\n";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
vk::VkPipelineLayout BufferRenderInstance::getPipelineLayout (void) const
{
return *m_pipelineLayout;
}
void BufferRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
{
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
std::vector<vk::VkDescriptorSet> sets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
sets.push_back(**m_descriptorSets[setNdx]);
switch (m_descriptorSetCount)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE:
{
// \note dynamic offset replaces the view offset, i.e. it is not offset relative to the view offset
const deUint32 numOffsets = (!m_setDynamicOffset) ? (0u) : ((deUint32)m_dynamicOffset.size());
const deUint32* const dynamicOffsetPtr = (!m_setDynamicOffset) ? (DE_NULL) : (&m_dynamicOffset.front());
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, (int)sets.size(), &sets.front(), numOffsets, dynamicOffsetPtr);
break;
}
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
{
deUint32 dynamicOffsetNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
// \note dynamic offset replaces the view offset, i.e. it is not offset relative to the view offset
const deUint32 numOffsets = (!m_setDynamicOffset) ? (0u) : (getInterfaceNumResources(m_shaderInterface));
const deUint32* const dynamicOffsetPtr = (!m_setDynamicOffset) ? (DE_NULL) : (&m_dynamicOffset[dynamicOffsetNdx]);
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), descriptorSetNdx, 1, &sets[setNdx], numOffsets, dynamicOffsetPtr);
dynamicOffsetNdx += getInterfaceNumResources(m_shaderInterface);
}
break;
}
default:
DE_FATAL("Impossible");
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, **m_updateTemplates[setNdx], getPipelineLayout(), setNdx, (const void*)m_updateRegistry[setNdx].getRawPointer());
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
deUint32 descriptorNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 numDescriptors = m_descriptorsPerSet[setNdx];
m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, setNdx, descriptorNdx, numDescriptors);
descriptorNdx += numDescriptors;
}
}
m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
}
tcu::TestStatus BufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
{
const deUint32 numDescriptorSets = getDescriptorSetCount(m_descriptorSetCount);
const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f);
tcu::Surface reference (m_targetSize.x(), m_targetSize.y());
tcu::Vec4 sample0 = tcu::Vec4(0.0f);
tcu::Vec4 sample1 = tcu::Vec4(0.0f);
if (m_stageFlags)
{
const tcu::Vec4 colors[] =
{
tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), // green
tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // yellow
tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), // blue
tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), // red
};
for (deUint32 setNdx = 0; setNdx < numDescriptorSets; setNdx++)
{
sample0 += colors[2 * (setNdx % 2)];
sample1 += colors[2 * (setNdx % 2) + 1];
}
if (numDescriptorSets > 1)
{
sample0 = sample0 / tcu::Vec4(float(numDescriptorSets));
sample1 = sample1 / tcu::Vec4(float(numDescriptorSets));
}
}
else
{
sample0 = green;
sample1 = yellow;
}
drawQuadrantReferenceResult(reference.getAccess(), sample1, sample0, sample0, sample1);
if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Image verification failed");
else
return tcu::TestStatus::pass("Pass");
}
class ComputeInstanceResultBuffer
{
public:
enum
{
DATA_SIZE = sizeof(tcu::Vec4[4])
};
ComputeInstanceResultBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator);
void readResultContentsTo (tcu::Vec4 (*results)[4]) const;
inline vk::VkBuffer getBuffer (void) const { return *m_buffer; }
inline const vk::VkBufferMemoryBarrier* getResultReadBarrier (void) const { return &m_bufferBarrier; }
private:
static vk::Move<vk::VkBuffer> createResultBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
de::MovePtr<vk::Allocation>* outAllocation);
static vk::VkBufferMemoryBarrier createResultBufferBarrier (vk::VkBuffer buffer);
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
de::MovePtr<vk::Allocation> m_bufferMem;
const vk::Unique<vk::VkBuffer> m_buffer;
const vk::VkBufferMemoryBarrier m_bufferBarrier;
};
ComputeInstanceResultBuffer::ComputeInstanceResultBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator)
: m_vki (vki)
, m_device (device)
, m_bufferMem (DE_NULL)
, m_buffer (createResultBuffer(m_vki, m_device, allocator, &m_bufferMem))
, m_bufferBarrier (createResultBufferBarrier(*m_buffer))
{
}
void ComputeInstanceResultBuffer::readResultContentsTo (tcu::Vec4 (*results)[4]) const
{
invalidateAlloc(m_vki, m_device, *m_bufferMem);
deMemcpy(*results, m_bufferMem->getHostPtr(), sizeof(*results));
}
vk::Move<vk::VkBuffer> ComputeInstanceResultBuffer::createResultBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
de::MovePtr<vk::Allocation>* outAllocation)
{
const vk::VkBufferCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
(vk::VkDeviceSize)DATA_SIZE, // size
vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
vk::Move<vk::VkBuffer> buffer (vk::createBuffer(vki, device, &createInfo));
de::MovePtr<vk::Allocation> allocation (allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
const float clearValue = -1.0f;
void* mapPtr = allocation->getHostPtr();
for (size_t offset = 0; offset < DATA_SIZE; offset += sizeof(float))
deMemcpy(((deUint8*)mapPtr) + offset, &clearValue, sizeof(float));
flushAlloc(vki, device, *allocation);
*outAllocation = allocation;
return buffer;
}
vk::VkBufferMemoryBarrier ComputeInstanceResultBuffer::createResultBufferBarrier (vk::VkBuffer buffer)
{
const vk::VkBufferMemoryBarrier bufferBarrier =
{
vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
DE_NULL,
vk::VK_ACCESS_SHADER_WRITE_BIT, // srcAccessMask
vk::VK_ACCESS_HOST_READ_BIT, // dstAccessMask
VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex
buffer, // buffer
(vk::VkDeviceSize)0u, // offset
DATA_SIZE, // size
};
return bufferBarrier;
}
class ComputePipeline
{
public:
ComputePipeline (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::BinaryCollection& programCollection,
deUint32 numDescriptorSets,
const vk::VkDescriptorSetLayout* descriptorSetLayouts);
inline vk::VkPipeline getPipeline (void) const { return *m_pipeline; };
inline vk::VkPipelineLayout getPipelineLayout (void) const { return *m_pipelineLayout; };
private:
static vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 numDescriptorSets,
const vk::VkDescriptorSetLayout* descriptorSetLayouts);
static vk::Move<vk::VkPipeline> createPipeline (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::BinaryCollection& programCollection,
vk::VkPipelineLayout layout);
const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
const vk::Unique<vk::VkPipeline> m_pipeline;
};
ComputePipeline::ComputePipeline (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::BinaryCollection& programCollection,
deUint32 numDescriptorSets,
const vk::VkDescriptorSetLayout* descriptorSetLayouts)
: m_pipelineLayout (createPipelineLayout(vki, device, numDescriptorSets, descriptorSetLayouts))
, m_pipeline (createPipeline(vki, device, programCollection, *m_pipelineLayout))
{
}
vk::Move<vk::VkPipelineLayout> ComputePipeline::createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 numDescriptorSets,
const vk::VkDescriptorSetLayout* descriptorSetLayouts)
{
const vk::VkPipelineLayoutCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
numDescriptorSets, // descriptorSetCount
descriptorSetLayouts, // pSetLayouts
0u, // pushConstantRangeCount
DE_NULL, // pPushConstantRanges
};
return vk::createPipelineLayout(vki, device, &createInfo);
}
vk::Move<vk::VkPipeline> ComputePipeline::createPipeline (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::BinaryCollection& programCollection,
vk::VkPipelineLayout layout)
{
const vk::Unique<vk::VkShaderModule> computeModule (vk::createShaderModule(vki, device, programCollection.get("compute"), (vk::VkShaderModuleCreateFlags)0u));
const vk::VkPipelineShaderStageCreateInfo cs =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
DE_NULL,
(vk::VkPipelineShaderStageCreateFlags)0,
vk::VK_SHADER_STAGE_COMPUTE_BIT, // stage
*computeModule, // shader
"main",
DE_NULL, // pSpecializationInfo
};
const vk::VkComputePipelineCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
DE_NULL,
0u, // flags
cs, // cs
layout, // layout
(vk::VkPipeline)0, // basePipelineHandle
0u, // basePipelineIndex
};
return createComputePipeline(vki, device, (vk::VkPipelineCache)0u, &createInfo);
}
class ComputeCommand
{
public:
ComputeCommand (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkPipeline pipeline,
vk::VkPipelineLayout pipelineLayout,
const tcu::UVec3& numWorkGroups,
ShaderInputInterface shaderInterface,
DescriptorSetCount descriptorSetCount,
const vk::VkDescriptorSet* descriptorSets,
int numDynamicOffsets,
const deUint32* dynamicOffsets,
int numPreBarriers,
const vk::VkBufferMemoryBarrier* preBarriers,
int numPostBarriers,
const vk::VkBufferMemoryBarrier* postBarriers);
void submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, std::vector<UpdateTemplateHandleSp>* updateTemplates = DE_NULL, std::vector<RawUpdateRegistry>* updateRegistry = DE_NULL) const;
void submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, vk::DescriptorSetUpdateBuilder& updateBuilder, std::vector<deUint32>& descriptorsPerSet) const;
private:
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkPipeline m_pipeline;
const vk::VkPipelineLayout m_pipelineLayout;
const tcu::UVec3 m_numWorkGroups;
const ShaderInputInterface m_shaderInterface;
const DescriptorSetCount m_descriptorSetCount;
const vk::VkDescriptorSet* const m_descriptorSets;
const int m_numDynamicOffsets;
const deUint32* const m_dynamicOffsets;
const int m_numPreBarriers;
const vk::VkBufferMemoryBarrier* const m_preBarriers;
const int m_numPostBarriers;
const vk::VkBufferMemoryBarrier* const m_postBarriers;
};
ComputeCommand::ComputeCommand (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkPipeline pipeline,
vk::VkPipelineLayout pipelineLayout,
const tcu::UVec3& numWorkGroups,
ShaderInputInterface shaderInterface,
DescriptorSetCount descriptorSetCount,
const vk::VkDescriptorSet* descriptorSets,
int numDynamicOffsets,
const deUint32* dynamicOffsets,
int numPreBarriers,
const vk::VkBufferMemoryBarrier* preBarriers,
int numPostBarriers,
const vk::VkBufferMemoryBarrier* postBarriers)
: m_vki (vki)
, m_device (device)
, m_pipeline (pipeline)
, m_pipelineLayout (pipelineLayout)
, m_numWorkGroups (numWorkGroups)
, m_shaderInterface (shaderInterface)
, m_descriptorSetCount (descriptorSetCount)
, m_descriptorSets (descriptorSets)
, m_numDynamicOffsets (numDynamicOffsets)
, m_dynamicOffsets (dynamicOffsets)
, m_numPreBarriers (numPreBarriers)
, m_preBarriers (preBarriers)
, m_numPostBarriers (numPostBarriers)
, m_postBarriers (postBarriers)
{
}
void ComputeCommand::submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, std::vector<UpdateTemplateHandleSp>* updateTemplates, std::vector<RawUpdateRegistry>* updateRegistry) const
{
const vk::VkCommandPoolCreateInfo cmdPoolCreateInfo =
{
vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
DE_NULL,
vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // flags
queueFamilyIndex, // queueFamilyIndex
};
const vk::Unique<vk::VkCommandPool> cmdPool (vk::createCommandPool(m_vki, m_device, &cmdPoolCreateInfo));
const vk::VkCommandBufferAllocateInfo cmdBufCreateInfo =
{
vk::VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
DE_NULL,
*cmdPool, // cmdPool
vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY, // level
1u, // count
};
const vk::Unique<vk::VkCommandBuffer> cmd (vk::allocateCommandBuffer(m_vki, m_device, &cmdBufCreateInfo));
beginCommandBuffer(m_vki, *cmd);
m_vki.cmdBindPipeline(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline);
// normal update
if (updateTemplates == DE_NULL)
{
switch (m_descriptorSetCount)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE:
{
m_vki.cmdBindDescriptorSets(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, 0, getDescriptorSetCount(m_descriptorSetCount), m_descriptorSets, m_numDynamicOffsets, m_dynamicOffsets);
break;
}
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
{
deUint32 dynamicOffsetNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
// \note dynamic offset replaces the view offset, i.e. it is not offset relative to the view offset
const deUint32 numOffsets = (!m_numDynamicOffsets) ? (0u) : (getInterfaceNumResources(m_shaderInterface));
const deUint32* const dynamicOffsetPtr = (!m_numDynamicOffsets) ? (DE_NULL) : (&m_dynamicOffsets[dynamicOffsetNdx]);
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdBindDescriptorSets(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, descriptorSetNdx, 1u, &m_descriptorSets[setNdx], numOffsets, dynamicOffsetPtr);
dynamicOffsetNdx += getInterfaceNumResources(m_shaderInterface);
}
break;
}
default:
DE_FATAL("Impossible");
}
}
// update with push template
else
{
for (deUint32 setNdx = 0; setNdx < (deUint32)(*updateTemplates).size(); setNdx++)
m_vki.cmdPushDescriptorSetWithTemplateKHR(*cmd, **(*updateTemplates)[setNdx], m_pipelineLayout, getDescriptorSetNdx(m_descriptorSetCount, setNdx), (const void*)(*updateRegistry)[setNdx].getRawPointer());
}
if (m_numPreBarriers)
m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0,
0, (const vk::VkMemoryBarrier*)DE_NULL,
m_numPreBarriers, m_preBarriers,
0, (const vk::VkImageMemoryBarrier*)DE_NULL);
m_vki.cmdDispatch(*cmd, m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, (vk::VkDependencyFlags)0,
0, (const vk::VkMemoryBarrier*)DE_NULL,
m_numPostBarriers, m_postBarriers,
0, (const vk::VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(m_vki, *cmd);
submitCommandsAndWait(m_vki, m_device, queue, cmd.get());
}
//cmdPushDescriptorSet variant
void ComputeCommand::submitAndWait (deUint32 queueFamilyIndex, vk::VkQueue queue, vk::DescriptorSetUpdateBuilder& updateBuilder, std::vector<deUint32>& descriptorsPerSet) const
{
const vk::VkCommandPoolCreateInfo cmdPoolCreateInfo =
{
vk::VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
DE_NULL,
vk::VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, // flags
queueFamilyIndex, // queueFamilyIndex
};
const vk::Unique<vk::VkCommandPool> cmdPool (vk::createCommandPool(m_vki, m_device, &cmdPoolCreateInfo));
const vk::Unique<vk::VkCommandBuffer> cmd (vk::allocateCommandBuffer(m_vki, m_device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
beginCommandBuffer(m_vki, *cmd);
m_vki.cmdBindPipeline(*cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipeline);
{
deUint32 descriptorNdx = 0u;
for (deUint32 setNdx = 0; setNdx < (deUint32)descriptorsPerSet.size(); setNdx++)
{
const deUint32 numDescriptors = descriptorsPerSet[setNdx];
updateBuilder.updateWithPush(m_vki, *cmd, vk::VK_PIPELINE_BIND_POINT_COMPUTE, m_pipelineLayout, getDescriptorSetNdx(m_descriptorSetCount, setNdx), descriptorNdx, numDescriptors);
descriptorNdx += numDescriptors;
}
}
if (m_numPreBarriers)
m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (vk::VkDependencyFlags)0,
0, (const vk::VkMemoryBarrier*)DE_NULL,
m_numPreBarriers, m_preBarriers,
0, (const vk::VkImageMemoryBarrier*)DE_NULL);
m_vki.cmdDispatch(*cmd, m_numWorkGroups.x(), m_numWorkGroups.y(), m_numWorkGroups.z());
m_vki.cmdPipelineBarrier(*cmd, vk::VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, (vk::VkDependencyFlags)0,
0, (const vk::VkMemoryBarrier*)DE_NULL,
m_numPostBarriers, m_postBarriers,
0, (const vk::VkImageMemoryBarrier*)DE_NULL);
endCommandBuffer(m_vki, *cmd);
submitCommandsAndWait(m_vki, m_device, queue, cmd.get());
}
class BufferComputeInstance : public vkt::TestInstance
{
public:
BufferComputeInstance (Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool viewOffset,
bool dynamicOffset,
bool dynamicOffsetNonZero);
private:
vk::Move<vk::VkBuffer> createColorDataBuffer (deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation);
vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (deUint32 setNdx) const;
vk::Move<vk::VkDescriptorPool> createDescriptorPool (void) const;
vk::Move<vk::VkDescriptorSet> createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf);
void writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf);
void writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
tcu::TestStatus iterate (void);
void logTestPlan (void) const;
tcu::TestStatus testResourceAccess (void);
enum
{
STATIC_OFFSET_VALUE_A = 256,
DYNAMIC_OFFSET_VALUE_A = 512,
STATIC_OFFSET_VALUE_B = 1024,
DYNAMIC_OFFSET_VALUE_B = 768,
};
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const bool m_setViewOffset;
const bool m_setDynamicOffset;
const bool m_dynamicOffsetNonZero;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vk::Allocator& m_allocator;
const ComputeInstanceResultBuffer m_result;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
std::vector<deUint32> m_descriptorsPerSet;
};
BufferComputeInstance::BufferComputeInstance (Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool viewOffset,
bool dynamicOffset,
bool dynamicOffsetNonZero)
: vkt::TestInstance (context)
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_setViewOffset (viewOffset)
, m_setDynamicOffset (dynamicOffset)
, m_dynamicOffsetNonZero (dynamicOffsetNonZero)
, m_updateTemplates ()
, m_vki (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_allocator (context.getDefaultAllocator())
, m_result (m_vki, m_device, m_allocator)
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorsPerSet ()
{
if (m_dynamicOffsetNonZero)
DE_ASSERT(m_setDynamicOffset);
}
vk::Move<vk::VkBuffer> BufferComputeInstance::createColorDataBuffer (deUint32 offset, deUint32 bufferSize, const tcu::Vec4& value1, const tcu::Vec4& value2, de::MovePtr<vk::Allocation>* outAllocation)
{
DE_ASSERT(offset + sizeof(tcu::Vec4[2]) <= bufferSize);
const bool isUniformBuffer = isUniformDescriptorType(m_descriptorType);
const vk::VkBufferUsageFlags usageFlags = (isUniformBuffer) ? (vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
const vk::VkBufferCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
(vk::VkDeviceSize)bufferSize, // size
usageFlags, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
vk::Move<vk::VkBuffer> buffer (vk::createBuffer(m_vki, m_device, &createInfo));
de::MovePtr<vk::Allocation> allocation (allocateAndBindObjectMemory(m_vki, m_device, m_allocator, *buffer, vk::MemoryRequirement::HostVisible));
void* mapPtr = allocation->getHostPtr();
if (offset)
deMemset(mapPtr, 0x5A, (size_t)offset);
deMemcpy((deUint8*)mapPtr + offset, value1.getPtr(), sizeof(tcu::Vec4));
deMemcpy((deUint8*)mapPtr + offset + sizeof(tcu::Vec4), value2.getPtr(), sizeof(tcu::Vec4));
deMemset((deUint8*)mapPtr + offset + 2 * sizeof(tcu::Vec4), 0x5A, (size_t)bufferSize - (size_t)offset - 2 * sizeof(tcu::Vec4));
flushAlloc(m_vki, m_device, *allocation);
*outAllocation = allocation;
return buffer;
}
vk::Move<vk::VkDescriptorSetLayout> BufferComputeInstance::createDescriptorSetLayout (deUint32 setNdx) const
{
vk::DescriptorSetLayoutBuilder builder;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
deUint32 binding = 0;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
if (setNdx == 0)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 0u);
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 2u);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
default:
DE_FATAL("Impossible");
};
return builder.build(m_vki, m_device, extraFlags);
}
vk::Move<vk::VkDescriptorPool> BufferComputeInstance::createDescriptorPool (void) const
{
return vk::DescriptorPoolBuilder()
.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
.addType(m_descriptorType, getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface))
.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(m_descriptorSetCount));
}
vk::Move<vk::VkDescriptorSet> BufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf)
{
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(*descriptorSet, layout, setNdx, viewA, offsetA, viewB, offsetB, resBuf);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(*descriptorSet, setNdx, viewA, offsetA, viewB, offsetB, resBuf);
}
return descriptorSet;
}
void BufferComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(resBuf, 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkDescriptorBufferInfo bufferInfos[2] =
{
vk::makeDescriptorBufferInfo(viewA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
vk::makeDescriptorBufferInfo(viewB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
};
deUint32 numDescriptors = 0u;
deUint32 binding = 0u;
// result
if (setNdx == 0)
{
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
numDescriptors++;
}
// buffers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &bufferInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &bufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding), m_descriptorType, &bufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding + 2), m_descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), m_descriptorType, &bufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), m_descriptorType, &bufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, 2u, bufferInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
m_descriptorsPerSet.push_back(numDescriptors);
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
m_updateBuilder.update(m_vki, m_device);
m_updateBuilder.clear();
}
}
void BufferComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkBuffer viewA, deUint32 offsetA, vk::VkBuffer viewB, deUint32 offsetB, vk::VkBuffer resBuf, bool withPush, vk::VkPipelineLayout pipelineLayout)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(resBuf, 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkDescriptorBufferInfo bufferInfos[2] =
{
vk::makeDescriptorBufferInfo(viewA, (vk::VkDeviceSize)offsetA, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
vk::makeDescriptorBufferInfo(viewB, (vk::VkDeviceSize)offsetB, (vk::VkDeviceSize)sizeof(tcu::Vec4[2])),
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // descriptorUpdateEntryCount
DE_NULL, // pDescriptorUpdateEntries
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_COMPUTE,
pipelineLayout,
setNdx
};
deUint32 binding = 0u;
deUint32 offset = 0u;
RawUpdateRegistry updateRegistry;
if (setNdx == 0)
updateRegistry.addWriteObject(resultInfo);
updateRegistry.addWriteObject(bufferInfos[0]);
updateRegistry.addWriteObject(bufferInfos[1]);
// result
if (setNdx == 0)
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, updateRegistry.getWriteObjectOffset(offset++), 0));
// buffers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding + 2, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(binding++, 0, 2, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), sizeof(bufferInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
m_updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
m_updateRegistry.push_back(updateRegistry);
if (!withPush)
{
m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, **m_updateTemplates.back(), m_updateRegistry.back().getRawPointer());
}
}
tcu::TestStatus BufferComputeInstance::iterate (void)
{
logTestPlan();
return testResourceAccess();
}
void BufferComputeInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Accessing resource in a compute program.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " source descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType)
<< " and one destination VK_DESCRIPTOR_TYPE_STORAGE_BUFFER to store results to.\n"
<< "Source descriptor buffer view(s) have " << ((m_setViewOffset) ? ("non-") : ("")) << "zero offset.\n";
if (isDynamicDescriptorType(m_descriptorType))
{
if (m_setDynamicOffset)
{
msg << "Source buffer(s) are given a dynamic offset at bind time.\n"
<< "The supplied dynamic offset is " << ((m_dynamicOffsetNonZero) ? ("non-") : ("")) << "zero.\n";
}
else
{
msg << "Dynamic offset is not supplied at bind time. Expecting bind to offset 0.\n";
}
}
msg << "Destination buffer is pre-initialized to -1.\n";
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
tcu::TestStatus BufferComputeInstance::testResourceAccess (void)
{
enum
{
ADDRESSABLE_SIZE = 256, // allocate a lot more than required
};
const bool isDynamicCase = isDynamicDescriptorType(m_descriptorType);
const bool isUniformBuffer = isUniformDescriptorType(m_descriptorType);
const tcu::Vec4 color[] =
{
tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f), // green
tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // yellow
tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f), // blue
tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f), // red
};
std::vector<deUint32> bindTimeOffsets;
std::vector<tcu::Vec4> colors;
std::vector<deUint32> dataOffsets;
std::vector<deUint32> viewOffsets;
std::vector<deUint32> bufferSizes;
std::vector<AllocationSp> bufferMems;
std::vector<BufferHandleSp> buffers;
for (deUint32 bufferNdx = 0; bufferNdx < getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface); bufferNdx++)
{
const deUint32 staticOffsets[] =
{
STATIC_OFFSET_VALUE_A,
STATIC_OFFSET_VALUE_B
};
const deUint32 dynamicOffset[] =
{
DYNAMIC_OFFSET_VALUE_A,
DYNAMIC_OFFSET_VALUE_B
};
const deUint32 parity = bufferNdx % 2;
bindTimeOffsets.push_back((m_dynamicOffsetNonZero) ? (dynamicOffset[parity]) : (0u));
const deUint32 dataOffset = ((isDynamicCase) ? (bindTimeOffsets.back()) : 0) + ((m_setViewOffset) ? (staticOffsets[parity]) : (0u));
const deUint32 viewOffset = ((m_setViewOffset) ? (staticOffsets[parity]) : (0u));
colors.push_back(color[bufferNdx % DE_LENGTH_OF_ARRAY(color)]);
dataOffsets.push_back(dataOffset);
viewOffsets.push_back(viewOffset);
bufferSizes.push_back(dataOffsets.back() + ADDRESSABLE_SIZE);
de::MovePtr<vk::Allocation> bufferMem;
vk::Move<vk::VkBuffer> buffer (createColorDataBuffer(dataOffsets.back(), bufferSizes.back(), color[(bufferNdx * 2) % DE_LENGTH_OF_ARRAY(color)], color[(bufferNdx * 2 + 1) % DE_LENGTH_OF_ARRAY(color)], &bufferMem));
bufferMems.push_back(AllocationSp(bufferMem.release()));
buffers.push_back(BufferHandleSp(new BufferHandleUp(buffer)));
}
const vk::Unique<vk::VkDescriptorPool> descriptorPool(createDescriptorPool());
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
std::vector<DescriptorSetHandleSp> descriptorSets;
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
std::vector<vk::VkDescriptorSet> setHandles;
const deUint32 numSrcBuffers = getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface);
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 ndx0 = (setNdx * getInterfaceNumResources(m_shaderInterface)) % numSrcBuffers;
const deUint32 ndx1 = (setNdx * getInterfaceNumResources(m_shaderInterface) + 1) % numSrcBuffers;
vk::Move<vk::VkDescriptorSetLayout> layout = createDescriptorSetLayout(setNdx);
vk::Move<vk::VkDescriptorSet> set = createDescriptorSet(*descriptorPool, *layout, setNdx, **buffers[ndx0], viewOffsets[ndx0], **buffers[ndx1], viewOffsets[ndx1], m_result.getBuffer());
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(set)));
layoutHandles.push_back(**descriptorSetLayouts.back());
setHandles.push_back(**descriptorSets.back());
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && m_descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(m_vki, m_device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
layoutHandles.push_back(**descriptorSetLayouts.back());
}
}
const ComputePipeline pipeline (m_vki, m_device, m_context.getBinaryCollection(), (int)layoutHandles.size(), &layoutHandles.front());
const vk::VkAccessFlags inputBit = (isUniformBuffer) ? (vk::VK_ACCESS_UNIFORM_READ_BIT) : (vk::VK_ACCESS_SHADER_READ_BIT);
std::vector<vk::VkBufferMemoryBarrier> bufferBarriers;
for (deUint32 bufferNdx = 0; bufferNdx < numSrcBuffers; bufferNdx++)
{
const vk::VkBufferMemoryBarrier barrier =
{
vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
DE_NULL,
vk::VK_ACCESS_HOST_WRITE_BIT, // srcAccessMask
inputBit, // dstAccessMask
VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex
**buffers[bufferNdx], // buffer
(vk::VkDeviceSize)0u, // offset
(vk::VkDeviceSize)bufferSizes[bufferNdx], // size
};
bufferBarriers.push_back(barrier);
}
const deUint32* const dynamicOffsets = (m_setDynamicOffset) ? (&bindTimeOffsets.front()) : (DE_NULL);
const deUint32 numDynamicOffsets = (m_setDynamicOffset) ? (numSrcBuffers) : (0);
const vk::VkBufferMemoryBarrier* const preBarriers = &bufferBarriers.front();
const int numPreBarriers = numSrcBuffers;
const vk::VkBufferMemoryBarrier* const postBarriers = m_result.getResultReadBarrier();
const int numPostBarriers = 1;
const ComputeCommand compute (m_vki,
m_device,
pipeline.getPipeline(),
pipeline.getPipelineLayout(),
tcu::UVec3(4, 1, 1),
m_shaderInterface,
m_descriptorSetCount, &setHandles.front(),
numDynamicOffsets, dynamicOffsets,
numPreBarriers, preBarriers,
numPostBarriers, postBarriers);
tcu::Vec4 refQuadrantValue14 = tcu::Vec4(0.0f);
tcu::Vec4 refQuadrantValue23 = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
deUint32 offset = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? 1 : 3;
refQuadrantValue14 += color[(2 * setNdx * getInterfaceNumResources(m_shaderInterface) + offset) % DE_LENGTH_OF_ARRAY(color)];
refQuadrantValue23 += color[(2 * setNdx * getInterfaceNumResources(m_shaderInterface)) % DE_LENGTH_OF_ARRAY(color)];
}
refQuadrantValue14 = refQuadrantValue14 / tcu::Vec4((float)getDescriptorSetCount(m_descriptorSetCount));
refQuadrantValue23 = refQuadrantValue23 / tcu::Vec4((float)getDescriptorSetCount(m_descriptorSetCount));
const tcu::Vec4 references[4] =
{
refQuadrantValue14,
refQuadrantValue23,
refQuadrantValue23,
refQuadrantValue14,
};
tcu::Vec4 results[4];
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 ndx0 = (setNdx * getInterfaceNumResources(m_shaderInterface)) % numSrcBuffers;
const deUint32 ndx1 = (setNdx * getInterfaceNumResources(m_shaderInterface) + 1) % numSrcBuffers;
writeDescriptorSetWithTemplate(DE_NULL, layoutHandles[setNdx], setNdx, **buffers[ndx0], viewOffsets[ndx0], **buffers[ndx1], viewOffsets[ndx1], m_result.getBuffer(), true, pipeline.getPipelineLayout());
}
compute.submitAndWait(m_queueFamilyIndex, m_queue, &m_updateTemplates, &m_updateRegistry);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 ndx0 = (setNdx * getInterfaceNumResources(m_shaderInterface)) % numSrcBuffers;
const deUint32 ndx1 = (setNdx * getInterfaceNumResources(m_shaderInterface) + 1) % numSrcBuffers;
writeDescriptorSet(DE_NULL, setNdx, **buffers[ndx0], viewOffsets[ndx0], **buffers[ndx1], viewOffsets[ndx1], m_result.getBuffer());
}
compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder, m_descriptorsPerSet);
}
else
{
compute.submitAndWait(m_queueFamilyIndex, m_queue);
}
m_result.readResultContentsTo(&results);
// verify
if (results[0] == references[0] &&
results[1] == references[1] &&
results[2] == references[2] &&
results[3] == references[3])
{
return tcu::TestStatus::pass("Pass");
}
else if (results[0] == tcu::Vec4(-1.0f) &&
results[1] == tcu::Vec4(-1.0f) &&
results[2] == tcu::Vec4(-1.0f) &&
results[3] == tcu::Vec4(-1.0f))
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Result buffer was not written to."
<< tcu::TestLog::EndMessage;
return tcu::TestStatus::fail("Result buffer was not written to");
}
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Error expected ["
<< references[0] << ", "
<< references[1] << ", "
<< references[2] << ", "
<< references[3] << "], got ["
<< results[0] << ", "
<< results[1] << ", "
<< results[2] << ", "
<< results[3] << "]"
<< tcu::TestLog::EndMessage;
return tcu::TestStatus::fail("Invalid result values");
}
}
class QuadrantRendederCase : public vkt::TestCase
{
public:
QuadrantRendederCase (tcu::TestContext& testCtx,
const char* name,
const char* description,
glu::GLSLVersion glslVersion,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount);
private:
virtual std::string genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const = 0;
virtual std::string genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const = 0;
virtual std::string genResourceAccessSource (vk::VkShaderStageFlagBits stage) const = 0;
virtual std::string genNoAccessSource (void) const = 0;
std::string genVertexSource (void) const;
std::string genTessCtrlSource (void) const;
std::string genTessEvalSource (void) const;
std::string genGeometrySource (void) const;
std::string genFragmentSource (void) const;
std::string genComputeSource (void) const;
void initPrograms (vk::SourceCollections& programCollection) const;
protected:
const glu::GLSLVersion m_glslVersion;
const vk::VkShaderStageFlags m_exitingStages;
const vk::VkShaderStageFlags m_activeStages;
const DescriptorSetCount m_descriptorSetCount;
};
QuadrantRendederCase::QuadrantRendederCase (tcu::TestContext& testCtx,
const char* name,
const char* description,
glu::GLSLVersion glslVersion,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount)
: vkt::TestCase (testCtx, name, description)
, m_glslVersion (glslVersion)
, m_exitingStages (exitingStages)
, m_activeStages (activeStages)
, m_descriptorSetCount (descriptorSetCount)
{
DE_ASSERT((m_exitingStages & m_activeStages) == m_activeStages);
}
std::string QuadrantRendederCase::genVertexSource (void) const
{
const char* const nextStageName = ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u) ? ("tsc")
: ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u) ? ("geo")
: ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u) ? ("frag")
: (DE_NULL);
const char* const fragColorPrec = ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? "highp" : "mediump";
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
std::ostringstream buf;
if ((m_activeStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
{
const bool onlyVS = (m_activeStages == vk::VK_SHADER_STAGE_VERTEX_BIT);
// active vertex shader
buf << versionDecl << "\n"
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT);
buf << genResourceDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT, 0);
buf << "layout(location = 0) out " << fragColorPrec << " vec4 " << nextStageName << "_color;\n"
<< (onlyVS ? "" : "layout(location = 1) flat out highp int " + de::toString(nextStageName) + "_quadrant_id;\n")
<< genPerVertexBlock(vk::VK_SHADER_STAGE_VERTEX_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 result_position;\n"
<< " highp int quadrant_id;\n"
<< s_quadrantGenVertexPosSource
<< " gl_Position = result_position;\n"
<< (onlyVS ? "" : "\t" + de::toString(nextStageName) + "_quadrant_id = quadrant_id;\n")
<< "\n"
<< " highp vec4 result_color;\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_VERTEX_BIT)
<< " " << nextStageName << "_color = result_color;\n"
<< "}\n";
}
else
{
// do nothing
buf << versionDecl << "\n"
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_VERTEX_BIT)
<< "layout(location = 1) flat out highp int " << nextStageName << "_quadrant_id;\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_VERTEX_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 result_position;\n"
<< " highp int quadrant_id;\n"
<< s_quadrantGenVertexPosSource
<< " gl_Position = result_position;\n"
<< " " << nextStageName << "_quadrant_id = quadrant_id;\n"
<< "}\n";
}
return buf.str();
}
std::string QuadrantRendederCase::genTessCtrlSource (void) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
const bool extRequired = glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
const char* const tessExtDecl = extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
std::ostringstream buf;
if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
{
// contributing not implemented
DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
// active tc shader
buf << versionDecl << "\n"
<< tessExtDecl
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
<< "layout(vertices=3) out;\n"
<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, 0)
<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
<< "layout(location = 0) out highp vec4 tes_color[];\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 result_color;\n"
<< " highp int quadrant_id = tsc_quadrant_id[gl_InvocationID];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
<< "\n"
<< " tes_color[gl_InvocationID] = result_color;\n"
<< "\n"
<< " // no dynamic input block indexing\n"
<< " highp vec4 position;\n"
<< " if (gl_InvocationID == 0)\n"
<< " position = gl_in[0].gl_Position;\n"
<< " else if (gl_InvocationID == 1)\n"
<< " position = gl_in[1].gl_Position;\n"
<< " else\n"
<< " position = gl_in[2].gl_Position;\n"
<< " gl_out[gl_InvocationID].gl_Position = position;\n"
<< " gl_TessLevelInner[0] = 2.8;\n"
<< " gl_TessLevelInner[1] = 2.8;\n"
<< " gl_TessLevelOuter[0] = 2.8;\n"
<< " gl_TessLevelOuter[1] = 2.8;\n"
<< " gl_TessLevelOuter[2] = 2.8;\n"
<< " gl_TessLevelOuter[3] = 2.8;\n"
<< "}\n";
}
else if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
{
// active te shader, tc passthru
buf << versionDecl << "\n"
<< tessExtDecl
<< "layout(vertices=3) out;\n"
<< "layout(location = 1) flat in highp int tsc_quadrant_id[];\n"
<< "layout(location = 1) flat out highp int tes_quadrant_id[];\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " tes_quadrant_id[gl_InvocationID] = tsc_quadrant_id[0];\n"
<< "\n"
<< " // no dynamic input block indexing\n"
<< " highp vec4 position;\n"
<< " if (gl_InvocationID == 0)\n"
<< " position = gl_in[0].gl_Position;\n"
<< " else if (gl_InvocationID == 1)\n"
<< " position = gl_in[1].gl_Position;\n"
<< " else\n"
<< " position = gl_in[2].gl_Position;\n"
<< " gl_out[gl_InvocationID].gl_Position = position;\n"
<< " gl_TessLevelInner[0] = 2.8;\n"
<< " gl_TessLevelInner[1] = 2.8;\n"
<< " gl_TessLevelOuter[0] = 2.8;\n"
<< " gl_TessLevelOuter[1] = 2.8;\n"
<< " gl_TessLevelOuter[2] = 2.8;\n"
<< " gl_TessLevelOuter[3] = 2.8;\n"
<< "}\n";
}
else
{
// passthrough not implemented
DE_FATAL("not implemented");
}
return buf.str();
}
std::string QuadrantRendederCase::genTessEvalSource (void) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
const bool extRequired = glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
const char* const tessExtDecl = extRequired ? "#extension GL_EXT_tessellation_shader : require\n" : "";
std::ostringstream buf;
if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
{
// contributing not implemented
DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT);
// active te shader
buf << versionDecl << "\n"
<< tessExtDecl
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
<< "layout(triangles) in;\n"
<< genResourceDeclarations(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, 0)
<< "layout(location = 1) flat in highp int tes_quadrant_id[];\n"
<< "layout(location = 0) out mediump vec4 frag_color;\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " highp vec4 result_color;\n"
<< " highp int quadrant_id = tes_quadrant_id[0];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
<< "\n"
<< " frag_color = result_color;\n"
<< " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
<< "}\n";
}
else if ((m_activeStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
{
// contributing not implemented
DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
// active tc shader, te is passthru
buf << versionDecl << "\n"
<< tessExtDecl
<< "layout(triangles) in;\n"
<< "layout(location = 0) in highp vec4 tes_color[];\n"
<< "layout(location = 0) out mediump vec4 frag_color;\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " frag_color = tes_color[0];\n"
<< " gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
<< "}\n";
}
else
{
// passthrough not implemented
DE_FATAL("not implemented");
}
return buf.str();
}
std::string QuadrantRendederCase::genGeometrySource (void) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
const bool extRequired = glu::glslVersionIsES(m_glslVersion) && m_glslVersion <= glu::GLSL_VERSION_310_ES;
const char* const geomExtDecl = extRequired ? "#extension GL_EXT_geometry_shader : require\n" : "";
std::ostringstream buf;
if ((m_activeStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
{
// contributing not implemented
DE_ASSERT(m_activeStages == vk::VK_SHADER_STAGE_GEOMETRY_BIT);
// active geometry shader
buf << versionDecl << "\n"
<< geomExtDecl
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< "layout(triangles) in;\n"
<< "layout(triangle_strip, max_vertices=4) out;\n"
<< genResourceDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT, 0)
<< "layout(location = 1) flat in highp int geo_quadrant_id[];\n"
<< "layout(location = 0) out mediump vec4 frag_color;\n"
<< genPerVertexBlock(vk::VK_SHADER_STAGE_GEOMETRY_BIT, m_glslVersion)
<< "void main (void)\n"
<< "{\n"
<< " highp int quadrant_id;\n"
<< " highp vec4 result_color;\n"
<< "\n"
<< " quadrant_id = geo_quadrant_id[0];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< " frag_color = result_color;\n"
<< " gl_Position = gl_in[0].gl_Position;\n"
<< " EmitVertex();\n"
<< "\n"
<< " quadrant_id = geo_quadrant_id[1];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< " frag_color = result_color;\n"
<< " gl_Position = gl_in[1].gl_Position;\n"
<< " EmitVertex();\n"
<< "\n"
<< " quadrant_id = geo_quadrant_id[2];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< " frag_color = result_color;\n"
<< " gl_Position = gl_in[0].gl_Position * 0.5 + gl_in[2].gl_Position * 0.5;\n"
<< " EmitVertex();\n"
<< "\n"
<< " quadrant_id = geo_quadrant_id[0];\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< " frag_color = result_color;\n"
<< " gl_Position = gl_in[2].gl_Position;\n"
<< " EmitVertex();\n"
<< "}\n";
}
else
{
// passthrough not implemented
DE_FATAL("not implemented");
}
return buf.str();
}
std::string QuadrantRendederCase::genFragmentSource (void) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
std::ostringstream buf;
if ((m_activeStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
{
buf << versionDecl << "\n"
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_GEOMETRY_BIT)
<< genResourceDeclarations(vk::VK_SHADER_STAGE_FRAGMENT_BIT, 0);
if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
{
// there are other stages, this is just a contributor
buf << "layout(location = 0) in mediump vec4 frag_color;\n";
}
buf << "layout(location = 1) flat in highp int frag_quadrant_id;\n"
<< "layout(location = 0) out mediump vec4 o_color;\n"
<< "void main (void)\n"
<< "{\n"
<< " highp int quadrant_id = frag_quadrant_id;\n"
<< " highp vec4 result_color;\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_FRAGMENT_BIT);
if (m_activeStages != vk::VK_SHADER_STAGE_FRAGMENT_BIT)
{
// just contributor
buf << " if (frag_quadrant_id < 2)\n"
<< " o_color = result_color;\n"
<< " else\n"
<< " o_color = frag_color;\n";
}
else
buf << " o_color = result_color;\n";
buf << "}\n";
}
else if (m_activeStages == 0u)
{
// special case, no active stages
buf << versionDecl << "\n"
<< "layout(location = 1) flat in highp int frag_quadrant_id;\n"
<< "layout(location = 0) out mediump vec4 o_color;\n"
<< "void main (void)\n"
<< "{\n"
<< " highp int quadrant_id = frag_quadrant_id;\n"
<< " highp vec4 result_color;\n"
<< genNoAccessSource()
<< " o_color = result_color;\n"
<< "}\n";
}
else
{
// passthrough
buf << versionDecl << "\n"
<< "layout(location = 0) in mediump vec4 frag_color;\n"
"layout(location = 0) out mediump vec4 o_color;\n"
"void main (void)\n"
"{\n"
" o_color = frag_color;\n"
"}\n";
}
return buf.str();
}
std::string QuadrantRendederCase::genComputeSource (void) const
{
const char* const versionDecl = glu::getGLSLVersionDeclaration(m_glslVersion);
std::ostringstream buf;
buf << versionDecl << "\n"
<< genExtensionDeclarations(vk::VK_SHADER_STAGE_COMPUTE_BIT)
<< "layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
<< genResourceDeclarations(vk::VK_SHADER_STAGE_COMPUTE_BIT, 1)
<< "layout(set = 0, binding = 0, std140) writeonly buffer OutBuf\n"
<< "{\n"
<< " highp vec4 read_colors[4];\n"
<< "} b_out;\n"
<< "void main (void)\n"
<< "{\n"
<< " highp int quadrant_id = int(gl_WorkGroupID.x);\n"
<< " highp vec4 result_color;\n"
<< genResourceAccessSource(vk::VK_SHADER_STAGE_COMPUTE_BIT)
<< " b_out.read_colors[gl_WorkGroupID.x] = result_color;\n"
<< "}\n";
return buf.str();
}
void QuadrantRendederCase::initPrograms (vk::SourceCollections& programCollection) const
{
if ((m_exitingStages & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0u)
programCollection.glslSources.add("vertex") << glu::VertexSource(genVertexSource());
if ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0u)
programCollection.glslSources.add("tess_ctrl") << glu::TessellationControlSource(genTessCtrlSource());
if ((m_exitingStages & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0u)
programCollection.glslSources.add("tess_eval") << glu::TessellationEvaluationSource(genTessEvalSource());
if ((m_exitingStages & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0u)
programCollection.glslSources.add("geometry") << glu::GeometrySource(genGeometrySource());
if ((m_exitingStages & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0u)
programCollection.glslSources.add("fragment") << glu::FragmentSource(genFragmentSource());
if ((m_exitingStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) != 0u)
programCollection.glslSources.add("compute") << glu::ComputeSource(genComputeSource());
}
class BufferDescriptorCase : public QuadrantRendederCase
{
public:
enum
{
FLAG_VIEW_OFFSET = (1u << 1u),
FLAG_DYNAMIC_OFFSET_ZERO = (1u << 2u),
FLAG_DYNAMIC_OFFSET_NONZERO = (1u << 3u),
};
// enum continues where resource flags ends
DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
BufferDescriptorCase (tcu::TestContext& testCtx,
DescriptorUpdateMethod updateMethod,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
deUint32 flags);
private:
std::string genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const;
std::string genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
std::string genResourceAccessSource (vk::VkShaderStageFlagBits stage) const;
std::string genNoAccessSource (void) const;
vkt::TestInstance* createInstance (vkt::Context& context) const;
const DescriptorUpdateMethod m_updateMethod;
const bool m_viewOffset;
const bool m_dynamicOffsetSet;
const bool m_dynamicOffsetNonZero;
const bool m_isPrimaryCmdBuf;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
};
BufferDescriptorCase::BufferDescriptorCase (tcu::TestContext& testCtx,
DescriptorUpdateMethod updateMethod,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
deUint32 flags)
: QuadrantRendederCase (testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages, descriptorSetCount)
, m_updateMethod (updateMethod)
, m_viewOffset ((flags & FLAG_VIEW_OFFSET) != 0u)
, m_dynamicOffsetSet ((flags & (FLAG_DYNAMIC_OFFSET_ZERO | FLAG_DYNAMIC_OFFSET_NONZERO)) != 0u)
, m_dynamicOffsetNonZero ((flags & FLAG_DYNAMIC_OFFSET_NONZERO) != 0u)
, m_isPrimaryCmdBuf (isPrimaryCmdBuf)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
{
}
std::string BufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
return "";
}
std::string BufferDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
{
DE_UNREF(stage);
const bool isUniform = isUniformDescriptorType(m_descriptorType);
const char* const storageType = (isUniform) ? ("uniform") : ("buffer");
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::ostringstream buf;
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
// Result buffer is bound only to the first descriptor set in compute shader cases
const int descBinding = numUsedBindings - ((m_activeStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) ? (setNdx == 0 ? 0 : 1) : 0);
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
const deUint32 descriptorSet = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
buf << "layout(set = " << descriptorSet << ", binding = " << (descBinding) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << ";\n";
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " << (descBinding) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "A\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "A;\n"
<< "layout(set = " << descriptorSet << ", binding = " << (descBinding + 1) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "B\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " << de::toString(descBinding) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "A\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "A;\n"
<< "layout(set = " << descriptorSet << ", binding = " << de::toString(descBinding + 2) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "B\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " << de::toString(getArbitraryBindingIndex(0)) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "A\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "A;\n"
<< "layout(set = " << descriptorSet << ", binding = " << de::toString(getArbitraryBindingIndex(1)) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "B\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instance" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
buf << "layout(set = " << descriptorSet << ", binding = " << (descBinding) << ", std140) " << storageType << " BufferName" << setNdxPostfix << "\n"
<< "{\n"
<< " highp vec4 colorA;\n"
<< " highp vec4 colorB;\n"
<< "} b_instances" << setNdxPostfix << "[2];\n";
break;
default:
DE_FATAL("Impossible");
}
}
return buf.str();
}
std::string BufferDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::ostringstream buf;
buf << " result_color = vec4(0.0);\n";
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
buf << " if (quadrant_id == 1 || quadrant_id == 2)\n"
<< " result_color += b_instance" << setNdxPostfix << ".colorA;\n"
<< " else\n"
<< " result_color += b_instance" << setNdxPostfix << ".colorB;\n";
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
buf << " if (quadrant_id == 1 || quadrant_id == 2)\n"
<< " result_color += b_instance" << setNdxPostfix << "A.colorA;\n"
<< " else\n"
<< " result_color += b_instance" << setNdxPostfix << "B.colorB;\n";
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
buf << " if (quadrant_id == 1 || quadrant_id == 2)\n"
<< " result_color += b_instances" << setNdxPostfix << "[0].colorA;\n"
<< " else\n"
<< " result_color += b_instances" << setNdxPostfix << "[1].colorB;\n";
break;
default:
DE_FATAL("Impossible");
}
}
if (getDescriptorSetCount(m_descriptorSetCount) > 1)
buf << " result_color /= vec4(" << getDescriptorSetCount(m_descriptorSetCount) << ".0);\n";
return buf.str();
}
std::string BufferDescriptorCase::genNoAccessSource (void) const
{
return " if (quadrant_id == 1 || quadrant_id == 2)\n"
" result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
" else\n"
" result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
}
vkt::TestInstance* BufferDescriptorCase::createInstance (vkt::Context& context) const
{
verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages);
if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
{
DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
return new BufferComputeInstance(context, m_updateMethod, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
}
else
return new BufferRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_descriptorSetCount, m_activeStages, m_shaderInterface, m_viewOffset, m_dynamicOffsetSet, m_dynamicOffsetNonZero);
}
class ImageInstanceImages
{
public:
ImageInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
int numImages,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
private:
static std::vector<tcu::TextureLevelPyramid> createSourceImages (int numImages,
vk::VkImageViewType viewType,
tcu::TextureFormat imageFormat);
static std::vector<ImageHandleSp> createImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
std::vector<AllocationSp>& imageMemory,
const std::vector<tcu::TextureLevelPyramid>& sourceImages);
static std::vector<ImageViewHandleSp> createImageViews (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkImageViewType viewType,
const std::vector<tcu::TextureLevelPyramid>& sourceImages,
const std::vector<ImageHandleSp>& images,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
static vk::Move<vk::VkImage> createImage (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& sourceImage,
de::MovePtr<vk::Allocation>* outAllocation);
static vk::Move<vk::VkImageView> createImageView (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& sourceImage,
vk::VkImage image,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
static void populateSourceImage (tcu::TextureLevelPyramid* dst,
vk::VkImageViewType viewType,
int imageNdx);
static void uploadImage (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkImage image,
vk::VkImageLayout layout,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& data);
protected:
enum
{
IMAGE_SIZE = 64,
NUM_MIP_LEVELS = 2,
ARRAY_SIZE = 2,
};
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
const tcu::TextureFormat m_imageFormat;
const std::vector<tcu::TextureLevelPyramid> m_sourceImage;
std::vector<AllocationSp> m_imageMemory;
const std::vector<ImageHandleSp> m_image;
const std::vector<ImageViewHandleSp> m_imageView;
};
ImageInstanceImages::ImageInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
int numImages,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
: m_viewType (viewType)
, m_baseMipLevel (baseMipLevel)
, m_baseArraySlice (baseArraySlice)
, m_imageFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
, m_sourceImage (createSourceImages(numImages, viewType, m_imageFormat))
, m_imageMemory ()
, m_image (createImages(vki, device, allocator, queueFamilyIndex, queue, descriptorType, viewType, m_imageMemory, m_sourceImage))
, m_imageView (createImageViews(vki, device, viewType, m_sourceImage, m_image, m_baseMipLevel, m_baseArraySlice))
{
}
std::vector<tcu::TextureLevelPyramid> ImageInstanceImages::createSourceImages (int numImages,
vk::VkImageViewType viewType,
tcu::TextureFormat imageFormat)
{
std::vector<tcu::TextureLevelPyramid> sourceImages(numImages, tcu::TextureLevelPyramid(imageFormat, NUM_MIP_LEVELS));
for (int imageNdx = 0; imageNdx < numImages; imageNdx++)
populateSourceImage(&sourceImages.at(imageNdx), viewType, imageNdx);
return sourceImages;
}
std::vector<ImageHandleSp> ImageInstanceImages::createImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
std::vector<AllocationSp>& imageMemory,
const std::vector<tcu::TextureLevelPyramid>& sourceImages)
{
std::vector<ImageHandleSp> images;
const vk::VkImageLayout layout = getImageLayoutForDescriptorType(descriptorType);
for (int imageNdx = 0; imageNdx < (int)sourceImages.size(); imageNdx++)
{
de::MovePtr<vk::Allocation> memory;
vk::Move<vk::VkImage> image = createImage(vki, device, allocator, descriptorType, viewType, sourceImages[imageNdx], &memory);
uploadImage(vki, device, queueFamilyIndex, queue, allocator, *image, layout, viewType, sourceImages[imageNdx]);
imageMemory.push_back(AllocationSp(memory.release()));
images.push_back(ImageHandleSp(new ImageHandleUp(image)));
}
return images;
}
std::vector<ImageViewHandleSp> ImageInstanceImages::createImageViews (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkImageViewType viewType,
const std::vector<tcu::TextureLevelPyramid>& sourceImages,
const std::vector<ImageHandleSp>& images,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
{
std::vector<ImageViewHandleSp> imageViews;
for (int imageNdx = 0; imageNdx < (int)sourceImages.size(); imageNdx++)
{
vk::Move<vk::VkImageView> imageView = createImageView(vki, device, viewType, sourceImages[imageNdx], **images[imageNdx], baseMipLevel, baseArraySlice);
imageViews.push_back(ImageViewHandleSp(new ImageViewHandleUp(imageView)));
}
return imageViews;
}
vk::Move<vk::VkImage> ImageInstanceImages::createImage (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& sourceImage,
de::MovePtr<vk::Allocation>* outAllocation)
{
const tcu::ConstPixelBufferAccess baseLevel = sourceImage.getLevel(0);
const bool isCube = (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY);
const bool isStorage = (descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
const deUint32 readUsage = (isStorage) ? (vk::VK_IMAGE_USAGE_STORAGE_BIT) : (vk::VK_IMAGE_USAGE_SAMPLED_BIT);
const deUint32 arraySize = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (baseLevel.getHeight())
: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? (baseLevel.getDepth())
: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (baseLevel.getDepth()) // cube: numFaces * numLayers
: (0);
const vk::VkExtent3D extent =
{
// x
(deUint32)baseLevel.getWidth(),
// y
(viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1u) : (deUint32)baseLevel.getHeight(),
// z
(viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ((deUint32)baseLevel.getDepth()) : (1u),
};
const vk::VkImageCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
DE_NULL,
isCube ? (vk::VkImageCreateFlags)vk::VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : (vk::VkImageCreateFlags)0,
viewTypeToImageType(viewType), // imageType
vk::mapTextureFormat(baseLevel.getFormat()), // format
extent, // extent
(deUint32)sourceImage.getNumLevels(), // mipLevels
arraySize, // arraySize
vk::VK_SAMPLE_COUNT_1_BIT, // samples
vk::VK_IMAGE_TILING_OPTIMAL, // tiling
readUsage | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
vk::VK_IMAGE_LAYOUT_UNDEFINED, // initialLayout
};
vk::Move<vk::VkImage> image (vk::createImage(vki, device, &createInfo));
*outAllocation = allocateAndBindObjectMemory(vki, device, allocator, *image, vk::MemoryRequirement::Any);
return image;
}
vk::Move<vk::VkImageView> ImageInstanceImages::createImageView (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& sourceImage,
vk::VkImage image,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
{
const tcu::ConstPixelBufferAccess baseLevel = sourceImage.getLevel(0);
const deUint32 viewTypeBaseSlice = (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * baseArraySlice) : (baseArraySlice);
const deUint32 viewArraySize = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D) ? (1)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (baseLevel.getHeight() - viewTypeBaseSlice)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D) ? (1)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? (baseLevel.getDepth() - viewTypeBaseSlice)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE) ? (6)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (baseLevel.getDepth() - viewTypeBaseSlice) // cube: numFaces * numLayers
: (0);
DE_ASSERT(viewArraySize > 0);
const vk::VkImageSubresourceRange resourceRange =
{
vk::VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
baseMipLevel, // baseMipLevel
sourceImage.getNumLevels() - baseMipLevel, // mipLevels
viewTypeBaseSlice, // baseArraySlice
viewArraySize, // arraySize
};
const vk::VkImageViewCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
DE_NULL,
(vk::VkImageViewCreateFlags)0,
image, // image
viewType, // viewType
vk::mapTextureFormat(baseLevel.getFormat()), // format
{
vk::VK_COMPONENT_SWIZZLE_R,
vk::VK_COMPONENT_SWIZZLE_G,
vk::VK_COMPONENT_SWIZZLE_B,
vk::VK_COMPONENT_SWIZZLE_A
}, // channels
resourceRange, // subresourceRange
};
return vk::createImageView(vki, device, &createInfo);
}
void ImageInstanceImages::populateSourceImage (tcu::TextureLevelPyramid* dst, vk::VkImageViewType viewType, int imageNdx)
{
const int numLevels = dst->getNumLevels();
for (int level = 0; level < numLevels; ++level)
{
const int width = IMAGE_SIZE >> level;
const int height = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (ARRAY_SIZE)
: (IMAGE_SIZE >> level);
const int depth = (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? (1)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? (ARRAY_SIZE)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * ARRAY_SIZE)
: (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (IMAGE_SIZE >> level)
: (1);
dst->allocLevel(level, width, height, depth);
{
const tcu::PixelBufferAccess levelAccess = dst->getLevel(level);
for (int z = 0; z < depth; ++z)
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
{
const int gradPos = x + y + z;
const int gradMax = width + height + depth - 3;
int red = 255 * gradPos / gradMax; //!< gradient from 0 -> max (detects large offset errors)
int green = ((gradPos % 2 == 0) ? (127) : (0)) + ((gradPos % 4 < 3) ? (128) : (0)); //!< 3-level M pattern (detects small offset errors)
int blue = (128 * level / numLevels) + ((imageNdx % 2 == 0) ? 127 : 0); //!< level and image index (detects incorrect lod / image)
DE_ASSERT(de::inRange(red, 0, 255));
DE_ASSERT(de::inRange(green, 0, 255));
DE_ASSERT(de::inRange(blue, 0, 255));
if (imageNdx % 3 == 0) red = 255 - red;
if (imageNdx % 4 == 0) green = 255 - green;
if (imageNdx % 5 == 0) blue = 255 - blue;
levelAccess.setPixel(tcu::IVec4(red, green, blue, 255), x, y, z);
}
}
}
}
void ImageInstanceImages::uploadImage (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkImage image,
vk::VkImageLayout layout,
vk::VkImageViewType viewType,
const tcu::TextureLevelPyramid& data)
{
const deUint32 arraySize = (viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? (1) :
(viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? (6 * (deUint32)ARRAY_SIZE) :
((deUint32)ARRAY_SIZE);
const deUint32 dataBufferSize = getTextureLevelPyramidDataSize(data);
const vk::VkBufferCreateInfo bufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
dataBufferSize, // size
vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
const vk::Unique<vk::VkBuffer> dataBuffer (vk::createBuffer(vki, device, &bufferCreateInfo));
const de::MovePtr<vk::Allocation> dataBufferMemory = allocateAndBindObjectMemory(vki, device, allocator, *dataBuffer, vk::MemoryRequirement::HostVisible);
std::vector<vk::VkBufferImageCopy> copySlices;
// copy data to buffer
writeTextureLevelPyramidData(dataBufferMemory->getHostPtr(), dataBufferSize, data, viewType , &copySlices);
flushAlloc(vki, device, *dataBufferMemory);
// copy buffer to image
copyBufferToImage(vki, device, queue, queueFamilyIndex, *dataBuffer, dataBufferSize, copySlices, DE_NULL, vk::VK_IMAGE_ASPECT_COLOR_BIT, data.getNumLevels(), arraySize, image, layout);
}
class ImageFetchInstanceImages : private ImageInstanceImages
{
public:
ImageFetchInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
static tcu::IVec3 getFetchPos (vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
int fetchPosNdx);
tcu::Vec4 fetchImageValue (int fetchPosNdx, int setNdx) const;
inline tcu::TextureLevelPyramid getSourceImage (int ndx) const { return m_sourceImage[ndx]; }
inline vk::VkImageView getImageView (int ndx) const { return **m_imageView[ndx % m_imageView.size()]; }
private:
enum
{
// some arbitrary sample points for all four quadrants
SAMPLE_POINT_0_X = 6,
SAMPLE_POINT_0_Y = 13,
SAMPLE_POINT_0_Z = 49,
SAMPLE_POINT_1_X = 51,
SAMPLE_POINT_1_Y = 40,
SAMPLE_POINT_1_Z = 44,
SAMPLE_POINT_2_X = 42,
SAMPLE_POINT_2_Y = 26,
SAMPLE_POINT_2_Z = 19,
SAMPLE_POINT_3_X = 25,
SAMPLE_POINT_3_Y = 25,
SAMPLE_POINT_3_Z = 18,
};
const ShaderInputInterface m_shaderInterface;
};
ImageFetchInstanceImages::ImageFetchInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
: ImageInstanceImages (vki,
device,
queueFamilyIndex,
queue,
allocator,
descriptorType,
viewType,
getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface), // numImages
baseMipLevel,
baseArraySlice)
, m_shaderInterface (shaderInterface)
{
}
bool isImageViewTypeArray (vk::VkImageViewType type)
{
return type == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY || type == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
}
tcu::IVec3 ImageFetchInstanceImages::getFetchPos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int fetchPosNdx)
{
const tcu::IVec3 fetchPositions[4] =
{
tcu::IVec3(SAMPLE_POINT_0_X, SAMPLE_POINT_0_Y, SAMPLE_POINT_0_Z),
tcu::IVec3(SAMPLE_POINT_1_X, SAMPLE_POINT_1_Y, SAMPLE_POINT_1_Z),
tcu::IVec3(SAMPLE_POINT_2_X, SAMPLE_POINT_2_Y, SAMPLE_POINT_2_Z),
tcu::IVec3(SAMPLE_POINT_3_X, SAMPLE_POINT_3_Y, SAMPLE_POINT_3_Z),
};
const tcu::IVec3 coord = de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
const deUint32 imageSize = (deUint32)IMAGE_SIZE >> baseMipLevel;
const deUint32 arraySize = isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
switch (viewType)
{
case vk::VK_IMAGE_VIEW_TYPE_1D:
case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY: return tcu::IVec3(coord.x() % imageSize, coord.y() % arraySize, 0);
case vk::VK_IMAGE_VIEW_TYPE_2D:
case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY: return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % arraySize);
case vk::VK_IMAGE_VIEW_TYPE_CUBE:
case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % (arraySize * 6));
case vk::VK_IMAGE_VIEW_TYPE_3D: return tcu::IVec3(coord.x() % imageSize, coord.y() % imageSize, coord.z() % imageSize);
default:
DE_FATAL("Impossible");
return tcu::IVec3();
}
}
tcu::Vec4 ImageFetchInstanceImages::fetchImageValue (int fetchPosNdx, int setNdx) const
{
DE_ASSERT(de::inBounds(fetchPosNdx, 0, 4));
const tcu::TextureLevelPyramid& fetchSrcA = getSourceImage(setNdx * getInterfaceNumResources(m_shaderInterface));
const tcu::TextureLevelPyramid& fetchSrcB = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? fetchSrcA : getSourceImage(setNdx * getInterfaceNumResources(m_shaderInterface) + 1);
const tcu::TextureLevelPyramid& fetchSrc = ((fetchPosNdx % 2) == 0) ? (fetchSrcA) : (fetchSrcB); // sampling order is ABAB
tcu::IVec3 fetchPos = getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
// add base array layer into the appropriate coordinate, based on the view type
if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
fetchPos.z() += 6 * m_baseArraySlice;
else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)
fetchPos.y() += m_baseArraySlice;
else
fetchPos.z() += m_baseArraySlice;
return fetchSrc.getLevel(m_baseMipLevel).getPixel(fetchPos.x(), fetchPos.y(), fetchPos.z());
}
class ImageFetchRenderInstance : public SingleCmdRenderInstance
{
public:
ImageFetchRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
private:
static std::vector<DescriptorSetLayoutHandleSp> createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod);
static vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout);
static vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface);
static std::vector<DescriptorSetHandleSp> createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
const ImageFetchInstanceImages& images,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout = DE_NULL);
static void writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkImageView viewA,
vk::VkImageView viewB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
static void writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkImageView viewA,
vk::VkImageView viewB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush = false,
vk::VkPipelineLayout pipelineLayout = 0);
void logTestPlan (void) const;
vk::VkPipelineLayout getPipelineLayout (void) const;
void writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const;
tcu::TestStatus verifyResultImage (const tcu::ConstPixelBufferAccess& result) const;
enum
{
RENDER_SIZE = 128,
};
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const vk::VkShaderStageFlags m_stageFlags;
const ShaderInputInterface m_shaderInterface;
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
const std::vector<DescriptorSetLayoutHandleSp> m_descriptorSetLayouts;
const vk::Unique<vk::VkPipelineLayout> m_pipelineLayout;
const ImageFetchInstanceImages m_images;
const vk::Unique<vk::VkDescriptorPool> m_descriptorPool;
std::vector<deUint32> m_descriptorsPerSet;
const std::vector<DescriptorSetHandleSp> m_descriptorSets;
};
ImageFetchRenderInstance::ImageFetchRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
: SingleCmdRenderInstance (context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_stageFlags (stageFlags)
, m_shaderInterface (shaderInterface)
, m_viewType (viewType)
, m_baseMipLevel (baseMipLevel)
, m_baseArraySlice (baseArraySlice)
, m_updateTemplates ()
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorSetLayouts (createDescriptorSetLayouts(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_stageFlags, m_updateMethod))
, m_pipelineLayout (createPipelineLayout(m_vki, m_device, m_descriptorSetLayouts))
, m_images (m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
, m_descriptorPool (createDescriptorPool(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface))
, m_descriptorsPerSet ()
, m_descriptorSets (createDescriptorSets(m_vki, m_updateMethod, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_descriptorSetLayouts, *m_descriptorPool, m_images, m_updateBuilder, m_updateTemplates, m_updateRegistry, m_descriptorsPerSet, *m_pipelineLayout))
{
}
std::vector<DescriptorSetLayoutHandleSp> ImageFetchRenderInstance::createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod)
{
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::DescriptorSetLayoutBuilder builder;
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(descriptorType, stageFlags);
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, 0u);
builder.addSingleIndexedBinding(descriptorType, stageFlags, 2u);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(descriptorType, 2u, stageFlags);
break;
default:
DE_FATAL("Impossible");
}
vk::Move<vk::VkDescriptorSetLayout> layout = builder.build(vki, device, extraFlags);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
}
}
return descriptorSetLayouts;
}
vk::Move<vk::VkPipelineLayout> ImageFetchRenderInstance::createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout)
{
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
for (size_t setNdx = 0; setNdx < descriptorSetLayout.size(); setNdx++)
layoutHandles.push_back(**descriptorSetLayout[setNdx]);
const vk::VkPipelineLayoutCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
(deUint32)layoutHandles.size(), // descriptorSetCount
&layoutHandles.front(), // pSetLayouts
0u, // pushConstantRangeCount
DE_NULL, // pPushConstantRanges
};
return vk::createPipelineLayout(vki, device, &createInfo);
}
vk::Move<vk::VkDescriptorPool> ImageFetchRenderInstance::createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface)
{
return vk::DescriptorPoolBuilder()
.addType(descriptorType, getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface))
.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(descriptorSetCount));
}
std::vector<DescriptorSetHandleSp> ImageFetchRenderInstance::createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
const ImageFetchInstanceImages& images,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout)
{
std::vector<DescriptorSetHandleSp> descriptorSets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::VkDescriptorSetLayout layout = **descriptorSetLayouts[getDescriptorSetNdx(descriptorSetCount, setNdx)];
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::VkImageView viewA = images.getImageView(setNdx * getInterfaceNumResources(shaderInterface));
vk::VkImageView viewB = images.getImageView(setNdx * getInterfaceNumResources(shaderInterface) + 1);
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplates, updateRegistry);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateTemplates, updateRegistry, true, pipelineLayout);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, descriptorsPerSet, updateMethod);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, descriptorsPerSet);
}
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(descriptorSet)));
}
return descriptorSets;
}
void ImageFetchRenderInstance::writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkImageView viewA,
vk::VkImageView viewB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod)
{
DE_UNREF(layout);
DE_UNREF(pool);
const vk::VkImageLayout imageLayout = getImageLayoutForDescriptorType(descriptorType);
const vk::VkDescriptorImageInfo imageInfos[2] =
{
makeDescriptorImageInfo(viewA, imageLayout),
makeDescriptorImageInfo(viewB, imageLayout),
};
deUint32 numDescriptors = 0u;
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &imageInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), descriptorType, &imageInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, imageInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
descriptorsPerSet.push_back(numDescriptors);
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateBuilder.update(vki, device);
updateBuilder.clear();
}
}
void ImageFetchRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkImageView viewA,
vk::VkImageView viewB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush,
vk::VkPipelineLayout pipelineLayout)
{
DE_UNREF(pool);
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
0
};
const vk::VkImageLayout imageLayout = getImageLayoutForDescriptorType(descriptorType);
const vk::VkDescriptorImageInfo imageInfos[2] =
{
makeDescriptorImageInfo(viewA, imageLayout),
makeDescriptorImageInfo(viewB, imageLayout),
};
RawUpdateRegistry updateRegistry;
updateRegistry.addWriteObject(imageInfos[0]);
updateRegistry.addWriteObject(imageInfos[1]);
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(1, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(2, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(0, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(imageInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
registry.push_back(updateRegistry);
if (!withPush)
{
vki.updateDescriptorSetWithTemplate(device, descriptorSet, **updateTemplates.back(), registry.back().getRawPointer());
}
}
void ImageFetchRenderInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Rendering 2x2 grid.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
if (m_baseMipLevel)
msg << "Image view base mip level = " << m_baseMipLevel << "\n";
if (m_baseArraySlice)
msg << "Image view base array slice = " << m_baseArraySlice << "\n";
if (m_stageFlags == 0u)
{
msg << "Descriptors are not accessed in any shader stage.\n";
}
else
{
msg << "Color in each cell is fetched using the descriptor(s):\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": fetching at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
msg << " from descriptor " << srcResourceNdx;
}
msg << "\n";
}
msg << "Descriptors are accessed in {"
<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0) ? (" vertex") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? (" tess_control") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) ? (" tess_evaluation") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0) ? (" geometry") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0) ? (" fragment") : (""))
<< " } stages.";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
vk::VkPipelineLayout ImageFetchRenderInstance::getPipelineLayout (void) const
{
return *m_pipelineLayout;
}
void ImageFetchRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
{
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
std::vector<vk::VkDescriptorSet> sets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
sets.push_back(**m_descriptorSets[setNdx]);
switch (m_descriptorSetCount)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE:
{
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, (int)sets.size(), &sets.front(), 0, DE_NULL);
break;
}
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), descriptorSetNdx, 1, &sets[setNdx], 0, DE_NULL);
}
break;
}
default:
DE_FATAL("Impossible");
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, **m_updateTemplates[setNdx], getPipelineLayout(), getDescriptorSetNdx(m_descriptorSetCount, setNdx), (const void*)m_updateRegistry[setNdx].getRawPointer());
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
deUint32 descriptorNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 numDescriptors = m_descriptorsPerSet[setNdx];
m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, getDescriptorSetNdx(m_descriptorSetCount, setNdx), descriptorNdx, numDescriptors);
descriptorNdx += numDescriptors;
}
}
m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
}
tcu::TestStatus ImageFetchRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
{
const deUint32 numDescriptorSets = getDescriptorSetCount(m_descriptorSetCount);
const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f);
const bool doFetch = (m_stageFlags != 0u); // no active stages? Then don't fetch
tcu::Surface reference (m_targetSize.x(), m_targetSize.y());
tcu::Vec4 sample0 = tcu::Vec4(0.0f);
tcu::Vec4 sample1 = tcu::Vec4(0.0f);
tcu::Vec4 sample2 = tcu::Vec4(0.0f);
tcu::Vec4 sample3 = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < numDescriptorSets; setNdx++)
{
sample0 += (!doFetch) ? (yellow) : (m_images.fetchImageValue(0, setNdx));
sample1 += (!doFetch) ? (green) : (m_images.fetchImageValue(1, setNdx));
sample2 += (!doFetch) ? (green) : (m_images.fetchImageValue(2, setNdx));
sample3 += (!doFetch) ? (yellow) : (m_images.fetchImageValue(3, setNdx));
}
if (numDescriptorSets > 1)
{
sample0 = sample0 / tcu::Vec4(float(numDescriptorSets));
sample1 = sample1 / tcu::Vec4(float(numDescriptorSets));
sample2 = sample2 / tcu::Vec4(float(numDescriptorSets));
sample3 = sample3 / tcu::Vec4(float(numDescriptorSets));
}
drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Image verification failed");
else
return tcu::TestStatus::pass("Pass");
}
class ImageFetchComputeInstance : public vkt::TestInstance
{
public:
ImageFetchComputeInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice);
private:
vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (deUint32 setNdx) const;
vk::Move<vk::VkDescriptorPool> createDescriptorPool (void) const;
vk::Move<vk::VkDescriptorSet> createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx);
void writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx);
void writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
tcu::TestStatus iterate (void);
void logTestPlan (void) const;
tcu::TestStatus testResourceAccess (void);
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vk::Allocator& m_allocator;
const ComputeInstanceResultBuffer m_result;
const ImageFetchInstanceImages m_images;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
std::vector<deUint32> m_descriptorsPerSet;
};
ImageFetchComputeInstance::ImageFetchComputeInstance (Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice)
: vkt::TestInstance (context)
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_viewType (viewType)
, m_baseMipLevel (baseMipLevel)
, m_baseArraySlice (baseArraySlice)
, m_updateTemplates ()
, m_vki (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_allocator (context.getDefaultAllocator())
, m_result (m_vki, m_device, m_allocator)
, m_images (m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice)
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorsPerSet ()
{
}
vk::Move<vk::VkDescriptorSetLayout> ImageFetchComputeInstance::createDescriptorSetLayout (deUint32 setNdx) const
{
vk::DescriptorSetLayoutBuilder builder;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
deUint32 binding = 0;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
if (setNdx == 0)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding);
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 2);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
default:
DE_FATAL("Impossible");
};
return builder.build(m_vki, m_device, extraFlags);
}
vk::Move<vk::VkDescriptorPool> ImageFetchComputeInstance::createDescriptorPool (void) const
{
return vk::DescriptorPoolBuilder()
.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
.addType(m_descriptorType, getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface))
.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(m_descriptorSetCount));
}
vk::Move<vk::VkDescriptorSet> ImageFetchComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx)
{
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(*descriptorSet, layout, setNdx);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(*descriptorSet, setNdx);
}
return descriptorSet;
}
void ImageFetchComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkImageLayout imageLayout = getImageLayoutForDescriptorType(m_descriptorType);
const vk::VkDescriptorImageInfo imageInfos[2] =
{
makeDescriptorImageInfo(m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface)), imageLayout),
makeDescriptorImageInfo(m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1), imageLayout),
};
deUint32 binding = 0u;
deUint32 numDescriptors = 0u;
// result
if (setNdx == 0)
{
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
numDescriptors++;
}
// images
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &imageInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &imageInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding), m_descriptorType, &imageInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding + 2), m_descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), m_descriptorType, &imageInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), m_descriptorType, &imageInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, 2u, imageInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
m_descriptorsPerSet.push_back(numDescriptors);
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
m_updateBuilder.update(m_vki, m_device);
m_updateBuilder.clear();
}
}
void ImageFetchComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush, vk::VkPipelineLayout pipelineLayout)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkImageLayout imageLayout = getImageLayoutForDescriptorType(m_descriptorType);
const vk::VkDescriptorImageInfo imageInfos[2] =
{
makeDescriptorImageInfo(m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface)), imageLayout),
makeDescriptorImageInfo(m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1), imageLayout),
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_COMPUTE,
pipelineLayout,
setNdx
};
deUint32 binding = 0u;
deUint32 offset = 0u;
RawUpdateRegistry updateRegistry;
if (setNdx == 0)
updateRegistry.addWriteObject(resultInfo);
updateRegistry.addWriteObject(imageInfos[0]);
updateRegistry.addWriteObject(imageInfos[1]);
// result
if (setNdx == 0)
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, updateRegistry.getWriteObjectOffset(offset++), 0));
// images
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding + 2, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(binding++, 0, 2, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), sizeof(imageInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
m_updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
m_updateRegistry.push_back(updateRegistry);
if (!withPush)
{
m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, **m_updateTemplates.back(), m_updateRegistry.back().getRawPointer());
}
}
tcu::TestStatus ImageFetchComputeInstance::iterate (void)
{
logTestPlan();
return testResourceAccess();
}
void ImageFetchComputeInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Fetching 4 values from image in compute shader.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
<< "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
if (m_baseMipLevel)
msg << "Image view base mip level = " << m_baseMipLevel << "\n";
if (m_baseArraySlice)
msg << "Image view base array slice = " << m_baseArraySlice << "\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": fetch at position " << m_images.getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
msg << " from descriptor " << srcResourceNdx;
}
msg << "\n";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
tcu::TestStatus ImageFetchComputeInstance::testResourceAccess (void)
{
const vk::Unique<vk::VkDescriptorPool> descriptorPool (createDescriptorPool());
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
std::vector<DescriptorSetHandleSp> descriptorSets;
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
std::vector<vk::VkDescriptorSet> setHandles;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
vk::Move<vk::VkDescriptorSetLayout> layout = createDescriptorSetLayout(setNdx);
vk::Move<vk::VkDescriptorSet> set = createDescriptorSet(*descriptorPool, *layout, setNdx);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(set)));
layoutHandles.push_back(**descriptorSetLayouts.back());
setHandles.push_back(**descriptorSets.back());
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && m_descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(m_vki, m_device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
layoutHandles.push_back(**descriptorSetLayouts.back());
}
}
const ComputePipeline pipeline (m_vki, m_device, m_context.getBinaryCollection(), (int)layoutHandles.size(), &layoutHandles.front());
const deUint32* const dynamicOffsets = DE_NULL;
const int numDynamicOffsets = 0;
const vk::VkBufferMemoryBarrier* const preBarriers = DE_NULL;
const int numPreBarriers = 0;
const vk::VkBufferMemoryBarrier* const postBarriers = m_result.getResultReadBarrier();
const int numPostBarriers = 1;
const ComputeCommand compute (m_vki,
m_device,
pipeline.getPipeline(),
pipeline.getPipelineLayout(),
tcu::UVec3(4, 1, 1),
m_shaderInterface,
m_descriptorSetCount, &setHandles.front(),
numDynamicOffsets, dynamicOffsets,
numPreBarriers, preBarriers,
numPostBarriers, postBarriers);
tcu::Vec4 results[4];
bool anyResultSet = false;
bool allResultsOk = true;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSetWithTemplate(DE_NULL, layoutHandles[setNdx], setNdx, true, pipeline.getPipelineLayout());
compute.submitAndWait(m_queueFamilyIndex, m_queue, &m_updateTemplates, &m_updateRegistry);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSet(DE_NULL, setNdx);
compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder, m_descriptorsPerSet);
}
else
{
compute.submitAndWait(m_queueFamilyIndex, m_queue);
}
m_result.readResultContentsTo(&results);
// verify
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
const tcu::Vec4 result = results[resultNdx];
tcu::Vec4 reference = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
reference += m_images.fetchImageValue(resultNdx, setNdx);
if (getDescriptorSetCount(m_descriptorSetCount) > 1)
reference = reference / tcu::Vec4((float)getDescriptorSetCount(m_descriptorSetCount));
const tcu::Vec4 conversionThreshold = tcu::Vec4(1.0f / 255.0f);
if (result != tcu::Vec4(-1.0f))
anyResultSet = true;
if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
{
allResultsOk = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
<< tcu::TestLog::EndMessage;
}
}
// read back and verify
if (allResultsOk)
return tcu::TestStatus::pass("Pass");
else if (anyResultSet)
return tcu::TestStatus::fail("Invalid result values");
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Result buffer was not written to."
<< tcu::TestLog::EndMessage;
return tcu::TestStatus::fail("Result buffer was not written to");
}
}
class ImageSampleInstanceImages : private ImageInstanceImages
{
public:
ImageSampleInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool immutable);
static std::vector<tcu::Sampler> getRefSamplers (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface);
static std::vector<SamplerHandleSp> getSamplers (const vk::DeviceInterface& vki,
vk::VkDevice device,
std::vector<tcu::Sampler>& refSamplers,
const tcu::TextureFormat imageFormat);
static tcu::Vec4 getSamplePos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx);
tcu::Vec4 fetchSampleValue (int samplePosNdx, int setNdx) const;
inline tcu::TextureLevelPyramid getSourceImage (int ndx) const { return m_sourceImage[ndx % m_sourceImage.size()]; }
inline vk::VkImageView getImageView (int ndx) const { return **m_imageView[ndx % m_imageView.size()]; }
inline tcu::Sampler getRefSampler (int ndx) const { return m_refSampler[ndx % m_refSampler.size()]; }
inline vk::VkSampler getSampler (int ndx) const { return **m_sampler[ndx % m_sampler.size()]; }
inline bool isImmutable (void) const { return m_isImmutable; }
private:
static int getNumImages (vk::VkDescriptorType descriptorType, DescriptorSetCount descriptorSetCount, ShaderInputInterface shaderInterface);
static tcu::Sampler createRefSampler (int ndx);
static vk::Move<vk::VkSampler> createSampler (const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format);
static tcu::Texture1DArrayView getRef1DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
static tcu::Texture2DArrayView getRef2DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
static tcu::Texture3DView getRef3DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
static tcu::TextureCubeArrayView getRefCubeView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage);
const vk::VkDescriptorType m_descriptorType;
const ShaderInputInterface m_shaderInterface;
const bool m_isImmutable;
std::vector<tcu::Sampler> m_refSampler;
std::vector<SamplerHandleSp> m_sampler;
};
ImageSampleInstanceImages::ImageSampleInstanceImages (const vk::DeviceInterface& vki,
vk::VkDevice device,
deUint32 queueFamilyIndex,
vk::VkQueue queue,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool immutable)
: ImageInstanceImages (vki,
device,
queueFamilyIndex,
queue,
allocator,
descriptorType,
viewType,
getNumImages(descriptorType, descriptorSetCount, shaderInterface),
baseMipLevel,
baseArraySlice)
, m_descriptorType (descriptorType)
, m_shaderInterface (shaderInterface)
, m_isImmutable (immutable)
, m_refSampler (getRefSamplers(descriptorSetCount, shaderInterface))
, m_sampler (getSamplers(vki, device, m_refSampler, m_imageFormat))
{
}
std::vector<tcu::Sampler> ImageSampleInstanceImages::getRefSamplers (DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface)
{
std::vector<tcu::Sampler> refSamplers;
for (deUint32 samplerNdx = 0; samplerNdx < getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface); samplerNdx++)
refSamplers.push_back(createRefSampler(samplerNdx));
return refSamplers;
}
std::vector<SamplerHandleSp> ImageSampleInstanceImages::getSamplers (const vk::DeviceInterface& vki,
vk::VkDevice device,
std::vector<tcu::Sampler>& refSamplers,
const tcu::TextureFormat imageFormat)
{
std::vector<SamplerHandleSp> samplers;
for (deUint32 samplerNdx = 0; samplerNdx < (deUint32)refSamplers.size(); samplerNdx++)
{
vk::Move<vk::VkSampler> sampler = createSampler(vki, device, refSamplers[samplerNdx], imageFormat);
samplers.push_back(SamplerHandleSp(new SamplerHandleUp(sampler)));
}
return samplers;
}
tcu::Vec4 ImageSampleInstanceImages::getSamplePos (vk::VkImageViewType viewType, deUint32 baseMipLevel, deUint32 baseArraySlice, int samplePosNdx)
{
DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
const deUint32 imageSize = (deUint32)IMAGE_SIZE >> baseMipLevel;
const deUint32 arraySize = isImageViewTypeArray(viewType) ? ARRAY_SIZE - baseArraySlice : 1;
// choose arbitrary values that are not ambiguous with NEAREST filtering
switch (viewType)
{
case vk::VK_IMAGE_VIEW_TYPE_1D:
case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY:
case vk::VK_IMAGE_VIEW_TYPE_2D:
case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY:
case vk::VK_IMAGE_VIEW_TYPE_3D:
{
const tcu::Vec3 coords[4] =
{
tcu::Vec3(0.75f,
0.5f,
(float)(12u % imageSize) + 0.25f),
tcu::Vec3((float)(23u % imageSize) + 0.25f,
(float)(73u % imageSize) + 0.5f,
(float)(16u % imageSize) + 0.5f + (float)imageSize),
tcu::Vec3(-(float)(43u % imageSize) + 0.25f,
(float)(84u % imageSize) + 0.5f + (float)imageSize,
(float)(117u % imageSize) + 0.75f),
tcu::Vec3((float)imageSize + 0.5f,
(float)(75u % imageSize) + 0.25f,
(float)(83u % imageSize) + 0.25f + (float)imageSize),
};
const deUint32 slices[4] =
{
0u % arraySize,
4u % arraySize,
9u % arraySize,
2u % arraySize,
};
if (viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY)
return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
(float)slices[samplePosNdx],
0.0f,
0.0f);
else if (viewType == vk::VK_IMAGE_VIEW_TYPE_2D || viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY)
return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
coords[samplePosNdx].y() / (float)imageSize,
(float)slices[samplePosNdx],
0.0f);
else if (viewType == vk::VK_IMAGE_VIEW_TYPE_3D)
return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize,
coords[samplePosNdx].y() / (float)imageSize,
coords[samplePosNdx].z() / (float)imageSize,
0.0f);
else
{
DE_FATAL("Impossible");
return tcu::Vec4();
}
}
case vk::VK_IMAGE_VIEW_TYPE_CUBE:
case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY:
{
// \note these values are in [0, texSize]*3 space for convenience
const tcu::Vec3 coords[4] =
{
tcu::Vec3(0.75f,
0.5f,
(float)imageSize),
tcu::Vec3((float)(13u % imageSize) + 0.25f,
0.0f,
(float)(16u % imageSize) + 0.5f),
tcu::Vec3(0.0f,
(float)(84u % imageSize) + 0.5f,
(float)(10u % imageSize) + 0.75f),
tcu::Vec3((float)imageSize,
(float)(75u % imageSize) + 0.25f,
(float)(83u % imageSize) + 0.75f),
};
const deUint32 slices[4] =
{
1u % arraySize,
2u % arraySize,
9u % arraySize,
5u % arraySize,
};
DE_ASSERT(de::inRange(coords[samplePosNdx].x(), 0.0f, (float)imageSize));
DE_ASSERT(de::inRange(coords[samplePosNdx].y(), 0.0f, (float)imageSize));
DE_ASSERT(de::inRange(coords[samplePosNdx].z(), 0.0f, (float)imageSize));
// map to [-1, 1]*3 space
return tcu::Vec4(coords[samplePosNdx].x() / (float)imageSize * 2.0f - 1.0f,
coords[samplePosNdx].y() / (float)imageSize * 2.0f - 1.0f,
coords[samplePosNdx].z() / (float)imageSize * 2.0f - 1.0f,
(float)slices[samplePosNdx]);
}
default:
DE_FATAL("Impossible");
return tcu::Vec4();
}
}
tcu::Vec4 ImageSampleInstanceImages::fetchSampleValue (int samplePosNdx, int setNdx) const
{
DE_ASSERT(de::inBounds(samplePosNdx, 0, 4));
// texture order is ABAB
const bool isSamplerCase = (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER);
const deUint32 numImages = (isSamplerCase) ? 1 : getInterfaceNumResources(m_shaderInterface);
const tcu::TextureLevelPyramid& sampleSrcA = getSourceImage(setNdx * numImages);
const tcu::TextureLevelPyramid& sampleSrcB = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? sampleSrcA : getSourceImage(setNdx * numImages + 1);
const tcu::TextureLevelPyramid& sampleSrc = (isSamplerCase) ? (sampleSrcA) : ((samplePosNdx % 2) == 0) ? (sampleSrcA) : (sampleSrcB);
// sampler order is ABAB
const tcu::Sampler& samplerA = getRefSampler(setNdx * getInterfaceNumResources(m_shaderInterface));
const tcu::Sampler& samplerB = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? (samplerA) : getRefSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1);
const tcu::Sampler& sampler = ((samplePosNdx % 2) == 0) ? (samplerA) : (samplerB);
const tcu::Vec4 samplePos = getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
const float lod = 0.0f;
std::vector<tcu::ConstPixelBufferAccess> levelStorage;
switch (m_viewType)
{
case vk::VK_IMAGE_VIEW_TYPE_1D:
case vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY: return getRef1DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), lod);
case vk::VK_IMAGE_VIEW_TYPE_2D:
case vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY: return getRef2DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
case vk::VK_IMAGE_VIEW_TYPE_3D: return getRef3DView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), lod);
case vk::VK_IMAGE_VIEW_TYPE_CUBE:
case vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY: return getRefCubeView(sampleSrc, m_baseMipLevel, m_baseArraySlice, &levelStorage).sample(sampler, samplePos.x(), samplePos.y(), samplePos.z(), samplePos.w(), lod);
default:
{
DE_FATAL("Impossible");
return tcu::Vec4();
}
}
}
int ImageSampleInstanceImages::getNumImages (vk::VkDescriptorType descriptorType, DescriptorSetCount descriptorSetCount, ShaderInputInterface shaderInterface)
{
// If we are testing separate samplers, just one image is enough
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
return getDescriptorSetCount(descriptorSetCount);
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
// combined: numImages == numSamplers
return getInterfaceNumResources(shaderInterface) * getDescriptorSetCount(descriptorSetCount);
}
else
{
DE_FATAL("Impossible");
return 0;
}
}
tcu::Sampler ImageSampleInstanceImages::createRefSampler (int ndx)
{
if (ndx % 2 == 0)
{
// linear, wrapping
return tcu::Sampler(tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::REPEAT_GL, tcu::Sampler::LINEAR, tcu::Sampler::LINEAR);
}
else
{
// nearest, clamping
return tcu::Sampler(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::NEAREST, tcu::Sampler::NEAREST);
}
}
vk::Move<vk::VkSampler> ImageSampleInstanceImages::createSampler (const vk::DeviceInterface& vki, vk::VkDevice device, const tcu::Sampler& sampler, const tcu::TextureFormat& format)
{
const vk::VkSamplerCreateInfo createInfo = vk::mapSampler(sampler, format);
return vk::createSampler(vki, device, &createInfo);
}
tcu::Texture1DArrayView ImageSampleInstanceImages::getRef1DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
{
DE_ASSERT(levelStorage->empty());
const deUint32 numSlices = (deUint32)source.getLevel(0).getHeight();
const deUint32 numLevels = (deUint32)source.getNumLevels();
// cut pyramid from baseMipLevel
for (deUint32 level = baseMipLevel; level < numLevels; ++level)
{
// cut levels from baseArraySlice
const tcu::ConstPixelBufferAccess wholeLevel = source.getLevel(level);
const tcu::ConstPixelBufferAccess cutLevel = tcu::getSubregion(wholeLevel, 0, baseArraySlice, wholeLevel.getWidth(), numSlices - baseArraySlice);
levelStorage->push_back(cutLevel);
}
return tcu::Texture1DArrayView((int)levelStorage->size(), &levelStorage->front());
}
tcu::Texture2DArrayView ImageSampleInstanceImages::getRef2DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
{
DE_ASSERT(levelStorage->empty());
const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth();
const deUint32 numLevels = (deUint32)source.getNumLevels();
// cut pyramid from baseMipLevel
for (deUint32 level = baseMipLevel; level < numLevels; ++level)
{
// cut levels from baseArraySlice
const tcu::ConstPixelBufferAccess wholeLevel = source.getLevel(level);
const tcu::ConstPixelBufferAccess cutLevel = tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice, wholeLevel.getWidth(), wholeLevel.getHeight(), numSlices - baseArraySlice);
levelStorage->push_back(cutLevel);
}
return tcu::Texture2DArrayView((int)levelStorage->size(), &levelStorage->front());
}
tcu::Texture3DView ImageSampleInstanceImages::getRef3DView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
{
DE_ASSERT(levelStorage->empty());
DE_ASSERT(baseArraySlice == 0);
DE_UNREF(baseArraySlice);
const deUint32 numLevels = (deUint32)source.getNumLevels();
// cut pyramid from baseMipLevel
for (deUint32 level = baseMipLevel; level < numLevels; ++level)
levelStorage->push_back(source.getLevel(level));
return tcu::Texture3DView((int)levelStorage->size(), &levelStorage->front());
}
tcu::TextureCubeArrayView ImageSampleInstanceImages::getRefCubeView (const tcu::TextureLevelPyramid& source, deUint32 baseMipLevel, deUint32 baseArraySlice, std::vector<tcu::ConstPixelBufferAccess>* levelStorage)
{
DE_ASSERT(levelStorage->empty());
const deUint32 numSlices = (deUint32)source.getLevel(0).getDepth() / 6;
const deUint32 numLevels = (deUint32)source.getNumLevels();
// cut pyramid from baseMipLevel
for (deUint32 level = baseMipLevel; level < numLevels; ++level)
{
// cut levels from baseArraySlice
const tcu::ConstPixelBufferAccess wholeLevel = source.getLevel(level);
const tcu::ConstPixelBufferAccess cutLevel = tcu::getSubregion(wholeLevel, 0, 0, baseArraySlice * 6, wholeLevel.getWidth(), wholeLevel.getHeight(), (numSlices - baseArraySlice) * 6);
levelStorage->push_back(cutLevel);
}
return tcu::TextureCubeArrayView((int)levelStorage->size(), &levelStorage->front());
}
class ImageSampleRenderInstance : public SingleCmdRenderInstance
{
public:
ImageSampleRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool isImmutable);
private:
static std::vector<DescriptorSetLayoutHandleSp> createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
const ImageSampleInstanceImages& images,
DescriptorUpdateMethod updateMethod);
static vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout);
static vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface);
static std::vector<DescriptorSetHandleSp> createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout = DE_NULL);
static void writeSamplerDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
static void writeImageSamplerDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
static void writeSamplerDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::VkDescriptorSetLayout layout,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush = false,
vk::VkPipelineLayout pipelineLayout = 0);
static void writeImageSamplerDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::VkDescriptorSetLayout layout,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush = false,
vk::VkPipelineLayout pipelineLayout = 0);
void logTestPlan (void) const;
vk::VkPipelineLayout getPipelineLayout (void) const;
void writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const;
tcu::TestStatus verifyResultImage (const tcu::ConstPixelBufferAccess& result) const;
enum
{
RENDER_SIZE = 128,
};
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const vk::VkShaderStageFlags m_stageFlags;
const ShaderInputInterface m_shaderInterface;
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
const ImageSampleInstanceImages m_images;
std::vector<deUint32> m_descriptorsPerSet;
const std::vector<DescriptorSetLayoutHandleSp> m_descriptorSetLayouts;
const vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
const vk::Unique<vk::VkDescriptorPool> m_descriptorPool;
const std::vector<DescriptorSetHandleSp> m_descriptorSets;
};
ImageSampleRenderInstance::ImageSampleRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool isImmutable)
: SingleCmdRenderInstance (context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_stageFlags (stageFlags)
, m_shaderInterface (shaderInterface)
, m_viewType (viewType)
, m_baseMipLevel (baseMipLevel)
, m_baseArraySlice (baseArraySlice)
, m_updateTemplates ()
, m_updateRegistry ()
, m_updateBuilder ()
, m_images (m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutable)
, m_descriptorSetLayouts (createDescriptorSetLayouts(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_stageFlags, m_images, m_updateMethod))
, m_pipelineLayout (createPipelineLayout(m_vki, m_device, m_descriptorSetLayouts))
, m_descriptorPool (createDescriptorPool(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface))
, m_descriptorSets (createDescriptorSets(m_vki, m_updateMethod, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_descriptorSetLayouts, *m_descriptorPool, isImmutable, m_images, m_updateBuilder, m_updateTemplates, m_updateRegistry, m_descriptorsPerSet, *m_pipelineLayout))
{
}
std::vector<DescriptorSetLayoutHandleSp> ImageSampleRenderInstance::createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
const ImageSampleInstanceImages& images,
DescriptorUpdateMethod updateMethod)
{
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
const vk::VkSampler samplers[2] =
{
images.getSampler(setNdx * getInterfaceNumResources(shaderInterface)),
images.getSampler(setNdx * getInterfaceNumResources(shaderInterface) + 1),
};
vk::DescriptorSetLayoutBuilder builder;
const bool addSeparateImage = descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
// (combined)samplers follow
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
if (addSeparateImage)
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
if (addSeparateImage)
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
builder.addSingleSamplerBinding(descriptorType, stageFlags, (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedSamplerBinding(descriptorType, stageFlags, 0u, (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
if (addSeparateImage)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags, 1u);
builder.addSingleIndexedSamplerBinding(descriptorType, stageFlags, 2u, (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
if (addSeparateImage)
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
builder.addSingleIndexedSamplerBinding(descriptorType, stageFlags, getArbitraryBindingIndex(0), (images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
builder.addSingleIndexedSamplerBinding(descriptorType, stageFlags, getArbitraryBindingIndex(1), (images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
if (addSeparateImage)
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, stageFlags);
builder.addArraySamplerBinding(descriptorType, 2u, stageFlags, (images.isImmutable()) ? (samplers) : (DE_NULL));
break;
default:
DE_FATAL("Impossible");
}
vk::Move<vk::VkDescriptorSetLayout> layout = builder.build(vki, device, extraFlags);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
}
}
return descriptorSetLayouts;
}
vk::Move<vk::VkPipelineLayout> ImageSampleRenderInstance::createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout)
{
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
for (size_t setNdx = 0; setNdx < descriptorSetLayout.size(); setNdx++)
layoutHandles.push_back(**descriptorSetLayout[setNdx]);
const vk::VkPipelineLayoutCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
(deUint32)layoutHandles.size(), // descriptorSetCount
&layoutHandles.front(), // pSetLayouts
0u, // pushConstantRangeCount
DE_NULL, // pPushConstantRanges
};
return vk::createPipelineLayout(vki, device, &createInfo);
}
vk::Move<vk::VkDescriptorPool> ImageSampleRenderInstance::createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface)
{
vk::DescriptorPoolBuilder builder;
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
{
// separate samplers need image to sample
builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, getDescriptorSetCount(descriptorSetCount));
// also need sample to use, indifferent of whether immutable or not
builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLER, getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface));
}
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
// combined image samplers
builder.addType(vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface));
}
else
DE_FATAL("Impossible");
return builder.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(descriptorSetCount));
}
std::vector<DescriptorSetHandleSp> ImageSampleRenderInstance::createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout)
{
std::vector<DescriptorSetHandleSp> descriptorSets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::VkDescriptorSetLayout layout = **descriptorSetLayouts[getDescriptorSetNdx(descriptorSetCount, setNdx)];
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSetWithTemplate(vki, device, descriptorSetCount, shaderInterface, isImmutable, images, *descriptorSet, setNdx, layout, updateTemplates, updateRegistry);
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSetWithTemplate(vki, device, descriptorSetCount, shaderInterface, isImmutable, images, *descriptorSet, setNdx, layout, updateTemplates, updateRegistry);
else
DE_FATAL("Impossible");
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSetWithTemplate(vki, device, descriptorSetCount, shaderInterface, isImmutable, images, DE_NULL, setNdx, layout, updateTemplates, updateRegistry, true, pipelineLayout);
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSetWithTemplate(vki, device, descriptorSetCount, shaderInterface, isImmutable, images, DE_NULL, setNdx, layout, updateTemplates, updateRegistry, true, pipelineLayout);
else
DE_FATAL("Impossible");
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, setNdx, updateBuilder, descriptorsPerSet, updateMethod);
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, setNdx, updateBuilder, descriptorsPerSet, updateMethod);
else
DE_FATAL("Impossible");
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
if (descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, setNdx, updateBuilder, descriptorsPerSet);
else if (descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSet(vki, device, shaderInterface, isImmutable, images, *descriptorSet, setNdx, updateBuilder, descriptorsPerSet);
else
DE_FATAL("Impossible");
}
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(descriptorSet)));
}
return descriptorSets;
}
void ImageSampleRenderInstance::writeSamplerDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod)
{
const vk::VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(images.getImageView(setNdx), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const vk::VkDescriptorImageInfo samplersInfos[2] =
{
makeDescriptorImageInfo(images.getSampler(setNdx * getInterfaceNumResources(shaderInterface))),
makeDescriptorImageInfo(images.getSampler(setNdx * getInterfaceNumResources(shaderInterface) + 1)),
};
const deUint32 samplerLocation = shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS ? 1u : 0u;
deUint32 numDescriptors = 1u;
// stand alone texture
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(samplerLocation), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
// samplers
if (!isImmutable || (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH))
{
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
}
descriptorsPerSet.push_back(numDescriptors);
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateBuilder.update(vki, device);
updateBuilder.clear();
}
}
void ImageSampleRenderInstance::writeImageSamplerDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod)
{
const vk::VkSampler samplers[2] =
{
(isImmutable && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? (0) : (images.getSampler(setNdx * getInterfaceNumResources(shaderInterface))),
(isImmutable && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH) ? (0) : (images.getSampler(setNdx * getInterfaceNumResources(shaderInterface) + 1)),
};
const vk::VkDescriptorImageInfo imageSamplers[2] =
{
vk::makeDescriptorImageInfo(samplers[0], images.getImageView(setNdx * getInterfaceNumResources(shaderInterface)), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
vk::makeDescriptorImageInfo(samplers[1], images.getImageView(setNdx * getInterfaceNumResources(shaderInterface) + 1), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
};
deUint32 numDescriptors = 0u;
// combined image samplers
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
descriptorsPerSet.push_back(numDescriptors);
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateBuilder.update(vki, device);
updateBuilder.clear();
}
}
void ImageSampleRenderInstance::writeSamplerDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::VkDescriptorSetLayout layout,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush,
vk::VkPipelineLayout pipelineLayout)
{
const vk::VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(images.getImageView(setNdx), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const vk::VkDescriptorImageInfo samplersInfos[2] =
{
makeDescriptorImageInfo(images.getSampler(setNdx * getInterfaceNumResources(shaderInterface))),
makeDescriptorImageInfo(images.getSampler(setNdx * getInterfaceNumResources(shaderInterface) + 1)),
};
const deUint32 samplerLocation = shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS ? 1u : 0u;
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
getDescriptorSetNdx(descriptorSetCount, setNdx)
};
RawUpdateRegistry updateRegistry;
updateRegistry.addWriteObject(imageInfo);
updateRegistry.addWriteObject(samplersInfos[0]);
updateRegistry.addWriteObject(samplersInfos[1]);
// stand alone texture
updateEntries.push_back(createTemplateBinding(samplerLocation, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, updateRegistry.getWriteObjectOffset(0), 0));
// samplers
if (!isImmutable || withPush)
{
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(2), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(2), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(2), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(1, 0, 2, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(1), sizeof(samplersInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
registry.push_back(updateRegistry);
if (!withPush)
{
vki.updateDescriptorSetWithTemplate(device, descriptorSet, **updateTemplates.back(), registry.back().getRawPointer());
}
}
void ImageSampleRenderInstance::writeImageSamplerDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool isImmutable,
const ImageSampleInstanceImages& images,
vk::VkDescriptorSet descriptorSet,
deUint32 setNdx,
vk::VkDescriptorSetLayout layout,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush,
vk::VkPipelineLayout pipelineLayout)
{
const vk::VkSampler samplers[2] =
{
(isImmutable && !withPush) ? (0) : (images.getSampler(setNdx * getInterfaceNumResources(shaderInterface))),
(isImmutable && !withPush) ? (0) : (images.getSampler(setNdx * getInterfaceNumResources(shaderInterface) + 1)),
};
const vk::VkDescriptorImageInfo imageSamplers[2] =
{
vk::makeDescriptorImageInfo(samplers[0], images.getImageView(setNdx * getInterfaceNumResources(shaderInterface)), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
vk::makeDescriptorImageInfo(samplers[1], images.getImageView(setNdx * getInterfaceNumResources(shaderInterface) + 1), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
getDescriptorSetNdx(descriptorSetCount, setNdx)
};
RawUpdateRegistry updateRegistry;
updateRegistry.addWriteObject(imageSamplers[0]);
updateRegistry.addWriteObject(imageSamplers[1]);
// combined image samplers
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(1, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(2, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(0, 0, 2, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(0), sizeof(imageSamplers[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
registry.push_back(updateRegistry);
if (!withPush)
{
vki.updateDescriptorSetWithTemplate(device, descriptorSet, **updateTemplates.back(), registry.back().getRawPointer());
}
}
void ImageSampleRenderInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Rendering 2x2 grid.\n";
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
{
msg << ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
}
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
msg << ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
}
else
DE_FATAL("Impossible");
msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
if (m_baseMipLevel)
msg << "Image view base mip level = " << m_baseMipLevel << "\n";
if (m_baseArraySlice)
msg << "Image view base array slice = " << m_baseArraySlice << "\n";
if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
msg << "Sampler mode is LINEAR, with WRAP\n";
else
msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
if (m_stageFlags == 0u)
{
msg << "Descriptors are not accessed in any shader stage.\n";
}
else
{
msg << "Color in each cell is fetched using the descriptor(s):\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
msg << " using sampler " << srcResourceNdx;
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
msg << " from combined image sampler " << srcResourceNdx;
else
DE_FATAL("Impossible");
}
msg << "\n";
}
msg << "Descriptors are accessed in {"
<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0) ? (" vertex") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? (" tess_control") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) ? (" tess_evaluation") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0) ? (" geometry") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0) ? (" fragment") : (""))
<< " } stages.";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
vk::VkPipelineLayout ImageSampleRenderInstance::getPipelineLayout (void) const
{
return *m_pipelineLayout;
}
void ImageSampleRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
{
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
std::vector<vk::VkDescriptorSet> setHandles;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
setHandles.push_back(**m_descriptorSets[setNdx]);
switch (m_descriptorSetCount)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE:
{
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0u, (int)setHandles.size(), &setHandles.front(), 0u, DE_NULL);
break;
}
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), descriptorSetNdx, 1u, &setHandles[setNdx], 0u, DE_NULL);
}
break;
}
default:
DE_FATAL("Impossible");
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, **m_updateTemplates[setNdx], getPipelineLayout(), descriptorSetNdx, (const void*)m_updateRegistry[setNdx].getRawPointer());
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
deUint32 descriptorNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
const deUint32 numDescriptors = m_descriptorsPerSet[setNdx];
m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, descriptorSetNdx, descriptorNdx, numDescriptors);
descriptorNdx += numDescriptors;
}
}
m_vki.cmdDraw(cmd, 6u * 4u, 1u, 0u, 0u); // render four quads (two separate triangles)
}
tcu::TestStatus ImageSampleRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
{
const deUint32 numDescriptorSets = getDescriptorSetCount(m_descriptorSetCount);
const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f);
const bool doFetch = (m_stageFlags != 0u); // no active stages? Then don't fetch
const tcu::RGBA threshold = tcu::RGBA(8, 8, 8, 8); // source image is high-frequency so the threshold is quite large to tolerate sampling errors
tcu::Surface reference (m_targetSize.x(), m_targetSize.y());
tcu::Vec4 sample0 = tcu::Vec4(0.0f);
tcu::Vec4 sample1 = tcu::Vec4(0.0f);
tcu::Vec4 sample2 = tcu::Vec4(0.0f);
tcu::Vec4 sample3 = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < numDescriptorSets; setNdx++)
{
sample0 += (!doFetch) ? (yellow) : (m_images.fetchSampleValue(0, setNdx));
sample1 += (!doFetch) ? (green) : (m_images.fetchSampleValue(1, setNdx));
sample2 += (!doFetch) ? (green) : (m_images.fetchSampleValue(2, setNdx));
sample3 += (!doFetch) ? (yellow) : (m_images.fetchSampleValue(3, setNdx));
}
if (numDescriptorSets > 1)
{
sample0 = sample0 / tcu::Vec4(float(numDescriptorSets));
sample1 = sample1 / tcu::Vec4(float(numDescriptorSets));
sample2 = sample2 / tcu::Vec4(float(numDescriptorSets));
sample3 = sample3 / tcu::Vec4(float(numDescriptorSets));
}
drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, threshold, tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Image verification failed");
else
return tcu::TestStatus::pass("Pass");
}
class ImageSampleComputeInstance : public vkt::TestInstance
{
public:
ImageSampleComputeInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool isImmutableSampler);
private:
vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (deUint32 setNdx) const;
vk::Move<vk::VkDescriptorPool> createDescriptorPool (void) const;
vk::Move<vk::VkDescriptorSet> createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx);
void writeDescriptorSet (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkPipelineLayout pipelineLayout = DE_NULL);
void writeImageSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx);
void writeImageSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
void writeSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx);
void writeSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
tcu::TestStatus iterate (void);
void logTestPlan (void) const;
tcu::TestStatus testResourceAccess (void);
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
const bool m_isImmutableSampler;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vk::Allocator& m_allocator;
const ComputeInstanceResultBuffer m_result;
const ImageSampleInstanceImages m_images;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
std::vector<deUint32> m_descriptorsPerSet;
};
ImageSampleComputeInstance::ImageSampleComputeInstance (Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 baseMipLevel,
deUint32 baseArraySlice,
bool isImmutableSampler)
: vkt::TestInstance (context)
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_viewType (viewType)
, m_baseMipLevel (baseMipLevel)
, m_baseArraySlice (baseArraySlice)
, m_isImmutableSampler (isImmutableSampler)
, m_updateTemplates ()
, m_vki (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_allocator (context.getDefaultAllocator())
, m_result (m_vki, m_device, m_allocator)
, m_images (m_vki, m_device, m_queueFamilyIndex, m_queue, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, isImmutableSampler)
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorsPerSet ()
{
}
vk::Move<vk::VkDescriptorSetLayout> ImageSampleComputeInstance::createDescriptorSetLayout (deUint32 setNdx) const
{
const vk::VkSampler samplers[2] =
{
m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface)),
m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1),
};
vk::DescriptorSetLayoutBuilder builder;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
deUint32 binding = 0;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
// result buffer
if (setNdx == 0)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
// (combined)samplers follow
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++, (m_images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding, (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 1u);
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 2u, (m_images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(0), (m_images.isImmutable()) ? (&samplers[0]) : (DE_NULL));
builder.addSingleIndexedSamplerBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(1), (m_images.isImmutable()) ? (&samplers[1]) : (DE_NULL));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
builder.addArraySamplerBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT, (m_images.isImmutable()) ? (samplers) : (DE_NULL));
break;
default:
DE_FATAL("Impossible");
};
return builder.build(m_vki, m_device, extraFlags);
}
vk::Move<vk::VkDescriptorPool> ImageSampleComputeInstance::createDescriptorPool (void) const
{
vk::DescriptorPoolBuilder builder;
builder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
builder.addType(m_descriptorType, getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface));
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
builder.addType(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, getDescriptorSetCount(m_descriptorSetCount));
return builder.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(m_descriptorSetCount));
}
vk::Move<vk::VkDescriptorSet> ImageSampleComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx)
{
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
vk::Move<vk::VkDescriptorSet> descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
writeDescriptorSet(*descriptorSet, layout, setNdx);
return descriptorSet;
}
return vk::Move<vk::VkDescriptorSet>();
}
void ImageSampleComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, vk::VkPipelineLayout pipelineLayout)
{
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSetWithTemplate(descriptorSet, layout, setNdx);
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSetWithTemplate(descriptorSet, layout, setNdx);
else
DE_FATAL("Impossible");
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSetWithTemplate(descriptorSet, layout, setNdx, true, pipelineLayout);
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSetWithTemplate(descriptorSet, layout, setNdx, true, pipelineLayout);
else
DE_FATAL("Impossible");
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSet(descriptorSet, setNdx);
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSet(descriptorSet, setNdx);
else
DE_FATAL("Impossible");
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
writeSamplerDescriptorSet(descriptorSet, setNdx);
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
writeImageSamplerDescriptorSet(descriptorSet, setNdx);
else
DE_FATAL("Impossible");
}
}
void ImageSampleComputeInstance::writeSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(m_images.getImageView(setNdx), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const vk::VkDescriptorImageInfo samplersInfos[2] =
{
makeDescriptorImageInfo(m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface))),
makeDescriptorImageInfo(m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)),
};
deUint32 binding = 0u;
deUint32 numDescriptors = 0u;
// result
if (setNdx == 0)
{
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
numDescriptors++;
}
// stand alone texture
{
const deUint32 texutreBinding = (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? (binding + 1) : (binding++);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(texutreBinding), vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, &imageInfo);
numDescriptors++;
}
// samplers
if (!m_isImmutableSampler || (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH))
{
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding + 2), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), vk::VK_DESCRIPTOR_TYPE_SAMPLER, &samplersInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_SAMPLER, 2u, samplersInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
}
m_descriptorsPerSet.push_back(numDescriptors);
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
m_updateBuilder.update(m_vki, m_device);
m_updateBuilder.clear();
}
}
void ImageSampleComputeInstance::writeSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush, vk::VkPipelineLayout pipelineLayout)
{
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkDescriptorImageInfo imageInfo = makeDescriptorImageInfo(m_images.getImageView(setNdx), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
const vk::VkDescriptorImageInfo samplersInfos[2] =
{
makeDescriptorImageInfo(m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface))),
makeDescriptorImageInfo(m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)),
};
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_COMPUTE,
pipelineLayout,
getDescriptorSetNdx(m_descriptorSetCount, setNdx)
};
deUint32 binding = 0u;
deUint32 offset = 0u;
RawUpdateRegistry updateRegistry;
if (setNdx == 0)
updateRegistry.addWriteObject(resultInfo);
updateRegistry.addWriteObject(imageInfo);
updateRegistry.addWriteObject(samplersInfos[0]);
updateRegistry.addWriteObject(samplersInfos[1]);
// result
if (setNdx == 0)
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, updateRegistry.getWriteObjectOffset(offset++), 0));
// stand alone texture
{
const deUint32 textureBinding = (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? (binding + 1) : (binding++);
updateEntries.push_back(createTemplateBinding(textureBinding, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, updateRegistry.getWriteObjectOffset(offset++), 0));
}
// samplers
if (!m_isImmutableSampler || withPush)
{
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding + 2, 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(binding++, 0, 2, vk::VK_DESCRIPTOR_TYPE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), sizeof(samplersInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
m_updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
m_updateRegistry.push_back(updateRegistry);
if (!withPush)
{
m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, **m_updateTemplates.back(), m_updateRegistry.back().getRawPointer());
}
}
void ImageSampleComputeInstance::writeImageSamplerDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkSampler samplers[2] =
{
(m_isImmutableSampler && (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)) ? (0) : (m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface))),
(m_isImmutableSampler && (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)) ? (0) : (m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)),
};
const vk::VkDescriptorImageInfo imageSamplers[2] =
{
makeDescriptorImageInfo(samplers[0], m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface)), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
makeDescriptorImageInfo(samplers[1], m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
};
deUint32 binding = 0u;
deUint32 numDescriptors = 0u;
// result
if (setNdx == 0)
{
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
numDescriptors++;
}
// combined image samplers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding + 2u), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageSamplers[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 2u, imageSamplers);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
m_descriptorsPerSet.push_back(numDescriptors);
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
m_updateBuilder.update(m_vki, m_device);
m_updateBuilder.clear();
}
}
void ImageSampleComputeInstance::writeImageSamplerDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush, vk::VkPipelineLayout pipelineLayout)
{
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkSampler samplers[2] =
{
(m_isImmutableSampler && !withPush) ? (0) : (m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface))),
(m_isImmutableSampler && !withPush) ? (0) : (m_images.getSampler(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)),
};
const vk::VkDescriptorImageInfo imageSamplers[2] =
{
makeDescriptorImageInfo(samplers[0], m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface)), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
makeDescriptorImageInfo(samplers[1], m_images.getImageView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1), vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL),
};
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_COMPUTE,
pipelineLayout,
getDescriptorSetNdx(m_descriptorSetCount, setNdx)
};
deUint32 binding = 0u;
deUint32 offset = 0u;
RawUpdateRegistry updateRegistry;
if (setNdx == 0)
updateRegistry.addWriteObject(resultInfo);
updateRegistry.addWriteObject(imageSamplers[0]);
updateRegistry.addWriteObject(imageSamplers[1]);
// result
if (setNdx == 0)
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, updateRegistry.getWriteObjectOffset(offset++), 0));
// combined image samplers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding + 2, 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(binding++, 0, 2, vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, updateRegistry.getWriteObjectOffset(offset++), sizeof(imageSamplers[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
m_updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
m_updateRegistry.push_back(updateRegistry);
if (!withPush)
{
m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, **m_updateTemplates.back(), m_updateRegistry.back().getRawPointer());
}
}
tcu::TestStatus ImageSampleComputeInstance::iterate (void)
{
logTestPlan();
return testResourceAccess();
}
void ImageSampleComputeInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Accessing resource in a compute program.\n";
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
{
msg << ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " VK_DESCRIPTOR_TYPE_SAMPLER descriptor(s) and a single texture.\n";
}
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
{
msg << ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER descriptor(s).\n";
}
else
DE_FATAL("Impossible");
msg << "Image view type is " << vk::getImageViewTypeName(m_viewType) << "\n";
if (m_baseMipLevel)
msg << "Image view base mip level = " << m_baseMipLevel << "\n";
if (m_baseArraySlice)
msg << "Image view base array slice = " << m_baseArraySlice << "\n";
if (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR)
msg << "Sampler mode is LINEAR, with WRAP\n";
else
msg << "Sampler 0 mode is LINEAR, with WRAP\nSampler 1 mode is NEAREST with CLAMP\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": sample at position " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
msg << " using sampler " << srcResourceNdx;
else if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
msg << " from combined image sampler " << srcResourceNdx;
else
DE_FATAL("Impossible");
}
msg << "\n";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
tcu::TestStatus ImageSampleComputeInstance::testResourceAccess (void)
{
const vk::Unique<vk::VkDescriptorPool> descriptorPool(createDescriptorPool());
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
std::vector<DescriptorSetHandleSp> descriptorSets;
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
std::vector<vk::VkDescriptorSet> setHandles;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
vk::Move<vk::VkDescriptorSetLayout> layout = createDescriptorSetLayout(setNdx);
vk::Move<vk::VkDescriptorSet> set = createDescriptorSet(*descriptorPool, *layout, setNdx);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(set)));
layoutHandles.push_back(**descriptorSetLayouts.back());
setHandles.push_back(**descriptorSets.back());
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && m_descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(m_vki, m_device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
layoutHandles.push_back(**descriptorSetLayouts.back());
}
}
const ComputePipeline pipeline (m_vki, m_device, m_context.getBinaryCollection(), (int)layoutHandles.size(), &layoutHandles.front());
const deUint32* const dynamicOffsets = DE_NULL;
const int numDynamicOffsets = 0;
const vk::VkBufferMemoryBarrier* const preBarriers = DE_NULL;
const int numPreBarriers = 0;
const vk::VkBufferMemoryBarrier* const postBarriers = m_result.getResultReadBarrier();
const int numPostBarriers = 1;
const ComputeCommand compute (m_vki,
m_device,
pipeline.getPipeline(),
pipeline.getPipelineLayout(),
tcu::UVec3(4, 1, 1),
m_shaderInterface,
m_descriptorSetCount, &setHandles.front(),
numDynamicOffsets, dynamicOffsets,
numPreBarriers, preBarriers,
numPostBarriers, postBarriers);
tcu::Vec4 results[4];
bool anyResultSet = false;
bool allResultsOk = true;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSet(DE_NULL, layoutHandles[getDescriptorSetNdx(m_descriptorSetCount, setNdx)], setNdx, pipeline.getPipelineLayout()); // descriptor set not applicable
compute.submitAndWait(m_queueFamilyIndex, m_queue, &m_updateTemplates, &m_updateRegistry);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSet(DE_NULL, layoutHandles[getDescriptorSetNdx(m_descriptorSetCount, setNdx)], setNdx, pipeline.getPipelineLayout()); // descriptor set not applicable
compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder, m_descriptorsPerSet);
}
else
{
compute.submitAndWait(m_queueFamilyIndex, m_queue);
}
m_result.readResultContentsTo(&results);
// verify
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
// source image is high-frequency so the threshold is quite large to tolerate sampling errors
const tcu::Vec4 samplingThreshold = tcu::Vec4(8.0f / 255.0f);
const tcu::Vec4 result = results[resultNdx];
tcu::Vec4 reference = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
reference += m_images.fetchSampleValue(resultNdx, setNdx);
reference = reference / tcu::Vec4((float)getDescriptorSetCount(m_descriptorSetCount));
if (result != tcu::Vec4(-1.0f))
anyResultSet = true;
if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), samplingThreshold)))
{
allResultsOk = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Test sample " << resultNdx << ":\n"
<< "\tSampling at " << m_images.getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, resultNdx) << "\n"
<< "\tError expected " << reference << ", got " << result
<< tcu::TestLog::EndMessage;
}
}
// read back and verify
if (allResultsOk)
return tcu::TestStatus::pass("Pass");
else if (anyResultSet)
return tcu::TestStatus::fail("Invalid result values");
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Result buffer was not written to."
<< tcu::TestLog::EndMessage;
return tcu::TestStatus::fail("Result buffer was not written to");
}
}
class ImageDescriptorCase : public QuadrantRendederCase
{
public:
enum
{
FLAG_BASE_MIP = (1u << 1u),
FLAG_BASE_SLICE = (1u << 2u),
};
// enum continues where resource flags ends
DE_STATIC_ASSERT((deUint32)FLAG_BASE_MIP == (deUint32)RESOURCE_FLAG_LAST);
ImageDescriptorCase (tcu::TestContext& testCtx,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 flags);
private:
std::string genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const;
std::string genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
std::string genFetchCoordStr (int fetchPosNdx) const;
std::string genSampleCoordStr (int samplePosNdx) const;
std::string genResourceAccessSource (vk::VkShaderStageFlagBits stage) const;
std::string genNoAccessSource (void) const;
vkt::TestInstance* createInstance (vkt::Context& context) const;
private:
const bool m_isPrimaryCmdBuf;
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const vk::VkImageViewType m_viewType;
const deUint32 m_baseMipLevel;
const deUint32 m_baseArraySlice;
const bool m_isImmutableSampler;
};
ImageDescriptorCase::ImageDescriptorCase (tcu::TestContext& testCtx,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkImageViewType viewType,
deUint32 flags)
: QuadrantRendederCase (testCtx, name, description,
// \note 1D textures are not supported in ES
(viewType == vk::VK_IMAGE_VIEW_TYPE_1D || viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? glu::GLSL_VERSION_440 : glu::GLSL_VERSION_310_ES,
exitingStages, activeStages, descriptorSetCount)
, m_isPrimaryCmdBuf (isPrimaryCmdBuf)
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_viewType (viewType)
, m_baseMipLevel (((flags & FLAG_BASE_MIP) != 0) ? (1u) : (0u))
, m_baseArraySlice (((flags & FLAG_BASE_SLICE) != 0) ? (1u) : (0u))
, m_isImmutableSampler ((flags & RESOURCE_FLAG_IMMUTABLE_SAMPLER) != 0)
{
}
std::string ImageDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
return "#extension GL_OES_texture_cube_map_array : require\n";
else
return "";
}
std::string ImageDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
{
DE_UNREF(stage);
// Vulkan-style resources are arrays implicitly, OpenGL-style are not
const std::string dimensionBase = (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? ("1D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? ("2D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ("3D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? ("Cube")
: (DE_NULL);
const std::string dimensionArray = (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? ("1DArray")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? ("2DArray")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ("3D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE || m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? ("CubeArray")
: (DE_NULL);
const std::string dimension = isImageViewTypeArray(m_viewType) ? dimensionArray : dimensionBase;
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::string buf;
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
// Result buffer is bound only to the first descriptor set in compute shader cases
const int descBinding = numUsedBindings - ((m_activeStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) ? (setNdx == 0 ? 0 : 1) : 0);
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
const deUint32 descriptorSet = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
{
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + ";\n";
break;
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + ";\n";
break;
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + ";\n";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + ";\n";
break;
default:
DE_FATAL("invalid descriptor");
}
break;
}
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
{
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
if (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS)
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "B;\n";
else
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "B;\n";
break;
default:
DE_FATAL("invalid descriptor");
}
break;
}
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
{
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 2) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "B;\n";
break;
default:
DE_FATAL("invalid descriptor");
}
break;
}
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
{
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(0)) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(1)) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(0)) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(1)) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(0)) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(1)) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "B;\n";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(0)) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "A;\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(getArbitraryBindingIndex(1)) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "B;\n";
break;
default:
DE_FATAL("invalid descriptor");
}
break;
}
case SHADER_INPUT_DESCRIPTOR_ARRAY:
{
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimension + " u_separateTexture" + setNdxPostfix + ";\n"
"layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding + 1) + ") uniform highp sampler u_separateSampler" + setNdxPostfix + "[2];\n";
break;
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp sampler" + dimension + " u_combinedTextureSampler" + setNdxPostfix + "[2];\n";
break;
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ") uniform highp texture" + dimensionBase + " u_separateTexture" + setNdxPostfix + "[2];\n";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
buf += "layout(set = " + de::toString(descriptorSet) + ", binding = " + de::toString(descBinding) + ", rgba8) readonly uniform highp image" + dimension + " u_image" + setNdxPostfix + "[2];\n";
break;
default:
DE_FATAL("invalid descriptor");
}
break;
}
default:
DE_FATAL("Impossible");
}
}
return buf;
}
std::string ImageDescriptorCase::genFetchCoordStr (int fetchPosNdx) const
{
DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
const tcu::IVec3 fetchPos = ImageFetchInstanceImages::getFetchPos(m_viewType, m_baseMipLevel, m_baseArraySlice, fetchPosNdx);
if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
{
return de::toString(fetchPos.x());
}
else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
{
std::ostringstream buf;
buf << "ivec2(" << fetchPos.x() << ", " << fetchPos.y() << ")";
return buf.str();
}
else
{
std::ostringstream buf;
buf << "ivec3(" << fetchPos.x() << ", " << fetchPos.y() << ", " << fetchPos.z() << ")";
return buf.str();
}
}
std::string ImageDescriptorCase::genSampleCoordStr (int samplePosNdx) const
{
DE_ASSERT(m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER || m_descriptorType == vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
const tcu::Vec4 fetchPos = ImageSampleInstanceImages::getSamplePos(m_viewType, m_baseMipLevel, m_baseArraySlice, samplePosNdx);
if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D)
{
std::ostringstream buf;
buf << "float(" << fetchPos.x() << ")";
return buf.str();
}
else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY || m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D)
{
std::ostringstream buf;
buf << "vec2(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "))";
return buf.str();
}
else if (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY)
{
std::ostringstream buf;
buf << "vec4(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "), float(" << fetchPos.w() << "))";
return buf.str();
}
else
{
std::ostringstream buf;
buf << "vec3(float(" << fetchPos.x() << "), float(" << fetchPos.y() << "), float(" << fetchPos.z() << "))";
return buf.str();
}
}
std::string ImageDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
const char* const dimension = (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D) ? ("1D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY) ? ("1DArray")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D) ? ("2D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY) ? ("2DArray")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_3D) ? ("3D")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE) ? ("Cube")
: (m_viewType == vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) ? ("CubeArray")
: (DE_NULL);
const char* const accessPostfixA = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? ("")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? ("[0]")
: (DE_NULL);
const char* const accessPostfixB = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? ("")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? ("[1]")
: (DE_NULL);
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::ostringstream buf;
buf << " result_color = vec4(0.0);\n";
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
{
const std::string coodStr[4] =
{
genSampleCoordStr(0),
genSampleCoordStr(1),
genSampleCoordStr(2),
genSampleCoordStr(3),
};
if (m_descriptorType == vk::VK_DESCRIPTOR_TYPE_SAMPLER)
{
buf << " if (quadrant_id == 0)\n"
<< " result_color += textureLod(sampler" << dimension << "(u_separateTexture" << setNdxPostfix << ", u_separateSampler" << setNdxPostfix << accessPostfixA << "), " << coodStr[0] << ", 0.0);\n"
<< " else if (quadrant_id == 1)\n"
<< " result_color += textureLod(sampler" << dimension << "(u_separateTexture" << setNdxPostfix << ", u_separateSampler" << setNdxPostfix << accessPostfixB << "), " << coodStr[1] << ", 0.0);\n"
<< " else if (quadrant_id == 2)\n"
<< " result_color += textureLod(sampler" << dimension << "(u_separateTexture" << setNdxPostfix << ", u_separateSampler" << setNdxPostfix << accessPostfixA << "), " << coodStr[2] << ", 0.0);\n"
<< " else\n"
<< " result_color += textureLod(sampler" << dimension << "(u_separateTexture" << setNdxPostfix << ", u_separateSampler" << setNdxPostfix << accessPostfixB << "), " << coodStr[3] << ", 0.0);\n";
}
else
{
buf << " if (quadrant_id == 0)\n"
<< " result_color += textureLod(u_combinedTextureSampler" << setNdxPostfix << accessPostfixA << ", " << coodStr[0] << ", 0.0);\n"
<< " else if (quadrant_id == 1)\n"
<< " result_color += textureLod(u_combinedTextureSampler" << setNdxPostfix << accessPostfixB << ", " << coodStr[1] << ", 0.0);\n"
<< " else if (quadrant_id == 2)\n"
<< " result_color += textureLod(u_combinedTextureSampler" << setNdxPostfix << accessPostfixA << ", " << coodStr[2] << ", 0.0);\n"
<< " else\n"
<< " result_color += textureLod(u_combinedTextureSampler" << setNdxPostfix << accessPostfixB << ", " << coodStr[3] << ", 0.0);\n";
}
break;
}
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
{
const std::string coodStr[4] =
{
genFetchCoordStr(0),
genFetchCoordStr(1),
genFetchCoordStr(2),
genFetchCoordStr(3),
};
buf << " if (quadrant_id == 0)\n"
<< " result_color += imageLoad(u_image" << setNdxPostfix << accessPostfixA << ", " << coodStr[0] << ");\n"
<< " else if (quadrant_id == 1)\n"
<< " result_color += imageLoad(u_image" << setNdxPostfix << accessPostfixB << ", " << coodStr[1] << ");\n"
<< " else if (quadrant_id == 2)\n"
<< " result_color += imageLoad(u_image" << setNdxPostfix << accessPostfixA << ", " << coodStr[2] << ");\n"
<< " else\n"
<< " result_color += imageLoad(u_image" << setNdxPostfix << accessPostfixB << ", " << coodStr[3] << ");\n";
break;
}
default:
DE_FATAL("invalid descriptor");
}
}
if (getDescriptorSetCount(m_descriptorSetCount) > 1)
buf << " result_color /= vec4(" << getDescriptorSetCount(m_descriptorSetCount) << ".0);\n";
return buf.str();
}
std::string ImageDescriptorCase::genNoAccessSource (void) const
{
return " if (quadrant_id == 1 || quadrant_id == 2)\n"
" result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
" else\n"
" result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
}
vkt::TestInstance* ImageDescriptorCase::createInstance (vkt::Context& context) const
{
verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages, m_viewType);
switch (m_descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
{
DE_ASSERT(m_isPrimaryCmdBuf);
return new ImageSampleComputeInstance(context, m_updateMethod, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
}
else
return new ImageSampleRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_descriptorSetCount, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice, m_isImmutableSampler);
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
{
DE_ASSERT(m_isPrimaryCmdBuf);
return new ImageFetchComputeInstance(context, m_updateMethod, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
}
else
return new ImageFetchRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_descriptorSetCount, m_activeStages, m_shaderInterface, m_viewType, m_baseMipLevel, m_baseArraySlice);
default:
DE_FATAL("Impossible");
return DE_NULL;
}
}
class TexelBufferInstanceBuffers
{
public:
TexelBufferInstanceBuffers (vkt::Context& context,
const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool hasViewOffset);
private:
static std::vector<de::ArrayBuffer<deUint8> > createSourceBuffers (tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers);
static std::vector<tcu::ConstPixelBufferAccess> createSourceViews (const std::vector<de::ArrayBuffer<deUint8> >& sourceBuffers,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset);
static std::vector<BufferHandleSp> createBuffers (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
const std::vector<de::ArrayBuffer<deUint8> >& sourceBuffers,
std::vector<AllocationSp>& bufferMemory,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset);
static std::vector<BufferViewHandleSp> createBufferViews (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<BufferHandleSp>& buffers,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset);
static std::vector<vk::VkBufferMemoryBarrier> createBufferBarriers (vk::VkDescriptorType descriptorType,
const std::vector<BufferHandleSp>& buffers,
deUint32 numTexelBuffers);
static vk::Move<vk::VkBuffer> createBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
de::MovePtr<vk::Allocation> *outAllocation);
static vk::Move<vk::VkBufferView> createBufferView (const vk::DeviceInterface& vki,
vk::VkDevice device,
const tcu::TextureFormat& textureFormat,
deUint32 offset,
vk::VkBuffer buffer);
static vk::VkBufferMemoryBarrier createBarrier (vk::VkDescriptorType descriptorType,
vk::VkBuffer buffer);
static void populateSourceBuffer (const tcu::PixelBufferAccess& access,
deUint32 bufferNdx);
static void uploadData (const vk::DeviceInterface& vki,
vk::VkDevice device,
const vk::Allocation& memory,
const de::ArrayBuffer<deUint8>& data);
deUint32 getViewOffset (vkt::Context& context,
bool hasViewOffset,
vk::VkDescriptorType descriptorType);
public:
static int getFetchPos (int fetchPosNdx);
tcu::Vec4 fetchTexelValue (int fetchPosNdx, int setNdx) const;
inline int getNumTexelBuffers (void) const { return m_numTexelBuffers; }
const tcu::TextureFormat& getTextureFormat (void) const { return m_imageFormat; }
inline vk::VkBufferView getBufferView (int ndx) const { return **m_bufferView[ndx % m_bufferView.size()]; }
inline tcu::ConstPixelBufferAccess getSourceView (int ndx) const { return m_sourceView[ndx % m_sourceView.size()]; }
inline const vk::VkBufferMemoryBarrier* getBufferInitBarriers (void) const { return &m_bufferBarrier.front(); }
private:
enum
{
BUFFER_SIZE = 512,
VIEW_DATA_SIZE = 256, //!< size in bytes
VIEW_WIDTH = 64, //!< size in pixels
};
enum
{
// some arbitrary points
SAMPLE_POINT_0 = 6,
SAMPLE_POINT_1 = 51,
SAMPLE_POINT_2 = 42,
SAMPLE_POINT_3 = 25,
};
const deUint32 m_numTexelBuffers;
const tcu::TextureFormat m_imageFormat;
const ShaderInputInterface m_shaderInterface;
const deUint32 m_viewOffset;
const std::vector<de::ArrayBuffer<deUint8> > m_sourceBuffer;
const std::vector<tcu::ConstPixelBufferAccess> m_sourceView;
std::vector<AllocationSp> m_bufferMemory;
const std::vector<BufferHandleSp> m_buffer;
const std::vector<BufferViewHandleSp> m_bufferView;
const std::vector<vk::VkBufferMemoryBarrier> m_bufferBarrier;
};
deUint32 TexelBufferInstanceBuffers::getViewOffset(vkt::Context& context,
bool hasViewOffset,
vk::VkDescriptorType descriptorType)
{
if (!hasViewOffset)
return 0u;
if (!context.getTexelBufferAlignmentFeaturesEXT().texelBufferAlignment)
return (deUint32)context.getDeviceProperties().limits.minTexelBufferOffsetAlignment;
vk::VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT alignmentProperties;
deMemset(&alignmentProperties, 0, sizeof(alignmentProperties));
alignmentProperties.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES_EXT;
vk::VkPhysicalDeviceProperties2 properties2;
deMemset(&properties2, 0, sizeof(properties2));
properties2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
properties2.pNext = &alignmentProperties;
context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &properties2);
vk::VkBool32 singleTexelAlignment = isUniformDescriptorType(descriptorType) ? alignmentProperties.uniformTexelBufferOffsetSingleTexelAlignment :
alignmentProperties.storageTexelBufferOffsetSingleTexelAlignment;
vk::VkDeviceSize align = isUniformDescriptorType(descriptorType) ? alignmentProperties.uniformTexelBufferOffsetAlignmentBytes :
alignmentProperties.storageTexelBufferOffsetAlignmentBytes;
// format is rgba8
if (singleTexelAlignment)
return de::min(4u, (deUint32)align);
else
return (deUint32)align;
}
TexelBufferInstanceBuffers::TexelBufferInstanceBuffers (vkt::Context& context,
const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool hasViewOffset)
: m_numTexelBuffers (getInterfaceNumResources(shaderInterface) * getDescriptorSetCount(descriptorSetCount))
, m_imageFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8)
, m_shaderInterface (shaderInterface)
, m_viewOffset (getViewOffset(context, hasViewOffset, descriptorType))
, m_sourceBuffer (createSourceBuffers(m_imageFormat, m_numTexelBuffers))
, m_sourceView (createSourceViews(m_sourceBuffer, m_imageFormat, m_numTexelBuffers, m_viewOffset))
, m_bufferMemory ()
, m_buffer (createBuffers(vki, device, allocator, descriptorType, m_sourceBuffer, m_bufferMemory, m_imageFormat, m_numTexelBuffers, m_viewOffset))
, m_bufferView (createBufferViews(vki, device, m_buffer, m_imageFormat, m_numTexelBuffers, m_viewOffset))
, m_bufferBarrier (createBufferBarriers(descriptorType, m_buffer, m_numTexelBuffers))
{
}
std::vector<de::ArrayBuffer<deUint8> > TexelBufferInstanceBuffers::createSourceBuffers (tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers)
{
DE_ASSERT(BUFFER_SIZE % imageFormat.getPixelSize() == 0);
std::vector<de::ArrayBuffer<deUint8> > sourceBuffers(numTexelBuffers, BUFFER_SIZE);
for (deUint32 bufferNdx = 0; bufferNdx < numTexelBuffers; bufferNdx++)
populateSourceBuffer(tcu::PixelBufferAccess(imageFormat, tcu::IVec3(BUFFER_SIZE / imageFormat.getPixelSize(), 1, 1), sourceBuffers[bufferNdx].getPtr()), bufferNdx);
return sourceBuffers;
}
std::vector<tcu::ConstPixelBufferAccess> TexelBufferInstanceBuffers::createSourceViews (const std::vector<de::ArrayBuffer<deUint8> >& sourceBuffers,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset)
{
std::vector<tcu::ConstPixelBufferAccess> sourceViews;
for (deUint32 bufferNdx = 0; bufferNdx < numTexelBuffers; bufferNdx++)
sourceViews.push_back(tcu::ConstPixelBufferAccess(imageFormat, tcu::IVec3(VIEW_WIDTH, 1, 1), sourceBuffers[bufferNdx].getElementPtr(viewOffset)));
return sourceViews;
}
std::vector<BufferHandleSp> TexelBufferInstanceBuffers::createBuffers (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
const std::vector<de::ArrayBuffer<deUint8> >& sourceBuffers,
std::vector<AllocationSp>& bufferMemory,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset)
{
std::vector<BufferHandleSp> buffers;
for (deUint32 bufferNdx = 0; bufferNdx < numTexelBuffers; bufferNdx++)
{
de::MovePtr<vk::Allocation> memory;
vk::Move<vk::VkBuffer> buffer = createBuffer(vki, device, allocator, descriptorType, &memory);
vk::Move<vk::VkBufferView> bufferView = createBufferView(vki, device, imageFormat, viewOffset, *buffer);
uploadData(vki, device, *memory, sourceBuffers[bufferNdx]);
bufferMemory.push_back(AllocationSp(memory.release()));
buffers.push_back(BufferHandleSp(new BufferHandleUp(buffer)));
}
return buffers;
}
std::vector<BufferViewHandleSp> TexelBufferInstanceBuffers::createBufferViews (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<BufferHandleSp>& buffers,
tcu::TextureFormat imageFormat,
deUint32 numTexelBuffers,
deUint32 viewOffset)
{
std::vector<BufferViewHandleSp> bufferViews;
for (deUint32 bufferNdx = 0; bufferNdx < numTexelBuffers; bufferNdx++)
{
vk::Move<vk::VkBufferView> bufferView = createBufferView(vki, device, imageFormat, viewOffset, **buffers[bufferNdx]);
bufferViews.push_back(BufferViewHandleSp(new BufferViewHandleUp(bufferView)));
}
return bufferViews;
}
std::vector<vk::VkBufferMemoryBarrier> TexelBufferInstanceBuffers::createBufferBarriers (vk::VkDescriptorType descriptorType,
const std::vector<BufferHandleSp>& buffers,
deUint32 numTexelBuffers)
{
std::vector<vk::VkBufferMemoryBarrier> bufferBarriers;
for (deUint32 bufferNdx = 0; bufferNdx < numTexelBuffers; bufferNdx++)
bufferBarriers.push_back(createBarrier(descriptorType, **buffers[bufferNdx]));
return bufferBarriers;
}
vk::Move<vk::VkBuffer> TexelBufferInstanceBuffers::createBuffer (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::Allocator& allocator,
vk::VkDescriptorType descriptorType,
de::MovePtr<vk::Allocation> *outAllocation)
{
const vk::VkBufferUsageFlags usage = (isUniformDescriptorType(descriptorType)) ? (vk::VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) : (vk::VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT);
const vk::VkBufferCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
DE_NULL,
0u, // flags
(vk::VkDeviceSize)BUFFER_SIZE, // size
usage, // usage
vk::VK_SHARING_MODE_EXCLUSIVE, // sharingMode
0u, // queueFamilyCount
DE_NULL, // pQueueFamilyIndices
};
vk::Move<vk::VkBuffer> buffer (vk::createBuffer(vki, device, &createInfo));
de::MovePtr<vk::Allocation> allocation (allocateAndBindObjectMemory(vki, device, allocator, *buffer, vk::MemoryRequirement::HostVisible));
*outAllocation = allocation;
return buffer;
}
vk::Move<vk::VkBufferView> TexelBufferInstanceBuffers::createBufferView (const vk::DeviceInterface& vki,
vk::VkDevice device,
const tcu::TextureFormat& textureFormat,
deUint32 offset,
vk::VkBuffer buffer)
{
const vk::VkBufferViewCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
DE_NULL,
(vk::VkBufferViewCreateFlags)0,
buffer, // buffer
vk::mapTextureFormat(textureFormat), // format
(vk::VkDeviceSize)offset, // offset
(vk::VkDeviceSize)VIEW_DATA_SIZE // range
};
return vk::createBufferView(vki, device, &createInfo);
}
vk::VkBufferMemoryBarrier TexelBufferInstanceBuffers::createBarrier (vk::VkDescriptorType descriptorType, vk::VkBuffer buffer)
{
const vk::VkAccessFlags inputBit = (isUniformDescriptorType(descriptorType)) ? (vk::VK_ACCESS_UNIFORM_READ_BIT) : (vk::VK_ACCESS_SHADER_READ_BIT);
const vk::VkBufferMemoryBarrier barrier =
{
vk::VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
DE_NULL,
vk::VK_ACCESS_HOST_WRITE_BIT, // srcAccessMask
inputBit, // dstAccessMask
VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex
VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex
buffer, // buffer
0u, // offset
(vk::VkDeviceSize)BUFFER_SIZE // size
};
return barrier;
}
void TexelBufferInstanceBuffers::populateSourceBuffer (const tcu::PixelBufferAccess& access, deUint32 bufferNdx)
{
DE_ASSERT(access.getHeight() == 1);
DE_ASSERT(access.getDepth() == 1);
const deInt32 width = access.getWidth();
for (int x = 0; x < width; ++x)
{
int red = 255 * x / width; //!< gradient from 0 -> max (detects large offset errors)
int green = ((x % 2 == 0) ? (127) : (0)) + ((x % 4 < 3) ? (128) : (0)); //!< 3-level M pattern (detects small offset errors)
int blue = 16 * (x % 16); //!< 16-long triangle wave
DE_ASSERT(de::inRange(red, 0, 255));
DE_ASSERT(de::inRange(green, 0, 255));
DE_ASSERT(de::inRange(blue, 0, 255));
if (bufferNdx % 2 == 0) red = 255 - red;
if (bufferNdx % 3 == 0) green = 255 - green;
if (bufferNdx % 4 == 0) blue = 255 - blue;
access.setPixel(tcu::IVec4(red, green, blue, 255), x, 0, 0);
}
}
void TexelBufferInstanceBuffers::uploadData (const vk::DeviceInterface& vki, vk::VkDevice device, const vk::Allocation& memory, const de::ArrayBuffer<deUint8>& data)
{
deMemcpy(memory.getHostPtr(), data.getPtr(), data.size());
flushAlloc(vki, device, memory);
}
int TexelBufferInstanceBuffers::getFetchPos (int fetchPosNdx)
{
static const int fetchPositions[4] =
{
SAMPLE_POINT_0,
SAMPLE_POINT_1,
SAMPLE_POINT_2,
SAMPLE_POINT_3,
};
return de::getSizedArrayElement<4>(fetchPositions, fetchPosNdx);
}
tcu::Vec4 TexelBufferInstanceBuffers::fetchTexelValue (int fetchPosNdx, int setNdx) const
{
// source order is ABAB
const tcu::ConstPixelBufferAccess& texelSrcA = getSourceView(setNdx * getInterfaceNumResources(m_shaderInterface));
const tcu::ConstPixelBufferAccess& texelSrcB = getSourceView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1);
const tcu::ConstPixelBufferAccess& texelSrc = ((fetchPosNdx % 2) == 0) ? (texelSrcA) : (texelSrcB);
return texelSrc.getPixel(getFetchPos(fetchPosNdx), 0, 0);
}
class TexelBufferRenderInstance : public SingleCmdRenderInstance
{
public:
TexelBufferRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
bool nonzeroViewOffset);
private:
static std::vector<DescriptorSetLayoutHandleSp> createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod);
static vk::Move<vk::VkPipelineLayout> createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout);
static vk::Move<vk::VkDescriptorPool> createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface);
static std::vector<DescriptorSetHandleSp> createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
const TexelBufferInstanceBuffers& buffers,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout = DE_NULL);
static void writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkBufferView viewA,
vk::VkBufferView viewB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod = DESCRIPTOR_UPDATE_METHOD_NORMAL);
static void writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
deUint32 setNdx,
vk::VkDescriptorPool pool,
vk::VkBufferView viewA,
vk::VkBufferView viewB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush = false,
vk::VkPipelineLayout pipelineLayout = 0);
void logTestPlan (void) const;
vk::VkPipelineLayout getPipelineLayout (void) const;
void writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const;
tcu::TestStatus verifyResultImage (const tcu::ConstPixelBufferAccess& result) const;
enum
{
RENDER_SIZE = 128,
};
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const vk::VkShaderStageFlags m_stageFlags;
const ShaderInputInterface m_shaderInterface;
const bool m_nonzeroViewOffset;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
const std::vector<DescriptorSetLayoutHandleSp> m_descriptorSetLayouts;
const vk::Move<vk::VkPipelineLayout> m_pipelineLayout;
const TexelBufferInstanceBuffers m_texelBuffers;
const vk::Unique<vk::VkDescriptorPool> m_descriptorPool;
std::vector<deUint32> m_descriptorsPerSet;
const std::vector<DescriptorSetHandleSp> m_descriptorSets;
};
TexelBufferRenderInstance::TexelBufferRenderInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
vk::VkShaderStageFlags stageFlags,
ShaderInputInterface shaderInterface,
bool nonzeroViewOffset)
: SingleCmdRenderInstance (context, isPrimaryCmdBuf, tcu::UVec2(RENDER_SIZE, RENDER_SIZE))
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_stageFlags (stageFlags)
, m_shaderInterface (shaderInterface)
, m_nonzeroViewOffset (nonzeroViewOffset)
, m_updateTemplates ()
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorSetLayouts (createDescriptorSetLayouts(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_stageFlags, m_updateMethod))
, m_pipelineLayout (createPipelineLayout(m_vki, m_device, m_descriptorSetLayouts))
, m_texelBuffers (context, m_vki, m_device, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_nonzeroViewOffset)
, m_descriptorPool (createDescriptorPool(m_vki, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface))
, m_descriptorsPerSet ()
, m_descriptorSets (createDescriptorSets(m_vki, m_updateMethod, m_device, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_descriptorSetLayouts, *m_descriptorPool, m_texelBuffers, m_updateBuilder, m_updateTemplates, m_updateRegistry, m_descriptorsPerSet, *m_pipelineLayout))
{
}
std::vector<DescriptorSetLayoutHandleSp> TexelBufferRenderInstance::createDescriptorSetLayouts (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
vk::VkShaderStageFlags stageFlags,
DescriptorUpdateMethod updateMethod)
{
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::DescriptorSetLayoutBuilder builder;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(descriptorType, stageFlags);
builder.addSingleBinding(descriptorType, stageFlags);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, 0);
builder.addSingleIndexedBinding(descriptorType, stageFlags, 2);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(descriptorType, stageFlags, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(descriptorType, 2u, stageFlags);
break;
default:
DE_FATAL("Impossible");
}
vk::Move<vk::VkDescriptorSetLayout> layout = builder.build(vki, device, extraFlags);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
}
}
return descriptorSetLayouts;
}
vk::Move<vk::VkPipelineLayout> TexelBufferRenderInstance::createPipelineLayout (const vk::DeviceInterface& vki,
vk::VkDevice device,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayout)
{
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
for (size_t setNdx = 0; setNdx < descriptorSetLayout.size(); setNdx++)
layoutHandles.push_back(**descriptorSetLayout[setNdx]);
const vk::VkPipelineLayoutCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
DE_NULL,
(vk::VkPipelineLayoutCreateFlags)0,
(deUint32)layoutHandles.size(), // descriptorSetCount
&layoutHandles.front(), // pSetLayouts
0u, // pushConstantRangeCount
DE_NULL, // pPushConstantRanges
};
return vk::createPipelineLayout(vki, device, &createInfo);
}
vk::Move<vk::VkDescriptorPool> TexelBufferRenderInstance::createDescriptorPool (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface)
{
return vk::DescriptorPoolBuilder()
.addType(descriptorType, getDescriptorSetCount(descriptorSetCount) * getInterfaceNumResources(shaderInterface))
.build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(descriptorSetCount));
}
std::vector<DescriptorSetHandleSp> TexelBufferRenderInstance::createDescriptorSets (const vk::DeviceInterface& vki,
DescriptorUpdateMethod updateMethod,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
const std::vector<DescriptorSetLayoutHandleSp>& descriptorSetLayouts,
vk::VkDescriptorPool pool,
const TexelBufferInstanceBuffers& buffers,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& updateRegistry,
std::vector<deUint32>& descriptorsPerSet,
vk::VkPipelineLayout pipelineLayout)
{
std::vector<DescriptorSetHandleSp> descriptorSets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(descriptorSetCount); setNdx++)
{
vk::VkDescriptorSetLayout layout = **descriptorSetLayouts[getDescriptorSetNdx(descriptorSetCount, setNdx)];
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::VkBufferView viewA = buffers.getBufferView(setNdx * getInterfaceNumResources(shaderInterface));
vk::VkBufferView viewB = buffers.getBufferView(setNdx * getInterfaceNumResources(shaderInterface) + 1);
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(vki, device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, setNdx, pool, viewA, viewB, *descriptorSet, updateTemplates, updateRegistry);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
writeDescriptorSetWithTemplate(vki, device, descriptorType, shaderInterface, layout, setNdx, pool, viewA, viewB, *descriptorSet, updateTemplates, updateRegistry, true, pipelineLayout);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, descriptorsPerSet, updateMethod);
}
else if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(vki, device, descriptorType, shaderInterface, layout, pool, viewA, viewB, *descriptorSet, updateBuilder, descriptorsPerSet);
}
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(descriptorSet)));
}
return descriptorSets;
}
void TexelBufferRenderInstance::writeDescriptorSet (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
vk::VkDescriptorPool pool,
vk::VkBufferView viewA,
vk::VkBufferView viewB,
vk::VkDescriptorSet descriptorSet,
vk::DescriptorSetUpdateBuilder& updateBuilder,
std::vector<deUint32>& descriptorsPerSet,
DescriptorUpdateMethod updateMethod)
{
DE_UNREF(layout);
DE_UNREF(pool);
const vk::VkBufferView texelBufferInfos[2] =
{
viewA,
viewB,
};
deUint32 numDescriptors = 0u;
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &texelBufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(2u), descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), descriptorType, &texelBufferInfos[0]);
updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, 2u, texelBufferInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
descriptorsPerSet.push_back(numDescriptors);
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateBuilder.update(vki, device);
updateBuilder.clear();
}
}
void TexelBufferRenderInstance::writeDescriptorSetWithTemplate (const vk::DeviceInterface& vki,
vk::VkDevice device,
vk::VkDescriptorType descriptorType,
ShaderInputInterface shaderInterface,
vk::VkDescriptorSetLayout layout,
deUint32 setNdx,
vk::VkDescriptorPool pool,
vk::VkBufferView viewA,
vk::VkBufferView viewB,
vk::VkDescriptorSet descriptorSet,
std::vector<UpdateTemplateHandleSp>& updateTemplates,
std::vector<RawUpdateRegistry>& registry,
bool withPush,
vk::VkPipelineLayout pipelineLayout)
{
DE_UNREF(pool);
const vk::VkBufferView texelBufferInfos[2] =
{
viewA,
viewB,
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_GRAPHICS,
pipelineLayout,
setNdx
};
RawUpdateRegistry updateRegistry;
updateRegistry.addWriteObject(texelBufferInfos[0]);
updateRegistry.addWriteObject(texelBufferInfos[1]);
switch (shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(1, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(0, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(2, 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(0), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, descriptorType, updateRegistry.getWriteObjectOffset(1), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(0, 0, 2, descriptorType, updateRegistry.getWriteObjectOffset(0), sizeof(texelBufferInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(vki, device, &templateCreateInfo);
updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
registry.push_back(updateRegistry);
if (!withPush)
{
vki.updateDescriptorSetWithTemplate(device, descriptorSet, **updateTemplates.back(), registry.back().getRawPointer());
}
}
void TexelBufferRenderInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Rendering 2x2 grid.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
<< "Buffer format is " << vk::getFormatName(vk::mapTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
if (m_stageFlags == 0u)
{
msg << "Descriptors are not accessed in any shader stage.\n";
}
else
{
msg << "Color in each cell is fetched using the descriptor(s):\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
msg << " from texelBuffer " << srcResourceNdx;
}
msg << "\n";
}
msg << "Descriptors are accessed in {"
<< (((m_stageFlags & vk::VK_SHADER_STAGE_VERTEX_BIT) != 0) ? (" vertex") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) != 0) ? (" tess_control") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) != 0) ? (" tess_evaluation") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_GEOMETRY_BIT) != 0) ? (" geometry") : (""))
<< (((m_stageFlags & vk::VK_SHADER_STAGE_FRAGMENT_BIT) != 0) ? (" fragment") : (""))
<< " } stages.";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
vk::VkPipelineLayout TexelBufferRenderInstance::getPipelineLayout (void) const
{
return *m_pipelineLayout;
}
void TexelBufferRenderInstance::writeDrawCmdBuffer (vk::VkCommandBuffer cmd) const
{
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
std::vector<vk::VkDescriptorSet> sets;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
sets.push_back(**m_descriptorSets[setNdx]);
switch (m_descriptorSetCount)
{
case DESCRIPTOR_SET_COUNT_SINGLE:
case DESCRIPTOR_SET_COUNT_MULTIPLE:
{
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), 0, (deUint32)sets.size(), &sets.front(), 0, DE_NULL);
break;
}
case DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS:
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdBindDescriptorSets(cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, getPipelineLayout(), descriptorSetNdx, 1, &sets[setNdx], 0, DE_NULL);
}
break;
}
default:
DE_FATAL("Impossible");
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_vki.cmdPushDescriptorSetWithTemplateKHR(cmd, **m_updateTemplates[setNdx], getPipelineLayout(), descriptorSetNdx, (const void*)m_updateRegistry[setNdx].getRawPointer());
}
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
deUint32 descriptorNdx = 0u;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
const deUint32 numDescriptors = m_descriptorsPerSet[setNdx];
const deUint32 descriptorSetNdx = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
m_updateBuilder.updateWithPush(m_vki, cmd, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, descriptorSetNdx, descriptorNdx, numDescriptors);
descriptorNdx += numDescriptors;
}
}
m_vki.cmdDraw(cmd, 6 * 4, 1, 0, 0); // render four quads (two separate triangles)
}
tcu::TestStatus TexelBufferRenderInstance::verifyResultImage (const tcu::ConstPixelBufferAccess& result) const
{
const deUint32 numDescriptorSets = getDescriptorSetCount(m_descriptorSetCount);
const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f);
const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f);
const bool doFetch = (m_stageFlags != 0u); // no active stages? Then don't fetch
tcu::Surface reference (m_targetSize.x(), m_targetSize.y());
tcu::Vec4 sample0 = tcu::Vec4(0.0f);
tcu::Vec4 sample1 = tcu::Vec4(0.0f);
tcu::Vec4 sample2 = tcu::Vec4(0.0f);
tcu::Vec4 sample3 = tcu::Vec4(0.0f);
if (doFetch)
{
for (deUint32 setNdx = 0u; setNdx < numDescriptorSets; setNdx++)
{
sample0 += m_texelBuffers.fetchTexelValue(0, setNdx);
sample1 += m_texelBuffers.fetchTexelValue(1, setNdx);
sample2 += m_texelBuffers.fetchTexelValue(2, setNdx);
sample3 += m_texelBuffers.fetchTexelValue(3, setNdx);
}
if (numDescriptorSets > 1)
{
sample0 = sample0 / tcu::Vec4(float(numDescriptorSets));
sample1 = sample1 / tcu::Vec4(float(numDescriptorSets));
sample2 = sample2 / tcu::Vec4(float(numDescriptorSets));
sample3 = sample3 / tcu::Vec4(float(numDescriptorSets));
}
}
else
{
sample0 = yellow;
sample1 = green;
sample2 = green;
sample3 = yellow;
}
drawQuadrantReferenceResult(reference.getAccess(), sample0, sample1, sample2, sample3);
if (!bilinearCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", reference.getAccess(), result, tcu::RGBA(1, 1, 1, 1), tcu::COMPARE_LOG_RESULT))
return tcu::TestStatus::fail("Image verification failed");
else
return tcu::TestStatus::pass("Pass");
}
class TexelBufferComputeInstance : public vkt::TestInstance
{
public:
TexelBufferComputeInstance (vkt::Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool nonzeroViewOffset);
private:
vk::Move<vk::VkDescriptorSetLayout> createDescriptorSetLayout (deUint32 setNdx) const;
vk::Move<vk::VkDescriptorPool> createDescriptorPool (void) const;
vk::Move<vk::VkDescriptorSet> createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx);
void writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx);
void writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush = false, vk::VkPipelineLayout pipelineLayout = DE_NULL);
tcu::TestStatus iterate (void);
void logTestPlan (void) const;
tcu::TestStatus testResourceAccess (void);
const DescriptorUpdateMethod m_updateMethod;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const bool m_nonzeroViewOffset;
const vk::DeviceInterface& m_vki;
const vk::VkDevice m_device;
const vk::VkQueue m_queue;
const deUint32 m_queueFamilyIndex;
vk::Allocator& m_allocator;
std::vector<UpdateTemplateHandleSp> m_updateTemplates;
const ComputeInstanceResultBuffer m_result;
const TexelBufferInstanceBuffers m_texelBuffers;
std::vector<RawUpdateRegistry> m_updateRegistry;
vk::DescriptorSetUpdateBuilder m_updateBuilder;
std::vector<deUint32> m_descriptorsPerSet;
};
TexelBufferComputeInstance::TexelBufferComputeInstance (Context& context,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
bool nonzeroViewOffset)
: vkt::TestInstance (context)
, m_updateMethod (updateMethod)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_nonzeroViewOffset (nonzeroViewOffset)
, m_vki (context.getDeviceInterface())
, m_device (context.getDevice())
, m_queue (context.getUniversalQueue())
, m_queueFamilyIndex (context.getUniversalQueueFamilyIndex())
, m_allocator (context.getDefaultAllocator())
, m_updateTemplates ()
, m_result (m_vki, m_device, m_allocator)
, m_texelBuffers (context, m_vki, m_device, m_allocator, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_nonzeroViewOffset)
, m_updateRegistry ()
, m_updateBuilder ()
, m_descriptorsPerSet ()
{
}
vk::Move<vk::VkDescriptorSetLayout> TexelBufferComputeInstance::createDescriptorSetLayout (deUint32 setNdx) const
{
vk::DescriptorSetLayoutBuilder builder;
vk::VkDescriptorSetLayoutCreateFlags extraFlags = 0;
deUint32 binding = 0;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE ||
m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
extraFlags |= vk::VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR;
}
if (setNdx == 0)
builder.addSingleIndexedBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding++);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
builder.addSingleBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding);
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, binding + 2);
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(0));
builder.addSingleIndexedBinding(m_descriptorType, vk::VK_SHADER_STAGE_COMPUTE_BIT, getArbitraryBindingIndex(1));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
builder.addArrayBinding(m_descriptorType, 2u, vk::VK_SHADER_STAGE_COMPUTE_BIT);
break;
default:
DE_FATAL("Impossible");
};
return builder.build(m_vki, m_device, extraFlags);
}
vk::Move<vk::VkDescriptorPool> TexelBufferComputeInstance::createDescriptorPool (void) const
{
return vk::DescriptorPoolBuilder()
.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
.addType(m_descriptorType, getDescriptorSetCount(m_descriptorSetCount) * getInterfaceNumResources(m_shaderInterface))
.build(m_vki, m_device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, getDescriptorSetCount(m_descriptorSetCount));
}
vk::Move<vk::VkDescriptorSet> TexelBufferComputeInstance::createDescriptorSet (vk::VkDescriptorPool pool, vk::VkDescriptorSetLayout layout, deUint32 setNdx)
{
const vk::VkDescriptorSetAllocateInfo allocInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
DE_NULL,
pool,
1u,
&layout
};
vk::Move<vk::VkDescriptorSet> descriptorSet;
if (m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH && m_updateMethod != DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
descriptorSet = allocateDescriptorSet(m_vki, m_device, &allocInfo);
}
else
{
descriptorSet = vk::Move<vk::VkDescriptorSet>();
}
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE)
{
writeDescriptorSetWithTemplate(*descriptorSet, layout, setNdx);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
writeDescriptorSet(*descriptorSet, setNdx);
}
return descriptorSet;
}
void TexelBufferComputeInstance::writeDescriptorSet (vk::VkDescriptorSet descriptorSet, deUint32 setNdx)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkBufferView texelBufferInfos[2] =
{
m_texelBuffers.getBufferView(setNdx * getInterfaceNumResources(m_shaderInterface)),
m_texelBuffers.getBufferView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)
};
deUint32 binding = 0u;
deUint32 numDescriptors = 0u;
// result
if (setNdx == 0)
{
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultInfo);
numDescriptors++;
}
// texel buffers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &texelBufferInfos[0]);
numDescriptors++;
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &texelBufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding), m_descriptorType, &texelBufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding + 2), m_descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(0)), m_descriptorType, &texelBufferInfos[0]);
m_updateBuilder.writeSingle(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(getArbitraryBindingIndex(1)), m_descriptorType, &texelBufferInfos[1]);
numDescriptors += 2;
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
m_updateBuilder.writeArray(descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(binding++), m_descriptorType, 2u, texelBufferInfos);
numDescriptors++;
break;
default:
DE_FATAL("Impossible");
}
m_descriptorsPerSet.push_back(numDescriptors);
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
m_updateBuilder.update(m_vki, m_device);
m_updateBuilder.clear();
}
}
void TexelBufferComputeInstance::writeDescriptorSetWithTemplate (vk::VkDescriptorSet descriptorSet, vk::VkDescriptorSetLayout layout, deUint32 setNdx, bool withPush, vk::VkPipelineLayout pipelineLayout)
{
const vk::VkDescriptorBufferInfo resultInfo = vk::makeDescriptorBufferInfo(m_result.getBuffer(), 0u, (vk::VkDeviceSize)ComputeInstanceResultBuffer::DATA_SIZE);
const vk::VkBufferView texelBufferInfos[2] =
{
m_texelBuffers.getBufferView(setNdx * getInterfaceNumResources(m_shaderInterface)),
m_texelBuffers.getBufferView(setNdx * getInterfaceNumResources(m_shaderInterface) + 1)
};
std::vector<vk::VkDescriptorUpdateTemplateEntry> updateEntries;
vk::VkDescriptorUpdateTemplateCreateInfo templateCreateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR,
DE_NULL,
0,
0, // updateCount
DE_NULL, // pUpdates
withPush ? vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR : vk::VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
layout,
vk::VK_PIPELINE_BIND_POINT_COMPUTE,
pipelineLayout,
setNdx
};
deUint32 binding = 0u;
deUint32 offset = 0u;
RawUpdateRegistry updateRegistry;
if (setNdx == 0)
updateRegistry.addWriteObject(resultInfo);
updateRegistry.addWriteObject(texelBufferInfos[0]);
updateRegistry.addWriteObject(texelBufferInfos[1]);
// result
if (setNdx == 0)
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, updateRegistry.getWriteObjectOffset(offset++), 0));
// texel buffers
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding++, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(binding, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(binding + 2, 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(0), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
updateEntries.push_back(createTemplateBinding(getArbitraryBindingIndex(1), 0, 1, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), 0));
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
updateEntries.push_back(createTemplateBinding(binding++, 0, 2, m_descriptorType, updateRegistry.getWriteObjectOffset(offset++), sizeof(texelBufferInfos[0])));
break;
default:
DE_FATAL("Impossible");
}
templateCreateInfo.pDescriptorUpdateEntries = &updateEntries[0];
templateCreateInfo.descriptorUpdateEntryCount = (deUint32)updateEntries.size();
vk::Move<vk::VkDescriptorUpdateTemplate> updateTemplate = vk::createDescriptorUpdateTemplate(m_vki, m_device, &templateCreateInfo);
m_updateTemplates.push_back(UpdateTemplateHandleSp(new UpdateTemplateHandleUp(updateTemplate)));
m_updateRegistry.push_back(updateRegistry);
if (!withPush)
{
m_vki.updateDescriptorSetWithTemplate(m_device, descriptorSet, **m_updateTemplates[setNdx], m_updateRegistry.back().getRawPointer());
}
}
tcu::TestStatus TexelBufferComputeInstance::iterate (void)
{
logTestPlan();
return testResourceAccess();
}
void TexelBufferComputeInstance::logTestPlan (void) const
{
std::ostringstream msg;
msg << "Fetching 4 values from image in compute shader.\n"
<< ((m_descriptorSetCount == DESCRIPTOR_SET_COUNT_SINGLE) ? "Single descriptor set. " : "Multiple descriptor sets. ")
<< "Each descriptor set contains "
<< ((m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? "single" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? "two" :
(m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? "an array (size 2) of" :
(const char*)DE_NULL)
<< " descriptor(s) of type " << vk::getDescriptorTypeName(m_descriptorType) << "\n"
<< "Buffer view is created with a " << ((m_nonzeroViewOffset) ? ("non-zero") : ("zero")) << " offset.\n"
<< "Buffer format is " << vk::getFormatName(vk::mapTextureFormat(m_texelBuffers.getTextureFormat())) << ".\n";
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
msg << "Test sample " << resultNdx << ": fetch at position " << m_texelBuffers.getFetchPos(resultNdx);
if (m_shaderInterface != SHADER_INPUT_SINGLE_DESCRIPTOR)
{
const int srcResourceNdx = (resultNdx % 2); // ABAB source
msg << " from texelBuffer " << srcResourceNdx;
}
msg << "\n";
}
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< msg.str()
<< tcu::TestLog::EndMessage;
}
tcu::TestStatus TexelBufferComputeInstance::testResourceAccess (void)
{
const vk::Unique<vk::VkDescriptorPool> descriptorPool(createDescriptorPool());
std::vector<DescriptorSetLayoutHandleSp> descriptorSetLayouts;
std::vector<DescriptorSetHandleSp> descriptorSets;
std::vector<vk::VkDescriptorSetLayout> layoutHandles;
std::vector<vk::VkDescriptorSet> setHandles;
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
{
vk::Move<vk::VkDescriptorSetLayout> layout = createDescriptorSetLayout(setNdx);
vk::Move<vk::VkDescriptorSet> set = createDescriptorSet(*descriptorPool, *layout, setNdx);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(layout)));
descriptorSets.push_back(DescriptorSetHandleSp(new DescriptorSetHandleUp(set)));
layoutHandles.push_back(**descriptorSetLayouts.back());
setHandles.push_back(**descriptorSets.back());
// Add an empty descriptor set layout between sets 0 and 2
if (setNdx == 0 && m_descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS)
{
vk::DescriptorSetLayoutBuilder emptyBuilder;
vk::Move<vk::VkDescriptorSetLayout> emptyLayout = emptyBuilder.build(m_vki, m_device, (vk::VkDescriptorSetLayoutCreateFlags)0);
descriptorSetLayouts.push_back(DescriptorSetLayoutHandleSp(new DescriptorSetLayoutHandleUp(emptyLayout)));
layoutHandles.push_back(**descriptorSetLayouts.back());
}
}
const ComputePipeline pipeline (m_vki, m_device, m_context.getBinaryCollection(), (int)layoutHandles.size(), &layoutHandles.front());
const deUint32* const dynamicOffsets = DE_NULL;
const int numDynamicOffsets = 0;
const vk::VkBufferMemoryBarrier* const preBarriers = m_texelBuffers.getBufferInitBarriers();
const int numPreBarriers = m_texelBuffers.getNumTexelBuffers();
const vk::VkBufferMemoryBarrier* const postBarriers = m_result.getResultReadBarrier();
const int numPostBarriers = 1;
const ComputeCommand compute (m_vki,
m_device,
pipeline.getPipeline(),
pipeline.getPipelineLayout(),
tcu::UVec3(4, 1, 1),
m_shaderInterface,
m_descriptorSetCount, &setHandles.front(),
numDynamicOffsets, dynamicOffsets,
numPreBarriers, preBarriers,
numPostBarriers, postBarriers);
tcu::Vec4 results[4];
bool anyResultSet = false;
bool allResultsOk = true;
if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSetWithTemplate(DE_NULL, layoutHandles[setNdx], setNdx, true, pipeline.getPipelineLayout());
compute.submitAndWait(m_queueFamilyIndex, m_queue, &m_updateTemplates, &m_updateRegistry);
}
else if (m_updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH)
{
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
writeDescriptorSet(DE_NULL, setNdx);
compute.submitAndWait(m_queueFamilyIndex, m_queue, m_updateBuilder, m_descriptorsPerSet);
}
else
{
compute.submitAndWait(m_queueFamilyIndex, m_queue);
}
m_result.readResultContentsTo(&results);
// verify
for (int resultNdx = 0; resultNdx < 4; ++resultNdx)
{
const tcu::Vec4 result = results[resultNdx];
const tcu::Vec4 conversionThreshold = tcu::Vec4(1.0f / 255.0f);
tcu::Vec4 reference = tcu::Vec4(0.0f);
for (deUint32 setNdx = 0; setNdx < getDescriptorSetCount(m_descriptorSetCount); setNdx++)
reference += m_texelBuffers.fetchTexelValue(resultNdx, setNdx);
reference = reference / tcu::Vec4((float)getDescriptorSetCount(m_descriptorSetCount));
if (result != tcu::Vec4(-1.0f))
anyResultSet = true;
if (tcu::boolAny(tcu::greaterThan(tcu::abs(result - reference), conversionThreshold)))
{
allResultsOk = false;
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Test sample " << resultNdx << ": Expected " << reference << ", got " << result
<< tcu::TestLog::EndMessage;
}
}
// read back and verify
if (allResultsOk)
return tcu::TestStatus::pass("Pass");
else if (anyResultSet)
return tcu::TestStatus::fail("Invalid result values");
else
{
m_context.getTestContext().getLog()
<< tcu::TestLog::Message
<< "Result buffer was not written to."
<< tcu::TestLog::EndMessage;
return tcu::TestStatus::fail("Result buffer was not written to");
}
}
class TexelBufferDescriptorCase : public QuadrantRendederCase
{
public:
enum
{
FLAG_VIEW_OFFSET = (1u << 1u),
};
// enum continues where resource flags ends
DE_STATIC_ASSERT((deUint32)FLAG_VIEW_OFFSET == (deUint32)RESOURCE_FLAG_LAST);
TexelBufferDescriptorCase (tcu::TestContext& testCtx,
DescriptorUpdateMethod updateMethod,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
deUint32 flags);
private:
std::string genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const;
std::string genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const;
std::string genResourceAccessSource (vk::VkShaderStageFlagBits stage) const;
std::string genNoAccessSource (void) const;
vkt::TestInstance* createInstance (vkt::Context& context) const;
const DescriptorUpdateMethod m_updateMethod;
const bool m_isPrimaryCmdBuf;
const vk::VkDescriptorType m_descriptorType;
const DescriptorSetCount m_descriptorSetCount;
const ShaderInputInterface m_shaderInterface;
const bool m_nonzeroViewOffset;
};
TexelBufferDescriptorCase::TexelBufferDescriptorCase (tcu::TestContext& testCtx,
DescriptorUpdateMethod updateMethod,
const char* name,
const char* description,
bool isPrimaryCmdBuf,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface shaderInterface,
deUint32 flags)
: QuadrantRendederCase (testCtx, name, description, glu::GLSL_VERSION_310_ES, exitingStages, activeStages, descriptorSetCount)
, m_updateMethod (updateMethod)
, m_isPrimaryCmdBuf (isPrimaryCmdBuf)
, m_descriptorType (descriptorType)
, m_descriptorSetCount (descriptorSetCount)
, m_shaderInterface (shaderInterface)
, m_nonzeroViewOffset (((flags & FLAG_VIEW_OFFSET) != 0) ? (1u) : (0u))
{
}
std::string TexelBufferDescriptorCase::genExtensionDeclarations (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
return "#extension GL_EXT_texture_buffer : require\n";
}
std::string TexelBufferDescriptorCase::genResourceDeclarations (vk::VkShaderStageFlagBits stage, int numUsedBindings) const
{
DE_UNREF(stage);
const bool isUniform = isUniformDescriptorType(m_descriptorType);
const char* const storageType = (isUniform) ? ("textureBuffer ") : ("readonly imageBuffer ");
const char* const formatQualifier = (isUniform) ? ("") : (", rgba8");
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::ostringstream buf;
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
// Result buffer is bound only to the first descriptor set in compute shader cases
const int descBinding = numUsedBindings - ((m_activeStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) ? (setNdx == 0 ? 0 : 1) : 0);
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
const deUint32 descriptorSet = getDescriptorSetNdx(m_descriptorSetCount, setNdx);
switch (m_shaderInterface)
{
case SHADER_INPUT_SINGLE_DESCRIPTOR:
buf << "layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << ";\n";
break;
case SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "A;\n"
"layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding + 1) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "A;\n"
"layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding + 2) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS:
buf << "layout(set = " << descriptorSet << ", binding = " + de::toString(getArbitraryBindingIndex(0)) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "A;\n"
"layout(set = " << descriptorSet << ", binding = " + de::toString(getArbitraryBindingIndex(1)) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "B;\n";
break;
case SHADER_INPUT_DESCRIPTOR_ARRAY:
buf << "layout(set = " << descriptorSet << ", binding = " + de::toString(descBinding) + formatQualifier + ") uniform highp " + storageType + "u_texelBuffer" << setNdxPostfix << "[2];\n";
break;
default:
DE_FATAL("Impossible");
return "";
}
}
return buf.str();
}
std::string TexelBufferDescriptorCase::genResourceAccessSource (vk::VkShaderStageFlagBits stage) const
{
DE_UNREF(stage);
const char* const accessPostfixA = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? ("")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? ("A")
: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? ("[0]")
: (DE_NULL);
const char* const accessPostfixB = (m_shaderInterface == SHADER_INPUT_SINGLE_DESCRIPTOR) ? ("")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) ? ("B")
: (m_shaderInterface == SHADER_INPUT_DESCRIPTOR_ARRAY) ? ("[1]")
: (DE_NULL);
const char* const fetchFunc = (isUniformDescriptorType(m_descriptorType)) ? ("texelFetch") : ("imageLoad");
const deUint32 numSets = getDescriptorSetCount(m_descriptorSetCount);
std::ostringstream buf;
buf << " result_color = vec4(0.0);\n";
for (deUint32 setNdx = 0; setNdx < numSets; setNdx++)
{
const std::string setNdxPostfix = (numSets == 1) ? "" : de::toString(setNdx);
buf << " if (quadrant_id == 0)\n"
<< " result_color += " << fetchFunc << "(u_texelBuffer" << setNdxPostfix << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(0) << ");\n"
<< " else if (quadrant_id == 1)\n"
<< " result_color += " << fetchFunc << "(u_texelBuffer" << setNdxPostfix << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(1) << ");\n"
<< " else if (quadrant_id == 2)\n"
<< " result_color += " << fetchFunc << "(u_texelBuffer" << setNdxPostfix << accessPostfixA << ", " << TexelBufferInstanceBuffers::getFetchPos(2) << ");\n"
<< " else\n"
<< " result_color += " << fetchFunc << "(u_texelBuffer" << setNdxPostfix << accessPostfixB << ", " << TexelBufferInstanceBuffers::getFetchPos(3) << ");\n";
}
if (getDescriptorSetCount(m_descriptorSetCount) > 1)
buf << " result_color /= vec4(" << getDescriptorSetCount(m_descriptorSetCount) << ".0);\n";
return buf.str();
}
std::string TexelBufferDescriptorCase::genNoAccessSource (void) const
{
return " if (quadrant_id == 1 || quadrant_id == 2)\n"
" result_color = vec4(0.0, 1.0, 0.0, 1.0);\n"
" else\n"
" result_color = vec4(1.0, 1.0, 0.0, 1.0);\n";
}
vkt::TestInstance* TexelBufferDescriptorCase::createInstance (vkt::Context& context) const
{
verifyDriverSupport(context.getUsedApiVersion(), context.getDeviceFeatures(), context.getDeviceExtensions(), m_updateMethod, m_descriptorType, m_activeStages);
if (m_exitingStages == vk::VK_SHADER_STAGE_COMPUTE_BIT)
{
DE_ASSERT(m_isPrimaryCmdBuf); // secondaries are only valid within renderpass
return new TexelBufferComputeInstance(context, m_updateMethod, m_descriptorType, m_descriptorSetCount, m_shaderInterface, m_nonzeroViewOffset);
}
else
return new TexelBufferRenderInstance(context, m_updateMethod, m_isPrimaryCmdBuf, m_descriptorType, m_descriptorSetCount, m_activeStages, m_shaderInterface, m_nonzeroViewOffset);
}
void createShaderAccessImageTests (tcu::TestCaseGroup* group,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface dimension,
deUint32 resourceFlags)
{
static const struct
{
vk::VkImageViewType viewType;
const char* name;
const char* description;
deUint32 flags;
} s_imageTypes[] =
{
{ vk::VK_IMAGE_VIEW_TYPE_1D, "1d", "1D image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_1D, "1d_base_mip", "1D image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_1D, "1d_base_slice", "1D image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE },
{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY, "1d_array", "1D array image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY, "1d_array_base_mip", "1D array image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_1D_ARRAY, "1d_array_base_slice", "1D array image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE },
{ vk::VK_IMAGE_VIEW_TYPE_2D, "2d", "2D image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_2D, "2d_base_mip", "2D image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_2D, "2d_base_slice", "2D image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE },
{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY, "2d_array", "2D array image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY, "2d_array_base_mip", "2D array image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_2D_ARRAY, "2d_array_base_slice", "2D array image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE },
{ vk::VK_IMAGE_VIEW_TYPE_3D, "3d", "3D image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_3D, "3d_base_mip", "3D image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
// no 3d array textures
{ vk::VK_IMAGE_VIEW_TYPE_CUBE, "cube", "Cube image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_CUBE, "cube_base_mip", "Cube image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_CUBE, "cube_base_slice", "Cube image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE },
{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, "cube_array", "Cube image view", 0u },
{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, "cube_array_base_mip", "Cube image subview with base mip level", ImageDescriptorCase::FLAG_BASE_MIP },
{ vk::VK_IMAGE_VIEW_TYPE_CUBE_ARRAY, "cube_array_base_slice", "Cube image subview with base array slice", ImageDescriptorCase::FLAG_BASE_SLICE }
};
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_imageTypes); ++ndx)
{
// never overlap
DE_ASSERT((s_imageTypes[ndx].flags & resourceFlags) == 0u);
// skip some image view variations to avoid unnecessary bloating
if ((descriptorType != vk::VK_DESCRIPTOR_TYPE_SAMPLER) && (dimension == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) && (s_imageTypes[ndx].viewType != vk::VK_IMAGE_VIEW_TYPE_2D))
continue;
if ((dimension == SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS) && (activeStages & vk::VK_SHADER_STAGE_COMPUTE_BIT) && (s_imageTypes[ndx].viewType != vk::VK_IMAGE_VIEW_TYPE_2D))
continue;
if ((dimension == SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS) && (s_imageTypes[ndx].viewType != vk::VK_IMAGE_VIEW_TYPE_2D))
continue;
if ((descriptorSetCount == DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS) && (s_imageTypes[ndx].viewType != vk::VK_IMAGE_VIEW_TYPE_2D))
continue;
group->addChild(new ImageDescriptorCase(group->getTestContext(),
s_imageTypes[ndx].name,
s_imageTypes[ndx].description,
isPrimaryCmdBuf,
updateMethod,
descriptorType,
exitingStages,
activeStages,
descriptorSetCount,
dimension,
s_imageTypes[ndx].viewType,
s_imageTypes[ndx].flags | resourceFlags));
}
}
void createShaderAccessTexelBufferTests (tcu::TestCaseGroup* group,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface dimension,
deUint32 resourceFlags)
{
DE_ASSERT(resourceFlags == 0);
DE_UNREF(resourceFlags);
static const struct
{
const char* name;
const char* description;
deUint32 flags;
} s_texelBufferTypes[] =
{
{ "offset_zero", "View offset is zero", 0u },
{ "offset_nonzero", "View offset is non-zero", TexelBufferDescriptorCase::FLAG_VIEW_OFFSET },
};
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_texelBufferTypes); ++ndx)
{
group->addChild(new TexelBufferDescriptorCase(group->getTestContext(),
updateMethod,
s_texelBufferTypes[ndx].name,
s_texelBufferTypes[ndx].description,
isPrimaryCmdBuf,
descriptorType,
exitingStages,
activeStages,
descriptorSetCount,
dimension,
s_texelBufferTypes[ndx].flags));
}
}
void createShaderAccessBufferTests (tcu::TestCaseGroup* group,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags exitingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface dimension,
deUint32 resourceFlags)
{
DE_ASSERT(resourceFlags == 0u);
DE_UNREF(resourceFlags);
static const struct
{
const char* name;
const char* description;
bool isForDynamicCases;
deUint32 flags;
} s_bufferTypes[] =
{
{ "offset_view_zero", "View offset is zero", false, 0u },
{ "offset_view_nonzero", "View offset is non-zero", false, BufferDescriptorCase::FLAG_VIEW_OFFSET },
{ "offset_view_zero_dynamic_zero", "View offset is zero, dynamic offset is zero", true, BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_ZERO },
{ "offset_view_zero_dynamic_nonzero", "View offset is zero, dynamic offset is non-zero", true, BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO },
{ "offset_view_nonzero_dynamic_zero", "View offset is non-zero, dynamic offset is zero", true, BufferDescriptorCase::FLAG_VIEW_OFFSET | BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_ZERO },
{ "offset_view_nonzero_dynamic_nonzero", "View offset is non-zero, dynamic offset is non-zero", true, BufferDescriptorCase::FLAG_VIEW_OFFSET | BufferDescriptorCase::FLAG_DYNAMIC_OFFSET_NONZERO },
};
const bool isDynamicCase = isDynamicDescriptorType(descriptorType);
if (isDynamicCase)
{
if (updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH || updateMethod == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
{
// Can't support push descriptor sets with dynamic UBOs or SSBOs
return;
}
}
for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_bufferTypes); ++ndx)
{
if (isDynamicCase == s_bufferTypes[ndx].isForDynamicCases)
group->addChild(new BufferDescriptorCase(group->getTestContext(),
updateMethod,
s_bufferTypes[ndx].name,
s_bufferTypes[ndx].description,
isPrimaryCmdBuf,
descriptorType,
exitingStages,
activeStages,
descriptorSetCount,
dimension,
s_bufferTypes[ndx].flags));
}
}
} // anonymous
tcu::TestCaseGroup* createShaderAccessTests (tcu::TestContext& testCtx)
{
static const struct
{
const bool isPrimary;
const char* name;
const char* description;
} s_bindTypes[] =
{
{ true, "primary_cmd_buf", "Bind in primary command buffer" },
{ false, "secondary_cmd_buf", "Bind in secondary command buffer" },
};
static const struct
{
const DescriptorUpdateMethod method;
const char* name;
const char* description;
} s_updateMethods[] =
{
{ DESCRIPTOR_UPDATE_METHOD_NORMAL, "", "Use regular descriptor updates" },
{ DESCRIPTOR_UPDATE_METHOD_WITH_TEMPLATE, "with_template", "Use descriptor update templates" },
{ DESCRIPTOR_UPDATE_METHOD_WITH_PUSH, "with_push", "Use push descriptor updates" },
{ DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE, "with_push_template", "Use push descriptor update templates" },
};
static const struct
{
const vk::VkDescriptorType descriptorType;
const char* name;
const char* description;
deUint32 flags;
} s_descriptorTypes[] =
{
{ vk::VK_DESCRIPTOR_TYPE_SAMPLER, "sampler_mutable", "VK_DESCRIPTOR_TYPE_SAMPLER with mutable sampler", 0u },
{ vk::VK_DESCRIPTOR_TYPE_SAMPLER, "sampler_immutable", "VK_DESCRIPTOR_TYPE_SAMPLER with immutable sampler", RESOURCE_FLAG_IMMUTABLE_SAMPLER },
{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler_mutable", "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with mutable sampler", 0u },
{ vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, "combined_image_sampler_immutable", "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER with immutable sampler", RESOURCE_FLAG_IMMUTABLE_SAMPLER },
// \note No way to access SAMPLED_IMAGE without a sampler
//{ vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_image", "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE", 0u },
{ vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_image", "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE", 0u },
{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, "uniform_texel_buffer", "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER", 0u },
{ vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, "storage_texel_buffer", "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER", 0u },
{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, "uniform_buffer", "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER", 0u },
{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, "storage_buffer", "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER", 0u },
{ vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, "uniform_buffer_dynamic", "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC", 0u },
{ vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, "storage_buffer_dynamic", "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC", 0u },
};
static const struct
{
const char* name;
const char* description;
vk::VkShaderStageFlags existingStages; //!< stages that exists
vk::VkShaderStageFlags activeStages; //!< stages that access resource
bool supportsSecondaryCmdBufs;
} s_shaderStages[] =
{
{
"no_access",
"No accessing stages",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
0u,
true,
},
{
"vertex",
"Vertex stage",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_VERTEX_BIT,
true,
},
{
"tess_ctrl",
"Tessellation control stage",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,
true,
},
{
"tess_eval",
"Tessellation evaluation stage",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,
true,
},
{
"geometry",
"Geometry stage",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_GEOMETRY_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_GEOMETRY_BIT,
true,
},
{
"fragment",
"Fragment stage",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_FRAGMENT_BIT,
true,
},
{
"compute",
"Compute stage",
vk::VK_SHADER_STAGE_COMPUTE_BIT,
vk::VK_SHADER_STAGE_COMPUTE_BIT,
false,
},
{
"vertex_fragment",
"Vertex and fragment stages",
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT,
true,
}
};
static const struct
{
ShaderInputInterface dimension;
const char* name;
const char* description;
} s_variableDimensions[] =
{
{ SHADER_INPUT_SINGLE_DESCRIPTOR, "single_descriptor", "Single descriptor" },
{ SHADER_INPUT_MULTIPLE_CONTIGUOUS_DESCRIPTORS, "multiple_contiguous_descriptors", "Multiple descriptors" },
{ SHADER_INPUT_MULTIPLE_DISCONTIGUOUS_DESCRIPTORS, "multiple_discontiguous_descriptors", "Multiple descriptors" },
{ SHADER_INPUT_MULTIPLE_ARBITRARY_DESCRIPTORS, "multiple_arbitrary_descriptors", "Multiple descriptors" },
{ SHADER_INPUT_DESCRIPTOR_ARRAY, "descriptor_array", "Descriptor array" },
};
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "shader_access", "Access resource via descriptor in a single descriptor set"));
// .primary_cmd_buf...
for (int bindTypeNdx = 0; bindTypeNdx < DE_LENGTH_OF_ARRAY(s_bindTypes); ++bindTypeNdx)
{
de::MovePtr<tcu::TestCaseGroup> bindGroup(new tcu::TestCaseGroup(testCtx, s_bindTypes[bindTypeNdx].name, s_bindTypes[bindTypeNdx].description));
for (int updateMethodNdx = 0; updateMethodNdx < DE_LENGTH_OF_ARRAY(s_updateMethods); ++updateMethodNdx)
{
de::MovePtr<tcu::TestCaseGroup> updateMethodGroup(new tcu::TestCaseGroup(testCtx, s_updateMethods[updateMethodNdx].name, s_updateMethods[updateMethodNdx].description));
// .sampler, .combined_image_sampler, other resource types ...
for (int descriptorNdx = 0; descriptorNdx < DE_LENGTH_OF_ARRAY(s_descriptorTypes); ++descriptorNdx)
{
de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, s_descriptorTypes[descriptorNdx].name, s_descriptorTypes[descriptorNdx].description));
for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(s_shaderStages); ++stageNdx)
{
if (s_bindTypes[bindTypeNdx].isPrimary || s_shaderStages[stageNdx].supportsSecondaryCmdBufs)
{
de::MovePtr<tcu::TestCaseGroup> stageGroup (new tcu::TestCaseGroup(testCtx, s_shaderStages[stageNdx].name, s_shaderStages[stageNdx].description));
de::MovePtr<tcu::TestCaseGroup> multipleGroup (new tcu::TestCaseGroup(testCtx, "multiple_descriptor_sets", "Multiple descriptor sets"));
de::MovePtr<tcu::TestCaseGroup> multipleDiscontiguousGroup (new tcu::TestCaseGroup(testCtx, "multiple_discontiguous_descriptor_sets", "Multiple discontiguous descriptor sets"));
for (int dimensionNdx = 0; dimensionNdx < DE_LENGTH_OF_ARRAY(s_variableDimensions); ++dimensionNdx)
{
de::MovePtr<tcu::TestCaseGroup> dimensionSingleDescriptorSetGroup (new tcu::TestCaseGroup(testCtx, s_variableDimensions[dimensionNdx].name, s_variableDimensions[dimensionNdx].description));
de::MovePtr<tcu::TestCaseGroup> dimensionMultipleDescriptorSetsGroup (new tcu::TestCaseGroup(testCtx, s_variableDimensions[dimensionNdx].name, s_variableDimensions[dimensionNdx].description));
de::MovePtr<tcu::TestCaseGroup> dimensionMultipleDiscontiguousDescriptorSetsGroup (new tcu::TestCaseGroup(testCtx, s_variableDimensions[dimensionNdx].name, s_variableDimensions[dimensionNdx].description));
void (*createTestsFunc)(tcu::TestCaseGroup* group,
bool isPrimaryCmdBuf,
DescriptorUpdateMethod updateMethod,
vk::VkDescriptorType descriptorType,
vk::VkShaderStageFlags existingStages,
vk::VkShaderStageFlags activeStages,
DescriptorSetCount descriptorSetCount,
ShaderInputInterface dimension,
deUint32 resourceFlags);
switch (s_descriptorTypes[descriptorNdx].descriptorType)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
createTestsFunc = createShaderAccessImageTests;
break;
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
createTestsFunc = createShaderAccessTexelBufferTests;
break;
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
createTestsFunc = createShaderAccessBufferTests;
break;
default:
createTestsFunc = DE_NULL;
DE_FATAL("Impossible");
}
if (createTestsFunc)
{
createTestsFunc(dimensionSingleDescriptorSetGroup.get(),
s_bindTypes[bindTypeNdx].isPrimary,
s_updateMethods[updateMethodNdx].method,
s_descriptorTypes[descriptorNdx].descriptorType,
s_shaderStages[stageNdx].existingStages,
s_shaderStages[stageNdx].activeStages,
DESCRIPTOR_SET_COUNT_SINGLE,
s_variableDimensions[dimensionNdx].dimension,
s_descriptorTypes[descriptorNdx].flags);
createTestsFunc(dimensionMultipleDescriptorSetsGroup.get(),
s_bindTypes[bindTypeNdx].isPrimary,
s_updateMethods[updateMethodNdx].method,
s_descriptorTypes[descriptorNdx].descriptorType,
s_shaderStages[stageNdx].existingStages,
s_shaderStages[stageNdx].activeStages,
DESCRIPTOR_SET_COUNT_MULTIPLE,
s_variableDimensions[dimensionNdx].dimension,
s_descriptorTypes[descriptorNdx].flags);
createTestsFunc(dimensionMultipleDiscontiguousDescriptorSetsGroup.get(),
s_bindTypes[bindTypeNdx].isPrimary,
s_updateMethods[updateMethodNdx].method,
s_descriptorTypes[descriptorNdx].descriptorType,
s_shaderStages[stageNdx].existingStages,
s_shaderStages[stageNdx].activeStages,
DESCRIPTOR_SET_COUNT_MULTIPLE_DISCONTIGUOUS,
s_variableDimensions[dimensionNdx].dimension,
s_descriptorTypes[descriptorNdx].flags);
}
else
DE_FATAL("Impossible");
stageGroup->addChild(dimensionSingleDescriptorSetGroup.release());
// Only one descriptor set layout can be created with VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR set
if (s_updateMethods[updateMethodNdx].method == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH || s_updateMethods[updateMethodNdx].method == DESCRIPTOR_UPDATE_METHOD_WITH_PUSH_TEMPLATE)
continue;
multipleGroup->addChild(dimensionMultipleDescriptorSetsGroup.release());
multipleDiscontiguousGroup->addChild(dimensionMultipleDiscontiguousDescriptorSetsGroup.release());
}
stageGroup->addChild(multipleGroup.release());
stageGroup->addChild(multipleDiscontiguousGroup.release());
typeGroup->addChild(stageGroup.release());
}
}
if (s_updateMethods[updateMethodNdx].method != DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
updateMethodGroup->addChild(typeGroup.release());
}
else
{
bindGroup->addChild(typeGroup.release());
}
}
if (s_updateMethods[updateMethodNdx].method != DESCRIPTOR_UPDATE_METHOD_NORMAL)
{
bindGroup->addChild(updateMethodGroup.release());
}
}
group->addChild(bindGroup.release());
}
return group.release();
}
} // BindingModel
} // vkt