/*------------------------------------------------------------------------- * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief RenderPass tests *//*--------------------------------------------------------------------*/ #include "vktRenderPassTests.hpp" #include "vktRenderPassMultisampleTests.hpp" #include "vktRenderPassMultisampleResolveTests.hpp" #include "vktTestCaseUtil.hpp" #include "vktTestGroupUtil.hpp" #include "vkDefs.hpp" #include "vkDeviceUtil.hpp" #include "vkImageUtil.hpp" #include "vkMemUtil.hpp" #include "vkPlatform.hpp" #include "vkPrograms.hpp" #include "vkQueryUtil.hpp" #include "vkRef.hpp" #include "vkRefUtil.hpp" #include "vkStrUtil.hpp" #include "vkTypeUtil.hpp" #include "tcuFloat.hpp" #include "tcuFormatUtil.hpp" #include "tcuMaybe.hpp" #include "tcuResultCollector.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include "tcuVectorUtil.hpp" #include "deRandom.hpp" #include "deSTLUtil.hpp" #include "deSharedPtr.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include #include #include #include using namespace vk; using tcu::BVec4; using tcu::IVec2; using tcu::IVec4; using tcu::UVec2; using tcu::UVec4; using tcu::Vec2; using tcu::Vec4; using tcu::Maybe; using tcu::just; using tcu::nothing; using tcu::ConstPixelBufferAccess; using tcu::PixelBufferAccess; using tcu::TestLog; using de::UniquePtr; using std::pair; using std::set; using std::string; using std::vector; namespace vkt { namespace { enum AllocationKind { ALLOCATION_KIND_SUBALLOCATED, ALLOCATION_KIND_DEDICATED, }; de::MovePtr allocateBuffer (const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkBuffer& buffer, const MemoryRequirement requirement, Allocator& allocator, AllocationKind allocationKind) { switch (allocationKind) { case ALLOCATION_KIND_SUBALLOCATED: { const VkMemoryRequirements memoryRequirements = getBufferMemoryRequirements(vkd, device, buffer); return allocator.allocate(memoryRequirements, requirement); } case ALLOCATION_KIND_DEDICATED: { return allocateDedicated(vki, vkd, physDevice, device, buffer, requirement); } default: { TCU_THROW(InternalError, "Invalid allocation kind"); } } } de::MovePtr allocateImage (const InstanceInterface& vki, const DeviceInterface& vkd, const VkPhysicalDevice& physDevice, const VkDevice device, const VkImage& image, const MemoryRequirement requirement, Allocator& allocator, AllocationKind allocationKind) { switch (allocationKind) { case ALLOCATION_KIND_SUBALLOCATED: { const VkMemoryRequirements memoryRequirements = getImageMemoryRequirements(vkd, device, image); return allocator.allocate(memoryRequirements, requirement); } case ALLOCATION_KIND_DEDICATED: { return allocateDedicated(vki, vkd, physDevice, device, image, requirement); } default: { TCU_THROW(InternalError, "Invalid allocation kind"); } } } enum BoolOp { BOOLOP_AND, BOOLOP_OR, BOOLOP_EQ, BOOLOP_NEQ }; const char* boolOpToString (BoolOp op) { switch (op) { case BOOLOP_OR: return "||"; case BOOLOP_AND: return "&&"; case BOOLOP_EQ: return "=="; case BOOLOP_NEQ: return "!="; default: DE_FATAL("Unknown boolean operation."); return DE_NULL; } } bool performBoolOp (BoolOp op, bool a, bool b) { switch (op) { case BOOLOP_OR: return a || b; case BOOLOP_AND: return a && b; case BOOLOP_EQ: return a == b; case BOOLOP_NEQ: return a != b; default: DE_FATAL("Unknown boolean operation."); return false; } } BoolOp boolOpFromIndex (size_t index) { const BoolOp ops[] = { BOOLOP_OR, BOOLOP_AND, BOOLOP_EQ, BOOLOP_NEQ }; return ops[index % DE_LENGTH_OF_ARRAY(ops)]; } Move createFramebuffer (const DeviceInterface& vk, VkDevice device, VkFramebufferCreateFlags pCreateInfo_flags, VkRenderPass pCreateInfo_renderPass, deUint32 pCreateInfo_attachmentCount, const VkImageView* pCreateInfo_pAttachments, deUint32 pCreateInfo_width, deUint32 pCreateInfo_height, deUint32 pCreateInfo_layers) { const VkFramebufferCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, DE_NULL, pCreateInfo_flags, pCreateInfo_renderPass, pCreateInfo_attachmentCount, pCreateInfo_pAttachments, pCreateInfo_width, pCreateInfo_height, pCreateInfo_layers, }; return createFramebuffer(vk, device, &pCreateInfo); } Move createImage (const DeviceInterface& vk, VkDevice device, VkImageCreateFlags pCreateInfo_flags, VkImageType pCreateInfo_imageType, VkFormat pCreateInfo_format, VkExtent3D pCreateInfo_extent, deUint32 pCreateInfo_mipLevels, deUint32 pCreateInfo_arrayLayers, VkSampleCountFlagBits pCreateInfo_samples, VkImageTiling pCreateInfo_tiling, VkImageUsageFlags pCreateInfo_usage, VkSharingMode pCreateInfo_sharingMode, deUint32 pCreateInfo_queueFamilyCount, const deUint32* pCreateInfo_pQueueFamilyIndices, VkImageLayout pCreateInfo_initialLayout) { const VkImageCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, DE_NULL, pCreateInfo_flags, pCreateInfo_imageType, pCreateInfo_format, pCreateInfo_extent, pCreateInfo_mipLevels, pCreateInfo_arrayLayers, pCreateInfo_samples, pCreateInfo_tiling, pCreateInfo_usage, pCreateInfo_sharingMode, pCreateInfo_queueFamilyCount, pCreateInfo_pQueueFamilyIndices, pCreateInfo_initialLayout }; return createImage(vk, device, &pCreateInfo); } void bindBufferMemory (const DeviceInterface& vk, VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memOffset) { VK_CHECK(vk.bindBufferMemory(device, buffer, mem, memOffset)); } void bindImageMemory (const DeviceInterface& vk, VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memOffset) { VK_CHECK(vk.bindImageMemory(device, image, mem, memOffset)); } Move createImageView (const DeviceInterface& vk, VkDevice device, VkImageViewCreateFlags pCreateInfo_flags, VkImage pCreateInfo_image, VkImageViewType pCreateInfo_viewType, VkFormat pCreateInfo_format, VkComponentMapping pCreateInfo_components, VkImageSubresourceRange pCreateInfo_subresourceRange) { const VkImageViewCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, DE_NULL, pCreateInfo_flags, pCreateInfo_image, pCreateInfo_viewType, pCreateInfo_format, pCreateInfo_components, pCreateInfo_subresourceRange, }; return createImageView(vk, device, &pCreateInfo); } Move createBuffer (const DeviceInterface& vk, VkDevice device, VkBufferCreateFlags pCreateInfo_flags, VkDeviceSize pCreateInfo_size, VkBufferUsageFlags pCreateInfo_usage, VkSharingMode pCreateInfo_sharingMode, deUint32 pCreateInfo_queueFamilyCount, const deUint32* pCreateInfo_pQueueFamilyIndices) { const VkBufferCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, DE_NULL, pCreateInfo_flags, pCreateInfo_size, pCreateInfo_usage, pCreateInfo_sharingMode, pCreateInfo_queueFamilyCount, pCreateInfo_pQueueFamilyIndices, }; return createBuffer(vk, device, &pCreateInfo); } void cmdBeginRenderPass (const DeviceInterface& vk, VkCommandBuffer cmdBuffer, VkRenderPass pRenderPassBegin_renderPass, VkFramebuffer pRenderPassBegin_framebuffer, VkRect2D pRenderPassBegin_renderArea, deUint32 pRenderPassBegin_clearValueCount, const VkClearValue* pRenderPassBegin_pAttachmentClearValues, VkSubpassContents contents) { const VkRenderPassBeginInfo pRenderPassBegin = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, DE_NULL, pRenderPassBegin_renderPass, pRenderPassBegin_framebuffer, pRenderPassBegin_renderArea, pRenderPassBegin_clearValueCount, pRenderPassBegin_pAttachmentClearValues, }; vk.cmdBeginRenderPass(cmdBuffer, &pRenderPassBegin, contents); } void beginCommandBuffer (const DeviceInterface& vk, VkCommandBuffer cmdBuffer, VkCommandBufferUsageFlags pBeginInfo_flags, VkRenderPass pInheritanceInfo_renderPass, deUint32 pInheritanceInfo_subpass, VkFramebuffer pInheritanceInfo_framebuffer, VkBool32 pInheritanceInfo_occlusionQueryEnable, VkQueryControlFlags pInheritanceInfo_queryFlags, VkQueryPipelineStatisticFlags pInheritanceInfo_pipelineStatistics) { const VkCommandBufferInheritanceInfo pInheritanceInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, DE_NULL, pInheritanceInfo_renderPass, pInheritanceInfo_subpass, pInheritanceInfo_framebuffer, pInheritanceInfo_occlusionQueryEnable, pInheritanceInfo_queryFlags, pInheritanceInfo_pipelineStatistics, }; const VkCommandBufferBeginInfo pBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, DE_NULL, pBeginInfo_flags, &pInheritanceInfo, }; VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &pBeginInfo)); } void endCommandBuffer (const DeviceInterface& vk, VkCommandBuffer cmdBuffer) { VK_CHECK(vk.endCommandBuffer(cmdBuffer)); } void queueSubmit (const DeviceInterface& vk, VkQueue queue, deUint32 cmdBufferCount, const VkCommandBuffer* pCmdBuffers, VkFence fence) { const VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO, DE_NULL, 0u, // waitSemaphoreCount (const VkSemaphore*)DE_NULL, // pWaitSemaphores (const VkPipelineStageFlags*)DE_NULL, cmdBufferCount, // commandBufferCount pCmdBuffers, 0u, // signalSemaphoreCount (const VkSemaphore*)DE_NULL, // pSignalSemaphores }; VK_CHECK(vk.queueSubmit(queue, 1u, &submitInfo, fence)); } void waitForFences (const DeviceInterface& vk, VkDevice device, deUint32 fenceCount, const VkFence* pFences, VkBool32 waitAll, deUint64 timeout) { VK_CHECK(vk.waitForFences(device, fenceCount, pFences, waitAll, timeout)); } VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat) { const tcu::TextureFormat format = mapVkFormat(vkFormat); DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21); switch (format.order) { case tcu::TextureFormat::DS: return VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT; case tcu::TextureFormat::D: return VK_IMAGE_ASPECT_DEPTH_BIT; case tcu::TextureFormat::S: return VK_IMAGE_ASPECT_STENCIL_BIT; default: return VK_IMAGE_ASPECT_COLOR_BIT; } } VkAccessFlags getAllMemoryReadFlags (void) { return VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_HOST_READ_BIT | VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT | VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; } VkAccessFlags getAllMemoryWriteFlags (void) { return VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; } VkAccessFlags getMemoryFlagsForLayout (const VkImageLayout layout) { switch (layout) { case VK_IMAGE_LAYOUT_GENERAL: return getAllMemoryReadFlags() | getAllMemoryWriteFlags(); case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return VK_ACCESS_SHADER_READ_BIT; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return VK_ACCESS_TRANSFER_READ_BIT; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return VK_ACCESS_TRANSFER_WRITE_BIT; case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR: return VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; default: return (VkAccessFlags)0; } } VkPipelineStageFlags getAllPipelineStageFlags (void) { return VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT | VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT | VK_PIPELINE_STAGE_VERTEX_INPUT_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT; } class AttachmentReference { public: AttachmentReference (deUint32 attachment, VkImageLayout layout) : m_attachment (attachment) , m_layout (layout) { } deUint32 getAttachment (void) const { return m_attachment; } VkImageLayout getImageLayout (void) const { return m_layout; } private: deUint32 m_attachment; VkImageLayout m_layout; }; class Subpass { public: Subpass (VkPipelineBindPoint pipelineBindPoint, VkSubpassDescriptionFlags flags, const vector& inputAttachments, const vector& colorAttachments, const vector& resolveAttachments, AttachmentReference depthStencilAttachment, const vector& preserveAttachments) : m_pipelineBindPoint (pipelineBindPoint) , m_flags (flags) , m_inputAttachments (inputAttachments) , m_colorAttachments (colorAttachments) , m_resolveAttachments (resolveAttachments) , m_depthStencilAttachment (depthStencilAttachment) , m_preserveAttachments (preserveAttachments) { } VkPipelineBindPoint getPipelineBindPoint (void) const { return m_pipelineBindPoint; } VkSubpassDescriptionFlags getFlags (void) const { return m_flags; } const vector& getInputAttachments (void) const { return m_inputAttachments; } const vector& getColorAttachments (void) const { return m_colorAttachments; } const vector& getResolveAttachments (void) const { return m_resolveAttachments; } const AttachmentReference& getDepthStencilAttachment (void) const { return m_depthStencilAttachment; } const vector& getPreserveAttachments (void) const { return m_preserveAttachments; } private: VkPipelineBindPoint m_pipelineBindPoint; VkSubpassDescriptionFlags m_flags; vector m_inputAttachments; vector m_colorAttachments; vector m_resolveAttachments; AttachmentReference m_depthStencilAttachment; vector m_preserveAttachments; }; class SubpassDependency { public: SubpassDependency (deUint32 srcPass, deUint32 dstPass, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags outputMask, VkAccessFlags inputMask, VkDependencyFlags flags) : m_srcPass (srcPass) , m_dstPass (dstPass) , m_srcStageMask (srcStageMask) , m_dstStageMask (dstStageMask) , m_outputMask (outputMask) , m_inputMask (inputMask) , m_flags (flags) { } deUint32 getSrcPass (void) const { return m_srcPass; } deUint32 getDstPass (void) const { return m_dstPass; } VkPipelineStageFlags getSrcStageMask (void) const { return m_srcStageMask; } VkPipelineStageFlags getDstStageMask (void) const { return m_dstStageMask; } VkAccessFlags getOutputMask (void) const { return m_outputMask; } VkAccessFlags getInputMask (void) const { return m_inputMask; } VkDependencyFlags getFlags (void) const { return m_flags; } private: deUint32 m_srcPass; deUint32 m_dstPass; VkPipelineStageFlags m_srcStageMask; VkPipelineStageFlags m_dstStageMask; VkAccessFlags m_outputMask; VkAccessFlags m_inputMask; VkDependencyFlags m_flags; }; class Attachment { public: Attachment (VkFormat format, VkSampleCountFlagBits samples, VkAttachmentLoadOp loadOp, VkAttachmentStoreOp storeOp, VkAttachmentLoadOp stencilLoadOp, VkAttachmentStoreOp stencilStoreOp, VkImageLayout initialLayout, VkImageLayout finalLayout) : m_format (format) , m_samples (samples) , m_loadOp (loadOp) , m_storeOp (storeOp) , m_stencilLoadOp (stencilLoadOp) , m_stencilStoreOp (stencilStoreOp) , m_initialLayout (initialLayout) , m_finalLayout (finalLayout) { } VkFormat getFormat (void) const { return m_format; } VkSampleCountFlagBits getSamples (void) const { return m_samples; } VkAttachmentLoadOp getLoadOp (void) const { return m_loadOp; } VkAttachmentStoreOp getStoreOp (void) const { return m_storeOp; } VkAttachmentLoadOp getStencilLoadOp (void) const { return m_stencilLoadOp; } VkAttachmentStoreOp getStencilStoreOp (void) const { return m_stencilStoreOp; } VkImageLayout getInitialLayout (void) const { return m_initialLayout; } VkImageLayout getFinalLayout (void) const { return m_finalLayout; } private: VkFormat m_format; VkSampleCountFlagBits m_samples; VkAttachmentLoadOp m_loadOp; VkAttachmentStoreOp m_storeOp; VkAttachmentLoadOp m_stencilLoadOp; VkAttachmentStoreOp m_stencilStoreOp; VkImageLayout m_initialLayout; VkImageLayout m_finalLayout; }; class RenderPass { public: RenderPass (const vector& attachments, const vector& subpasses, const vector& dependencies, const vector inputAspects = vector()) : m_attachments (attachments) , m_subpasses (subpasses) , m_dependencies (dependencies) , m_inputAspects (inputAspects) { } const vector& getAttachments (void) const { return m_attachments; } const vector& getSubpasses (void) const { return m_subpasses; } const vector& getDependencies (void) const { return m_dependencies; } const vector getInputAspects (void) const { return m_inputAspects; } private: const vector m_attachments; const vector m_subpasses; const vector m_dependencies; const vector m_inputAspects; }; struct TestConfig { enum RenderTypes { RENDERTYPES_NONE = 0, RENDERTYPES_CLEAR = (1<<1), RENDERTYPES_DRAW = (1<<2) }; enum CommandBufferTypes { COMMANDBUFFERTYPES_INLINE = (1<<0), COMMANDBUFFERTYPES_SECONDARY = (1<<1) }; enum ImageMemory { IMAGEMEMORY_STRICT = (1<<0), IMAGEMEMORY_LAZY = (1<<1) }; TestConfig (const RenderPass& renderPass_, RenderTypes renderTypes_, CommandBufferTypes commandBufferTypes_, ImageMemory imageMemory_, const UVec2& targetSize_, const UVec2& renderPos_, const UVec2& renderSize_, deUint32 seed_, AllocationKind allocationKind_) : renderPass (renderPass_) , renderTypes (renderTypes_) , commandBufferTypes (commandBufferTypes_) , imageMemory (imageMemory_) , targetSize (targetSize_) , renderPos (renderPos_) , renderSize (renderSize_) , seed (seed_) , allocationKind (allocationKind_) { } RenderPass renderPass; RenderTypes renderTypes; CommandBufferTypes commandBufferTypes; ImageMemory imageMemory; UVec2 targetSize; UVec2 renderPos; UVec2 renderSize; deUint32 seed; AllocationKind allocationKind; }; TestConfig::RenderTypes operator| (TestConfig::RenderTypes a, TestConfig::RenderTypes b) { return (TestConfig::RenderTypes)(((deUint32)a) | ((deUint32)b)); } TestConfig::CommandBufferTypes operator| (TestConfig::CommandBufferTypes a, TestConfig::CommandBufferTypes b) { return (TestConfig::CommandBufferTypes)(((deUint32)a) | ((deUint32)b)); } TestConfig::ImageMemory operator| (TestConfig::ImageMemory a, TestConfig::ImageMemory b) { return (TestConfig::ImageMemory)(((deUint32)a) | ((deUint32)b)); } void logRenderPassInfo (TestLog& log, const RenderPass& renderPass) { const tcu::ScopedLogSection section (log, "RenderPass", "RenderPass"); { const tcu::ScopedLogSection attachmentsSection (log, "Attachments", "Attachments"); const vector& attachments = renderPass.getAttachments(); for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { const tcu::ScopedLogSection attachmentSection (log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx)); const Attachment& attachment = attachments[attachmentNdx]; log << TestLog::Message << "Format: " << attachment.getFormat() << TestLog::EndMessage; log << TestLog::Message << "Samples: " << attachment.getSamples() << TestLog::EndMessage; log << TestLog::Message << "LoadOp: " << attachment.getLoadOp() << TestLog::EndMessage; log << TestLog::Message << "StoreOp: " << attachment.getStoreOp() << TestLog::EndMessage; log << TestLog::Message << "StencilLoadOp: " << attachment.getStencilLoadOp() << TestLog::EndMessage; log << TestLog::Message << "StencilStoreOp: " << attachment.getStencilStoreOp() << TestLog::EndMessage; log << TestLog::Message << "InitialLayout: " << attachment.getInitialLayout() << TestLog::EndMessage; log << TestLog::Message << "FinalLayout: " << attachment.getFinalLayout() << TestLog::EndMessage; } } if (!renderPass.getInputAspects().empty()) { const tcu::ScopedLogSection inputAspectSection (log, "InputAspects", "InputAspects"); for (size_t aspectNdx = 0; aspectNdx < renderPass.getInputAspects().size(); aspectNdx++) { const VkInputAttachmentAspectReferenceKHR& inputAspect (renderPass.getInputAspects()[aspectNdx]); log << TestLog::Message << "Subpass: " << inputAspect.subpass << TestLog::EndMessage; log << TestLog::Message << "InputAttachmentIndex: " << inputAspect.inputAttachmentIndex << TestLog::EndMessage; log << TestLog::Message << "AspectFlags: " << getImageAspectFlagsStr(inputAspect.aspectMask) << TestLog::EndMessage; } } { const tcu::ScopedLogSection subpassesSection (log, "Subpasses", "Subpasses"); const vector& subpasses = renderPass.getSubpasses(); for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++) { const tcu::ScopedLogSection subpassSection (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx)); const Subpass& subpass = subpasses[subpassNdx]; const vector& inputAttachments = subpass.getInputAttachments(); const vector& colorAttachments = subpass.getColorAttachments(); const vector& resolveAttachments = subpass.getResolveAttachments(); const vector& preserveAttachments = subpass.getPreserveAttachments(); if (!inputAttachments.empty()) { const tcu::ScopedLogSection inputAttachmentsSection (log, "Inputs", "Inputs"); for (size_t inputNdx = 0; inputNdx < inputAttachments.size(); inputNdx++) { const tcu::ScopedLogSection inputAttachmentSection (log, "Input" + de::toString(inputNdx), "Input " + de::toString(inputNdx)); const AttachmentReference& inputAttachment = inputAttachments[inputNdx]; log << TestLog::Message << "Attachment: " << inputAttachment.getAttachment() << TestLog::EndMessage; log << TestLog::Message << "Layout: " << inputAttachment.getImageLayout() << TestLog::EndMessage; } } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED) { const tcu::ScopedLogSection depthStencilAttachmentSection (log, "DepthStencil", "DepthStencil"); const AttachmentReference& depthStencilAttachment = subpass.getDepthStencilAttachment(); log << TestLog::Message << "Attachment: " << depthStencilAttachment.getAttachment() << TestLog::EndMessage; log << TestLog::Message << "Layout: " << depthStencilAttachment.getImageLayout() << TestLog::EndMessage; } if (!colorAttachments.empty()) { const tcu::ScopedLogSection colorAttachmentsSection (log, "Colors", "Colors"); for (size_t colorNdx = 0; colorNdx < colorAttachments.size(); colorNdx++) { const tcu::ScopedLogSection colorAttachmentSection (log, "Color" + de::toString(colorNdx), "Color " + de::toString(colorNdx)); const AttachmentReference& colorAttachment = colorAttachments[colorNdx]; log << TestLog::Message << "Attachment: " << colorAttachment.getAttachment() << TestLog::EndMessage; log << TestLog::Message << "Layout: " << colorAttachment.getImageLayout() << TestLog::EndMessage; } } if (!resolveAttachments.empty()) { const tcu::ScopedLogSection resolveAttachmentsSection (log, "Resolves", "Resolves"); for (size_t resolveNdx = 0; resolveNdx < resolveAttachments.size(); resolveNdx++) { const tcu::ScopedLogSection resolveAttachmentSection (log, "Resolve" + de::toString(resolveNdx), "Resolve " + de::toString(resolveNdx)); const AttachmentReference& resolveAttachment = resolveAttachments[resolveNdx]; log << TestLog::Message << "Attachment: " << resolveAttachment.getAttachment() << TestLog::EndMessage; log << TestLog::Message << "Layout: " << resolveAttachment.getImageLayout() << TestLog::EndMessage; } } if (!preserveAttachments.empty()) { const tcu::ScopedLogSection preserveAttachmentsSection (log, "Preserves", "Preserves"); for (size_t preserveNdx = 0; preserveNdx < preserveAttachments.size(); preserveNdx++) { const tcu::ScopedLogSection preserveAttachmentSection (log, "Preserve" + de::toString(preserveNdx), "Preserve " + de::toString(preserveNdx)); const deUint32 preserveAttachment = preserveAttachments[preserveNdx]; log << TestLog::Message << "Attachment: " << preserveAttachment << TestLog::EndMessage; } } } } if (!renderPass.getDependencies().empty()) { const tcu::ScopedLogSection dependenciesSection (log, "Dependencies", "Dependencies"); for (size_t depNdx = 0; depNdx < renderPass.getDependencies().size(); depNdx++) { const tcu::ScopedLogSection dependencySection (log, "Dependency" + de::toString(depNdx), "Dependency " + de::toString(depNdx)); const SubpassDependency& dep = renderPass.getDependencies()[depNdx]; log << TestLog::Message << "Source: " << dep.getSrcPass() << TestLog::EndMessage; log << TestLog::Message << "Destination: " << dep.getDstPass() << TestLog::EndMessage; log << TestLog::Message << "Source Stage Mask: " << dep.getSrcStageMask() << TestLog::EndMessage; log << TestLog::Message << "Destination Stage Mask: " << dep.getDstStageMask() << TestLog::EndMessage; log << TestLog::Message << "Input Mask: " << dep.getInputMask() << TestLog::EndMessage; log << TestLog::Message << "Output Mask: " << dep.getOutputMask() << TestLog::EndMessage; log << TestLog::Message << "Dependency Flags: " << getDependencyFlagsStr(dep.getFlags()) << TestLog::EndMessage; } } } std::string clearColorToString (VkFormat vkFormat, VkClearColorValue value) { const tcu::TextureFormat format = mapVkFormat(vkFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format); std::ostringstream stream; stream << "("; switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: for (int i = 0; i < 4; i++) { if (i > 0) stream << ", "; if (channelMask[i]) stream << value.int32[i]; else stream << "Undef"; } break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: for (int i = 0; i < 4; i++) { if (i > 0) stream << ", "; if (channelMask[i]) stream << value.uint32[i]; else stream << "Undef"; } break; case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: for (int i = 0; i < 4; i++) { if (i > 0) stream << ", "; if (channelMask[i]) stream << value.float32[i]; else stream << "Undef"; } break; default: DE_FATAL("Unknown channel class"); } stream << ")"; return stream.str(); } std::string clearValueToString (VkFormat vkFormat, VkClearValue value) { const tcu::TextureFormat format = mapVkFormat(vkFormat); if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order)) { std::ostringstream stream; stream << "("; if (tcu::hasStencilComponent(format.order)) stream << "stencil: " << value.depthStencil.stencil; if (tcu::hasStencilComponent(format.order) && tcu::hasDepthComponent(format.order)) stream << ", "; if (tcu::hasDepthComponent(format.order)) stream << "depth: " << value.depthStencil.depth; stream << ")"; return stream.str(); } else return clearColorToString(vkFormat, value.color); } VkClearColorValue randomColorClearValue (const Attachment& attachment, de::Random& rng) { const float clearNan = tcu::Float32::nan().asFloat(); const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format); VkClearColorValue clearColor; switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: { for (int ndx = 0; ndx < 4; ndx++) { if (!channelMask[ndx]) clearColor.int32[ndx] = std::numeric_limits::min(); else clearColor.uint32[ndx] = rng.getBool() ? 1u : 0u; } break; } case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: { for (int ndx = 0; ndx < 4; ndx++) { if (!channelMask[ndx]) clearColor.uint32[ndx] = std::numeric_limits::max(); else clearColor.uint32[ndx] = rng.getBool() ? 1u : 0u; } break; } case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: { for (int ndx = 0; ndx < 4; ndx++) { if (!channelMask[ndx]) clearColor.float32[ndx] = clearNan; else clearColor.float32[ndx] = rng.getBool() ? 1.0f : 0.0f; } break; } default: DE_FATAL("Unknown channel class"); } return clearColor; } VkAttachmentDescription createAttachmentDescription (const Attachment& attachment) { const VkAttachmentDescription attachmentDescription = { 0, // flags attachment.getFormat(), // format attachment.getSamples(), // samples attachment.getLoadOp(), // loadOp attachment.getStoreOp(), // storeOp attachment.getStencilLoadOp(), // stencilLoadOp attachment.getStencilStoreOp(), // stencilStoreOp attachment.getInitialLayout(), // initialLayout attachment.getFinalLayout(), // finalLayout }; return attachmentDescription; } VkAttachmentReference createAttachmentReference (const AttachmentReference& referenceInfo) { const VkAttachmentReference reference = { referenceInfo.getAttachment(), // attachment; referenceInfo.getImageLayout() // layout; }; return reference; } VkSubpassDescription createSubpassDescription (const Subpass& subpass, vector* attachmentReferenceLists, vector* preserveAttachmentReferences) { vector& inputAttachmentReferences = attachmentReferenceLists[0]; vector& colorAttachmentReferences = attachmentReferenceLists[1]; vector& resolveAttachmentReferences = attachmentReferenceLists[2]; vector& depthStencilAttachmentReferences = attachmentReferenceLists[3]; for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) colorAttachmentReferences.push_back(createAttachmentReference(subpass.getColorAttachments()[attachmentNdx])); for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++) inputAttachmentReferences.push_back(createAttachmentReference(subpass.getInputAttachments()[attachmentNdx])); for (size_t attachmentNdx = 0; attachmentNdx < subpass.getResolveAttachments().size(); attachmentNdx++) resolveAttachmentReferences.push_back(createAttachmentReference(subpass.getResolveAttachments()[attachmentNdx])); depthStencilAttachmentReferences.push_back(createAttachmentReference(subpass.getDepthStencilAttachment())); for (size_t attachmentNdx = 0; attachmentNdx < subpass.getPreserveAttachments().size(); attachmentNdx++) preserveAttachmentReferences->push_back(subpass.getPreserveAttachments()[attachmentNdx]); DE_ASSERT(resolveAttachmentReferences.empty() || colorAttachmentReferences.size() == resolveAttachmentReferences.size()); { const VkSubpassDescription subpassDescription = { subpass.getFlags(), // flags; subpass.getPipelineBindPoint(), // pipelineBindPoint; (deUint32)inputAttachmentReferences.size(), // inputCount; inputAttachmentReferences.empty() ? DE_NULL : &inputAttachmentReferences[0], // inputAttachments; (deUint32)colorAttachmentReferences.size(), // colorCount; colorAttachmentReferences.empty() ? DE_NULL : &colorAttachmentReferences[0], // colorAttachments; resolveAttachmentReferences.empty() ? DE_NULL : &resolveAttachmentReferences[0], // resolveAttachments; &depthStencilAttachmentReferences[0], // pDepthStencilAttachment; (deUint32)preserveAttachmentReferences->size(), // preserveCount; preserveAttachmentReferences->empty() ? DE_NULL : &(*preserveAttachmentReferences)[0] // preserveAttachments; }; return subpassDescription; } } VkSubpassDependency createSubpassDependency (const SubpassDependency& dependencyInfo) { const VkSubpassDependency dependency = { dependencyInfo.getSrcPass(), // srcSubpass; dependencyInfo.getDstPass(), // destSubpass; dependencyInfo.getSrcStageMask(), // srcStageMask; dependencyInfo.getDstStageMask(), // destStageMask; dependencyInfo.getOutputMask(), // outputMask; dependencyInfo.getInputMask(), // inputMask; dependencyInfo.getFlags() // dependencyFlags; }; return dependency; } Move createRenderPass (const DeviceInterface& vk, VkDevice device, const RenderPass& renderPassInfo) { const size_t perSubpassAttachmentReferenceLists = 4; vector attachments; vector subpasses; vector dependencies; vector > attachmentReferenceLists(renderPassInfo.getSubpasses().size() * perSubpassAttachmentReferenceLists); vector > preserveAttachments(renderPassInfo.getSubpasses().size()); for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) attachments.push_back(createAttachmentDescription(renderPassInfo.getAttachments()[attachmentNdx])); for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++) subpasses.push_back(createSubpassDescription(renderPassInfo.getSubpasses()[subpassNdx], &(attachmentReferenceLists[subpassNdx * perSubpassAttachmentReferenceLists]), &preserveAttachments[subpassNdx])); for (size_t depNdx = 0; depNdx < renderPassInfo.getDependencies().size(); depNdx++) dependencies.push_back(createSubpassDependency(renderPassInfo.getDependencies()[depNdx])); if (renderPassInfo.getInputAspects().empty()) { const VkRenderPassCreateInfo createInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, DE_NULL, (VkRenderPassCreateFlags)0u, (deUint32)attachments.size(), (attachments.empty() ? DE_NULL : &attachments[0]), (deUint32)subpasses.size(), (subpasses.empty() ? DE_NULL : &subpasses[0]), (deUint32)dependencies.size(), (dependencies.empty() ? DE_NULL : &dependencies[0]) }; return createRenderPass(vk, device, &createInfo); } else { const VkRenderPassInputAttachmentAspectCreateInfoKHR inputAspectCreateInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR, DE_NULL, (deUint32)renderPassInfo.getInputAspects().size(), renderPassInfo.getInputAspects().data(), }; const VkRenderPassCreateInfo createInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, &inputAspectCreateInfo, (VkRenderPassCreateFlags)0u, (deUint32)attachments.size(), (attachments.empty() ? DE_NULL : &attachments[0]), (deUint32)subpasses.size(), (subpasses.empty() ? DE_NULL : &subpasses[0]), (deUint32)dependencies.size(), (dependencies.empty() ? DE_NULL : &dependencies[0]) }; return createRenderPass(vk, device, &createInfo); } } Move createFramebuffer (const DeviceInterface& vk, VkDevice device, VkRenderPass renderPass, const UVec2& size, const vector& attachments) { return createFramebuffer(vk, device, 0u, renderPass, (deUint32)attachments.size(), attachments.empty() ? DE_NULL : &attachments[0], size.x(), size.y(), 1u); } Move createAttachmentImage (const DeviceInterface& vk, VkDevice device, deUint32 queueIndex, const UVec2& size, VkFormat format, VkSampleCountFlagBits samples, VkImageUsageFlags usageFlags, VkImageLayout layout) { VkImageUsageFlags targetUsageFlags = 0; const tcu::TextureFormat textureFormat = mapVkFormat(format); DE_ASSERT(!(tcu::hasDepthComponent(vk::mapVkFormat(format).order) || tcu::hasStencilComponent(vk::mapVkFormat(format).order)) || ((usageFlags & vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0)); DE_ASSERT((tcu::hasDepthComponent(vk::mapVkFormat(format).order) || tcu::hasStencilComponent(vk::mapVkFormat(format).order)) || ((usageFlags & vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0)); if (tcu::hasDepthComponent(textureFormat.order) || tcu::hasStencilComponent(textureFormat.order)) targetUsageFlags |= vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; else targetUsageFlags |= vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; return createImage(vk, device, (VkImageCreateFlags)0, VK_IMAGE_TYPE_2D, format, vk::makeExtent3D(size.x(), size.y(), 1u), 1u /* mipLevels */, 1u /* arraySize */, samples, VK_IMAGE_TILING_OPTIMAL, usageFlags | targetUsageFlags, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex, layout); } de::MovePtr createImageMemory (const InstanceInterface& vki, const VkPhysicalDevice& vkd, const DeviceInterface& vk, VkDevice device, Allocator& allocator, VkImage image, bool lazy, AllocationKind allocationKind) { const MemoryRequirement memoryRequirement = lazy ? MemoryRequirement::LazilyAllocated : MemoryRequirement::Any; de::MovePtr allocation = allocateImage(vki, vk, vkd, device, image, memoryRequirement, allocator, allocationKind); bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset()); return allocation; } Move createImageAttachmentView (const DeviceInterface& vk, VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect) { const VkImageSubresourceRange range = { aspect, 0, 1, 0, 1 }; return createImageView(vk, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range); } VkClearValue randomClearValue (const Attachment& attachment, de::Random& rng) { const float clearNan = tcu::Float32::nan().asFloat(); const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); if (tcu::hasStencilComponent(format.order) || tcu::hasDepthComponent(format.order)) { VkClearValue clearValue; clearValue.depthStencil.depth = clearNan; clearValue.depthStencil.stencil = 0xCDu; if (tcu::hasStencilComponent(format.order)) clearValue.depthStencil.stencil = rng.getBool() ? 0xFFu : 0x0u; if (tcu::hasDepthComponent(format.order)) clearValue.depthStencil.depth = rng.getBool() ? 1.0f : 0.0f; return clearValue; } else { VkClearValue clearValue; clearValue.color = randomColorClearValue(attachment, rng); return clearValue; } } class AttachmentResources { public: AttachmentResources (const InstanceInterface& vki, const VkPhysicalDevice& physDevice, const DeviceInterface& vk, VkDevice device, Allocator& allocator, deUint32 queueIndex, const UVec2& size, const Attachment& attachmentInfo, VkImageUsageFlags usageFlags, const AllocationKind allocationKind) : m_image (createAttachmentImage(vk, device, queueIndex, size, attachmentInfo.getFormat(), attachmentInfo.getSamples(), usageFlags, VK_IMAGE_LAYOUT_UNDEFINED)) , m_imageMemory (createImageMemory(vki, physDevice, vk, device, allocator, *m_image, ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) != 0), allocationKind)) , m_attachmentView (createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), getImageAspectFlags(attachmentInfo.getFormat()))) { const tcu::TextureFormat format = mapVkFormat(attachmentInfo.getFormat()); const bool isDepthFormat = tcu::hasDepthComponent(format.order); const bool isStencilFormat = tcu::hasStencilComponent(format.order); if (isDepthFormat && isStencilFormat) { m_depthInputAttachmentView = createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), VK_IMAGE_ASPECT_DEPTH_BIT); m_stencilInputAttachmentView = createImageAttachmentView(vk, device, *m_image, attachmentInfo.getFormat(), VK_IMAGE_ASPECT_STENCIL_BIT); m_inputAttachmentViews = std::make_pair(*m_depthInputAttachmentView, *m_stencilInputAttachmentView); } else m_inputAttachmentViews = std::make_pair(*m_attachmentView, (vk::VkImageView)0u); if ((usageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) == 0) { if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order)) { const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachmentInfo.getFormat()); const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachmentInfo.getFormat()); m_bufferSize = size.x() * size.y() * depthFormat.getPixelSize(); m_secondaryBufferSize = size.x() * size.y() * stencilFormat.getPixelSize(); m_buffer = createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex); m_bufferMemory = allocateBuffer(vki, vk, physDevice, device, *m_buffer, MemoryRequirement::HostVisible, allocator, allocationKind); bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset()); m_secondaryBuffer = createBuffer(vk, device, 0, m_secondaryBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex); m_secondaryBufferMemory = allocateBuffer(vki, vk, physDevice, device, *m_secondaryBuffer, MemoryRequirement::HostVisible, allocator, allocationKind); bindBufferMemory(vk, device, *m_secondaryBuffer, m_secondaryBufferMemory->getMemory(), m_secondaryBufferMemory->getOffset()); } else { m_bufferSize = size.x() * size.y() * format.getPixelSize(); m_buffer = createBuffer(vk, device, 0, m_bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_SHARING_MODE_EXCLUSIVE, 1, &queueIndex); m_bufferMemory = allocateBuffer(vki, vk, physDevice, device, *m_buffer, MemoryRequirement::HostVisible, allocator, allocationKind); bindBufferMemory(vk, device, *m_buffer, m_bufferMemory->getMemory(), m_bufferMemory->getOffset()); } } } const pair& getInputAttachmentViews (void) const { return m_inputAttachmentViews; } ~AttachmentResources (void) { } VkImageView getAttachmentView (void) const { return *m_attachmentView; } VkImage getImage (void) const { return *m_image; } VkBuffer getBuffer (void) const { DE_ASSERT(*m_buffer != DE_NULL); return *m_buffer; } VkDeviceSize getBufferSize (void) const { DE_ASSERT(*m_buffer != DE_NULL); return m_bufferSize; } const Allocation& getResultMemory (void) const { DE_ASSERT(m_bufferMemory); return *m_bufferMemory; } VkBuffer getSecondaryBuffer (void) const { DE_ASSERT(*m_secondaryBuffer != DE_NULL); return *m_secondaryBuffer; } VkDeviceSize getSecondaryBufferSize (void) const { DE_ASSERT(*m_secondaryBuffer != DE_NULL); return m_secondaryBufferSize; } const Allocation& getSecondaryResultMemory (void) const { DE_ASSERT(m_secondaryBufferMemory); return *m_secondaryBufferMemory; } private: const Unique m_image; const UniquePtr m_imageMemory; const Unique m_attachmentView; Move m_depthInputAttachmentView; Move m_stencilInputAttachmentView; pair m_inputAttachmentViews; Move m_buffer; VkDeviceSize m_bufferSize; de::MovePtr m_bufferMemory; Move m_secondaryBuffer; VkDeviceSize m_secondaryBufferSize; de::MovePtr m_secondaryBufferMemory; }; void uploadBufferData (const DeviceInterface& vk, VkDevice device, const Allocation& memory, size_t size, const void* data) { const VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType; DE_NULL, // pNext; memory.getMemory(), // mem; memory.getOffset(), // offset; (VkDeviceSize)size // size; }; void* const ptr = memory.getHostPtr(); deMemcpy(ptr, data, size); VK_CHECK(vk.flushMappedMemoryRanges(device, 1, &range)); } VkImageAspectFlagBits getPrimaryImageAspect (tcu::TextureFormat::ChannelOrder order) { DE_STATIC_ASSERT(tcu::TextureFormat::CHANNELORDER_LAST == 21); switch (order) { case tcu::TextureFormat::D: case tcu::TextureFormat::DS: return VK_IMAGE_ASPECT_DEPTH_BIT; case tcu::TextureFormat::S: return VK_IMAGE_ASPECT_STENCIL_BIT; default: return VK_IMAGE_ASPECT_COLOR_BIT; } } class RenderQuad { public: RenderQuad (const Vec2& posA, const Vec2& posB) : m_vertices(6) { m_vertices[0] = posA; m_vertices[1] = Vec2(posA[0], posB[1]); m_vertices[2] = posB; m_vertices[3] = posB; m_vertices[4] = Vec2(posB[0], posA[1]); m_vertices[5] = posA; } const Vec2& getCornerA (void) const { return m_vertices[0]; } const Vec2& getCornerB (void) const { return m_vertices[2]; } const void* getVertexPointer (void) const { return &m_vertices[0]; } size_t getVertexDataSize (void) const { return sizeof(Vec2) * m_vertices.size(); } private: vector m_vertices; }; class ColorClear { public: ColorClear (const UVec2& offset, const UVec2& size, const VkClearColorValue& color) : m_offset (offset) , m_size (size) , m_color (color) { } const UVec2& getOffset (void) const { return m_offset; } const UVec2& getSize (void) const { return m_size; } const VkClearColorValue& getColor (void) const { return m_color; } private: UVec2 m_offset; UVec2 m_size; VkClearColorValue m_color; }; class DepthStencilClear { public: DepthStencilClear (const UVec2& offset, const UVec2& size, float depth, deUint32 stencil) : m_offset (offset) , m_size (size) , m_depth (depth) , m_stencil (stencil) { } const UVec2& getOffset (void) const { return m_offset; } const UVec2& getSize (void) const { return m_size; } float getDepth (void) const { return m_depth; } deUint32 getStencil (void) const { return m_stencil; } private: const UVec2 m_offset; const UVec2 m_size; const float m_depth; const deUint32 m_stencil; }; class SubpassRenderInfo { public: SubpassRenderInfo (const RenderPass& renderPass, deUint32 subpassIndex, bool isSecondary_, const UVec2& viewportOffset, const UVec2& viewportSize, const Maybe& renderQuad, const vector& colorClears, const Maybe& depthStencilClear) : m_viewportOffset (viewportOffset) , m_viewportSize (viewportSize) , m_subpassIndex (subpassIndex) , m_isSecondary (isSecondary_) , m_flags (renderPass.getSubpasses()[subpassIndex].getFlags()) , m_renderQuad (renderQuad) , m_colorClears (colorClears) , m_depthStencilClear (depthStencilClear) , m_colorAttachments (renderPass.getSubpasses()[subpassIndex].getColorAttachments()) , m_inputAttachments (renderPass.getSubpasses()[subpassIndex].getInputAttachments()) { for (deUint32 attachmentNdx = 0; attachmentNdx < (deUint32)m_colorAttachments.size(); attachmentNdx++) m_colorAttachmentInfo.push_back(renderPass.getAttachments()[m_colorAttachments[attachmentNdx].getAttachment()]); if (renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED) { m_depthStencilAttachment = tcu::just(renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment()); m_depthStencilAttachmentInfo = tcu::just(renderPass.getAttachments()[renderPass.getSubpasses()[subpassIndex].getDepthStencilAttachment().getAttachment()]); } } const UVec2& getViewportOffset (void) const { return m_viewportOffset; } const UVec2& getViewportSize (void) const { return m_viewportSize; } deUint32 getSubpassIndex (void) const { return m_subpassIndex; } bool isSecondary (void) const { return m_isSecondary; } const Maybe& getRenderQuad (void) const { return m_renderQuad; } const vector& getColorClears (void) const { return m_colorClears; } const Maybe& getDepthStencilClear (void) const { return m_depthStencilClear; } deUint32 getInputAttachmentCount (void) const { return (deUint32)m_inputAttachments.size(); } deUint32 getInputAttachmentIndex (deUint32 attachmentNdx) const { return m_inputAttachments[attachmentNdx].getAttachment(); } VkImageLayout getInputAttachmentLayout (deUint32 attachmentNdx) const { return m_inputAttachments[attachmentNdx].getImageLayout(); } deUint32 getColorAttachmentCount (void) const { return (deUint32)m_colorAttachments.size(); } VkImageLayout getColorAttachmentLayout (deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getImageLayout(); } deUint32 getColorAttachmentIndex (deUint32 attachmentNdx) const { return m_colorAttachments[attachmentNdx].getAttachment(); } const Attachment& getColorAttachment (deUint32 attachmentNdx) const { return m_colorAttachmentInfo[attachmentNdx]; } Maybe getDepthStencilAttachmentLayout (void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getImageLayout()) : tcu::nothing(); } Maybe getDepthStencilAttachmentIndex (void) const { return m_depthStencilAttachment ? tcu::just(m_depthStencilAttachment->getAttachment()) : tcu::nothing(); }; const Maybe& getDepthStencilAttachment (void) const { return m_depthStencilAttachmentInfo; } VkSubpassDescriptionFlags getSubpassFlags (void) const { return m_flags; } private: UVec2 m_viewportOffset; UVec2 m_viewportSize; deUint32 m_subpassIndex; bool m_isSecondary; VkSubpassDescriptionFlags m_flags; Maybe m_renderQuad; vector m_colorClears; Maybe m_depthStencilClear; vector m_colorAttachments; vector m_colorAttachmentInfo; Maybe m_depthStencilAttachment; Maybe m_depthStencilAttachmentInfo; vector m_inputAttachments; }; Move createSubpassPipeline (const DeviceInterface& vk, VkDevice device, VkRenderPass renderPass, VkShaderModule vertexShaderModule, VkShaderModule fragmentShaderModule, VkPipelineLayout pipelineLayout, const SubpassRenderInfo& renderInfo) { const VkSpecializationInfo emptyShaderSpecializations = { 0u, // mapEntryCount DE_NULL, // pMap 0u, // dataSize DE_NULL, // pData }; Maybe rasterSamples; vector attachmentBlendStates; for (deUint32 attachmentNdx = 0; attachmentNdx < renderInfo.getColorAttachmentCount(); attachmentNdx++) { const Attachment& attachment = renderInfo.getColorAttachment(attachmentNdx); DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples()); rasterSamples = attachment.getSamples(); { const VkPipelineColorBlendAttachmentState attachmentBlendState = { VK_FALSE, // blendEnable VK_BLEND_FACTOR_SRC_ALPHA, // srcBlendColor VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // destBlendColor VK_BLEND_OP_ADD, // blendOpColor VK_BLEND_FACTOR_ONE, // srcBlendAlpha VK_BLEND_FACTOR_ONE, // destBlendAlpha VK_BLEND_OP_ADD, // blendOpAlpha VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT, // channelWriteMask }; attachmentBlendStates.push_back(attachmentBlendState); } } if (renderInfo.getDepthStencilAttachment()) { const Attachment& attachment = *renderInfo.getDepthStencilAttachment(); DE_ASSERT(!rasterSamples || *rasterSamples == attachment.getSamples()); rasterSamples = attachment.getSamples(); } // If there are no attachment use single sample if (!rasterSamples) rasterSamples = VK_SAMPLE_COUNT_1_BIT; const VkPipelineShaderStageCreateInfo shaderStages[2] = { { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineShaderStageCreateFlags)0u, VK_SHADER_STAGE_VERTEX_BIT, // stage vertexShaderModule, // shader "main", &emptyShaderSpecializations }, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineShaderStageCreateFlags)0u, VK_SHADER_STAGE_FRAGMENT_BIT, // stage fragmentShaderModule, // shader "main", &emptyShaderSpecializations } }; const VkVertexInputBindingDescription vertexBinding = { 0u, // binding (deUint32)sizeof(tcu::Vec2), // strideInBytes VK_VERTEX_INPUT_RATE_VERTEX, // stepRate }; const VkVertexInputAttributeDescription vertexAttrib = { 0u, // location 0u, // binding VK_FORMAT_R32G32_SFLOAT, // format 0u, // offsetInBytes }; const VkPipelineVertexInputStateCreateInfo vertexInputState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineVertexInputStateCreateFlags)0u, 1u, // bindingCount &vertexBinding, // pVertexBindingDescriptions 1u, // attributeCount &vertexAttrib, // pVertexAttributeDescriptions }; const VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineInputAssemblyStateCreateFlags)0u, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // topology VK_FALSE, // primitiveRestartEnable }; const VkViewport viewport = { (float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y(), (float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y(), 0.0f, 1.0f }; const VkRect2D scissor = { { (deInt32)renderInfo.getViewportOffset().x(), (deInt32)renderInfo.getViewportOffset().y() }, { renderInfo.getViewportSize().x(), renderInfo.getViewportSize().y() } }; const VkPipelineViewportStateCreateInfo viewportState = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, DE_NULL, (VkPipelineViewportStateCreateFlags)0u, 1u, &viewport, 1u, &scissor }; const VkPipelineRasterizationStateCreateInfo rasterState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineRasterizationStateCreateFlags)0u, VK_TRUE, // depthClipEnable VK_FALSE, // rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // fillMode VK_CULL_MODE_NONE, // cullMode VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace VK_FALSE, // depthBiasEnable 0.0f, // depthBias 0.0f, // depthBiasClamp 0.0f, // slopeScaledDepthBias 1.0f // lineWidth }; const VkPipelineMultisampleStateCreateInfo multisampleState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineMultisampleStateCreateFlags)0u, *rasterSamples, // rasterSamples VK_FALSE, // sampleShadingEnable 0.0f, // minSampleShading DE_NULL, // pSampleMask VK_FALSE, // alphaToCoverageEnable VK_FALSE, // alphaToOneEnable }; const size_t stencilIndex = renderInfo.getSubpassIndex(); const VkBool32 writeDepth = renderInfo.getDepthStencilAttachmentLayout() && *renderInfo.getDepthStencilAttachmentLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && *renderInfo.getDepthStencilAttachmentLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR ? VK_TRUE : VK_FALSE; const VkBool32 writeStencil = renderInfo.getDepthStencilAttachmentLayout() && *renderInfo.getDepthStencilAttachmentLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && *renderInfo.getDepthStencilAttachmentLayout() != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR ? VK_TRUE : VK_FALSE; const VkPipelineDepthStencilStateCreateInfo depthStencilState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineDepthStencilStateCreateFlags)0u, writeDepth, // depthTestEnable writeDepth, // depthWriteEnable VK_COMPARE_OP_ALWAYS, // depthCompareOp VK_FALSE, // depthBoundsEnable writeStencil, // stencilTestEnable { VK_STENCIL_OP_REPLACE, // stencilFailOp VK_STENCIL_OP_REPLACE, // stencilPassOp VK_STENCIL_OP_REPLACE, // stencilDepthFailOp VK_COMPARE_OP_ALWAYS, // stencilCompareOp ~0u, // stencilCompareMask ~0u, // stencilWriteMask ((stencilIndex % 2) == 0) ? ~0x0u : 0x0u // stencilReference }, // front { VK_STENCIL_OP_REPLACE, // stencilFailOp VK_STENCIL_OP_REPLACE, // stencilPassOp VK_STENCIL_OP_REPLACE, // stencilDepthFailOp VK_COMPARE_OP_ALWAYS, // stencilCompareOp ~0u, // stencilCompareMask ~0u, // stencilWriteMask ((stencilIndex % 2) == 0) ? ~0x0u : 0x0u // stencilReference }, // back 0.0f, // minDepthBounds; 1.0f // maxDepthBounds; }; const VkPipelineColorBlendStateCreateInfo blendState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineColorBlendStateCreateFlags)0u, VK_FALSE, // logicOpEnable VK_LOGIC_OP_COPY, // logicOp (deUint32)attachmentBlendStates.size(), // attachmentCount attachmentBlendStates.empty() ? DE_NULL : &attachmentBlendStates[0],// pAttachments { 0.0f, 0.0f, 0.0f, 0.0f } // blendConst }; const VkGraphicsPipelineCreateInfo createInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // sType DE_NULL, // pNext (VkPipelineCreateFlags)0u, 2, // stageCount shaderStages, // pStages &vertexInputState, // pVertexInputState &inputAssemblyState, // pInputAssemblyState DE_NULL, // pTessellationState &viewportState, // pViewportState &rasterState, // pRasterState &multisampleState, // pMultisampleState &depthStencilState, // pDepthStencilState &blendState, // pColorBlendState (const VkPipelineDynamicStateCreateInfo*)DE_NULL, // pDynamicState pipelineLayout, // layout renderPass, // renderPass renderInfo.getSubpassIndex(), // subpass DE_NULL, // basePipelineHandle 0u // basePipelineIndex }; return createGraphicsPipeline(vk, device, DE_NULL, &createInfo); } class SubpassRenderer { public: SubpassRenderer (Context& context, const DeviceInterface& vk, VkDevice device, Allocator& allocator, VkRenderPass renderPass, VkFramebuffer framebuffer, VkCommandPool commandBufferPool, deUint32 queueFamilyIndex, const vector& attachmentImages, const vector >& attachmentViews, const SubpassRenderInfo& renderInfo, const vector& attachmentInfos, const AllocationKind allocationKind) : m_renderInfo (renderInfo) { const InstanceInterface& vki = context.getInstanceInterface(); const VkPhysicalDevice& physDevice = context.getPhysicalDevice(); const deUint32 subpassIndex = renderInfo.getSubpassIndex(); vector bindings; for (deUint32 colorAttachmentNdx = 0; colorAttachmentNdx < renderInfo.getColorAttachmentCount(); colorAttachmentNdx++) m_colorAttachmentImages.push_back(attachmentImages[renderInfo.getColorAttachmentIndex(colorAttachmentNdx)]); if (renderInfo.getDepthStencilAttachmentIndex()) m_depthStencilAttachmentImage = attachmentImages[*renderInfo.getDepthStencilAttachmentIndex()]; if (renderInfo.getRenderQuad()) { const RenderQuad& renderQuad = *renderInfo.getRenderQuad(); if (renderInfo.getInputAttachmentCount() > 0) { deUint32 bindingIndex = 0; for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < renderInfo.getInputAttachmentCount(); inputAttachmentNdx++) { const Attachment attachmentInfo = attachmentInfos[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)]; const VkImageLayout layout = renderInfo.getInputAttachmentLayout(inputAttachmentNdx); const tcu::TextureFormat format = mapVkFormat(attachmentInfo.getFormat()); const bool isDepthFormat = tcu::hasDepthComponent(format.order); const bool isStencilFormat = tcu::hasStencilComponent(format.order); const deUint32 bindingCount = (isDepthFormat && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) && (isStencilFormat && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) ? 2u : 1u; for (deUint32 bindingNdx = 0; bindingNdx < bindingCount; bindingNdx++) { const VkDescriptorSetLayoutBinding binding = { bindingIndex, vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u, vk::VK_SHADER_STAGE_FRAGMENT_BIT, DE_NULL }; bindings.push_back(binding); bindingIndex++; } } const VkDescriptorSetLayoutCreateInfo createInfo = { vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, DE_NULL, 0u, (deUint32)bindings.size(), &bindings[0] }; m_descriptorSetLayout = vk::createDescriptorSetLayout(vk, device, &createInfo); } const VkDescriptorSetLayout descriptorSetLayout = *m_descriptorSetLayout; const VkPipelineLayoutCreateInfo pipelineLayoutParams = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // sType; DE_NULL, // pNext; (vk::VkPipelineLayoutCreateFlags)0, m_descriptorSetLayout ? 1u :0u , // setLayoutCount; m_descriptorSetLayout ? &descriptorSetLayout : DE_NULL, // pSetLayouts; 0u, // pushConstantRangeCount; DE_NULL, // pPushConstantRanges; }; m_vertexShaderModule = createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-vert"), 0u); m_fragmentShaderModule = createShaderModule(vk, device, context.getBinaryCollection().get(de::toString(subpassIndex) + "-frag"), 0u); m_pipelineLayout = createPipelineLayout(vk, device, &pipelineLayoutParams); m_pipeline = createSubpassPipeline(vk, device, renderPass, *m_vertexShaderModule, *m_fragmentShaderModule, *m_pipelineLayout, m_renderInfo); m_vertexBuffer = createBuffer(vk, device, 0u, (VkDeviceSize)renderQuad.getVertexDataSize(), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_SHARING_MODE_EXCLUSIVE, 1u, &queueFamilyIndex); m_vertexBufferMemory = allocateBuffer(vki, vk, physDevice, device, *m_vertexBuffer, MemoryRequirement::HostVisible, allocator, allocationKind); bindBufferMemory(vk, device, *m_vertexBuffer, m_vertexBufferMemory->getMemory(), m_vertexBufferMemory->getOffset()); uploadBufferData(vk, device, *m_vertexBufferMemory, renderQuad.getVertexDataSize(), renderQuad.getVertexPointer()); if (renderInfo.getInputAttachmentCount() > 0) { { const VkDescriptorPoolSize poolSize = { vk::VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, // \note Reserve 2 per input attachment since depthStencil attachments require 2. renderInfo.getInputAttachmentCount() * 2u }; const VkDescriptorPoolCreateInfo createInfo = { vk::VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, DE_NULL, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, // \note Reserve 2 per input attachment since depthStencil attachments require 2. renderInfo.getInputAttachmentCount() * 2u, 1u, &poolSize }; m_descriptorPool = vk::createDescriptorPool(vk, device, &createInfo); } { const VkDescriptorSetAllocateInfo allocateInfo = { vk::VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, DE_NULL, *m_descriptorPool, 1u, &descriptorSetLayout }; m_descriptorSet = vk::allocateDescriptorSet(vk, device, &allocateInfo); } { vector writes (bindings.size()); vector imageInfos (bindings.size()); deUint32 bindingIndex = 0; for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < renderInfo.getInputAttachmentCount(); inputAttachmentNdx++) { const Attachment attachmentInfo = attachmentInfos[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)]; const tcu::TextureFormat format = mapVkFormat(attachmentInfo.getFormat()); const bool isDepthFormat = tcu::hasDepthComponent(format.order); const bool isStencilFormat = tcu::hasStencilComponent(format.order); const VkImageLayout inputAttachmentLayout = renderInfo.getInputAttachmentLayout(inputAttachmentNdx); if (isDepthFormat && isStencilFormat) { if (inputAttachmentLayout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) { const VkDescriptorImageInfo imageInfo = { (VkSampler)0, attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].first, inputAttachmentLayout }; imageInfos[bindingIndex] = imageInfo; { const VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, DE_NULL, *m_descriptorSet, bindingIndex, 0u, 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[bindingIndex], DE_NULL, DE_NULL }; writes[bindingIndex] = write; bindingIndex++; } } if (inputAttachmentLayout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const VkDescriptorImageInfo imageInfo = { (VkSampler)0, attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].second, inputAttachmentLayout }; imageInfos[bindingIndex] = imageInfo; { const VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, DE_NULL, *m_descriptorSet, bindingIndex, 0u, 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[bindingIndex], DE_NULL, DE_NULL }; writes[bindingIndex] = write; bindingIndex++; } } } else { const VkDescriptorImageInfo imageInfo = { (VkSampler)0, attachmentViews[renderInfo.getInputAttachmentIndex(inputAttachmentNdx)].first, inputAttachmentLayout }; imageInfos[bindingIndex] = imageInfo; { const VkWriteDescriptorSet write = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, DE_NULL, *m_descriptorSet, bindingIndex, 0u, 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[bindingIndex], DE_NULL, DE_NULL }; writes[bindingIndex] = write; bindingIndex++; } } } vk.updateDescriptorSets(device, (deUint32)writes.size(), &writes[0], 0u, DE_NULL); } } } if (renderInfo.isSecondary()) { m_commandBuffer = allocateCommandBuffer(vk, device, commandBufferPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY); beginCommandBuffer(vk, *m_commandBuffer, vk::VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT, renderPass, subpassIndex, framebuffer, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0); pushRenderCommands(vk, *m_commandBuffer); endCommandBuffer(vk, *m_commandBuffer); } } bool isSecondary (void) const { return m_commandBuffer; } VkCommandBuffer getCommandBuffer (void) const { DE_ASSERT(isSecondary()); return *m_commandBuffer; } void pushRenderCommands (const DeviceInterface& vk, VkCommandBuffer commandBuffer) { if (!m_renderInfo.getColorClears().empty()) { const vector& colorClears (m_renderInfo.getColorClears()); for (deUint32 attachmentNdx = 0; attachmentNdx < m_renderInfo.getColorAttachmentCount(); attachmentNdx++) { const ColorClear& colorClear = colorClears[attachmentNdx]; const VkClearAttachment attachment = { VK_IMAGE_ASPECT_COLOR_BIT, attachmentNdx, makeClearValue(colorClear.getColor()), }; const VkClearRect rect = { { { (deInt32)colorClear.getOffset().x(), (deInt32)colorClear.getOffset().y() }, { colorClear.getSize().x(), colorClear.getSize().y() } }, // rect 0u, // baseArrayLayer 1u, // layerCount }; vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect); } } if (m_renderInfo.getDepthStencilClear()) { const DepthStencilClear& depthStencilClear = *m_renderInfo.getDepthStencilClear(); const deUint32 attachmentNdx = m_renderInfo.getColorAttachmentCount(); tcu::TextureFormat format = mapVkFormat(m_renderInfo.getDepthStencilAttachment()->getFormat()); const VkImageLayout layout = *m_renderInfo.getDepthStencilAttachmentLayout(); const VkClearAttachment attachment = { (VkImageAspectFlags)((hasDepthComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)), attachmentNdx, makeClearValueDepthStencil(depthStencilClear.getDepth(), depthStencilClear.getStencil()) }; const VkClearRect rect = { { { (deInt32)depthStencilClear.getOffset().x(), (deInt32)depthStencilClear.getOffset().y() }, { depthStencilClear.getSize().x(), depthStencilClear.getSize().y() } }, // rect 0u, // baseArrayLayer 1u, // layerCount }; if ((tcu::hasDepthComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) || (tcu::hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR)) { vk.cmdClearAttachments(commandBuffer, 1u, &attachment, 1u, &rect); } } vector selfDeps; VkPipelineStageFlags srcStages = 0; VkPipelineStageFlags dstStages = 0; for (deUint32 inputAttachmentNdx = 0; inputAttachmentNdx < m_renderInfo.getInputAttachmentCount(); inputAttachmentNdx++) { for (deUint32 colorAttachmentNdx = 0; colorAttachmentNdx < m_renderInfo.getColorAttachmentCount(); colorAttachmentNdx++) { if (m_renderInfo.getInputAttachmentIndex(inputAttachmentNdx) == m_renderInfo.getColorAttachmentIndex(colorAttachmentNdx)) { const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // dstAccessMask VK_IMAGE_LAYOUT_GENERAL, // oldLayout VK_IMAGE_LAYOUT_GENERAL, // newLayout VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex m_colorAttachmentImages[colorAttachmentNdx], // image { // subresourceRange VK_IMAGE_ASPECT_COLOR_BIT, // aspect 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; srcStages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; selfDeps.push_back(barrier); } } if (m_renderInfo.getDepthStencilAttachmentIndex() && (m_renderInfo.getInputAttachmentIndex(inputAttachmentNdx) == *m_renderInfo.getDepthStencilAttachmentIndex())) { const tcu::TextureFormat format = mapVkFormat(m_renderInfo.getDepthStencilAttachment()->getFormat()); const bool hasDepth = hasDepthComponent(format.order); const bool hasStencil = hasStencilComponent(format.order); const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType; DE_NULL, // pNext; VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // srcAccessMask VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // dstAccessMask VK_IMAGE_LAYOUT_GENERAL, // oldLayout VK_IMAGE_LAYOUT_GENERAL, // newLayout; VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex; m_depthStencilAttachmentImage, // image; { // subresourceRange; (hasDepth ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (hasStencil ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u), // aspect; 0, // baseMipLevel; 1, // mipLevels; 0, // baseArraySlice; 1 // arraySize; } }; srcStages |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; dstStages |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; selfDeps.push_back(barrier); } } if (!selfDeps.empty()) { DE_ASSERT(srcStages != 0); DE_ASSERT(dstStages != 0); vk.cmdPipelineBarrier(commandBuffer, srcStages, dstStages, VK_DEPENDENCY_BY_REGION_BIT, 0, DE_NULL, 0, DE_NULL, (deUint32)selfDeps.size(), &selfDeps[0]); } if (m_renderInfo.getRenderQuad()) { const VkDeviceSize offset = 0; const VkBuffer vertexBuffer = *m_vertexBuffer; vk.cmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline); if (m_descriptorSet) { const VkDescriptorSet descriptorSet = *m_descriptorSet; vk.cmdBindDescriptorSets(commandBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &descriptorSet, 0u, NULL); } vk.cmdBindVertexBuffers(commandBuffer, 0u, 1u, &vertexBuffer, &offset); vk.cmdDraw(commandBuffer, 6u, 1u, 0u, 0u); } } private: const SubpassRenderInfo m_renderInfo; Move m_commandBuffer; Move m_pipeline; Move m_descriptorSetLayout; Move m_pipelineLayout; Move m_vertexShaderModule; Move m_fragmentShaderModule; Move m_descriptorPool; Move m_descriptorSet; Move m_vertexBuffer; de::MovePtr m_vertexBufferMemory; vector m_colorAttachmentImages; VkImage m_depthStencilAttachmentImage; }; void pushImageInitializationCommands (const DeviceInterface& vk, VkCommandBuffer commandBuffer, const vector& attachmentInfo, const vector >& attachmentResources, deUint32 queueIndex, const vector >& clearValues) { { vector initializeLayouts; for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { if (!clearValues[attachmentNdx]) continue; const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType; DE_NULL, // pNext; (VkAccessFlags)0, // srcAccessMask getAllMemoryReadFlags() | VK_ACCESS_TRANSFER_WRITE_BIT, // dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // newLayout; queueIndex, // srcQueueFamilyIndex; queueIndex, // destQueueFamilyIndex; attachmentResources[attachmentNdx]->getImage(), // image; { // subresourceRange; getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect; 0, // baseMipLevel; 1, // mipLevels; 0, // baseArraySlice; 1 // arraySize; } }; initializeLayouts.push_back(barrier); } if (!initializeLayouts.empty()) vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)initializeLayouts.size(), &initializeLayouts[0]); } for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { if (!clearValues[attachmentNdx]) continue; const tcu::TextureFormat format = mapVkFormat(attachmentInfo[attachmentNdx].getFormat()); if (hasStencilComponent(format.order) || hasDepthComponent(format.order)) { const float clearNan = tcu::Float32::nan().asFloat(); const float clearDepth = hasDepthComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.depth : clearNan; const deUint32 clearStencil = hasStencilComponent(format.order) ? clearValues[attachmentNdx]->depthStencil.stencil : 0xDEu; const VkClearDepthStencilValue depthStencil = { clearDepth, clearStencil }; const VkImageSubresourceRange range = { (VkImageAspectFlags)((hasDepthComponent(format.order) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (hasStencilComponent(format.order) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0)), 0, 1, 0, 1 }; vk.cmdClearDepthStencilImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencil, 1, &range); } else { const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask; 0, // baseMipLevel; 1, // mipLevels; 0, // baseArrayLayer; 1 // layerCount; }; const VkClearColorValue clearColor = clearValues[attachmentNdx]->color; vk.cmdClearColorImage(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); } } { vector renderPassLayouts; for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { const VkImageLayout oldLayout = clearValues[attachmentNdx] ? VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL : VK_IMAGE_LAYOUT_UNDEFINED; const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType; DE_NULL, // pNext; (oldLayout != VK_IMAGE_LAYOUT_UNDEFINED ? getAllMemoryWriteFlags() : (VkAccessFlags)0), // srcAccessMask getAllMemoryReadFlags() | getMemoryFlagsForLayout(attachmentInfo[attachmentNdx].getInitialLayout()), // dstAccessMask oldLayout, // oldLayout attachmentInfo[attachmentNdx].getInitialLayout(), // newLayout; queueIndex, // srcQueueFamilyIndex; queueIndex, // destQueueFamilyIndex; attachmentResources[attachmentNdx]->getImage(), // image; { // subresourceRange; getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect; 0, // baseMipLevel; 1, // mipLevels; 0, // baseArraySlice; 1 // arraySize; } }; renderPassLayouts.push_back(barrier); } if (!renderPassLayouts.empty()) vk.cmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)renderPassLayouts.size(), &renderPassLayouts[0]); } } void pushRenderPassCommands (const DeviceInterface& vk, VkCommandBuffer commandBuffer, VkRenderPass renderPass, VkFramebuffer framebuffer, const vector >& subpassRenderers, const UVec2& renderPos, const UVec2& renderSize, const vector >& renderPassClearValues, TestConfig::RenderTypes render) { const float clearNan = tcu::Float32::nan().asFloat(); vector attachmentClearValues; for (size_t attachmentNdx = 0; attachmentNdx < renderPassClearValues.size(); attachmentNdx++) { if (renderPassClearValues[attachmentNdx]) attachmentClearValues.push_back(*renderPassClearValues[attachmentNdx]); else attachmentClearValues.push_back(makeClearValueColorF32(clearNan, clearNan, clearNan, clearNan)); } { const VkRect2D renderArea = { { (deInt32)renderPos.x(), (deInt32)renderPos.y() }, { renderSize.x(), renderSize.y() } }; for (size_t subpassNdx = 0; subpassNdx < subpassRenderers.size(); subpassNdx++) { const VkSubpassContents contents = subpassRenderers[subpassNdx]->isSecondary() ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE; if (subpassNdx == 0) cmdBeginRenderPass(vk, commandBuffer, renderPass, framebuffer, renderArea, (deUint32)attachmentClearValues.size(), attachmentClearValues.empty() ? DE_NULL : &attachmentClearValues[0], contents); else vk.cmdNextSubpass(commandBuffer, contents); if (render) { if (contents == VK_SUBPASS_CONTENTS_INLINE) { subpassRenderers[subpassNdx]->pushRenderCommands(vk, commandBuffer); } else if (contents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS) { const VkCommandBuffer cmd = subpassRenderers[subpassNdx]->getCommandBuffer(); vk.cmdExecuteCommands(commandBuffer, 1, &cmd); } else DE_FATAL("Invalid contents"); } } vk.cmdEndRenderPass(commandBuffer); } } void pushReadImagesToBuffers (const DeviceInterface& vk, VkCommandBuffer commandBuffer, deUint32 queueIndex, const vector >& attachmentResources, const vector& attachmentInfo, const vector& isLazy, const UVec2& targetSize) { { vector imageBarriers; for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { if (isLazy[attachmentNdx]) continue; const VkImageLayout oldLayout = attachmentInfo[attachmentNdx].getFinalLayout(); const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext getAllMemoryWriteFlags() | getMemoryFlagsForLayout(oldLayout), // srcAccessMask getAllMemoryReadFlags(), // dstAccessMask oldLayout, // oldLayout VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // newLayout queueIndex, // srcQueueFamilyIndex queueIndex, // destQueueFamilyIndex attachmentResources[attachmentNdx]->getImage(), // image { // subresourceRange getImageAspectFlags(attachmentInfo[attachmentNdx].getFormat()), // aspect; 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; imageBarriers.push_back(barrier); } if (!imageBarriers.empty()) vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(), getAllPipelineStageFlags(), (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)imageBarriers.size(), &imageBarriers[0]); } for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { if (isLazy[attachmentNdx]) continue; const tcu::TextureFormat::ChannelOrder order = mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order; const VkBufferImageCopy rect = { 0, // bufferOffset 0, // bufferRowLength 0, // bufferImageHeight { // imageSubresource (vk::VkImageAspectFlags)getPrimaryImageAspect(mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order), // aspect 0, // mipLevel 0, // arraySlice 1 // arraySize }, { 0, 0, 0 }, // imageOffset { targetSize.x(), targetSize.y(), 1u } // imageExtent }; vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getBuffer(), 1, &rect); if (tcu::TextureFormat::DS == order) { const VkBufferImageCopy stencilRect = { 0, // bufferOffset 0, // bufferRowLength 0, // bufferImageHeight { // imageSubresource VK_IMAGE_ASPECT_STENCIL_BIT, // aspect 0, // mipLevel 0, // arraySlice 1 // arraySize }, { 0, 0, 0 }, // imageOffset { targetSize.x(), targetSize.y(), 1u } // imageExtent }; vk.cmdCopyImageToBuffer(commandBuffer, attachmentResources[attachmentNdx]->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, attachmentResources[attachmentNdx]->getSecondaryBuffer(), 1, &stencilRect); } } { vector bufferBarriers; for (size_t attachmentNdx = 0; attachmentNdx < attachmentInfo.size(); attachmentNdx++) { if (isLazy[attachmentNdx]) continue; const tcu::TextureFormat::ChannelOrder order = mapVkFormat(attachmentInfo[attachmentNdx].getFormat()).order; const VkBufferMemoryBarrier bufferBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, DE_NULL, getAllMemoryWriteFlags(), getAllMemoryReadFlags(), queueIndex, queueIndex, attachmentResources[attachmentNdx]->getBuffer(), 0, attachmentResources[attachmentNdx]->getBufferSize() }; bufferBarriers.push_back(bufferBarrier); if (tcu::TextureFormat::DS == order) { const VkBufferMemoryBarrier secondaryBufferBarrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, DE_NULL, getAllMemoryWriteFlags(), getAllMemoryReadFlags(), queueIndex, queueIndex, attachmentResources[attachmentNdx]->getSecondaryBuffer(), 0, attachmentResources[attachmentNdx]->getSecondaryBufferSize() }; bufferBarriers.push_back(secondaryBufferBarrier); } } if (!bufferBarriers.empty()) vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(), getAllPipelineStageFlags(), (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, (deUint32)bufferBarriers.size(), &bufferBarriers[0], 0, (const VkImageMemoryBarrier*)DE_NULL); } } class PixelValue { public: PixelValue (const Maybe& x = nothing(), const Maybe& y = nothing(), const Maybe& z = nothing(), const Maybe& w = nothing()); void setUndefined (size_t ndx); void setValue (size_t ndx, bool value); Maybe getValue (size_t ndx) const; private: deUint16 m_status; }; PixelValue::PixelValue (const Maybe& x, const Maybe& y, const Maybe& z, const Maybe& w) : m_status (0) { const Maybe values[] = { x, y, z, w }; for (size_t ndx = 0; ndx < DE_LENGTH_OF_ARRAY(values); ndx++) { if (values[ndx]) setValue(ndx, *values[ndx]); else setUndefined(ndx); } DE_ASSERT(m_status <= 0xFFu); } void PixelValue::setUndefined (size_t ndx) { DE_ASSERT(ndx < 4); DE_ASSERT(m_status <= 0xFFu); m_status &= (deUint16)~(0x1u << (deUint16)(ndx * 2)); DE_ASSERT(m_status <= 0xFFu); } void PixelValue::setValue (size_t ndx, bool value) { DE_ASSERT(ndx < 4); DE_ASSERT(m_status <= 0xFFu); m_status = (deUint16)(m_status | (deUint16)(0x1u << (ndx * 2))); if (value) m_status = (deUint16)(m_status | (deUint16)(0x1u << (ndx * 2 + 1))); else m_status &= (deUint16)~(0x1u << (deUint16)(ndx * 2 + 1)); DE_ASSERT(m_status <= 0xFFu); } Maybe PixelValue::getValue (size_t ndx) const { DE_ASSERT(ndx < 4); DE_ASSERT(m_status <= 0xFFu); if ((m_status & (0x1u << (deUint16)(ndx * 2))) != 0) { return just((m_status & (0x1u << (deUint32)(ndx * 2 + 1))) != 0); } else return nothing(); } void clearReferenceValues (vector& values, const UVec2& targetSize, const UVec2& offset, const UVec2& size, const BVec4& mask, const PixelValue& value) { DE_ASSERT(targetSize.x() * targetSize.y() == (deUint32)values.size()); DE_ASSERT(offset.x() + size.x() <= targetSize.x()); DE_ASSERT(offset.y() + size.y() <= targetSize.y()); for (deUint32 y = offset.y(); y < offset.y() + size.y(); y++) for (deUint32 x = offset.x(); x < offset.x() + size.x(); x++) { for (int compNdx = 0; compNdx < 4; compNdx++) { if (mask[compNdx]) { if (value.getValue(compNdx)) values[x + y * targetSize.x()].setValue(compNdx, *value.getValue(compNdx)); else values[x + y * targetSize.x()].setUndefined(compNdx); } } } } void markUndefined (vector& values, const BVec4& mask, const UVec2& targetSize, const UVec2& offset, const UVec2& size) { DE_ASSERT(targetSize.x() * targetSize.y() == (deUint32)values.size()); for (deUint32 y = offset.y(); y < offset.y() + size.y(); y++) for (deUint32 x = offset.x(); x < offset.x() + size.x(); x++) { for (int compNdx = 0; compNdx < 4; compNdx++) { if (mask[compNdx]) values[x + y * targetSize.x()].setUndefined(compNdx); } } } PixelValue clearValueToPixelValue (const VkClearValue& value, const tcu::TextureFormat& format) { const bool isDepthAttachment = hasDepthComponent(format.order); const bool isStencilAttachment = hasStencilComponent(format.order); const bool isDepthOrStencilAttachment = isDepthAttachment || isStencilAttachment; PixelValue pixelValue; if (isDepthOrStencilAttachment) { if (isDepthAttachment) { if (value.depthStencil.depth == 1.0f) pixelValue.setValue(0, true); else if (value.depthStencil.depth == 0.0f) pixelValue.setValue(0, false); else DE_FATAL("Unknown depth value"); } if (isStencilAttachment) { if (value.depthStencil.stencil == 0xFFu) pixelValue.setValue(1, true); else if (value.depthStencil.stencil == 0x0u) pixelValue.setValue(1, false); else DE_FATAL("Unknown stencil value"); } } else { const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format); switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: for (int i = 0; i < 4; i++) { if (channelMask[i]) { if (value.color.int32[i] == 1) pixelValue.setValue(i, true); else if (value.color.int32[i] == 0) pixelValue.setValue(i, false); else DE_FATAL("Unknown clear color value"); } } break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: for (int i = 0; i < 4; i++) { if (channelMask[i]) { if (value.color.uint32[i] == 1u) pixelValue.setValue(i, true); else if (value.color.uint32[i] == 0u) pixelValue.setValue(i, false); else DE_FATAL("Unknown clear color value"); } } break; case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: for (int i = 0; i < 4; i++) { if (channelMask[i]) { if (value.color.float32[i] == 1.0f) pixelValue.setValue(i, true); else if (value.color.float32[i] == 0.0f) pixelValue.setValue(i, false); else DE_FATAL("Unknown clear color value"); } } break; default: DE_FATAL("Unknown channel class"); } } return pixelValue; } void renderReferenceValues (vector >& referenceAttachments, const RenderPass& renderPassInfo, const UVec2& targetSize, const vector >& imageClearValues, const vector >& renderPassClearValues, const vector& subpassRenderInfo, const UVec2& renderPos, const UVec2& renderSize) { const vector& subpasses = renderPassInfo.getSubpasses(); vector attachmentUsed (renderPassInfo.getAttachments().size(), false); referenceAttachments.resize(renderPassInfo.getAttachments().size()); for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentNdx]; reference.resize(targetSize.x() * targetSize.y()); if (imageClearValues[attachmentNdx]) clearReferenceValues(reference, targetSize, UVec2(0, 0), targetSize, BVec4(true), clearValueToPixelValue(*imageClearValues[attachmentNdx], format)); } for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++) { const Subpass& subpass = subpasses[subpassNdx]; const SubpassRenderInfo& renderInfo = subpassRenderInfo[subpassNdx]; const vector& colorAttachments = subpass.getColorAttachments(); // Apply load op if attachment was used for the first time for (size_t attachmentNdx = 0; attachmentNdx < colorAttachments.size(); attachmentNdx++) { const deUint32 attachmentIndex = colorAttachments[attachmentNdx].getAttachment(); if (!attachmentUsed[attachmentIndex]) { const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; vector& reference = referenceAttachments[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); DE_ASSERT(!tcu::hasDepthComponent(format.order)); DE_ASSERT(!tcu::hasStencilComponent(format.order)); if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(true), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format)); else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE) markUndefined(reference, BVec4(true), targetSize, renderPos, renderSize); attachmentUsed[attachmentIndex] = true; } } // Apply load op to depth/stencil attachment if it was used for the first time if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED) { const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); // Apply load op if attachment was used for the first time if (!attachmentUsed[attachmentIndex]) { const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; vector& reference = referenceAttachments[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); if (tcu::hasDepthComponent(format.order)) { if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(true, false, false, false), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format)); else if (attachment.getLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE) markUndefined(reference, BVec4(true, false, false, false), targetSize, renderPos, renderSize); } if (tcu::hasStencilComponent(format.order)) { if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) clearReferenceValues(reference, targetSize, renderPos, renderSize, BVec4(false, true, false, false), clearValueToPixelValue(*renderPassClearValues[attachmentIndex], format)); else if (attachment.getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_DONT_CARE) markUndefined(reference, BVec4(false, true, false, false), targetSize, renderPos, renderSize); } attachmentUsed[attachmentIndex] = true; } } for (size_t colorClearNdx = 0; colorClearNdx < renderInfo.getColorClears().size(); colorClearNdx++) { const ColorClear& colorClear = renderInfo.getColorClears()[colorClearNdx]; const UVec2 offset = colorClear.getOffset(); const UVec2 size = colorClear.getSize(); const deUint32 attachmentIndex = subpass.getColorAttachments()[colorClearNdx].getAttachment(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentIndex]; VkClearValue value; value.color = colorClear.getColor(); clearReferenceValues(reference, targetSize, offset, size, BVec4(true), clearValueToPixelValue(value, format)); } if (renderInfo.getDepthStencilClear()) { const DepthStencilClear& dsClear = *renderInfo.getDepthStencilClear(); const UVec2 offset = dsClear.getOffset(); const UVec2 size = dsClear.getSize(); const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); const VkImageLayout layout = subpass.getDepthStencilAttachment().getImageLayout(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const bool hasStencil = tcu::hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR; const bool hasDepth = tcu::hasDepthComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR; vector& reference = referenceAttachments[attachmentIndex]; VkClearValue value; value.depthStencil.depth = dsClear.getDepth(); value.depthStencil.stencil = dsClear.getStencil(); clearReferenceValues(reference, targetSize, offset, size, BVec4(hasDepth, hasStencil, false, false), clearValueToPixelValue(value, format)); } if (renderInfo.getRenderQuad()) { const RenderQuad& renderQuad = *renderInfo.getRenderQuad(); const Vec2 posA = renderQuad.getCornerA(); const Vec2 posB = renderQuad.getCornerB(); const Vec2 origin = Vec2((float)renderInfo.getViewportOffset().x(), (float)renderInfo.getViewportOffset().y()) + Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f); const Vec2 p = Vec2((float)renderInfo.getViewportSize().x(), (float)renderInfo.getViewportSize().y()) / Vec2(2.0f); const IVec2 posAI (deRoundFloatToInt32(origin.x() + (p.x() * posA.x())), deRoundFloatToInt32(origin.y() + (p.y() * posA.y()))); const IVec2 posBI (deRoundFloatToInt32(origin.x() + (p.x() * posB.x())), deRoundFloatToInt32(origin.y() + (p.y() * posB.y()))); DE_ASSERT(posAI.x() < posBI.x()); DE_ASSERT(posAI.y() < posBI.y()); if (subpass.getInputAttachments().empty()) { for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentRefNdx].getAttachment(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format); vector& reference = referenceAttachments[attachmentIndex]; for (int y = posAI.y(); y < (int)posBI.y(); y++) for (int x = posAI.x(); x < (int)posBI.x(); x++) { for (int compNdx = 0; compNdx < 4; compNdx++) { const size_t index = subpassNdx + attachmentIndex + compNdx; const BoolOp op = boolOpFromIndex(index); const bool boolX = x % 2 == (int)(index % 2); const bool boolY = y % 2 == (int)((index / 2) % 2); if (channelMask[compNdx]) reference[x + y * targetSize.x()].setValue(compNdx, performBoolOp(op, boolX, boolY)); } } } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED) { const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); const VkImageLayout layout = subpass.getDepthStencilAttachment().getImageLayout(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentIndex]; for (int y = posAI.y(); y < (int)posBI.y(); y++) for (int x = posAI.x(); x < (int)posBI.x(); x++) { if (tcu::hasDepthComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const size_t index = subpassNdx + 1; const BoolOp op = boolOpFromIndex(index); const bool boolX = x % 2 == (int)(index % 2); const bool boolY = y % 2 == (int)((index / 2) % 2); reference[x + y * targetSize.x()].setValue(0, performBoolOp(op, boolX, boolY)); } if (tcu::hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) { const size_t index = subpassNdx; reference[x + y * targetSize.x()].setValue(1, (index % 2) == 0); } } } } else { size_t outputComponentCount = 0; vector > inputs; DE_ASSERT(posAI.x() < posBI.x()); DE_ASSERT(posAI.y() < posBI.y()); for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentRefNdx].getAttachment(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const int componentCount = tcu::getNumUsedChannels(format.order); outputComponentCount += (size_t)componentCount; } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const Attachment& attachment (renderPassInfo.getAttachments()[subpass.getDepthStencilAttachment().getAttachment()]); const tcu::TextureFormat format (mapVkFormat(attachment.getFormat())); if (tcu::hasDepthComponent(format.order)) outputComponentCount++; } if (outputComponentCount > 0) { for (int y = posAI.y(); y < (int)posBI.y(); y++) for (int x = posAI.x(); x < (int)posBI.x(); x++) { for (size_t inputAttachmentNdx = 0; inputAttachmentNdx < subpass.getInputAttachments().size(); inputAttachmentNdx++) { const deUint32 attachmentIndex = subpass.getInputAttachments()[inputAttachmentNdx].getAttachment(); const VkImageLayout layout = subpass.getInputAttachments()[inputAttachmentNdx].getImageLayout(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const int componentCount = tcu::getNumUsedChannels(format.order); for (int compNdx = 0; compNdx < componentCount; compNdx++) { if ((compNdx != 0 || layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) && (compNdx != 1 || layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR)) { inputs.push_back(referenceAttachments[attachmentIndex][x + y * targetSize.x()].getValue(compNdx)); } } } const size_t inputsPerOutput = inputs.size() >= outputComponentCount ? ((inputs.size() / outputComponentCount) + ((inputs.size() % outputComponentCount) != 0 ? 1 : 0)) : 1; size_t outputValueNdx = 0; for (size_t attachmentRefNdx = 0; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentRefNdx].getAttachment(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentIndex]; const int componentCount = tcu::getNumUsedChannels(format.order); for (int compNdx = 0; compNdx < componentCount; compNdx++) { const size_t index = subpassNdx + attachmentIndex + outputValueNdx; const BoolOp op = boolOpFromIndex(index); const bool boolX = x % 2 == (int)(index % 2); const bool boolY = y % 2 == (int)((index / 2) % 2); Maybe output = tcu::just(performBoolOp(op, boolX, boolY)); for (size_t i = 0; i < inputsPerOutput; i++) { if (!output) break; else if (!inputs[((outputValueNdx + compNdx) * inputsPerOutput + i) % inputs.size()]) output = tcu::nothing(); else output = (*output) == (*inputs[((outputValueNdx + compNdx) * inputsPerOutput + i) % inputs.size()]); } if (output) reference[x + y * targetSize.x()].setValue(compNdx, *output); else reference[x + y * targetSize.x()].setUndefined(compNdx); } outputValueNdx += componentCount; } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); vector& reference = referenceAttachments[attachmentIndex]; const size_t index = subpassNdx + attachmentIndex; const BoolOp op = boolOpFromIndex(index); const bool boolX = x % 2 == (int)(index % 2); const bool boolY = y % 2 == (int)((index / 2) % 2); Maybe output = tcu::just(performBoolOp(op, boolX, boolY)); for (size_t i = 0; i < inputsPerOutput; i++) { if (!output) break; else if (inputs[(outputValueNdx * inputsPerOutput + i) % inputs.size()]) output = (*output) == (*inputs[(outputValueNdx * inputsPerOutput + i) % inputs.size()]); else output = tcu::nothing(); } if (output) reference[x + y * targetSize.x()].setValue(0, *output); else reference[x + y * targetSize.x()].setUndefined(0); } inputs.clear(); } } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) { const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); const Attachment& attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentIndex]; if (tcu::hasStencilComponent(format.order)) { for (int y = posAI.y(); y < (int)posBI.y(); y++) for (int x = posAI.x(); x < (int)posBI.x(); x++) { const size_t index = subpassNdx; reference[x + y * targetSize.x()].setValue(1, (index % 2) == 0); } } } } } } // Mark all attachments that were used but not stored as undefined for (size_t attachmentIndex = 0; attachmentIndex < renderPassInfo.getAttachments().size(); attachmentIndex++) { const Attachment attachment = renderPassInfo.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); vector& reference = referenceAttachments[attachmentIndex]; const bool isStencilAttachment = hasStencilComponent(format.order); const bool isDepthOrStencilAttachment = hasDepthComponent(format.order) || isStencilAttachment; if (attachmentUsed[attachmentIndex] && renderPassInfo.getAttachments()[attachmentIndex].getStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE) { if (isDepthOrStencilAttachment) markUndefined(reference, BVec4(true, false, false, false), targetSize, renderPos, renderSize); else markUndefined(reference, BVec4(true), targetSize, renderPos, renderSize); } if (attachmentUsed[attachmentIndex] && isStencilAttachment && renderPassInfo.getAttachments()[attachmentIndex].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_DONT_CARE) markUndefined(reference, BVec4(false, true, false, false), targetSize, renderPos, renderSize); } } void renderReferenceImagesFromValues (vector& referenceImages, const vector >& referenceValues, const UVec2& targetSize, const RenderPass& renderPassInfo) { referenceImages.resize(referenceValues.size()); for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const vector& reference = referenceValues[attachmentNdx]; const bool hasDepth = tcu::hasDepthComponent(format.order); const bool hasStencil = tcu::hasStencilComponent(format.order); const bool hasDepthOrStencil = hasDepth || hasStencil; tcu::TextureLevel& referenceImage = referenceImages[attachmentNdx]; referenceImage.setStorage(format, targetSize.x(), targetSize.y()); if (hasDepthOrStencil) { if (hasDepth) { const PixelBufferAccess depthAccess (tcu::getEffectiveDepthStencilAccess(referenceImage.getAccess(), tcu::Sampler::MODE_DEPTH)); for (deUint32 y = 0; y < targetSize.y(); y++) for (deUint32 x = 0; x < targetSize.x(); x++) { if (reference[x + y * targetSize.x()].getValue(0)) { if (*reference[x + y * targetSize.x()].getValue(0)) depthAccess.setPixDepth(1.0f, x, y); else depthAccess.setPixDepth(0.0f, x, y); } else // Fill with 3x3 grid depthAccess.setPixDepth(((x / 3) % 2) == ((y / 3) % 2) ? 0.33f : 0.66f, x, y); } } if (hasStencil) { const PixelBufferAccess stencilAccess (tcu::getEffectiveDepthStencilAccess(referenceImage.getAccess(), tcu::Sampler::MODE_STENCIL)); for (deUint32 y = 0; y < targetSize.y(); y++) for (deUint32 x = 0; x < targetSize.x(); x++) { if (reference[x + y * targetSize.x()].getValue(1)) { if (*reference[x + y * targetSize.x()].getValue(1)) stencilAccess.setPixStencil(0xFFu, x, y); else stencilAccess.setPixStencil(0x0u, x, y); } else // Fill with 3x3 grid stencilAccess.setPixStencil(((x / 3) % 2) == ((y / 3) % 2) ? 85 : 170, x, y); } } } else { for (deUint32 y = 0; y < targetSize.y(); y++) for (deUint32 x = 0; x < targetSize.x(); x++) { tcu::Vec4 color; for (int compNdx = 0; compNdx < 4; compNdx++) { if (reference[x + y * targetSize.x()].getValue(compNdx)) { if (*reference[x + y * targetSize.x()].getValue(compNdx)) color[compNdx] = 1.0f; else color[compNdx] = 0.0f; } else // Fill with 3x3 grid color[compNdx] = ((compNdx + (x / 3)) % 2) == ((y / 3) % 2) ? 0.33f : 0.66f; } referenceImage.getAccess().setPixel(color, x, y); } } } } bool verifyColorAttachment (const vector& reference, const ConstPixelBufferAccess& result, const PixelBufferAccess& errorImage) { const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); bool ok = true; DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size()); DE_ASSERT(result.getWidth() == errorImage.getWidth()); DE_ASSERT(result.getHeight() == errorImage.getHeight()); for (int y = 0; y < result.getHeight(); y++) for (int x = 0; x < result.getWidth(); x++) { const Vec4 resultColor = result.getPixel(x, y); const PixelValue& referenceValue = reference[x + y * result.getWidth()]; bool pixelOk = true; for (int compNdx = 0; compNdx < 4; compNdx++) { const Maybe maybeValue = referenceValue.getValue(compNdx); if (maybeValue) { const bool value = *maybeValue; if ((value && (resultColor[compNdx] != 1.0f)) || (!value && resultColor[compNdx] != 0.0f)) pixelOk = false; } } if (!pixelOk) { errorImage.setPixel(red, x, y); ok = false; } else errorImage.setPixel(green, x, y); } return ok; } bool verifyDepthAttachment (const vector& reference, const ConstPixelBufferAccess& result, const PixelBufferAccess& errorImage) { const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); bool ok = true; DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size()); DE_ASSERT(result.getWidth() == errorImage.getWidth()); DE_ASSERT(result.getHeight() == errorImage.getHeight()); for (int y = 0; y < result.getHeight(); y++) for (int x = 0; x < result.getWidth(); x++) { bool pixelOk = true; const float resultDepth = result.getPixDepth(x, y); const PixelValue& referenceValue = reference[x + y * result.getWidth()]; const Maybe maybeValue = referenceValue.getValue(0); if (maybeValue) { const bool value = *maybeValue; if ((value && (resultDepth != 1.0f)) || (!value && resultDepth != 0.0f)) pixelOk = false; } if (!pixelOk) { errorImage.setPixel(red, x, y); ok = false; } else errorImage.setPixel(green, x, y); } return ok; } bool verifyStencilAttachment (const vector& reference, const ConstPixelBufferAccess& result, const PixelBufferAccess& errorImage) { const Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); bool ok = true; DE_ASSERT(result.getWidth() * result.getHeight() == (int)reference.size()); DE_ASSERT(result.getWidth() == errorImage.getWidth()); DE_ASSERT(result.getHeight() == errorImage.getHeight()); for (int y = 0; y < result.getHeight(); y++) for (int x = 0; x < result.getWidth(); x++) { bool pixelOk = true; const deUint32 resultStencil = result.getPixStencil(x, y); const PixelValue& referenceValue = reference[x + y * result.getWidth()]; const Maybe maybeValue = referenceValue.getValue(1); if (maybeValue) { const bool value = *maybeValue; if ((value && (resultStencil != 0xFFu)) || (!value && resultStencil != 0x0u)) pixelOk = false; } if (!pixelOk) { errorImage.setPixel(red, x, y); ok = false; } else errorImage.setPixel(green, x, y); } return ok; } bool logAndVerifyImages (TestLog& log, const DeviceInterface& vk, VkDevice device, const vector >& attachmentResources, const vector& attachmentIsLazy, const RenderPass& renderPassInfo, const vector >& renderPassClearValues, const vector >& imageClearValues, const vector& subpassRenderInfo, const UVec2& targetSize, const TestConfig& config) { vector > referenceValues; vector referenceAttachments; bool isOk = true; log << TestLog::Message << "Reference images fill undefined pixels with 3x3 grid pattern." << TestLog::EndMessage; renderReferenceValues(referenceValues, renderPassInfo, targetSize, imageClearValues, renderPassClearValues, subpassRenderInfo, config.renderPos, config.renderSize); renderReferenceImagesFromValues(referenceAttachments, referenceValues, targetSize, renderPassInfo); for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { if (!attachmentIsLazy[attachmentNdx]) { const Attachment attachment = renderPassInfo.getAttachments()[attachmentNdx]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); if (tcu::hasDepthComponent(format.order) && tcu::hasStencilComponent(format.order)) { const tcu::TextureFormat depthFormat = getDepthCopyFormat(attachment.getFormat()); const VkDeviceSize depthBufferSize = targetSize.x() * targetSize.y() * depthFormat.getPixelSize(); void* const depthPtr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr(); const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachment.getFormat()); const VkDeviceSize stencilBufferSize = targetSize.x() * targetSize.y() * stencilFormat.getPixelSize(); void* const stencilPtr = attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr(); const VkMappedMemoryRange ranges[] = { { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType; DE_NULL, // pNext; attachmentResources[attachmentNdx]->getResultMemory().getMemory(), // mem; attachmentResources[attachmentNdx]->getResultMemory().getOffset(), // offset; depthBufferSize // size; }, { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType; DE_NULL, // pNext; attachmentResources[attachmentNdx]->getSecondaryResultMemory().getMemory(), // mem; attachmentResources[attachmentNdx]->getSecondaryResultMemory().getOffset(), // offset; stencilBufferSize // size; } }; VK_CHECK(vk.invalidateMappedMemoryRanges(device, 2u, ranges)); { const ConstPixelBufferAccess depthAccess (depthFormat, targetSize.x(), targetSize.y(), 1, depthPtr); const ConstPixelBufferAccess stencilAccess (stencilFormat, targetSize.x(), targetSize.y(), 1, stencilPtr); tcu::TextureLevel depthErrorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y()); tcu::TextureLevel stencilErrorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y()); log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Depth", "Attachment " + de::toString(attachmentNdx) + " Depth", depthAccess); log << TestLog::Image("Attachment" + de::toString(attachmentNdx) + "Stencil", "Attachment " + de::toString(attachmentNdx) + " Stencil", stencilAccess); log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess()); if (renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE && !verifyDepthAttachment(referenceValues[attachmentNdx], depthAccess, depthErrorImage.getAccess())) { log << TestLog::Image("DepthAttachmentError" + de::toString(attachmentNdx), "Depth Attachment Error " + de::toString(attachmentNdx), depthErrorImage.getAccess()); isOk = false; } if (renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE && !verifyStencilAttachment(referenceValues[attachmentNdx], stencilAccess, stencilErrorImage.getAccess())) { log << TestLog::Image("StencilAttachmentError" + de::toString(attachmentNdx), "Stencil Attachment Error " + de::toString(attachmentNdx), stencilErrorImage.getAccess()); isOk = false; } } } else { const VkDeviceSize bufferSize = targetSize.x() * targetSize.y() * format.getPixelSize(); void* const ptr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr(); const VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType; DE_NULL, // pNext; attachmentResources[attachmentNdx]->getResultMemory().getMemory(), // mem; attachmentResources[attachmentNdx]->getResultMemory().getOffset(), // offset; bufferSize // size; }; VK_CHECK(vk.invalidateMappedMemoryRanges(device, 1u, &range)); if (tcu::hasDepthComponent(format.order)) { const ConstPixelBufferAccess access (format, targetSize.x(), targetSize.y(), 1, ptr); tcu::TextureLevel errorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y()); log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access); log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess()); if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE) && !verifyDepthAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess())) { log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess()); isOk = false; } } else if (tcu::hasStencilComponent(format.order)) { const ConstPixelBufferAccess access (format, targetSize.x(), targetSize.y(), 1, ptr); tcu::TextureLevel errorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y()); log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access); log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess()); if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE) && !verifyStencilAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess())) { log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess()); isOk = false; } } else { const ConstPixelBufferAccess access (format, targetSize.x(), targetSize.y(), 1, ptr); tcu::TextureLevel errorImage (tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), targetSize.x(), targetSize.y()); log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), access); log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceAttachments[attachmentNdx].getAccess()); if ((renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE || renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE) && !verifyColorAttachment(referenceValues[attachmentNdx], access, errorImage.getAccess())) { log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess()); isOk = false; } } } } } return isOk; } std::string getInputAttachmentType (VkFormat vkFormat) { const tcu::TextureFormat format = mapVkFormat(vkFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: return "isubpassInput"; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: return "usubpassInput"; case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: return "subpassInput"; default: DE_FATAL("Unknown channel class"); return ""; } } std::string getAttachmentType (VkFormat vkFormat) { const tcu::TextureFormat format = mapVkFormat(vkFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: return "ivec4"; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: return "uvec4"; case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: return "vec4"; default: DE_FATAL("Unknown channel class"); return ""; } } void createTestShaders (SourceCollections& dst, TestConfig config) { if (config.renderTypes & TestConfig::RENDERTYPES_DRAW) { const vector& subpasses = config.renderPass.getSubpasses(); for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++) { const Subpass& subpass = subpasses[subpassNdx]; deUint32 inputAttachmentBinding = 0; std::ostringstream vertexShader; std::ostringstream fragmentShader; vertexShader << "#version 310 es\n" << "layout(location = 0) in highp vec2 a_position;\n" << "void main (void) {\n" << "\tgl_Position = vec4(a_position, 1.0, 1.0);\n" << "}\n"; fragmentShader << "#version 310 es\n" << "precision highp float;\n"; for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getInputAttachments()[attachmentNdx].getAttachment(); const VkImageLayout layout = subpass.getInputAttachments()[attachmentNdx].getImageLayout(); const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const bool isDepthFormat = tcu::hasDepthComponent(format.order); const bool isStencilFormat = tcu::hasStencilComponent(format.order); if (isDepthFormat || isStencilFormat) { if (isDepthFormat && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) { fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp subpassInput i_depth" << attachmentNdx << ";\n"; inputAttachmentBinding++; } if (isStencilFormat && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp usubpassInput i_stencil" << attachmentNdx << ";\n"; inputAttachmentBinding++; } } else { const std::string attachmentType = getInputAttachmentType(attachment.getFormat()); fragmentShader << "layout(input_attachment_index = " << attachmentNdx << ", set=0, binding=" << inputAttachmentBinding << ") uniform highp " << attachmentType << " i_color" << attachmentNdx << ";\n"; inputAttachmentBinding++; } } for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[subpass.getColorAttachments()[attachmentNdx].getAttachment()].getFormat()); fragmentShader << "layout(location = " << attachmentNdx << ") out highp " << attachmentType << " o_color" << attachmentNdx << ";\n"; } fragmentShader << "void main (void) {\n"; if (subpass.getInputAttachments().empty()) { for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentNdx].getAttachment(); const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[attachmentIndex].getFormat()); fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(vec4("; for (size_t compNdx = 0; compNdx < 4; compNdx++) { const size_t index = subpassNdx + attachmentIndex + compNdx; const BoolOp op = boolOpFromIndex(index); if (compNdx > 0) fragmentShader << ",\n\t\t"; fragmentShader << "((int(gl_FragCoord.x) % 2 == " << (index % 2) << ") " << boolOpToString(op) << " (" << "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2) << ") ? 1.0 : 0.0)"; } fragmentShader << "));\n"; } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const size_t index = subpassNdx + 1; const BoolOp op = boolOpFromIndex(index); fragmentShader << "\tgl_FragDepth = ((int(gl_FragCoord.x) % 2 == " << (index % 2) << ") " << boolOpToString(op) << " (" << "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2) << ") ? 1.0 : 0.0);\n"; } } else { size_t inputComponentCount = 0; size_t outputComponentCount = 0; for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getInputAttachments()[attachmentNdx].getAttachment(); const VkImageLayout layout = subpass.getInputAttachments()[attachmentNdx].getImageLayout(); const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const size_t componentCount = (size_t)tcu::getNumUsedChannels(format.order); if (layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) inputComponentCount += 1; else if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) inputComponentCount += 1; else inputComponentCount += componentCount; } for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentNdx].getAttachment(); const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const size_t componentCount = (size_t)tcu::getNumUsedChannels(format.order); outputComponentCount += componentCount; } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { outputComponentCount++; } if (outputComponentCount > 0) { const size_t inputsPerOutput = inputComponentCount >= outputComponentCount ? ((inputComponentCount / outputComponentCount) + ((inputComponentCount % outputComponentCount) != 0 ? 1 : 0)) : 1; fragmentShader << "\tbool inputs[" << inputComponentCount << "];\n"; if (outputComponentCount > 0) fragmentShader << "\tbool outputs[" << outputComponentCount << "];\n"; size_t inputValueNdx = 0; for (size_t attachmentNdx = 0; attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++) { const char* const components[] = { "x", "y", "z", "w" }; const deUint32 attachmentIndex = subpass.getInputAttachments()[attachmentNdx].getAttachment(); const VkImageLayout layout = subpass.getInputAttachments()[attachmentNdx].getImageLayout(); const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const size_t componentCount = (size_t)tcu::getNumUsedChannels(format.order); const bool isDepthFormat = tcu::hasDepthComponent(format.order); const bool isStencilFormat = tcu::hasStencilComponent(format.order); if (isDepthFormat || isStencilFormat) { if (isDepthFormat && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR) { fragmentShader << "\tinputs[" << inputValueNdx << "] = 1.0 == float(subpassLoad(i_depth" << attachmentNdx << ").x);\n"; inputValueNdx++; } if (isStencilFormat && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { fragmentShader << "\tinputs[" << inputValueNdx << "] = 255u == subpassLoad(i_stencil" << attachmentNdx << ").x;\n"; inputValueNdx++; } } else { for (size_t compNdx = 0; compNdx < componentCount; compNdx++) { fragmentShader << "\tinputs[" << inputValueNdx << "] = 1.0 == float(subpassLoad(i_color" << attachmentNdx << ")." << components[compNdx] << ");\n"; inputValueNdx++; } } } size_t outputValueNdx = 0; for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentNdx].getAttachment(); const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[attachmentIndex].getFormat()); const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const size_t componentCount = (size_t)tcu::getNumUsedChannels(format.order); for (size_t compNdx = 0; compNdx < componentCount; compNdx++) { const size_t index = subpassNdx + attachmentIndex + outputValueNdx; const BoolOp op = boolOpFromIndex(index); fragmentShader << "\toutputs[" << outputValueNdx + compNdx << "] = " << "(int(gl_FragCoord.x) % 2 == " << (index % 2) << ") " << boolOpToString(op) << " (" << "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2) << ");\n"; for (size_t i = 0; i < inputsPerOutput; i++) fragmentShader << "\toutputs[" << outputValueNdx + compNdx << "] = outputs[" << outputValueNdx + compNdx << "] == inputs[" << ((outputValueNdx + compNdx) * inputsPerOutput + i) % inputComponentCount << "];\n"; } fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "("; for (size_t compNdx = 0; compNdx < 4; compNdx++) { if (compNdx > 0) fragmentShader << ", "; if (compNdx < componentCount) fragmentShader << "outputs[" << outputValueNdx + compNdx << "]"; else fragmentShader << "0"; } outputValueNdx += componentCount; fragmentShader << ");\n"; } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL && subpass.getDepthStencilAttachment().getImageLayout() != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { const deUint32 attachmentIndex = subpass.getDepthStencilAttachment().getAttachment(); const size_t index = subpassNdx + attachmentIndex; const BoolOp op = boolOpFromIndex(index); fragmentShader << "\toutputs[" << outputValueNdx << "] = " << "(int(gl_FragCoord.x) % 2 == " << (index % 2) << ") " << boolOpToString(op) << " (" << "int(gl_FragCoord.y) % 2 == " << ((index / 2) % 2) << ");\n"; for (size_t i = 0; i < inputsPerOutput; i++) fragmentShader << "\toutputs[" << outputValueNdx << "] = outputs[" << outputValueNdx << "] == inputs[" << (outputValueNdx * inputsPerOutput + i) % inputComponentCount << "];\n"; fragmentShader << "\tgl_FragDepth = outputs[" << outputValueNdx << "] ? 1.0 : 0.0;"; } } } fragmentShader << "}\n"; dst.glslSources.add(de::toString(subpassNdx) + "-vert") << glu::VertexSource(vertexShader.str()); dst.glslSources.add(de::toString(subpassNdx) + "-frag") << glu::FragmentSource(fragmentShader.str()); } } } void initializeAttachmentIsLazy (vector& attachmentIsLazy, const vector& attachments, TestConfig::ImageMemory imageMemory) { bool lastAttachmentWasLazy = false; for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { if (attachments[attachmentNdx].getLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD && attachments[attachmentNdx].getStoreOp() != VK_ATTACHMENT_STORE_OP_STORE && attachments[attachmentNdx].getStencilLoadOp() != VK_ATTACHMENT_LOAD_OP_LOAD && attachments[attachmentNdx].getStencilStoreOp() != VK_ATTACHMENT_STORE_OP_STORE) { if (imageMemory == TestConfig::IMAGEMEMORY_LAZY || (imageMemory & TestConfig::IMAGEMEMORY_LAZY && !lastAttachmentWasLazy)) { attachmentIsLazy.push_back(true); lastAttachmentWasLazy = true; } else if (imageMemory & TestConfig::IMAGEMEMORY_STRICT) { attachmentIsLazy.push_back(false); lastAttachmentWasLazy = false; } else DE_FATAL("Unknown imageMemory"); } else attachmentIsLazy.push_back(false); } } enum AttachmentRefType { ATTACHMENTREFTYPE_COLOR, ATTACHMENTREFTYPE_DEPTH_STENCIL, ATTACHMENTREFTYPE_INPUT, ATTACHMENTREFTYPE_RESOLVE, }; VkImageUsageFlags getImageUsageFromLayout (VkImageLayout layout) { switch (layout) { case VK_IMAGE_LAYOUT_GENERAL: case VK_IMAGE_LAYOUT_PREINITIALIZED: return 0; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: return VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: return VK_IMAGE_USAGE_TRANSFER_SRC_BIT; case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: return VK_IMAGE_USAGE_TRANSFER_DST_BIT; default: DE_FATAL("Unexpected image layout"); return 0; } } void getImageUsageFromAttachmentReferences(vector& attachmentImageUsage, AttachmentRefType refType, size_t count, const AttachmentReference* references) { for (size_t referenceNdx = 0; referenceNdx < count; ++referenceNdx) { const deUint32 attachment = references[referenceNdx].getAttachment(); if (attachment != VK_ATTACHMENT_UNUSED) { VkImageUsageFlags usage; switch (refType) { case ATTACHMENTREFTYPE_COLOR: case ATTACHMENTREFTYPE_RESOLVE: usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; break; case ATTACHMENTREFTYPE_DEPTH_STENCIL: usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; break; case ATTACHMENTREFTYPE_INPUT: usage = VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; break; default: DE_FATAL("Unexpected attachment reference type"); usage = 0; break; } attachmentImageUsage[attachment] |= usage; } } } void getImageUsageFromAttachmentReferences(vector& attachmentImageUsage, AttachmentRefType refType, const vector& references) { if (!references.empty()) { getImageUsageFromAttachmentReferences(attachmentImageUsage, refType, references.size(), &references[0]); } } void initializeAttachmentImageUsage (Context &context, vector& attachmentImageUsage, const RenderPass& renderPassInfo, const vector& attachmentIsLazy, const vector >& clearValues) { attachmentImageUsage.resize(renderPassInfo.getAttachments().size(), VkImageUsageFlags(0)); for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); ++subpassNdx) { const Subpass& subpass = renderPassInfo.getSubpasses()[subpassNdx]; getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_COLOR, subpass.getColorAttachments()); getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_DEPTH_STENCIL, 1, &subpass.getDepthStencilAttachment()); getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_INPUT, subpass.getInputAttachments()); getImageUsageFromAttachmentReferences(attachmentImageUsage, ATTACHMENTREFTYPE_RESOLVE, subpass.getResolveAttachments()); } for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { const Attachment& attachment = renderPassInfo.getAttachments()[attachmentNdx]; const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), attachment.getFormat()); const VkFormatFeatureFlags supportedFeatures = formatProperties.optimalTilingFeatures; if ((supportedFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) != 0) attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_SAMPLED_BIT; if ((supportedFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0) attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_STORAGE_BIT; attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getInitialLayout()); attachmentImageUsage[attachmentNdx] |= getImageUsageFromLayout(attachment.getFinalLayout()); if (!attachmentIsLazy[attachmentNdx]) { if (clearValues[attachmentNdx]) attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } else { const VkImageUsageFlags allowedTransientBits = static_cast(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT); attachmentImageUsage[attachmentNdx] &= allowedTransientBits; attachmentImageUsage[attachmentNdx] |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT; } } } void initializeSubpassIsSecondary (vector& subpassIsSecondary, const vector& subpasses, TestConfig::CommandBufferTypes commandBuffer) { bool lastSubpassWasSecondary = false; for (size_t subpassNdx = 0; subpassNdx < subpasses.size(); subpassNdx++) { if (commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY || (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary)) { subpassIsSecondary.push_back(true); lastSubpassWasSecondary = true; } else if (commandBuffer & TestConfig::COMMANDBUFFERTYPES_INLINE) { subpassIsSecondary.push_back(false); lastSubpassWasSecondary = false; } else DE_FATAL("Unknown commandBuffer"); } } void initializeImageClearValues (de::Random& rng, vector >& clearValues, const vector& attachments, const vector& isLazy) { for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { if (!isLazy[attachmentNdx]) clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng))); else clearValues.push_back(nothing()); } } void initializeRenderPassClearValues (de::Random& rng, vector >& clearValues, const vector& attachments) { for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { if (attachments[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR || attachments[attachmentNdx].getStencilLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR) { clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng))); } else clearValues.push_back(nothing()); } } void initializeSubpassClearValues (de::Random& rng, vector >& clearValues, const RenderPass& renderPass) { clearValues.resize(renderPass.getSubpasses().size()); for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++) { const Subpass& subpass = renderPass.getSubpasses()[subpassNdx]; const vector& colorAttachments = subpass.getColorAttachments(); clearValues[subpassNdx].resize(colorAttachments.size()); for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++) { const AttachmentReference& attachmentRef = colorAttachments[attachmentRefNdx]; const Attachment& attachment = renderPass.getAttachments()[attachmentRef.getAttachment()]; clearValues[subpassNdx][attachmentRefNdx] = randomColorClearValue(attachment, rng); } } } void logSubpassRenderInfo (TestLog& log, const SubpassRenderInfo& info) { log << TestLog::Message << "Viewport, offset: " << info.getViewportOffset() << ", size: " << info.getViewportSize() << TestLog::EndMessage; if (info.isSecondary()) log << TestLog::Message << "Subpass uses secondary command buffers" << TestLog::EndMessage; else log << TestLog::Message << "Subpass uses inlined commands" << TestLog::EndMessage; for (deUint32 attachmentNdx = 0; attachmentNdx < info.getColorClears().size(); attachmentNdx++) { const ColorClear& colorClear = info.getColorClears()[attachmentNdx]; log << TestLog::Message << "Clearing color attachment " << attachmentNdx << ". Offset: " << colorClear.getOffset() << ", Size: " << colorClear.getSize() << ", Color: " << clearColorToString(info.getColorAttachment(attachmentNdx).getFormat(), colorClear.getColor()) << TestLog::EndMessage; } if (info.getDepthStencilClear()) { const DepthStencilClear& depthStencilClear = *info.getDepthStencilClear(); log << TestLog::Message << "Clearing depth stencil attachment" << ". Offset: " << depthStencilClear.getOffset() << ", Size: " << depthStencilClear.getSize() << ", Depth: " << depthStencilClear.getDepth() << ", Stencil: " << depthStencilClear.getStencil() << TestLog::EndMessage; } if (info.getRenderQuad()) { const RenderQuad& renderQuad = *info.getRenderQuad(); log << TestLog::Message << "Rendering grid quad to " << renderQuad.getCornerA() << " -> " << renderQuad.getCornerB() << TestLog::EndMessage; } } void logTestCaseInfo (TestLog& log, const TestConfig& config, const vector& attachmentIsLazy, const vector >& imageClearValues, const vector >& renderPassClearValues, const vector& subpassRenderInfo) { const RenderPass& renderPass = config.renderPass; logRenderPassInfo(log, renderPass); DE_ASSERT(attachmentIsLazy.size() == renderPass.getAttachments().size()); DE_ASSERT(imageClearValues.size() == renderPass.getAttachments().size()); DE_ASSERT(renderPassClearValues.size() == renderPass.getAttachments().size()); log << TestLog::Message << "TargetSize: " << config.targetSize << TestLog::EndMessage; log << TestLog::Message << "Render area, Offset: " << config.renderPos << ", Size: " << config.renderSize << TestLog::EndMessage; for (size_t attachmentNdx = 0; attachmentNdx < attachmentIsLazy.size(); attachmentNdx++) { const tcu::ScopedLogSection section (log, "Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx)); if (attachmentIsLazy[attachmentNdx]) log << TestLog::Message << "Is lazy." << TestLog::EndMessage; if (imageClearValues[attachmentNdx]) log << TestLog::Message << "Image is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *imageClearValues[attachmentNdx]) << " before rendering." << TestLog::EndMessage; if (renderPass.getAttachments()[attachmentNdx].getLoadOp() == VK_ATTACHMENT_LOAD_OP_CLEAR && renderPassClearValues[attachmentNdx]) log << TestLog::Message << "Attachment is cleared to " << clearValueToString(renderPass.getAttachments()[attachmentNdx].getFormat(), *renderPassClearValues[attachmentNdx]) << " in the beginning of the render pass." << TestLog::EndMessage; } for (size_t subpassNdx = 0; subpassNdx < renderPass.getSubpasses().size(); subpassNdx++) { const tcu::ScopedLogSection section (log, "Subpass" + de::toString(subpassNdx), "Subpass " + de::toString(subpassNdx)); logSubpassRenderInfo(log, subpassRenderInfo[subpassNdx]); } } float roundToViewport (float x, deUint32 offset, deUint32 size) { const float origin = (float)(offset) + ((float(size) / 2.0f)); const float p = (float)(size) / 2.0f; const deInt32 xi = deRoundFloatToInt32(origin + (p * x)); return (((float)xi) - origin) / p; } void initializeSubpassRenderInfo (vector& renderInfos, de::Random& rng, const RenderPass& renderPass, const TestConfig& config) { const TestConfig::CommandBufferTypes commandBuffer = config.commandBufferTypes; const vector& subpasses = renderPass.getSubpasses(); bool lastSubpassWasSecondary = false; for (deUint32 subpassNdx = 0; subpassNdx < (deUint32)subpasses.size(); subpassNdx++) { const Subpass& subpass = subpasses[subpassNdx]; const bool subpassIsSecondary = commandBuffer == TestConfig::COMMANDBUFFERTYPES_SECONDARY || (commandBuffer & TestConfig::COMMANDBUFFERTYPES_SECONDARY && !lastSubpassWasSecondary) ? true : false; const UVec2 viewportSize ((config.renderSize * UVec2(2)) / UVec2(3)); const UVec2 viewportOffset (config.renderPos.x() + (subpassNdx % 2) * (config.renderSize.x() / 3), config.renderPos.y() + ((subpassNdx / 2) % 2) * (config.renderSize.y() / 3)); vector colorClears; Maybe depthStencilClear; Maybe renderQuad; lastSubpassWasSecondary = subpassIsSecondary; if (config.renderTypes & TestConfig::RENDERTYPES_CLEAR) { const vector& colorAttachments = subpass.getColorAttachments(); for (size_t attachmentRefNdx = 0; attachmentRefNdx < colorAttachments.size(); attachmentRefNdx++) { const AttachmentReference& attachmentRef = colorAttachments[attachmentRefNdx]; const Attachment& attachment = renderPass.getAttachments()[attachmentRef.getAttachment()]; const UVec2 size ((viewportSize * UVec2(2)) / UVec2(3)); const UVec2 offset (viewportOffset.x() + ((deUint32)attachmentRefNdx % 2u) * (viewportSize.x() / 3u), viewportOffset.y() + (((deUint32)attachmentRefNdx / 2u) % 2u) * (viewportSize.y() / 3u)); const VkClearColorValue color = randomColorClearValue(attachment, rng); colorClears.push_back(ColorClear(offset, size, color)); } if (subpass.getDepthStencilAttachment().getAttachment() != VK_ATTACHMENT_UNUSED) { const Attachment& attachment = renderPass.getAttachments()[subpass.getDepthStencilAttachment().getAttachment()]; const UVec2 size ((viewportSize * UVec2(2)) / UVec2(3)); const UVec2 offset (viewportOffset.x() + ((deUint32)colorAttachments.size() % 2u) * (viewportSize.x() / 3u), viewportOffset.y() + (((deUint32)colorAttachments.size() / 2u) % 2u) * (viewportSize.y() / 3u)); const VkClearValue value = randomClearValue(attachment, rng); depthStencilClear = tcu::just(DepthStencilClear(offset, size, value.depthStencil.depth, value.depthStencil.stencil)); } } if (config.renderTypes & TestConfig::RENDERTYPES_DRAW) { const float w = (subpassNdx % 2) == 0 ? 1.0f : 1.25f; const float h = (subpassNdx % 2) == 0 ? 1.25f : 1.0f; const float x0 = roundToViewport((subpassNdx % 2) == 0 ? 1.0f - w : -1.0f, viewportOffset.x(), viewportSize.x()); const float x1 = roundToViewport((subpassNdx % 2) == 0 ? 1.0f : -1.0f + w, viewportOffset.x(), viewportSize.x()); const float y0 = roundToViewport(((subpassNdx / 2) % 2) == 0 ? 1.0f - h : -1.0f, viewportOffset.y(), viewportSize.y()); const float y1 = roundToViewport(((subpassNdx / 2) % 2) == 0 ? 1.0f : -1.0f + h, viewportOffset.y(), viewportSize.y()); renderQuad = tcu::just(RenderQuad(tcu::Vec2(x0, y0), tcu::Vec2(x1, y1))); } renderInfos.push_back(SubpassRenderInfo(renderPass, subpassNdx, subpassIsSecondary, viewportOffset, viewportSize, renderQuad, colorClears, depthStencilClear)); } } void checkTextureFormatSupport (TestLog& log, const InstanceInterface& vk, VkPhysicalDevice device, const vector& attachments) { bool supported = true; for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { const Attachment& attachment = attachments[attachmentNdx]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const bool isDepthOrStencilAttachment = hasDepthComponent(format.order) || hasStencilComponent(format.order); const VkFormatFeatureFlags flags = isDepthOrStencilAttachment? VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT : VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; VkFormatProperties properties; vk.getPhysicalDeviceFormatProperties(device, attachment.getFormat(), &properties); if ((properties.optimalTilingFeatures & flags) != flags) { supported = false; log << TestLog::Message << "Format: " << attachment.getFormat() << " not supported as " << (isDepthOrStencilAttachment ? "depth stencil attachment" : "color attachment") << TestLog::EndMessage; } } if (!supported) TCU_THROW(NotSupportedError, "Format not supported"); } tcu::TestStatus renderPassTest (Context& context, TestConfig config) { const UVec2 targetSize = config.targetSize; const UVec2 renderPos = config.renderPos; const UVec2 renderSize = config.renderSize; const RenderPass& renderPassInfo = config.renderPass; TestLog& log = context.getTestContext().getLog(); de::Random rng (config.seed); vector attachmentIsLazy; vector attachmentImageUsage; vector > imageClearValues; vector > renderPassClearValues; vector subpassIsSecondary; vector subpassRenderInfo; vector > subpassColorClearValues; if (config.allocationKind == ALLOCATION_KIND_DEDICATED) { const std::string extensionName("VK_KHR_dedicated_allocation"); if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), extensionName)) TCU_THROW(NotSupportedError, std::string(extensionName + " is not supported").c_str()); } if (!renderPassInfo.getInputAspects().empty()) { if (!de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), string("VK_KHR_maintenance2"))) TCU_THROW(NotSupportedError, "Extension VK_KHR_maintenance2 not supported."); } { bool requireDepthStencilLayout = false; for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { if (renderPassInfo.getAttachments()[attachmentNdx].getInitialLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || renderPassInfo.getAttachments()[attachmentNdx].getInitialLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR || renderPassInfo.getAttachments()[attachmentNdx].getFinalLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || renderPassInfo.getAttachments()[attachmentNdx].getFinalLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { requireDepthStencilLayout = true; break; } } for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size() && !requireDepthStencilLayout; subpassNdx++) { const Subpass& subpass (renderPassInfo.getSubpasses()[subpassNdx]); for (size_t attachmentNdx = 0; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { if (subpass.getColorAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || subpass.getColorAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { requireDepthStencilLayout = true; break; } } for (size_t attachmentNdx = 0; !requireDepthStencilLayout && attachmentNdx < subpass.getInputAttachments().size(); attachmentNdx++) { if (subpass.getInputAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || subpass.getInputAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { requireDepthStencilLayout = true; break; } } for (size_t attachmentNdx = 0; !requireDepthStencilLayout && attachmentNdx < subpass.getResolveAttachments().size(); attachmentNdx++) { if (subpass.getResolveAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || subpass.getResolveAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { requireDepthStencilLayout = true; break; } } if (subpass.getDepthStencilAttachment().getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR || subpass.getDepthStencilAttachment().getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR) { requireDepthStencilLayout = true; break; } } if (requireDepthStencilLayout && !de::contains(context.getDeviceExtensions().begin(), context.getDeviceExtensions().end(), string("VK_KHR_maintenance2"))) TCU_THROW(NotSupportedError, "VK_KHR_maintenance2 is not supported"); } initializeAttachmentIsLazy(attachmentIsLazy, renderPassInfo.getAttachments(), config.imageMemory); initializeImageClearValues(rng, imageClearValues, renderPassInfo.getAttachments(), attachmentIsLazy); initializeAttachmentImageUsage(context, attachmentImageUsage, renderPassInfo, attachmentIsLazy, imageClearValues); initializeRenderPassClearValues(rng, renderPassClearValues, renderPassInfo.getAttachments()); initializeSubpassIsSecondary(subpassIsSecondary, renderPassInfo.getSubpasses(), config.commandBufferTypes); initializeSubpassClearValues(rng, subpassColorClearValues, renderPassInfo); initializeSubpassRenderInfo(subpassRenderInfo, rng, renderPassInfo, config); logTestCaseInfo(log, config, attachmentIsLazy, imageClearValues, renderPassClearValues, subpassRenderInfo); checkTextureFormatSupport(log, context.getInstanceInterface(), context.getPhysicalDevice(), config.renderPass.getAttachments()); { const vk::VkPhysicalDeviceProperties properties = vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()); log << TestLog::Message << "Max color attachments: " << properties.limits.maxColorAttachments << TestLog::EndMessage; for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++) { if (renderPassInfo.getSubpasses()[subpassNdx].getColorAttachments().size() > (size_t)properties.limits.maxColorAttachments) TCU_THROW(NotSupportedError, "Subpass uses more than maxColorAttachments."); } } { const InstanceInterface& vki = context.getInstanceInterface(); const VkPhysicalDevice& physDevice = context.getPhysicalDevice(); const VkDevice device = context.getDevice(); const DeviceInterface& vk = context.getDeviceInterface(); const VkQueue queue = context.getUniversalQueue(); const deUint32 queueIndex = context.getUniversalQueueFamilyIndex(); Allocator& allocator = context.getDefaultAllocator(); const Unique renderPass (createRenderPass(vk, device, renderPassInfo)); const Unique commandBufferPool (createCommandPool(vk, device, queueIndex, 0)); const Unique initializeImagesCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); const Unique renderCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); const Unique readImagesToBuffersCommandBuffer (allocateCommandBuffer(vk, device, *commandBufferPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); vector > attachmentResources; vector > subpassRenderers; vector attachmentImages; vector attachmentViews; vector > inputAttachmentViews; for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { const Attachment& attachmentInfo = renderPassInfo.getAttachments()[attachmentNdx]; attachmentResources.push_back(de::SharedPtr(new AttachmentResources(vki, physDevice, vk, device, allocator, queueIndex, targetSize, attachmentInfo, attachmentImageUsage[attachmentNdx], config.allocationKind))); attachmentViews.push_back(attachmentResources[attachmentNdx]->getAttachmentView()); attachmentImages.push_back(attachmentResources[attachmentNdx]->getImage()); inputAttachmentViews.push_back(attachmentResources[attachmentNdx]->getInputAttachmentViews()); } beginCommandBuffer(vk, *initializeImagesCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0); pushImageInitializationCommands(vk, *initializeImagesCommandBuffer, renderPassInfo.getAttachments(), attachmentResources, queueIndex, imageClearValues); endCommandBuffer(vk, *initializeImagesCommandBuffer); { const Unique framebuffer (createFramebuffer(vk, device, *renderPass, targetSize, attachmentViews)); for (size_t subpassNdx = 0; subpassNdx < renderPassInfo.getSubpasses().size(); subpassNdx++) subpassRenderers.push_back(de::SharedPtr(new SubpassRenderer(context, vk, device, allocator, *renderPass, *framebuffer, *commandBufferPool, queueIndex, attachmentImages, inputAttachmentViews, subpassRenderInfo[subpassNdx], config.renderPass.getAttachments(), config.allocationKind))); beginCommandBuffer(vk, *renderCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0); pushRenderPassCommands(vk, *renderCommandBuffer, *renderPass, *framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, config.renderTypes); endCommandBuffer(vk, *renderCommandBuffer); beginCommandBuffer(vk, *readImagesToBuffersCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0); pushReadImagesToBuffers(vk, *readImagesToBuffersCommandBuffer, queueIndex, attachmentResources, renderPassInfo.getAttachments(), attachmentIsLazy, targetSize); endCommandBuffer(vk, *readImagesToBuffersCommandBuffer); { const VkCommandBuffer commandBuffers[] = { *initializeImagesCommandBuffer, *renderCommandBuffer, *readImagesToBuffersCommandBuffer }; const Unique fence (createFence(vk, device, 0u)); queueSubmit(vk, queue, DE_LENGTH_OF_ARRAY(commandBuffers), commandBuffers, *fence); waitForFences(vk, device, 1, &fence.get(), VK_TRUE, ~0ull); } } if (logAndVerifyImages(log, vk, device, attachmentResources, attachmentIsLazy, renderPassInfo, renderPassClearValues, imageClearValues, subpassRenderInfo, targetSize, config)) return tcu::TestStatus::pass("Pass"); else return tcu::TestStatus::fail("Result verification failed"); } } static const VkFormat s_coreColorFormats[] = { VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, VK_FORMAT_A8B8G8R8_SINT_PACK32, VK_FORMAT_A8B8G8R8_SRGB_PACK32, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2B10G10R10_UINT_PACK32, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM, VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT, VK_FORMAT_R16_SFLOAT, VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT, VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_R16G16B16A16_SNORM, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT, VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_SFLOAT }; static const VkFormat s_coreDepthStencilFormats[] = { VK_FORMAT_D16_UNORM, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT }; void addAttachmentTests (tcu::TestCaseGroup* group, AllocationKind allocationKind) { const deUint32 attachmentCounts[] = { 1, 3, 4, 8 }; 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 }; const VkImageLayout initialAndFinalColorLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; const VkImageLayout initialAndFinalDepthStencilLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; const VkImageLayout subpassLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; const VkImageLayout depthStencilLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; const TestConfig::RenderTypes renderCommands[] = { TestConfig::RENDERTYPES_NONE, TestConfig::RENDERTYPES_CLEAR, TestConfig::RENDERTYPES_DRAW, TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW, }; const TestConfig::CommandBufferTypes commandBuffers[] = { TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::COMMANDBUFFERTYPES_SECONDARY, TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY }; const TestConfig::ImageMemory imageMemories[] = { TestConfig::IMAGEMEMORY_STRICT, TestConfig::IMAGEMEMORY_LAZY, TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY }; const UVec2 targetSizes[] = { UVec2(64, 64), UVec2(63, 65) }; const UVec2 renderPositions[] = { UVec2(0, 0), UVec2(3, 17) }; const UVec2 renderSizes[] = { UVec2(32, 32), UVec2(60, 47) }; tcu::TestContext& testCtx = group->getTestContext(); de::Random rng (1433774382u); for (size_t attachmentCountNdx = 0; attachmentCountNdx < DE_LENGTH_OF_ARRAY(attachmentCounts); attachmentCountNdx++) { const deUint32 attachmentCount = attachmentCounts[attachmentCountNdx]; const deUint32 testCaseCount = (attachmentCount == 1 ? 100 : 200); de::MovePtr attachmentCountGroup (new tcu::TestCaseGroup(testCtx, de::toString(attachmentCount).c_str(), de::toString(attachmentCount).c_str())); for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++) { const bool useDepthStencil = rng.getBool(); VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_GENERAL; vector attachments; vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) { const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; const VkFormat format = rng.choose(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats)); const VkAttachmentLoadOp loadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp storeOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); const VkImageLayout initialLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkImageLayout finalizeLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); const VkAttachmentLoadOp stencilLoadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp stencilStoreOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); } if (useDepthStencil) { const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; const VkFormat format = rng.choose(DE_ARRAY_BEGIN(s_coreDepthStencilFormats), DE_ARRAY_END(s_coreDepthStencilFormats)); const VkAttachmentLoadOp loadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp storeOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); const VkImageLayout initialLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)); const VkImageLayout finalizeLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)); const VkAttachmentLoadOp stencilLoadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp stencilStoreOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); depthStencilLayout = rng.choose(DE_ARRAY_BEGIN(depthStencilLayouts), DE_ARRAY_END(depthStencilLayouts)); attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); } { const TestConfig::RenderTypes render = rng.choose(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands)); const TestConfig::CommandBufferTypes commandBuffer = rng.choose(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers)); const TestConfig::ImageMemory imageMemory = rng.choose(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories)); const vector subpasses (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference((useDepthStencil ? (deUint32)(attachments.size() - 1) : VK_ATTACHMENT_UNUSED), depthStencilLayout), vector())); const vector deps; const string testCaseName = de::toString(attachmentCountNdx * testCaseCount + testCaseNdx); const RenderPass renderPass (attachments, subpasses, deps); const UVec2 targetSize = rng.choose(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes)); const UVec2 renderPos = rng.choose(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions)); const UVec2 renderSize = rng.choose(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes)); addFunctionCaseWithPrograms(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 1293809, allocationKind)); } } group->addChild(attachmentCountGroup.release()); } } template T chooseRandom (de::Random& rng, const set& values) { size_t ndx = ((size_t)rng.getUint32()) % values.size(); typename set::const_iterator iter = values.begin(); for (; ndx > 0; ndx--) iter++; return *iter; } void addAttachmentAllocationTests (tcu::TestCaseGroup* group, AllocationKind allocationKind) { const deUint32 attachmentCounts[] = { 4, 8 }; 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 }; const VkImageLayout initialAndFinalColorLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; const VkImageLayout initialAndFinalDepthStencilLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; const VkImageLayout subpassLayouts[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, }; enum AllocationType { // Each pass uses one more attachmen than previous one ALLOCATIONTYPE_GROW, // Each pass uses one less attachment than previous one ALLOCATIONTYPE_SHRINK, // Each pass drops one attachment and picks up new one ALLOCATIONTYPE_ROLL, // Start by growing and end by shrinking ALLOCATIONTYPE_GROW_SHRINK, // Each subpass has single input and single output attachment ALLOCATIONTYPE_IO_CHAIN, // Each subpass has multiple inputs and multiple outputs attachment ALLOCATIONTYPE_IO_GENERIC }; const AllocationType allocationTypes[] = { ALLOCATIONTYPE_GROW, ALLOCATIONTYPE_SHRINK, ALLOCATIONTYPE_ROLL, ALLOCATIONTYPE_GROW_SHRINK, ALLOCATIONTYPE_IO_CHAIN, ALLOCATIONTYPE_IO_GENERIC }; const char* const allocationTypeStr[] = { "grow", "shrink", "roll", "grow_shrink", "input_output_chain", "input_output", }; const TestConfig::RenderTypes renderCommands[] = { TestConfig::RENDERTYPES_NONE, TestConfig::RENDERTYPES_CLEAR, TestConfig::RENDERTYPES_DRAW, TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW, }; const TestConfig::CommandBufferTypes commandBuffers[] = { TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::COMMANDBUFFERTYPES_SECONDARY, TestConfig::COMMANDBUFFERTYPES_INLINE|TestConfig::COMMANDBUFFERTYPES_SECONDARY }; const TestConfig::ImageMemory imageMemories[] = { TestConfig::IMAGEMEMORY_STRICT, TestConfig::IMAGEMEMORY_LAZY, TestConfig::IMAGEMEMORY_STRICT|TestConfig::IMAGEMEMORY_LAZY }; const UVec2 targetSizes[] = { UVec2(64, 64), UVec2(63, 65) }; const UVec2 renderPositions[] = { UVec2(0, 0), UVec2(3, 17) }; const UVec2 renderSizes[] = { UVec2(32, 32), UVec2(60, 47) }; tcu::TestContext& testCtx = group->getTestContext(); de::Random rng (3700649827u); for (size_t allocationTypeNdx = 0; allocationTypeNdx < DE_LENGTH_OF_ARRAY(allocationTypes); allocationTypeNdx++) { const AllocationType allocationType = allocationTypes[allocationTypeNdx]; const size_t testCaseCount = 100; de::MovePtr allocationTypeGroup (new tcu::TestCaseGroup(testCtx, allocationTypeStr[allocationTypeNdx], allocationTypeStr[allocationTypeNdx])); for (size_t testCaseNdx = 0; testCaseNdx < testCaseCount; testCaseNdx++) { if (allocationType == ALLOCATIONTYPE_IO_GENERIC) { const deUint32 attachmentCount = 4u + rng.getUint32() % 31u; const deUint32 subpassCount = 4u + rng.getUint32() % 31u; vector attachments; set definedAttachments; vector subpasses; set colorAttachments; set depthStencilAttachments; for (deUint32 attachmentIndex = 0; attachmentIndex < attachmentCount; attachmentIndex++) { const bool isDepthStencilAttachment = rng.getFloat() < 0.01f; const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; const VkAttachmentLoadOp loadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp storeOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); const VkImageLayout initialLayout = isDepthStencilAttachment ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkImageLayout finalizeLayout = isDepthStencilAttachment ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkAttachmentLoadOp stencilLoadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp stencilStoreOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); if (isDepthStencilAttachment) { const VkFormat format = rng.choose(DE_ARRAY_BEGIN(s_coreDepthStencilFormats), DE_ARRAY_END(s_coreDepthStencilFormats)); if (loadOp == VK_ATTACHMENT_LOAD_OP_LOAD || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR || stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD || stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) definedAttachments.insert(attachmentIndex); depthStencilAttachments.insert(attachmentIndex); attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); } else { const VkFormat format = rng.choose(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats)); if (loadOp == VK_ATTACHMENT_LOAD_OP_LOAD || loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) definedAttachments.insert(attachmentIndex); colorAttachments.insert(attachmentIndex); attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); } } vector > lastUseOfAttachment (attachments.size(), nothing()); vector deps; for (deUint32 subpassIndex = 0; subpassIndex < subpassCount; subpassIndex++) { const deUint32 colorAttachmentCount = depthStencilAttachments.empty() ? 1 + rng.getUint32() % de::min(4u, (deUint32)colorAttachments.size()) : rng.getUint32() % (de::min(4u, (deUint32)colorAttachments.size()) + 1u); const deUint32 inputAttachmentCount = rng.getUint32() % (deUint32)(de::min(4, definedAttachments.size()) + 1); const bool useDepthStencilAttachment = !depthStencilAttachments.empty() && (colorAttachmentCount == 0 || rng.getBool()); std::vector subpassColorAttachments (colorAttachmentCount); std::vector subpassInputAttachments (inputAttachmentCount); Maybe depthStencilAttachment (useDepthStencilAttachment ? just(chooseRandom(rng, depthStencilAttachments)) : nothing()); std::vector subpassPreserveAttachments; rng.choose(colorAttachments.begin(), colorAttachments.end(), subpassColorAttachments.begin(), colorAttachmentCount); rng.choose(definedAttachments.begin(), definedAttachments.end(), subpassInputAttachments.begin(), inputAttachmentCount); for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpassColorAttachments.size(); colorAttachmentNdx++) definedAttachments.insert(subpassColorAttachments[colorAttachmentNdx]); if (depthStencilAttachment) definedAttachments.insert(*depthStencilAttachment); { std::vector inputAttachmentReferences; std::vector colorAttachmentReferences; AttachmentReference depthStencilAttachmentReference (VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL); for (size_t colorAttachmentNdx = 0; colorAttachmentNdx < subpassColorAttachments.size(); colorAttachmentNdx++) { const deUint32 colorAttachmentIndex = subpassColorAttachments[colorAttachmentNdx]; // \todo [mika 2016-08-25] Check if attachment is not used as input attachment and use other image layouts const VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_GENERAL; if (lastUseOfAttachment[colorAttachmentIndex]) { const bool byRegion = rng.getBool(); deps.push_back(SubpassDependency(*lastUseOfAttachment[colorAttachmentIndex], subpassIndex, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u)); } lastUseOfAttachment[colorAttachmentIndex] = just(subpassIndex); colorAttachmentReferences.push_back(AttachmentReference((deUint32)subpassColorAttachments[colorAttachmentNdx], subpassLayout)); } for (size_t inputAttachmentNdx = 0; inputAttachmentNdx < subpassInputAttachments.size(); inputAttachmentNdx++) { const deUint32 inputAttachmentIndex = subpassInputAttachments[inputAttachmentNdx]; // \todo [mika 2016-08-25] Check if attachment is not used as color attachment and use other image layouts const VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_GENERAL; if(lastUseOfAttachment[inputAttachmentIndex]) { if(*lastUseOfAttachment[inputAttachmentIndex] == subpassIndex) { deps.push_back(SubpassDependency(subpassIndex, subpassIndex, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT)); } else { const bool byRegion = rng.getBool(); deps.push_back(SubpassDependency(*lastUseOfAttachment[inputAttachmentIndex], subpassIndex, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u)); } lastUseOfAttachment[inputAttachmentIndex] = just(subpassIndex); inputAttachmentReferences.push_back(AttachmentReference((deUint32)subpassInputAttachments[inputAttachmentNdx], subpassLayout)); } } if (depthStencilAttachment) { // \todo [mika 2016-08-25] Check if attachment is not used as input attachment and use other image layouts if (lastUseOfAttachment[*depthStencilAttachment]) { if(*lastUseOfAttachment[*depthStencilAttachment] == subpassIndex) { deps.push_back(SubpassDependency(subpassIndex, subpassIndex, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT)); } else { const bool byRegion = rng.getBool(); deps.push_back(SubpassDependency(*lastUseOfAttachment[*depthStencilAttachment], subpassIndex, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u)); } } lastUseOfAttachment[*depthStencilAttachment] = just(subpassIndex); depthStencilAttachmentReference = AttachmentReference(*depthStencilAttachment, VK_IMAGE_LAYOUT_GENERAL); } else depthStencilAttachmentReference = AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL); vector preserveAttachments; for (deUint32 attachmentIndex = 0; attachmentIndex < (deUint32)attachments.size(); attachmentIndex++) { if (lastUseOfAttachment[attachmentIndex] && (*lastUseOfAttachment[attachmentIndex]) != subpassIndex) preserveAttachments.push_back(attachmentIndex); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, inputAttachmentReferences, colorAttachmentReferences, vector(), depthStencilAttachmentReference, preserveAttachments)); } } { const TestConfig::RenderTypes render = rng.choose(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands)); const TestConfig::CommandBufferTypes commandBuffer = rng.choose(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers)); const TestConfig::ImageMemory imageMemory = rng.choose(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories)); const string testCaseName = de::toString(testCaseNdx); const UVec2 targetSize = rng.choose(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes)); const UVec2 renderPos = rng.choose(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions)); const UVec2 renderSize = rng.choose(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes)); const RenderPass renderPass (attachments, subpasses, deps); addFunctionCaseWithPrograms(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329, allocationKind)); } } else { const deUint32 attachmentCount = rng.choose(DE_ARRAY_BEGIN(attachmentCounts), DE_ARRAY_END(attachmentCounts)); vector attachments; vector subpasses; for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) { const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; const VkFormat format = rng.choose(DE_ARRAY_BEGIN(s_coreColorFormats), DE_ARRAY_END(s_coreColorFormats)); const VkAttachmentLoadOp loadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp storeOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); const VkImageLayout initialLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkImageLayout finalizeLayout = rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)); const VkAttachmentLoadOp stencilLoadOp = rng.choose(DE_ARRAY_BEGIN(loadOps), DE_ARRAY_END(loadOps)); const VkAttachmentStoreOp stencilStoreOp = rng.choose(DE_ARRAY_BEGIN(storeOps), DE_ARRAY_END(storeOps)); attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); } if (allocationType == ALLOCATIONTYPE_GROW) { for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++) { vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++) { const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } } else if (allocationType == ALLOCATIONTYPE_SHRINK) { for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++) { vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++) { const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } } else if (allocationType == ALLOCATIONTYPE_ROLL) { for (size_t subpassNdx = 0; subpassNdx < attachmentCount / 2; subpassNdx++) { vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < attachmentCount / 2; attachmentNdx++) { const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)(subpassNdx + attachmentNdx), subpassLayout)); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } } else if (allocationType == ALLOCATIONTYPE_GROW_SHRINK) { for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++) { vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < subpassNdx + 1; attachmentNdx++) { const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } for (size_t subpassNdx = 0; subpassNdx < attachmentCount; subpassNdx++) { vector colorAttachmentReferences; for (size_t attachmentNdx = 0; attachmentNdx < (attachmentCount - subpassNdx); attachmentNdx++) { const VkImageLayout subpassLayout = rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); } subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } } else if (allocationType == ALLOCATIONTYPE_IO_CHAIN) { subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)))), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); for (size_t subpassNdx = 1; subpassNdx < attachmentCount; subpassNdx++) { subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference((deUint32)(subpassNdx - 1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)), vector(1, AttachmentReference((deUint32)(subpassNdx), rng.choose(DE_ARRAY_BEGIN(subpassLayouts), DE_ARRAY_END(subpassLayouts)))), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); } } else DE_FATAL("Unknown allocation type"); { const TestConfig::RenderTypes render = rng.choose(DE_ARRAY_BEGIN(renderCommands), DE_ARRAY_END(renderCommands)); const TestConfig::CommandBufferTypes commandBuffer = rng.choose(DE_ARRAY_BEGIN(commandBuffers), DE_ARRAY_END(commandBuffers)); const TestConfig::ImageMemory imageMemory = rng.choose(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories)); const string testCaseName = de::toString(testCaseNdx); const UVec2 targetSize = rng.choose(DE_ARRAY_BEGIN(targetSizes), DE_ARRAY_END(targetSizes)); const UVec2 renderPos = rng.choose(DE_ARRAY_BEGIN(renderPositions), DE_ARRAY_END(renderPositions)); const UVec2 renderSize = rng.choose(DE_ARRAY_BEGIN(renderSizes), DE_ARRAY_END(renderSizes)); vector deps; for (size_t subpassNdx = 0; subpassNdx < subpasses.size() - 1; subpassNdx++) { const bool byRegion = rng.getBool(); deps.push_back(SubpassDependency((deUint32)subpassNdx, (deUint32)subpassNdx + 1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, byRegion ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u)); } const RenderPass renderPass (attachments, subpasses, deps); addFunctionCaseWithPrograms(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, TestConfig(renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, 80329, allocationKind)); } } } group->addChild(allocationTypeGroup.release()); } } void addSimpleTests (tcu::TestCaseGroup* group, AllocationKind allocationKind) { const UVec2 targetSize (64, 64); const UVec2 renderPos (0, 0); const UVec2 renderSize (64, 64); // color { const RenderPass renderPass (vector(1, Attachment(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())), vector()); addFunctionCaseWithPrograms(group, "color", "Single color attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // depth { const RenderPass renderPass (vector(1, Attachment(VK_FORMAT_X8_D24_UNORM_PACK32, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "depth", "Single depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // stencil { const RenderPass renderPass (vector(1, Attachment(VK_FORMAT_S8_UINT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "stencil", "Single stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // depth_stencil { const RenderPass renderPass (vector(1, Attachment(VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "depth_stencil", "Single depth stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // color_depth { const Attachment attachments[] = { Attachment(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), Attachment(VK_FORMAT_X8_D24_UNORM_PACK32, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), }; const RenderPass renderPass (vector(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "color_depth", "Color and depth attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // color_stencil { const Attachment attachments[] = { Attachment(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), Attachment(VK_FORMAT_S8_UINT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), }; const RenderPass renderPass (vector(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "color_stencil", "Color and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } // color_depth_stencil { const Attachment attachments[] = { Attachment(VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL), Attachment(VK_FORMAT_D24_UNORM_S8_UINT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), }; const RenderPass renderPass (vector(DE_ARRAY_BEGIN(attachments), DE_ARRAY_END(attachments)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(group, "color_depth_stencil", "Color, depth and stencil attachment case.", createTestShaders, renderPassTest, TestConfig(renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } } std::string formatToName (VkFormat format) { const std::string formatStr = de::toString(format); const std::string prefix = "VK_FORMAT_"; DE_ASSERT(formatStr.substr(0, prefix.length()) == prefix); return de::toLower(formatStr.substr(prefix.length())); } void addFormatTests (tcu::TestCaseGroup* group, AllocationKind allocationKind) { tcu::TestContext& testCtx = group->getTestContext(); const UVec2 targetSize (64, 64); const UVec2 renderPos (0, 0); const UVec2 renderSize (64, 64); const struct { const char* const str; const VkAttachmentStoreOp op; } storeOps[] = { { "store", VK_ATTACHMENT_STORE_OP_STORE }, { "dont_care", VK_ATTACHMENT_STORE_OP_DONT_CARE } }; const struct { const char* const str; const VkAttachmentLoadOp op; } loadOps[] = { { "clear", VK_ATTACHMENT_LOAD_OP_CLEAR }, { "load", VK_ATTACHMENT_LOAD_OP_LOAD }, { "dont_care", VK_ATTACHMENT_LOAD_OP_DONT_CARE } }; const struct { const char* const str; const TestConfig::RenderTypes types; } renderTypes[] = { { "clear", TestConfig::RENDERTYPES_CLEAR }, { "draw", TestConfig::RENDERTYPES_DRAW }, { "clear_draw", TestConfig::RENDERTYPES_CLEAR|TestConfig::RENDERTYPES_DRAW } }; // Color formats for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreColorFormats); formatNdx++) { const VkFormat format = s_coreColorFormats[formatNdx]; de::MovePtr formatGroup (new tcu::TestCaseGroup(testCtx, formatToName(format).c_str(), de::toString(format).c_str())); for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++) { const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op; de::MovePtr loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str)); for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++) { const RenderPass renderPass (vector(1, Attachment(format, VK_SAMPLE_COUNT_1_BIT, loadOp, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())), vector()); addFunctionCaseWithPrograms(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } formatGroup->addChild(loadOpGroup.release()); } { de::MovePtr inputGroup (new tcu::TestCaseGroup(testCtx, "input", "Test attachment format as input")); for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++) { const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op; de::MovePtr loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str)); for (size_t storeOpNdx = 0; storeOpNdx < DE_LENGTH_OF_ARRAY(storeOps); storeOpNdx++) { const VkAttachmentStoreOp storeOp = storeOps[storeOpNdx].op; de::MovePtr storeOpGroup (new tcu::TestCaseGroup(testCtx, storeOps[storeOpNdx].str, storeOps[storeOpNdx].str)); for (size_t useInputAspectNdx = 0; useInputAspectNdx < 2; useInputAspectNdx++) { const bool useInputAspect = useInputAspectNdx != 0; for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++) { { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(format, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)), vector(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, VK_IMAGE_ASPECT_COLOR_BIT }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : ""), renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(format, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)), vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, VK_IMAGE_ASPECT_COLOR_BIT }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : ""), string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } } } loadOpGroup->addChild(storeOpGroup.release()); } inputGroup->addChild(loadOpGroup.release()); } formatGroup->addChild(inputGroup.release()); } group->addChild(formatGroup.release()); } // Depth stencil formats for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(s_coreDepthStencilFormats); formatNdx++) { const VkFormat vkFormat = s_coreDepthStencilFormats[formatNdx]; const tcu::TextureFormat format = mapVkFormat(vkFormat); const bool isStencilAttachment = hasStencilComponent(format.order); const bool isDepthAttachment = hasDepthComponent(format.order); de::MovePtr formatGroup (new tcu::TestCaseGroup(testCtx, formatToName(vkFormat).c_str(), de::toString(vkFormat).c_str())); for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++) { const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op; de::MovePtr loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str)); for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++) { { const RenderPass renderPass (vector(1, Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, isDepthAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isDepthAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, isStencilAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isStencilAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())), vector()); addFunctionCaseWithPrograms(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } if (isStencilAttachment && isDepthAttachment) { { const RenderPass renderPass (vector(1, Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, isDepthAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isDepthAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, isStencilAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isStencilAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR), vector())), vector()); addFunctionCaseWithPrograms(loadOpGroup.get(), string(renderTypes[renderTypeNdx].str) + "_depth_read_only", renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } { const RenderPass renderPass (vector(1, Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, isDepthAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isDepthAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, isStencilAttachment ? loadOp : VK_ATTACHMENT_LOAD_OP_DONT_CARE, isStencilAttachment ? VK_ATTACHMENT_STORE_OP_STORE :VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR), vector())), vector()); addFunctionCaseWithPrograms(loadOpGroup.get(), string(renderTypes[renderTypeNdx].str) + "_stencil_read_only", renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 90239, allocationKind)); } } } formatGroup->addChild(loadOpGroup.release()); } { de::MovePtr inputGroup (new tcu::TestCaseGroup(testCtx, "input", "Test attachment format as input")); for (size_t loadOpNdx = 0; loadOpNdx < DE_LENGTH_OF_ARRAY(loadOps); loadOpNdx++) { const VkAttachmentLoadOp loadOp = loadOps[loadOpNdx].op; de::MovePtr loadOpGroup (new tcu::TestCaseGroup(testCtx, loadOps[loadOpNdx].str, loadOps[loadOpNdx].str)); for (size_t storeOpNdx = 0; storeOpNdx < DE_LENGTH_OF_ARRAY(storeOps); storeOpNdx++) { const VkAttachmentStoreOp storeOp = storeOps[storeOpNdx].op; de::MovePtr storeOpGroup (new tcu::TestCaseGroup(testCtx, storeOps[storeOpNdx].str, storeOps[storeOpNdx].str)); for (size_t useInputAspectNdx = 0; useInputAspectNdx < 2; useInputAspectNdx++) { const bool useInputAspect = useInputAspectNdx != 0; for (size_t renderTypeNdx = 0; renderTypeNdx < DE_LENGTH_OF_ARRAY(renderTypes); renderTypeNdx++) { { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, loadOp, storeOp, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)), vector(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 0u)); deps.push_back(SubpassDependency(1, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : ""), renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL)), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : ""), string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } if (isStencilAttachment && isDepthAttachment) { // Depth read only { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, loadOp, storeOp, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR)), vector(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 0u)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "") + "_depth_read_only", renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, loadOp, storeOp, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR)), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); deps.push_back(SubpassDependency(1, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "") + "_depth_read_only", string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } // Stencil read only { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, loadOp, storeOp, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); attachments.push_back(Attachment(vk::VK_FORMAT_R8G8B8A8_UNORM, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR)), vector(1, AttachmentReference(1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 0u)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "") + "_stencil_read_only", renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } { vector attachments; vector subpasses; vector deps; vector inputAspects; attachments.push_back(Attachment(vkFormat, VK_SAMPLE_COUNT_1_BIT, loadOp, storeOp, loadOp, storeOp, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL), vector())); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR)), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR), vector())); deps.push_back(SubpassDependency(0, 1, vk::VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | vk::VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); deps.push_back(SubpassDependency(1, 1, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, vk::VK_DEPENDENCY_BY_REGION_BIT)); if (useInputAspect) { const VkInputAttachmentAspectReferenceKHR inputAspect = { 0u, 0u, (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u) }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); addFunctionCaseWithPrograms(storeOpGroup.get(), string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "") + "_stencil_read_only", string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, TestConfig(renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, 89246, allocationKind)); } } } } } loadOpGroup->addChild(storeOpGroup.release()); } inputGroup->addChild(loadOpGroup.release()); } formatGroup->addChild(inputGroup.release()); } group->addChild(formatGroup.release()); } } void addRenderPassTests (tcu::TestCaseGroup* group, AllocationKind allocationKind) { addTestGroup(group, "simple", "Simple basic render pass tests", addSimpleTests, allocationKind); addTestGroup(group, "formats", "Tests for different image formats.", addFormatTests, allocationKind); addTestGroup(group, "attachment", "Attachment format and count tests with load and store ops and image layouts", addAttachmentTests, allocationKind); addTestGroup(group, "attachment_allocation", "Attachment allocation tests", addAttachmentAllocationTests, allocationKind); } de::MovePtr createSuballocationTests(tcu::TestContext& testCtx) { de::MovePtr suballocationTestsGroup(new tcu::TestCaseGroup(testCtx, "suballocation", "Suballocation RenderPass Tests")); addRenderPassTests(suballocationTestsGroup.get(), ALLOCATION_KIND_SUBALLOCATED); return suballocationTestsGroup; } de::MovePtr createDedicatedAllocationTests(tcu::TestContext& testCtx) { de::MovePtr dedicatedAllocationTestsGroup(new tcu::TestCaseGroup(testCtx, "dedicated_allocation", "RenderPass Tests For Dedicated Allocation")); addRenderPassTests(dedicatedAllocationTestsGroup.get(), ALLOCATION_KIND_DEDICATED); return dedicatedAllocationTestsGroup; } } // anonymous tcu::TestCaseGroup* createRenderPassTests (tcu::TestContext& testCtx) { de::MovePtr renderpassTests (new tcu::TestCaseGroup(testCtx, "renderpass", "RenderPass Tests")); de::MovePtr suballocationTestGroup = createSuballocationTests(testCtx); de::MovePtr dedicatedAllocationTestGroup = createDedicatedAllocationTests(testCtx); suballocationTestGroup->addChild(createRenderPassMultisampleTests(testCtx)); suballocationTestGroup->addChild(createRenderPassMultisampleResolveTests(testCtx)); renderpassTests->addChild(suballocationTestGroup.release()); renderpassTests->addChild(dedicatedAllocationTestGroup.release()); return renderpassTests.release(); } } // vkt