/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2018 The Khronos Group Inc. * Copyright (c) 2018 Google Inc. * Copyright (c) 2015 Imagination Technologies Ltd. * * 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 attachments unused by subpasses *//*--------------------------------------------------------------------*/ #include "vktRenderPassUnusedAttachmentTests.hpp" #include "pipeline/vktPipelineImageUtil.hpp" #include "vktTestCase.hpp" #include "vkImageUtil.hpp" #include "vkMemUtil.hpp" #include "vkPlatform.hpp" #include "vkPrograms.hpp" #include "vkQueryUtil.hpp" #include "vkCmdUtil.hpp" #include "vkRef.hpp" #include "vkRefUtil.hpp" #include "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "tcuImageCompare.hpp" #include "tcuPlatform.hpp" #include "tcuTextureUtil.hpp" #include "tcuTestLog.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include "deRandom.hpp" #include <cstring> #include <set> #include <sstream> #include <vector> namespace vkt { namespace renderpass { using namespace vk; namespace { struct TestParams { VkAttachmentLoadOp loadOp; VkAttachmentStoreOp storeOp; VkAttachmentLoadOp stencilLoadOp; VkAttachmentStoreOp stencilStoreOp; RenderPassType renderPassType; }; struct Vertex4RGBA { tcu::Vec4 position; tcu::Vec4 color; }; std::vector<Vertex4RGBA> createQuad (void) { std::vector<Vertex4RGBA> vertices; const float size = 0.8f; const tcu::Vec4 color (0.2f, 0.3f, 0.1f, 1.0f); const Vertex4RGBA lowerLeftVertex = {tcu::Vec4(-size, -size, 0.0f, 1.0f), color}; const Vertex4RGBA lowerRightVertex = {tcu::Vec4(size, -size, 0.0f, 1.0f), color}; const Vertex4RGBA upperLeftVertex = {tcu::Vec4(-size, size, 0.0f, 1.0f), color}; const Vertex4RGBA upperRightVertex = {tcu::Vec4(size, size, 0.0f, 1.0f), color}; vertices.push_back(lowerLeftVertex); vertices.push_back(lowerRightVertex); vertices.push_back(upperLeftVertex); vertices.push_back(upperLeftVertex); vertices.push_back(lowerRightVertex); vertices.push_back(upperRightVertex); return vertices; } template<typename AttachmentDesc, typename AttachmentRef, typename SubpassDesc, typename SubpassDep, typename RenderPassCreateInfo> Move<VkRenderPass> createRenderPass (const DeviceInterface& vk, VkDevice vkDevice, const TestParams testParams) { const VkImageAspectFlags aspectMask = testParams.renderPassType == RENDERPASS_TYPE_LEGACY ? 0 : VK_IMAGE_ASPECT_COLOR_BIT; const AttachmentDesc attachmentDescriptions[] = { // Result attachment AttachmentDesc ( DE_NULL, // const void* pNext (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout ), // Unused attachment AttachmentDesc ( DE_NULL, // const void* pNext (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples testParams.loadOp, // VkAttachmentLoadOp loadOp testParams.storeOp, // VkAttachmentStoreOp storeOp testParams.stencilLoadOp, // VkAttachmentLoadOp stencilLoadOp testParams.stencilStoreOp, // VkAttachmentStoreOp stencilStoreOp VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout ), // Input attachment AttachmentDesc ( DE_NULL, // const void* pNext (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout ) }; // Note: Attachment 1 is not referenced by any subpass. const AttachmentRef resultAttachmentRefSubpass0 ( DE_NULL, // const void* pNext 2u, // deUint32 attachment VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout aspectMask // VkImageAspectFlags aspectMask ); const AttachmentRef resultAttachmentRefSubpass1 ( DE_NULL, // const void* pNext 0u, // deUint32 attachment VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout aspectMask // VkImageAspectFlags aspectMask ); const AttachmentRef inputAttachmentRefSubpass1 ( DE_NULL, // const void* pNext 2u, // deUint32 attachment VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout aspectMask // VkImageAspectFlags aspectMask ); const SubpassDesc subpassDescriptions[] = { SubpassDesc ( DE_NULL, (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint 0u, // deUint32 viewMask 0u, // deUint32 inputAttachmentCount DE_NULL, // const VkAttachmentReference* pInputAttachments 1u, // deUint32 colorAttachmentCount &resultAttachmentRefSubpass0, // const VkAttachmentReference* pColorAttachments DE_NULL, // const VkAttachmentReference* pResolveAttachments DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment 0u, // deUint32 preserveAttachmentCount DE_NULL // const deUint32* pPreserveAttachments ), SubpassDesc ( DE_NULL, (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint 0u, // deUint32 viewMask 1u, // deUint32 inputAttachmentCount &inputAttachmentRefSubpass1, // const VkAttachmentReference* pInputAttachments 1u, // deUint32 colorAttachmentCount &resultAttachmentRefSubpass1, // const VkAttachmentReference* pColorAttachments DE_NULL, // const VkAttachmentReference* pResolveAttachments DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment 0u, // deUint32 preserveAttachmentCount DE_NULL // const deUint32* pPreserveAttachments ) }; const SubpassDep subpassDependency ( DE_NULL, // const void* pNext 0u, // uint32_t srcSubpass 1u, // uint32_t dstSubpass VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // VkPipelineStageFlags srcStageMask VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags 0u // deInt32 viewOffset ); const RenderPassCreateInfo renderPassInfo ( DE_NULL, // const void* pNext (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags 3u, // deUint32 attachmentCount attachmentDescriptions, // const VkAttachmentDescription* pAttachments 2u, // deUint32 subpassCount subpassDescriptions, // const VkSubpassDescription* pSubpasses 1u, // deUint32 dependencyCount &subpassDependency, // const VkSubpassDependency* pDependencies 0u, // deUint32 correlatedViewMaskCount DE_NULL // const deUint32* pCorrelatedViewMasks ); return renderPassInfo.createRenderPass(vk, vkDevice); } class UnusedAttachmentTest : public vkt::TestCase { public: UnusedAttachmentTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, const TestParams& testParams); virtual ~UnusedAttachmentTest (void); virtual void initPrograms (SourceCollections& sourceCollections) const; virtual TestInstance* createInstance (Context& context) const; private: const TestParams m_testParams; }; class UnusedAttachmentTestInstance : public vkt::TestInstance { public: UnusedAttachmentTestInstance (Context& context, const TestParams& testParams); virtual ~UnusedAttachmentTestInstance (void); virtual tcu::TestStatus iterate (void); template<typename RenderpassSubpass> void createCommandBuffer (const DeviceInterface& vk, VkDevice vkDevice); private: tcu::TestStatus verifyImage (void); const tcu::UVec2 m_renderSize; Move<VkImage> m_colorImage; de::MovePtr<Allocation> m_colorImageAlloc; Move<VkImageView> m_colorAttachmentView; Move<VkImage> m_unusedImage; de::MovePtr<Allocation> m_unusedImageAlloc; Move<VkImageView> m_unusedAttachmentView; Move<VkImage> m_inputImage; de::MovePtr<Allocation> m_inputImageAlloc; Move<VkImageView> m_inputAttachmentView; Move<VkDescriptorSetLayout> m_descriptorSetLayoutSubpass0; Move<VkDescriptorSetLayout> m_descriptorSetLayoutSubpass1; Move<VkDescriptorPool> m_descriptorPool; Move<VkDescriptorSet> m_descriptorSetSubpass1; Move<VkRenderPass> m_renderPass; Move<VkFramebuffer> m_framebuffer; Move<VkShaderModule> m_vertexShaderModule; Move<VkShaderModule> m_fragmentShaderModuleSubpass0; Move<VkShaderModule> m_fragmentShaderModuleSubpass1; Move<VkBuffer> m_vertexBuffer; std::vector<Vertex4RGBA> m_vertices; de::MovePtr<Allocation> m_vertexBufferAlloc; Move<VkBuffer> m_backingBuffer; de::MovePtr<Allocation> m_backingBufferAlloc; Move<VkPipelineLayout> m_pipelineLayoutSubpass0; Move<VkPipelineLayout> m_pipelineLayoutSubpass1; Move<VkPipeline> m_graphicsPipelineSubpass0; Move<VkPipeline> m_graphicsPipelineSubpass1; Move<VkCommandPool> m_cmdPool; Move<VkCommandBuffer> m_cmdBuffer; }; UnusedAttachmentTest::UnusedAttachmentTest (tcu::TestContext& testContext, const std::string& name, const std::string& description, const TestParams& testParams) : vkt::TestCase (testContext, name, description) , m_testParams (testParams) { } UnusedAttachmentTest::~UnusedAttachmentTest (void) { } TestInstance* UnusedAttachmentTest::createInstance (Context& context) const { return new UnusedAttachmentTestInstance(context, m_testParams); } void UnusedAttachmentTest::initPrograms (SourceCollections& sourceCollections) const { std::ostringstream fragmentSource; sourceCollections.glslSources.add("color_vert") << glu::VertexSource( "#version 450\n" "layout(location = 0) in highp vec4 position;\n" "layout(location = 1) in highp vec4 color;\n" "layout(location = 0) out highp vec4 vtxColor;\n" "void main (void)\n" "{\n" " gl_Position = position;\n" " vtxColor = color;\n" "}\n"); sourceCollections.glslSources.add("color_frag_sb0") << glu::FragmentSource( "#version 450\n" "layout(location = 0) in highp vec4 vtxColor;\n" "layout(location = 0) out highp vec4 fragColor;\n" "void main (void)\n" "{\n" " fragColor = vtxColor;\n" "}\n"); sourceCollections.glslSources.add("color_frag_sb1") << glu::FragmentSource( "#version 450\n" "layout(location = 0) in highp vec4 vtxColor;\n" "layout(location = 0) out highp vec4 fragColor;\n" "layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput inputColor;" "void main (void)\n" "{\n" " fragColor = subpassLoad(inputColor) + vtxColor;\n" "}\n"); } UnusedAttachmentTestInstance::UnusedAttachmentTestInstance (Context& context, const TestParams& testParams) : vkt::TestInstance (context) , m_renderSize (32u, 32u) , m_vertices (createQuad()) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); SimpleAllocator memAlloc (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())); const VkComponentMapping componentMappingRGBA = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; // Check for renderpass2 extension if used if (testParams.renderPassType == RENDERPASS_TYPE_RENDERPASS2) context.requireDeviceExtension("VK_KHR_create_renderpass2"); // Create color image { const VkImageCreateInfo colorImageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; m_colorImage = createImage(vk, vkDevice, &colorImageParams); // Allocate and bind color image memory m_colorImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset())); } // Create image which is not used by any subpass { const VkImageCreateInfo unusedImageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; m_unusedImage = createImage(vk, vkDevice, &unusedImageParams); // Allocate and bind unused image memory VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vk, vkDevice, *m_unusedImage); m_unusedImageAlloc = memAlloc.allocate(memoryRequirements, MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(vkDevice, *m_unusedImage, m_unusedImageAlloc->getMemory(), m_unusedImageAlloc->getOffset())); // Clear image with specific value to verify the contents don't change { const VkImageAspectFlags aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; Move<VkCommandPool> cmdPool; Move<VkCommandBuffer> cmdBuffer; VkClearValue clearValue; clearValue.color.float32[0] = 0.1f; clearValue.color.float32[1] = 0.2f; clearValue.color.float32[2] = 0.3f; clearValue.color.float32[3] = 0.4f; // Create command pool and buffer cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex); cmdBuffer = allocateCommandBuffer(vk, vkDevice, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); const VkImageMemoryBarrier preImageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkAccessFlags srcAccessMask; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; *m_unusedImage, // VkImage image; { // VkImageSubresourceRange subresourceRange; aspectMask, // VkImageAspect aspect; 0u, // deUint32 baseMipLevel; 1u, // deUint32 mipLevels; 0u, // deUint32 baseArraySlice; 1u // deUint32 arraySize; } }; const VkImageMemoryBarrier postImageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_SHADER_READ_BIT, // VkAccessFlags dstAccessMask; VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout oldLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // deUint32 srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // deUint32 dstQueueFamilyIndex; *m_unusedImage, // VkImage image; { // VkImageSubresourceRange subresourceRange; aspectMask, // VkImageAspect aspect; 0u, // deUint32 baseMipLevel; 1u, // deUint32 mipLevels; 0u, // deUint32 baseArraySlice; 1u // deUint32 arraySize; } }; const VkImageSubresourceRange clearRange = { aspectMask, // VkImageAspectFlags aspectMask; 0u, // deUint32 baseMipLevel; 1u, // deUint32 levelCount; 0u, // deUint32 baseArrayLayer; 1u // deUint32 layerCount; }; // Clear image beginCommandBuffer(vk, *cmdBuffer); vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &preImageBarrier); vk.cmdClearColorImage(*cmdBuffer, *m_unusedImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearValue.color, 1, &clearRange); vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier); endCommandBuffer(vk, *cmdBuffer); submitCommandsAndWait(vk, vkDevice, m_context.getUniversalQueue(), cmdBuffer.get()); } } // Create input image { const VkImageCreateInfo inputImageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; { m_renderSize.x(), m_renderSize.y(), 1u }, // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED // VkImageLayout initialLayout; }; m_inputImage = createImage(vk, vkDevice, &inputImageParams); // Allocate and bind input image memory m_inputImageAlloc = memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_inputImage), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(vkDevice, *m_inputImage, m_inputImageAlloc->getMemory(), m_inputImageAlloc->getOffset())); } // Create color attachment view { const VkImageViewCreateInfo colorAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_colorImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; componentMappingRGBA, // VkChannelMapping channels; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange; }; m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams); } // Create unused attachment view { const VkImageViewCreateInfo unusedAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_unusedImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; componentMappingRGBA, // VkChannelMapping channels; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange; }; m_unusedAttachmentView = createImageView(vk, vkDevice, &unusedAttachmentViewParams); } // Create input attachment view { const VkImageViewCreateInfo inputAttachmentViewParams = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkImageViewCreateFlags flags; *m_inputImage, // VkImage image; VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType; VK_FORMAT_R8G8B8A8_UNORM, // VkFormat format; componentMappingRGBA, // VkChannelMapping channels; { VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u } // VkImageSubresourceRange subresourceRange; }; m_inputAttachmentView = createImageView(vk, vkDevice, &inputAttachmentViewParams); } // Create render pass if (testParams.renderPassType == RENDERPASS_TYPE_LEGACY) m_renderPass = createRenderPass<AttachmentDescription1, AttachmentReference1, SubpassDescription1, SubpassDependency1, RenderPassCreateInfo1>(vk, vkDevice, testParams); else m_renderPass = createRenderPass<AttachmentDescription2, AttachmentReference2, SubpassDescription2, SubpassDependency2, RenderPassCreateInfo2>(vk, vkDevice, testParams); // Create framebuffer { const VkImageView imageViews[] = { *m_colorAttachmentView, *m_unusedAttachmentView, *m_inputAttachmentView }; const VkFramebufferCreateInfo framebufferParams = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkFramebufferCreateFlags flags; *m_renderPass, // VkRenderPass renderPass; 3u, // deUint32 attachmentCount; imageViews, // const VkImageView* pAttachments; (deUint32)m_renderSize.x(), // deUint32 width; (deUint32)m_renderSize.y(), // deUint32 height; 1u // deUint32 layers; }; m_framebuffer = createFramebuffer(vk, vkDevice, &framebufferParams); } // Create pipeline layout for subpass 0 { const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutParams = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext 0u, // VkDescriptorSetLayoutCreateFlags flags 0u, // deUint32 bindingCount DE_NULL // const VkDescriptorSetLayoutBinding* pBindings }; m_descriptorSetLayoutSubpass0 = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutParams); const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &m_descriptorSetLayoutSubpass0.get(), // const VkDescriptorSetLayout* pSetLayouts; 0u, // deUint32 pushConstantRangeCount; DE_NULL // const VkPushConstantRange* pPushConstantRanges; }; m_pipelineLayoutSubpass0 = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); } // Create pipeline layout for subpass 1 { const VkDescriptorSetLayoutBinding layoutBinding = { 0u, // deUint32 binding; VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType descriptorType; 1u, // deUint32 descriptorCount; VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlags stageFlags; DE_NULL // const VkSampler* pImmutableSamplers; }; const VkDescriptorSetLayoutCreateInfo descriptorSetLayoutParams = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext 0u, // VkDescriptorSetLayoutCreateFlags flags 1u, // deUint32 bindingCount &layoutBinding // const VkDescriptorSetLayoutBinding* pBindings }; m_descriptorSetLayoutSubpass1 = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutParams); const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineLayoutCreateFlags flags; 1u, // deUint32 setLayoutCount; &m_descriptorSetLayoutSubpass1.get(), // const VkDescriptorSetLayout* pSetLayouts; 0u, // deUint32 pushConstantRangeCount; DE_NULL // const VkPushConstantRange* pPushConstantRanges; }; m_pipelineLayoutSubpass1 = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams); } // Update descriptor set { const VkDescriptorPoolSize descriptorPoolSize = { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType type; 1u // deUint32 descriptorCount; }; const VkDescriptorPoolCreateInfo descriptorPoolCreateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // VkDescriptorPoolCreateFlags flags 1u, // deUint32 maxSets 1u, // deUint32 poolSizeCount &descriptorPoolSize // const VkDescriptorPoolSize* pPoolSizes }; m_descriptorPool = createDescriptorPool(vk, vkDevice, &descriptorPoolCreateInfo); const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext *m_descriptorPool, // VkDescriptorPool descriptorPool 1u, // deUint32 descriptorSetCount &m_descriptorSetLayoutSubpass1.get(), // const VkDescriptorSetLayout* pSetLayouts }; m_descriptorSetSubpass1 = allocateDescriptorSet(vk, vkDevice, &descriptorSetAllocateInfo); const VkDescriptorImageInfo inputImageInfo = { DE_NULL, // VkSampleri sampler; *m_inputAttachmentView, // VkImageView imageView; VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout imageLayout; }; const VkWriteDescriptorSet descriptorWrite = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, // VkStructureType sType; DE_NULL, // const void* pNext; *m_descriptorSetSubpass1, // VkDescriptorSet dstSet; 0u, // deUint32 dstBinding; 0u, // deUint32 dstArrayElement; 1u, // deUint32 descriptorCount; VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // VkDescriptorType descriptorType; &inputImageInfo, // const VkDescriptorImageInfo* pImageInfo; DE_NULL, // const VkDescriptorBufferInfo* pBufferInfo; DE_NULL // const VkBufferView* pTexelBufferView; }; vk.updateDescriptorSets(vkDevice, 1u, &descriptorWrite, 0u, DE_NULL); } m_vertexShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_vert"), 0); m_fragmentShaderModuleSubpass0 = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag_sb0"), 0); m_fragmentShaderModuleSubpass1 = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("color_frag_sb1"), 0); // Create pipelines { const VkVertexInputBindingDescription vertexInputBindingDescription = { 0u, // deUint32 binding; sizeof(Vertex4RGBA), // deUint32 strideInBytes; VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputStepRate inputRate; }; const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[2] = { { 0u, // deUint32 location; 0u, // deUint32 binding; VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; 0u // deUint32 offset; }, { 1u, // deUint32 location; 0u, // deUint32 binding; VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format; (deUint32)(sizeof(float) * 4), // deUint32 offset; } }; const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkPipelineVertexInputStateCreateFlags flags; 1u, // deUint32 vertexBindingDescriptionCount; &vertexInputBindingDescription, // const VkVertexInputBindingDescription* pVertexBindingDescriptions; 2u, // deUint32 vertexAttributeDescriptionCount; vertexInputAttributeDescriptions // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; }; const std::vector<VkViewport> viewports (1, makeViewport(m_renderSize)); const std::vector<VkRect2D> scissors (1, makeRect2D(m_renderSize)); { m_graphicsPipelineSubpass0 = makeGraphicsPipeline(vk, // const DeviceInterface& vk vkDevice, // const VkDevice device *m_pipelineLayoutSubpass0, // const VkPipelineLayout pipelineLayout *m_vertexShaderModule, // const VkShaderModule vertexShaderModule DE_NULL, // const VkShaderModule tessellationControlModule DE_NULL, // const VkShaderModule tessellationEvalModule DE_NULL, // const VkShaderModule geometryShaderModule *m_fragmentShaderModuleSubpass0, // const VkShaderModule fragmentShaderModule *m_renderPass, // const VkRenderPass renderPass viewports, // const std::vector<VkViewport>& viewports scissors, // const std::vector<VkRect2D>& scissors VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology 0u, // const deUint32 subpass 0u, // const deUint32 patchControlPoints &vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo m_graphicsPipelineSubpass1 = makeGraphicsPipeline(vk, // const DeviceInterface& vk vkDevice, // const VkDevice device *m_pipelineLayoutSubpass1, // const VkPipelineLayout pipelineLayout *m_vertexShaderModule, // const VkShaderModule vertexShaderModule DE_NULL, // const VkShaderModule tessellationControlModule DE_NULL, // const VkShaderModule tessellationEvalModule DE_NULL, // const VkShaderModule geometryShaderModule *m_fragmentShaderModuleSubpass1, // const VkShaderModule fragmentShaderModule *m_renderPass, // const VkRenderPass renderPass viewports, // const std::vector<VkViewport>& viewports scissors, // const std::vector<VkRect2D>& scissors VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology 1u, // const deUint32 subpass 0u, // const deUint32 patchControlPoints &vertexInputStateParams); // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo } } // Create vertex buffer { const VkBufferCreateInfo vertexBufferParams = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; 0u, // VkBufferCreateFlags flags; (VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()), // VkDeviceSize size; VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 1u, // deUint32 queueFamilyIndexCount; &queueFamilyIndex // const deUint32* pQueueFamilyIndices; }; m_vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams); m_vertexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset())); // Upload vertex data deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA)); flushAlloc(vk, vkDevice, *m_vertexBufferAlloc); } // Create command pool m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex); // Create command buffer if (testParams.renderPassType == RENDERPASS_TYPE_LEGACY) createCommandBuffer<RenderpassSubpass1>(vk, vkDevice); else createCommandBuffer<RenderpassSubpass2>(vk, vkDevice); } UnusedAttachmentTestInstance::~UnusedAttachmentTestInstance (void) { } template<typename RenderpassSubpass> void UnusedAttachmentTestInstance::createCommandBuffer (const DeviceInterface& vk, VkDevice vkDevice) { const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); const VkClearValue attachmentClearValues[] = { makeClearValueColorF32(0.5f, 0.5f, 0.5f, 1.0f), // color makeClearValueColorF32(0.5f, 0.5f, 0.5f, 1.0f), // unused makeClearValueColorF32(0.5f, 0.2f, 0.1f, 1.0f) // input }; const VkDeviceSize vertexBufferOffset = 0; m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); beginCommandBuffer(vk, *m_cmdBuffer, 0u); const VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; *m_renderPass, // VkRenderPass renderPass; *m_framebuffer, // VkFramebuffer framebuffer; makeRect2D(m_renderSize), // VkRect2D renderArea; 3u, // uint32_t clearValueCount; attachmentClearValues // const VkClearValue* pClearValues; }; RenderpassSubpass::cmdBeginRenderPass(vk, *m_cmdBuffer, &renderPassBeginInfo, &subpassBeginInfo); vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineSubpass0); vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset); vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0); vk.cmdNextSubpass(*m_cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_graphicsPipelineSubpass1); vk.cmdBindDescriptorSets(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayoutSubpass1, 0, 1, &m_descriptorSetSubpass1.get(), 0, DE_NULL); vk.cmdDraw(*m_cmdBuffer, (deUint32)m_vertices.size(), 1, 0, 0); RenderpassSubpass::cmdEndRenderPass(vk, *m_cmdBuffer, &subpassEndInfo); endCommandBuffer(vk, *m_cmdBuffer); } tcu::TestStatus UnusedAttachmentTestInstance::iterate (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get()); return verifyImage(); } tcu::TestStatus UnusedAttachmentTestInstance::verifyImage (void) { const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice vkDevice = m_context.getDevice(); const VkQueue queue = m_context.getUniversalQueue(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); SimpleAllocator allocator (vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice())); de::UniquePtr<tcu::TextureLevel> textureLevelResult (pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_colorImage, VK_FORMAT_R8G8B8A8_UNORM, m_renderSize).release()); const tcu::ConstPixelBufferAccess& resultAccess = textureLevelResult->getAccess(); de::UniquePtr<tcu::TextureLevel> textureLevelUnused (pipeline::readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator, *m_unusedImage, VK_FORMAT_R8G8B8A8_UNORM, m_renderSize).release()); const tcu::ConstPixelBufferAccess& unusedAccess = textureLevelUnused->getAccess(); tcu::TestLog& log = m_context.getTestContext().getLog(); // Log images log << tcu::TestLog::ImageSet("Result", "Result images") << tcu::TestLog::Image("Rendered", "Rendered image", resultAccess) << tcu::TestLog::Image("Unused", "Unused image", unusedAccess) << tcu::TestLog::EndImageSet; // Check the unused image data hasn't changed. for (int y = 0; y < unusedAccess.getHeight(); y++) for (int x = 0; x < unusedAccess.getWidth(); x++) { const tcu::Vec4 color = unusedAccess.getPixel(x, y); const tcu::Vec4 refColor = tcu::Vec4(0.1f, 0.2f, 0.3f, 0.4f); for (deUint32 cpnt = 0; cpnt < 4; cpnt++) if (de::abs(color[cpnt] - refColor[cpnt]) > 0.01f) return tcu::TestStatus::fail("Unused image contents has changed."); } // Check for rendered result. Just a quick sanity check to see if correct color is found at the center of the quad. const tcu::Vec4 resultColor = resultAccess.getPixel(resultAccess.getWidth() / 2, resultAccess.getHeight() / 2); const tcu::Vec4 refColor = tcu::Vec4(0.4f, 0.6f, 0.2f, 1.0f); for (deUint32 cpnt = 0; cpnt < 4; cpnt++) if (de::abs(resultColor[cpnt] - refColor[cpnt]) > 0.01f) return tcu::TestStatus::fail("Result image mismatch"); return tcu::TestStatus::pass("Pass"); } std::string loadOpToString (VkAttachmentLoadOp loadOp) { switch (loadOp) { case VK_ATTACHMENT_LOAD_OP_LOAD: return "load"; case VK_ATTACHMENT_LOAD_OP_CLEAR: return "clear"; case VK_ATTACHMENT_LOAD_OP_DONT_CARE: return "dontcare"; default: DE_FATAL("unexpected attachment load op"); return ""; }; } std::string storeOpToString (VkAttachmentStoreOp storeOp) { switch (storeOp) { case VK_ATTACHMENT_STORE_OP_STORE: return "store"; case VK_ATTACHMENT_STORE_OP_DONT_CARE: return "dontcare"; default: DE_FATAL("unexpected attachment store op"); return ""; }; } } // anonymous tcu::TestCaseGroup* createRenderPassUnusedAttachmentTests (tcu::TestContext& testCtx, const RenderPassType renderPassType) { de::MovePtr<tcu::TestCaseGroup> unusedAttTests (new tcu::TestCaseGroup(testCtx, "unused_attachment", "Unused attachment tests")); const VkAttachmentLoadOp loadOps[] = { VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_DONT_CARE }; const VkAttachmentStoreOp storeOps[] = { VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_DONT_CARE }; for (deUint32 loadOpIdx = 0; loadOpIdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpIdx++) { de::MovePtr<tcu::TestCaseGroup> loadOpGroup(new tcu::TestCaseGroup(testCtx, (std::string("loadop") + loadOpToString(loadOps[loadOpIdx])).c_str(), "")); for (deUint32 storeOpIdx = 0; storeOpIdx < DE_LENGTH_OF_ARRAY(storeOps); storeOpIdx++) { de::MovePtr<tcu::TestCaseGroup> storeOpGroup(new tcu::TestCaseGroup(testCtx, (std::string("storeop") + storeOpToString(storeOps[storeOpIdx])).c_str(), "")); for (deUint32 stencilLoadOpIdx = 0; stencilLoadOpIdx < DE_LENGTH_OF_ARRAY(loadOps); stencilLoadOpIdx++) { de::MovePtr<tcu::TestCaseGroup> stencilLoadOpGroup(new tcu::TestCaseGroup(testCtx, (std::string("stencilloadop") + loadOpToString(loadOps[stencilLoadOpIdx])).c_str(), "")); for (deUint32 stencilStoreOpIdx = 0; stencilStoreOpIdx < DE_LENGTH_OF_ARRAY(storeOps); stencilStoreOpIdx++) { TestParams params; const std::string testName = std::string("stencilstoreop") + storeOpToString(storeOps[stencilStoreOpIdx]); params.loadOp = loadOps[loadOpIdx]; params.storeOp = storeOps[storeOpIdx]; params.stencilLoadOp = loadOps[stencilLoadOpIdx]; params.stencilStoreOp = storeOps[stencilStoreOpIdx]; params.renderPassType = renderPassType; stencilLoadOpGroup->addChild(new UnusedAttachmentTest(testCtx, testName, "", params)); } storeOpGroup->addChild(stencilLoadOpGroup.release()); } loadOpGroup->addChild(storeOpGroup.release()); } unusedAttTests->addChild(loadOpGroup.release()); } return unusedAttTests.release(); } } // renderpass } // vkt