blob: e74eda33dae688f56445fb8d56af0a3812779d6e [file] [log] [blame]
/*-------------------------------------------------------------------------
* Vulkan Conformance Tests
* ------------------------
*
* Copyright (c) 2018 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 Tests for descriptor updates.
*//*--------------------------------------------------------------------*/
#include "vktBindingDescriptorUpdateTests.hpp"
#include "vktTestCase.hpp"
#include "vktTestCaseUtil.hpp"
#include "vkRefUtil.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkQueryUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkImageUtil.hpp"
#include "vkBarrierUtil.hpp"
#include "vkImageWithMemory.hpp"
#include "vkBufferWithMemory.hpp"
#include "tcuTexture.hpp"
#include "tcuTestLog.hpp"
#include <string>
#include <vector>
#include <utility>
namespace vkt
{
namespace BindingModel
{
namespace
{
// Test matches VkPositiveLayerTest.EmptyDescriptorUpdateTest
tcu::TestStatus EmptyDescriptorUpdateCase (Context& context)
{
const vk::DeviceInterface& vki = context.getDeviceInterface();
const vk::VkDevice device = context.getDevice();
vk::Allocator& allocator = context.getDefaultAllocator();
// Create layout with two uniform buffer descriptors w/ empty binding between them
vk::DescriptorSetLayoutBuilder builder;
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
builder.addBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, (vk::VkShaderStageFlags)0, DE_NULL);
builder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, vk::VK_SHADER_STAGE_ALL);
vk::Unique<vk::VkDescriptorSetLayout> layout (builder.build(vki, device, (vk::VkDescriptorSetLayoutCreateFlags)0));
// Create descriptor pool
vk::Unique<vk::VkDescriptorPool> descriptorPool (vk::DescriptorPoolBuilder().addType(vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2).build(vki, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
// Create descriptor set
const vk::VkDescriptorSetAllocateInfo setAllocateInfo =
{
vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
*descriptorPool, // VkDescriptorPool descriptorPool
1, // deUint32 descriptorSetCount
&layout.get() // const VkDescriptorSetLayout* pSetLayouts
};
vk::Unique<vk::VkDescriptorSet> descriptorSet (allocateDescriptorSet(vki, device, &setAllocateInfo));
// Create a buffer to be used for update
const vk::VkBufferCreateInfo bufferCreateInfo =
{
vk::VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType
DE_NULL, // const void* pNext
(vk::VkBufferCreateFlags)DE_NULL, // VkBufferCreateFlags flags
256, // VkDeviceSize size
vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, // VkBufferUsageFlags usage
vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode
0, // deUint32 queueFamilyIndexCount
DE_NULL // const deUint32* pQueueFamilyIndices
};
vk::Unique<vk::VkBuffer> buffer (createBuffer(vki, device, &bufferCreateInfo));
const vk::VkMemoryRequirements requirements = vk::getBufferMemoryRequirements(vki, device, *buffer);
de::MovePtr<vk::Allocation> allocation = allocator.allocate(requirements, vk::MemoryRequirement::Any);
VK_CHECK(vki.bindBufferMemory(device, *buffer, allocation->getMemory(), allocation->getOffset()));
// Only update the descriptor at binding 2
const vk::VkDescriptorBufferInfo descriptorInfo =
{
*buffer, // VkBuffer buffer
0, // VkDeviceSize offset
VK_WHOLE_SIZE // VkDeviceSize range
};
const vk::VkWriteDescriptorSet descriptorWrite =
{
vk::VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureTypes Type
DE_NULL, // const void* pNext
*descriptorSet, // VkDescriptorSet dstSet
2, // deUint32 dstBinding
0, // deUint32 dstArrayElement
1, // deUint32 descriptorCount
vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, // VkDescriptorType descriptorType
DE_NULL, // const VkDescriptorImageInfo* pImageInfo
&descriptorInfo, // const VkDescriptorBufferInfo* pBufferInfo
DE_NULL // const VkBufferView* pTexelBufferView
};
vki.updateDescriptorSets(device, 1, &descriptorWrite, 0, DE_NULL);
// Test should always pass
return tcu::TestStatus::pass("Pass");
}
tcu::TestCaseGroup* createEmptyDescriptorUpdateTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "empty_descriptor", "Update last descriptor in a set that includes an empty binding"));
addFunctionCase(group.get(), "uniform_buffer", "", EmptyDescriptorUpdateCase);
return group.release();
}
enum class PointerCase
{
ZERO = 0,
ONE,
DESTROYED,
};
struct SamplerlessParams
{
vk::VkDescriptorType type;
PointerCase pointer;
};
class SamplerlessDescriptorWriteTestCase : public vkt::TestCase
{
public:
SamplerlessDescriptorWriteTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const SamplerlessParams& params);
virtual ~SamplerlessDescriptorWriteTestCase (void) {}
virtual void initPrograms (vk::SourceCollections& programCollection) const;
virtual vkt::TestInstance* createInstance (Context& context) const;
virtual void checkSupport (Context& context) const;
vk::VkFormatFeatureFlagBits getMainImageFeature (void) const;
static const vk::VkFormat kImageFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
private:
SamplerlessParams m_params;
};
class SamplerlessDescriptorWriteTestInstance : public vkt::TestInstance
{
public:
SamplerlessDescriptorWriteTestInstance (Context& context, const SamplerlessParams& params);
virtual ~SamplerlessDescriptorWriteTestInstance (void) {}
vk::VkSampler getSamplerHandle (void) const;
virtual tcu::TestStatus iterate (void);
vk::VkExtent3D getMainImageExtent (void) const;
vk::VkImageUsageFlags getMainImageUsage (void) const;
vk::VkImageLayout getMainImageShaderLayout (void) const;
static const vk::VkFormat kImageFormat = SamplerlessDescriptorWriteTestCase::kImageFormat;
static const vk::VkExtent3D kFramebufferExtent;
static const vk::VkExtent3D kMinimumExtent;
static const tcu::Vec4 kDescriptorColor;
private:
SamplerlessParams m_params;
};
const vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::kFramebufferExtent = vk::makeExtent3D(64u, 64u, 1u);
const vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::kMinimumExtent = vk::makeExtent3D(1u, 1u, 1u);
const tcu::Vec4 SamplerlessDescriptorWriteTestInstance::kDescriptorColor {0.0f, 1.0f, 0.0f, 1.0f};
SamplerlessDescriptorWriteTestCase::SamplerlessDescriptorWriteTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const SamplerlessParams& params)
: vkt::TestCase{testCtx, name, description}
, m_params(params)
{
}
void SamplerlessDescriptorWriteTestCase::initPrograms (vk::SourceCollections& programCollection) const
{
const std::string vertexShader =
"#version 450\n"
"layout(location=0) in vec4 position;\n"
"void main() { gl_Position = position; }\n";
programCollection.glslSources.add("vert") << glu::VertexSource(vertexShader);
std::string descriptorDecl;
std::string readOp;
std::string extensions;
switch (m_params.type)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
extensions = "#extension GL_EXT_samplerless_texture_functions : require\n";
descriptorDecl = "layout(set=0, binding=0) uniform texture2D img;";
readOp = "texelFetch(img, ivec2(0, 0), 0)";
break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
descriptorDecl = "layout(rgba8, set=0, binding=0) uniform image2D img;";
readOp = "imageLoad(img, ivec2(0, 0))";
break;
case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
descriptorDecl = "layout(input_attachment_index=0, set=0, binding=0) uniform subpassInput img;";
readOp = "subpassLoad(img)";
break;
default:
DE_ASSERT(false);
break;
}
std::ostringstream fragmentShader;
fragmentShader
<< "#version 450\n"
<< extensions
<< descriptorDecl << "\n"
<< "layout(location = 0) out vec4 color_out;\n"
<< "void main()\n"
<< "{\n"
<< " color_out = " << readOp << ";\n"
<< "}\n"
;
programCollection.glslSources.add("frag") << glu::FragmentSource(fragmentShader.str());
}
vk::VkFormatFeatureFlagBits SamplerlessDescriptorWriteTestCase::getMainImageFeature (void) const
{
vk::VkFormatFeatureFlagBits feature = static_cast<vk::VkFormatFeatureFlagBits>(0);
switch (m_params.type)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: feature = vk::VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: feature = vk::VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; break;
case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: feature = vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; break;
default:
DE_ASSERT(false);
break;
}
return feature;
}
void SamplerlessDescriptorWriteTestCase::checkSupport (Context& context) const
{
const auto& vki = context.getInstanceInterface();
const auto physicalDevice = context.getPhysicalDevice();
const auto mainFeature = getMainImageFeature();
const vk::VkFormatFeatureFlags features =
(
vk::VK_FORMAT_FEATURE_TRANSFER_DST_BIT | // For color clearing.
vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | // For the separate frame buffer image (uses the same format).
mainFeature
);
const auto props = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kImageFormat);
if ((props.optimalTilingFeatures & features) != features)
TCU_THROW(NotSupportedError, "Image format does not support the required features");
}
vkt::TestInstance* SamplerlessDescriptorWriteTestCase::createInstance (Context& context) const
{
return new SamplerlessDescriptorWriteTestInstance{context, m_params};
}
SamplerlessDescriptorWriteTestInstance::SamplerlessDescriptorWriteTestInstance (Context& context, const SamplerlessParams& params)
: vkt::TestInstance{context}
, m_params(params)
{
}
struct DestroyedSampler
{
vk::VkSampler sampler;
DestroyedSampler (Context& context)
: sampler{DE_NULL}
{
const vk::VkSamplerCreateInfo createInfo =
{
vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkSamplerCreateFlags flags;
vk::VK_FILTER_NEAREST, // VkFilter magFilter;
vk::VK_FILTER_NEAREST, // VkFilter minFilter;
vk::VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode;
vk::VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeU;
vk::VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeV;
vk::VK_SAMPLER_ADDRESS_MODE_REPEAT, // VkSamplerAddressMode addressModeW;
0.0f, // float mipLodBias;
VK_FALSE, // VkBool32 anisotropyEnable;
1.0f, // float maxAnisotropy;
VK_FALSE, // VkBool32 compareEnable;
vk::VK_COMPARE_OP_NEVER, // VkCompareOp compareOp;
0.0f, // float minLod;
0.0f, // float maxLod;
vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor;
VK_FALSE, // VkBool32 unnormalizedCoordinates;
};
const auto newSampler = vk::createSampler(context.getDeviceInterface(), context.getDevice(), &createInfo);
sampler = newSampler.get();
// newSampler will be destroyed here and sampler will hold the former handle.
}
};
vk::VkSampler SamplerlessDescriptorWriteTestInstance::getSamplerHandle (void) const
{
if (m_params.pointer == PointerCase::ZERO) return vk::VkSampler{DE_NULL};
if (m_params.pointer == PointerCase::ONE) return vk::VkSampler{1};
static const DestroyedSampler destroyedSampler{m_context};
return destroyedSampler.sampler;
}
vk::VkExtent3D SamplerlessDescriptorWriteTestInstance::getMainImageExtent (void) const
{
const vk::VkExtent3D* extent = nullptr;
switch (m_params.type)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: // fallthrough
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: extent = &kMinimumExtent; break;
case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: extent = &kFramebufferExtent; break;
default:
DE_ASSERT(false);
break;
}
return *extent;
}
vk::VkImageUsageFlags SamplerlessDescriptorWriteTestInstance::getMainImageUsage (void) const
{
vk::VkImageUsageFlags usage = vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT; // Used when clearing the image.
switch (m_params.type)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: usage |= vk::VK_IMAGE_USAGE_SAMPLED_BIT; break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: usage |= vk::VK_IMAGE_USAGE_STORAGE_BIT; break;
case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: usage |= vk::VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; break;
default:
DE_ASSERT(false);
break;
}
return usage;
}
vk::VkImageLayout SamplerlessDescriptorWriteTestInstance::getMainImageShaderLayout (void) const
{
vk::VkImageLayout layout = vk::VK_IMAGE_LAYOUT_UNDEFINED;
switch (m_params.type)
{
case vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: // fallthrough
case vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: layout = vk::VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; break;
case vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: layout = vk::VK_IMAGE_LAYOUT_GENERAL; break;
default:
DE_ASSERT(false);
break;
}
return layout;
}
tcu::TestStatus SamplerlessDescriptorWriteTestInstance::iterate (void)
{
const auto& vkd = m_context.getDeviceInterface();
const auto device = m_context.getDevice();
auto& allocator = m_context.getDefaultAllocator();
const auto queue = m_context.getUniversalQueue();
const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
const auto tcuFormat = vk::mapVkFormat(kImageFormat);
const vk::VkImageCreateInfo mainImgCreateInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkImageCreateFlags flags;
vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
kImageFormat, // VkFormat format;
getMainImageExtent(), // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
getMainImageUsage(), // VkImageUsageFlags usage;
vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueIndex, // const deUint32* pQueueFamilyIndices;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
const vk::VkImageCreateInfo fbImgCreateInfo =
{
vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkImageCreateFlags flags;
vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
kImageFormat, // VkFormat format;
kFramebufferExtent, // VkExtent3D extent;
1u, // deUint32 mipLevels;
1u, // deUint32 arrayLayers;
vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
(vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | // VkImageUsageFlags usage;
vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT), // Used when verifying the image.
vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1u, // deUint32 queueFamilyIndexCount;
&queueIndex, // const deUint32* pQueueFamilyIndices;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
};
// Create main and framebuffer images.
const vk::ImageWithMemory mainImage {vkd, device, allocator, mainImgCreateInfo, vk::MemoryRequirement::Any};
const vk::ImageWithMemory fbImage {vkd, device, allocator, fbImgCreateInfo, vk::MemoryRequirement::Any};
// Corresponding image views.
const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
const auto mainView = vk::makeImageView(vkd, device, mainImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, colorSubresourceRange);
const auto fbView = vk::makeImageView(vkd, device, fbImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kImageFormat, colorSubresourceRange);
// Buffer to copy rendering result to.
const vk::VkDeviceSize resultsBufferSize = static_cast<vk::VkDeviceSize>(static_cast<deUint32>(tcu::getPixelSize(tcuFormat)) * kFramebufferExtent.width * kFramebufferExtent.height * kFramebufferExtent.depth);
const auto resultsBufferInfo = vk::makeBufferCreateInfo(resultsBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
const vk::BufferWithMemory resultsBuffer {vkd, device, allocator, resultsBufferInfo, vk::MemoryRequirement::HostVisible};
const std::vector<tcu::Vec4> fullScreenQuad =
{
{ -1.f, -1.f, 0.f, 1.f },
{ 1.f, -1.f, 0.f, 1.f },
{ -1.f, 1.f, 0.f, 1.f },
{ -1.f, 1.f, 0.f, 1.f },
{ 1.f, -1.f, 0.f, 1.f },
{ 1.f, 1.f, 0.f, 1.f },
};
// Vertex buffer.
const vk::VkDeviceSize vertexBufferSize = static_cast<vk::VkDeviceSize>(fullScreenQuad.size() * sizeof(decltype(fullScreenQuad)::value_type));
const auto vertexBufferInfo = vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
const vk::BufferWithMemory vertexBuffer {vkd, device, allocator, vertexBufferInfo, vk::MemoryRequirement::HostVisible};
// Copy data to vertex buffer.
const auto& vertexAlloc = vertexBuffer.getAllocation();
const auto vertexDataPtr = reinterpret_cast<char*>(vertexAlloc.getHostPtr()) + vertexAlloc.getOffset();
deMemcpy(vertexDataPtr, fullScreenQuad.data(), static_cast<size_t>(vertexBufferSize));
vk::flushAlloc(vkd, device, vertexAlloc);
// Descriptor set layout.
vk::DescriptorSetLayoutBuilder layoutBuilder;
layoutBuilder.addSingleBinding(m_params.type, vk::VK_SHADER_STAGE_ALL_GRAPHICS);
const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
// Descriptor pool.
vk::DescriptorPoolBuilder poolBuilder;
poolBuilder.addType(m_params.type);
const auto descriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
// Descriptor set.
const auto descriptorSet = vk::makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
// Update descriptor set with the descriptor.
// IMPORTANT: the chosen sampler handle is used here.
vk::DescriptorSetUpdateBuilder updateBuilder;
const auto descriptorImageInfo = vk::makeDescriptorImageInfo(getSamplerHandle(), mainView.get(), getMainImageShaderLayout());
updateBuilder.writeSingle(descriptorSet.get(), vk::DescriptorSetUpdateBuilder::Location::binding(0u), m_params.type, &descriptorImageInfo);
updateBuilder.update(vkd, device);
// Shader modules.
const auto vertexModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
// Render pass.
const vk::VkAttachmentDescription fbAttachment =
{
0u, // VkAttachmentDescriptionFlags flags;
kImageFormat, // VkFormat format;
vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
};
std::vector<vk::VkAttachmentDescription> attachmentDescs;
attachmentDescs.push_back(fbAttachment);
if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
{
// Add it as a frame buffer attachment.
const vk::VkAttachmentDescription inputAttachment =
{
0u, // VkAttachmentDescriptionFlags flags;
kImageFormat, // VkFormat format;
vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
vk::VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp;
vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp;
vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
getMainImageShaderLayout(), // VkImageLayout initialLayout;
getMainImageShaderLayout(), // VkImageLayout finalLayout;
};
attachmentDescs.push_back(inputAttachment);
}
std::vector<vk::VkAttachmentReference> inputAttachments;
if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
{
const vk::VkAttachmentReference inputRef =
{
1u, // deUint32 attachment;
getMainImageShaderLayout(), // VkImageLayout layout;
};
inputAttachments.push_back(inputRef);
}
const vk::VkAttachmentReference colorRef =
{
0u, // deUint32 attachment;
vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
};
const std::vector<vk::VkAttachmentReference> colorAttachments(1u, colorRef);
const vk::VkSubpassDescription subpass =
{
0u, // VkSubpassDescriptionFlags flags;
vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
static_cast<deUint32>(inputAttachments.size()), // deUint32 inputAttachmentCount;
(inputAttachments.empty() ? nullptr : inputAttachments.data()), // const VkAttachmentReference* pInputAttachments;
static_cast<deUint32>(colorAttachments.size()), // deUint32 colorAttachmentCount;
colorAttachments.data(), // const VkAttachmentReference* pColorAttachments;
0u, // const VkAttachmentReference* pResolveAttachments;
nullptr, // const VkAttachmentReference* pDepthStencilAttachment;
0u, // deUint32 preserveAttachmentCount;
nullptr, // const deUint32* pPreserveAttachments;
};
const std::vector<vk::VkSubpassDescription> subpasses(1u, subpass);
const vk::VkRenderPassCreateInfo renderPassInfo =
{
vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0u, // VkRenderPassCreateFlags flags;
static_cast<deUint32>(attachmentDescs.size()), // deUint32 attachmentCount;
attachmentDescs.data(), // const VkAttachmentDescription* pAttachments;
static_cast<deUint32>(subpasses.size()), // deUint32 subpassCount;
subpasses.data(), // const VkSubpassDescription* pSubpasses;
0u, // deUint32 dependencyCount;
nullptr, // const VkSubpassDependency* pDependencies;
};
const auto renderPass = vk::createRenderPass(vkd, device, &renderPassInfo);
// Framebuffer.
std::vector<vk::VkImageView> attachments;
attachments.push_back(fbView.get());
if (m_params.type == vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)
attachments.push_back(mainView.get());
const auto framebuffer = vk::makeFramebuffer(vkd, device, renderPass.get(), static_cast<deUint32>(attachments.size()), attachments.data(), kFramebufferExtent.width, kFramebufferExtent.height, kFramebufferExtent.depth);
// Pipeline layout.
const auto pipelineLayout = vk::makePipelineLayout(vkd, device, descriptorSetLayout.get());
// Graphics pipeline.
const std::vector<vk::VkViewport> viewports(1u, vk::makeViewport(kFramebufferExtent));
const std::vector<vk::VkRect2D> scissors(1u, vk::makeRect2D(kFramebufferExtent));
const auto pipeline = vk::makeGraphicsPipeline(
vkd, device, pipelineLayout.get(),
vertexModule.get(), DE_NULL, DE_NULL, DE_NULL, fragModule.get(),
renderPass.get(), viewports, scissors);
// Command pool and command buffer.
const auto cmdPool = vk::createCommandPool(vkd, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueIndex);
const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
const auto cmdBuffer = cmdBufferPtr.get();
// Draw quad.
const vk::VkRect2D renderArea = vk::makeRect2D(kFramebufferExtent);
const tcu::Vec4 clearFbColor (0.0f, 0.0f, 0.0f, 1.0f);
const vk::VkDeviceSize vertexBufferOffset = 0ull;
const auto vtxBufferBarrier = vk::makeBufferMemoryBarrier(vk::VK_ACCESS_HOST_WRITE_BIT, vk::VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT, vertexBuffer.get(), 0ull, vertexBufferSize);
const auto preClearBarrier = vk::makeImageMemoryBarrier(0u, vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_IMAGE_LAYOUT_UNDEFINED, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, mainImage.get(), colorSubresourceRange);
const auto postClearBarrier = vk::makeImageMemoryBarrier(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_SHADER_READ_BIT, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, getMainImageShaderLayout(), mainImage.get(), colorSubresourceRange);
const auto clearDescColor = vk::makeClearValueColor(kDescriptorColor);
vk::beginCommandBuffer(vkd, cmdBuffer);
vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_HOST_BIT, vk::VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0u, 0u, nullptr, 1u, &vtxBufferBarrier, 0u, nullptr);
vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preClearBarrier);
vkd.cmdClearColorImage(cmdBuffer, mainImage.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearDescColor.color, 1u, &colorSubresourceRange);
vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &postClearBarrier);
vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea, clearFbColor);
vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
vkd.cmdBindDescriptorSets(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(fullScreenQuad.size()), 1u, 0u, 0u);
vk::endRenderPass(vkd, cmdBuffer);
const tcu::IVec2 copySize{static_cast<int>(kFramebufferExtent.width), static_cast<int>(kFramebufferExtent.height)};
vk::copyImageToBuffer(vkd, cmdBuffer, fbImage.get(), resultsBuffer.get(), copySize);
vk::endCommandBuffer(vkd, cmdBuffer);
vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
// Check results.
const auto& resultsBufferAlloc = resultsBuffer.getAllocation();
vk::invalidateAlloc(vkd, device, resultsBufferAlloc);
const auto resultsBufferPtr = reinterpret_cast<const char*>(resultsBufferAlloc.getHostPtr()) + resultsBufferAlloc.getOffset();
const tcu::ConstPixelBufferAccess resultPixels {tcuFormat, copySize[0], copySize[1], 1, resultsBufferPtr};
bool pass = true;
for (int x = 0; pass && x < resultPixels.getWidth(); ++x)
for (int y = 0; pass && y < resultPixels.getHeight(); ++y)
for (int z = 0; pass && z < resultPixels.getDepth(); ++z)
{
const auto pixel = resultPixels.getPixel(x, y, z);
pass = (pixel == kDescriptorColor);
}
tcu::TestStatus status = tcu::TestStatus::pass("Pass");
if (!pass)
{
auto& log = m_context.getTestContext().getLog();
log << tcu::TestLog::Image("color", "Rendered image", resultPixels);
status = tcu::TestStatus::fail("Pixel mismatch; please check the rendered image");
}
return status;
}
tcu::TestCaseGroup* createSamplerlessWriteTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "samplerless", "Verify sampler unused with some descriptor image types"));
const std::vector<std::pair<vk::VkDescriptorType, std::string>> descriptorTypes =
{
std::make_pair(vk::VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, "sampled_img"),
std::make_pair(vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, "storage_img"),
std::make_pair(vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, "input_attachment"),
};
const std::vector<std::pair<PointerCase, std::string>> pointerCases =
{
std::make_pair(PointerCase::ZERO, "sampler_zero"),
std::make_pair(PointerCase::ONE, "sampler_one"),
std::make_pair(PointerCase::DESTROYED, "sampler_destroyed"),
};
for (const auto& typeCase : descriptorTypes)
for (const auto& pointerCase : pointerCases)
{
const std::string caseName = typeCase.second + "_" + pointerCase.second;
const SamplerlessParams params {typeCase.first, pointerCase.first};
group->addChild(new SamplerlessDescriptorWriteTestCase(testCtx, caseName, "", params));
}
return group.release();
}
} // anonymous
tcu::TestCaseGroup* createDescriptorUpdateTests (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "descriptor_update", "Update descriptor sets"));
group->addChild(createEmptyDescriptorUpdateTests(testCtx));
group->addChild(createSamplerlessWriteTests(testCtx));
return group.release();
}
} // BindingModel
} // vkt