| /*------------------------------------------------------------------------- |
| * 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 |