/*------------------------------------------------------------------------- * 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 "vktRenderPassTestsUtil.hpp" #include "vktRenderPassMultisampleTests.hpp" #include "vktRenderPassMultisampleResolveTests.hpp" #include "vktRenderPassSampleReadTests.hpp" #include "vktRenderPassSparseRenderTargetTests.hpp" #include "vktRenderPassSubpassDependencyTests.hpp" #include "vktRenderPassUnusedAttachmentTests.hpp" #include "vktRenderPassUnusedClearAttachmentTests.hpp" #include "vktRenderPassDepthStencilResolveTests.hpp" #include "vktRenderPassUnusedAttachmentSparseFillingTests.hpp" #include "vktRenderPassFragmentDensityMapTests.hpp" #include "vktRenderPassMultipleSubpassesMultipleCommandBuffersTests.hpp" #include "vktRenderPassLoadStoreOpNoneTests.hpp" #include "vktDynamicRenderingTests.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 "vkCmdUtil.hpp" #include "vkObjUtil.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 #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::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 { using namespace renderpass; typedef vector DepthValuesArray; static const deUint8 DEPTH_VALUES[] = { 0u, 255u, 1u }; enum AllocationKind { ALLOCATION_KIND_SUBALLOCATED, ALLOCATION_KIND_DEDICATED, }; struct TestConfigExternal { TestConfigExternal (AllocationKind allocationKind_, RenderingType renderingType_) : allocationKind (allocationKind_) , renderingType (renderingType_) { } AllocationKind allocationKind; RenderingType renderingType; }; 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)]; } static float requiredDepthEpsilon(VkFormat format) { // Possible precision loss in the unorm depth pipeline means that we need to check depths // that go in and back out of the depth buffer with an epsilon rather than an exact match deUint32 unormBits = 0; switch (format) { case VK_FORMAT_D16_UNORM: unormBits = 16; break; case VK_FORMAT_X8_D24_UNORM_PACK32: case VK_FORMAT_D24_UNORM_S8_UINT: unormBits = 24; break; case VK_FORMAT_D32_SFLOAT: case VK_FORMAT_D32_SFLOAT_S8_UINT: default: unormBits = 0; break; } if (unormBits > 0) return 1.0f / (float)((1 << unormBits) - 1); return 0.0f; // Require exact match } static bool depthsEqual(float a, float b, float epsilon) { return fabs(a - b) <= epsilon; } 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); } VkRenderPassBeginInfo createRenderPassBeginInfo (VkRenderPass pRenderPassBegin_renderPass, VkFramebuffer pRenderPassBegin_framebuffer, VkRect2D pRenderPassBegin_renderArea, deUint32 pRenderPassBegin_clearValueCount, const VkClearValue* pRenderPassBegin_pAttachmentClearValues) { const VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, DE_NULL, pRenderPassBegin_renderPass, pRenderPassBegin_framebuffer, pRenderPassBegin_renderArea, pRenderPassBegin_clearValueCount, pRenderPassBegin_pAttachmentClearValues, }; return renderPassBeginInfo; } 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 == 22); 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: 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: 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) { /* All relevant flags for a pipeline containing VS+PS. */ return VK_PIPELINE_STAGE_TRANSFER_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_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_HOST_BIT; } class AttachmentReference { public: AttachmentReference (deUint32 attachment, VkImageLayout layout, VkImageAspectFlags aspectMask = static_cast(0u)) : m_attachment (attachment) , m_layout (layout) , m_aspectMask (aspectMask) { } deUint32 getAttachment (void) const { return m_attachment; } VkImageLayout getImageLayout (void) const { return m_layout; } VkImageAspectFlags getAspectMask (void) const { return m_aspectMask; } void setImageLayout (VkImageLayout layout) { m_layout = layout; } private: deUint32 m_attachment; VkImageLayout m_layout; VkImageAspectFlags m_aspectMask; }; class Subpass { public: Subpass (VkPipelineBindPoint pipelineBindPoint, VkSubpassDescriptionFlags flags, const vector& inputAttachments, const vector& colorAttachments, const vector& resolveAttachments, AttachmentReference depthStencilAttachment, const vector& preserveAttachments, bool omitBlendState = false) : m_pipelineBindPoint (pipelineBindPoint) , m_flags (flags) , m_inputAttachments (inputAttachments) , m_colorAttachments (colorAttachments) , m_resolveAttachments (resolveAttachments) , m_depthStencilAttachment (depthStencilAttachment) , m_preserveAttachments (preserveAttachments) , m_omitBlendState (omitBlendState) { } 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; } bool getOmitBlendState (void) const { return m_omitBlendState; } private: VkPipelineBindPoint m_pipelineBindPoint; VkSubpassDescriptionFlags m_flags; vector m_inputAttachments; vector m_colorAttachments; vector m_resolveAttachments; AttachmentReference m_depthStencilAttachment; vector m_preserveAttachments; bool m_omitBlendState; }; class SubpassDependency { public: SubpassDependency (deUint32 srcPass, deUint32 dstPass, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkDependencyFlags flags) : m_srcPass (srcPass) , m_dstPass (dstPass) , m_srcStageMask (srcStageMask) , m_dstStageMask (dstStageMask) , m_srcAccessMask (srcAccessMask) , m_dstAccessMask (dstAccessMask) , 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 getSrcAccessMask (void) const { return m_srcAccessMask; } VkAccessFlags getDstAccessMask (void) const { return m_dstAccessMask; } VkDependencyFlags getFlags (void) const { return m_flags; } void setSrcAccessMask (const VkAccessFlags& flags) { m_srcAccessMask = flags; } void setDstAccessMask (const VkAccessFlags& flags) { m_dstAccessMask = flags; } private: deUint32 m_srcPass; deUint32 m_dstPass; VkPipelineStageFlags m_srcStageMask; VkPipelineStageFlags m_dstStageMask; VkAccessFlags m_srcAccessMask; VkAccessFlags m_dstAccessMask; 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_, deBool useFormatCompCount_, deUint32 seed_, deUint32 drawStartNdx_, AllocationKind allocationKind_, RenderingType renderingType_, vector requiredFeatures_ = vector()) : renderPass (renderPass_) , renderTypes (renderTypes_) , commandBufferTypes (commandBufferTypes_) , imageMemory (imageMemory_) , targetSize (targetSize_) , renderPos (renderPos_) , renderSize (renderSize_) , useFormatCompCount (useFormatCompCount_) , seed (seed_) , drawStartNdx (drawStartNdx_) , allocationKind (allocationKind_) , renderingType (renderingType_) , requiredFeatures (requiredFeatures_) { DepthValuesArray shuffledDepthValues (&DEPTH_VALUES[0], &DEPTH_VALUES[DE_LENGTH_OF_ARRAY(DEPTH_VALUES)]); de::Random rng (seed + 1); rng.shuffle(shuffledDepthValues.begin(), shuffledDepthValues.end()); depthValues.push_back(shuffledDepthValues[0]); depthValues.push_back(shuffledDepthValues[1]); } RenderPass renderPass; RenderTypes renderTypes; CommandBufferTypes commandBufferTypes; ImageMemory imageMemory; UVec2 targetSize; UVec2 renderPos; UVec2 renderSize; deBool useFormatCompCount; deUint32 seed; deUint32 drawStartNdx; AllocationKind allocationKind; RenderingType renderingType; vector requiredFeatures; DepthValuesArray depthValues; }; 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 checkSupport (Context& context, TestConfig config) { for (size_t featureNdx = 0; featureNdx < config.requiredFeatures.size(); featureNdx++) context.requireDeviceCoreFeature(config.requiredFeatures[featureNdx]); } void logRenderPassInfo (TestLog& log, const RenderPass& renderPass) { const bool useExternalInputAspect = !renderPass.getInputAspects().empty(); 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 (useExternalInputAspect) { const tcu::ScopedLogSection inputAspectSection (log, "InputAspects", "InputAspects"); for (size_t aspectNdx = 0; aspectNdx < renderPass.getInputAspects().size(); aspectNdx++) { const VkInputAttachmentAspectReference& 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 (!useExternalInputAspect) log << TestLog::Message << "AspectMask: " << inputAttachment.getAspectMask() << 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.getDstAccessMask() << TestLog::EndMessage; log << TestLog::Message << "Output Mask: " << dep.getSrcAccessMask() << TestLog::EndMessage; log << TestLog::Message << "Dependency Flags: " << getDependencyFlagsStr(dep.getFlags()) << TestLog::EndMessage; } } } std::string clearColorToString (VkFormat vkFormat, VkClearColorValue value, deBool useFormatCompCount) { const tcu::TextureFormat format = mapVkFormat(vkFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); const tcu::BVec4 channelMask = tcu::getTextureFormatChannelMask(format); const deUint32 componentCount = (useFormatCompCount ? (deUint32)tcu::getNumUsedChannels(format.order) : 4); std::ostringstream stream; stream << "("; switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: for (deUint32 i = 0; i < componentCount; i++) { if (i > 0) stream << ", "; if (channelMask[i]) stream << value.int32[i]; else stream << "Undef"; } break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: for (deUint32 i = 0; i < componentCount; 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 (deUint32 i = 0; i < componentCount; 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, deBool useFormatCompCount) { 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, useFormatCompCount); } VkClearColorValue randomColorClearValue (const Attachment& attachment, de::Random& rng, deBool useFormatCompCount) { 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); const deUint32 componentCount = (useFormatCompCount ? (deUint32)tcu::getNumUsedChannels(format.order) : 4); VkClearColorValue clearColor; switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: { for (deUint32 ndx = 0; ndx < componentCount; 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 (deUint32 ndx = 0; ndx < componentCount; 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 (deUint32 ndx = 0; ndx < componentCount; 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; } template AttachmentDesc createAttachmentDescription (const Attachment& attachment) { const AttachmentDesc attachmentDescription // VkAttachmentDescription || VkAttachmentDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags; attachment.getFormat(), // VkFormat format; || VkFormat format; attachment.getSamples(), // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples; attachment.getLoadOp(), // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp; attachment.getStoreOp(), // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp; attachment.getStencilLoadOp(), // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp; attachment.getStencilStoreOp(), // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp; attachment.getInitialLayout(), // VkImageLayout initialLayout; || VkImageLayout initialLayout; attachment.getFinalLayout() // VkImageLayout finalLayout; || VkImageLayout finalLayout; ); return attachmentDescription; } template AttachmentRef createAttachmentReference (const AttachmentReference& referenceInfo) { const AttachmentRef reference // VkAttachmentReference || VkAttachmentReference2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; referenceInfo.getAttachment(), // deUint32 attachment; || deUint32 attachment; referenceInfo.getImageLayout(), // VkImageLayout layout; || VkImageLayout layout; referenceInfo.getAspectMask() // || VkImageAspectFlags aspectMask; ); return reference; } template SubpassDesc 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 SubpassDesc subpassDescription // VkSubpassDescription || VkSubpassDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; subpass.getFlags(), // VkSubpassDescriptionFlags flags; || VkSubpassDescriptionFlags flags; subpass.getPipelineBindPoint(), // VkPipelineBindPoint pipelineBindPoint; || VkPipelineBindPoint pipelineBindPoint; 0u, // || deUint32 viewMask; (deUint32)inputAttachmentReferences.size(), // deUint32 inputAttachmentCount; || deUint32 inputAttachmentCount; inputAttachmentReferences.empty() ? DE_NULL : &inputAttachmentReferences[0], // const VkAttachmentReference* pInputAttachments; || const VkAttachmentReference2KHR* pInputAttachments; (deUint32)colorAttachmentReferences.size(), // deUint32 colorAttachmentCount; || deUint32 colorAttachmentCount; colorAttachmentReferences.empty() ? DE_NULL : &colorAttachmentReferences[0], // const VkAttachmentReference* pColorAttachments; || const VkAttachmentReference2KHR* pColorAttachments; resolveAttachmentReferences.empty() ? DE_NULL : &resolveAttachmentReferences[0], // const VkAttachmentReference* pResolveAttachments; || const VkAttachmentReference2KHR* pResolveAttachments; &depthStencilAttachmentReferences[0], // const VkAttachmentReference* pDepthStencilAttachment; || const VkAttachmentReference2KHR* pDepthStencilAttachment; (deUint32)preserveAttachmentReferences->size(), // deUint32 preserveAttachmentCount; || deUint32 preserveAttachmentCount; preserveAttachmentReferences->empty() ? DE_NULL : &(*preserveAttachmentReferences)[0] // const deUint32* pPreserveAttachments; || const deUint32* pPreserveAttachments; ); return subpassDescription; } } template SubpassDep createSubpassDependency (const SubpassDependency& dependencyInfo) { const SubpassDep dependency // VkSubpassDependency || VkSubpassDependency2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; dependencyInfo.getSrcPass(), // deUint32 srcSubpass; || deUint32 srcSubpass; dependencyInfo.getDstPass(), // deUint32 dstSubpass; || deUint32 dstSubpass; dependencyInfo.getSrcStageMask(), // VkPipelineStageFlags srcStageMask; || VkPipelineStageFlags srcStageMask; dependencyInfo.getDstStageMask(), // VkPipelineStageFlags dstStageMask; || VkPipelineStageFlags dstStageMask; dependencyInfo.getSrcAccessMask(), // VkAccessFlags srcAccessMask; || VkAccessFlags srcAccessMask; dependencyInfo.getDstAccessMask(), // VkAccessFlags dstAccessMask; || VkAccessFlags dstAccessMask; dependencyInfo.getFlags(), // VkDependencyFlags dependencyFlags; || VkDependencyFlags dependencyFlags; 0u // || deInt32 viewOffset; ); return dependency; } de::MovePtr createRenderPassInputAttachmentAspectCreateInfo(const RenderPass& renderPassInfo) { de::MovePtr result (DE_NULL); if (!renderPassInfo.getInputAspects().empty()) { const VkRenderPassInputAttachmentAspectCreateInfo inputAspectCreateInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO, DE_NULL, (deUint32)renderPassInfo.getInputAspects().size(), renderPassInfo.getInputAspects().data(), }; result = de::MovePtr(new VkRenderPassInputAttachmentAspectCreateInfo(inputAspectCreateInfo)); } return result; } template 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()); de::MovePtr inputAspectCreateInfo(createRenderPassInputAttachmentAspectCreateInfo(renderPassInfo)); 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])); const RenderPassCreateInfo renderPassCreator // VkRenderPassCreateInfo || VkRenderPassCreateInfo2KHR ( // VkStructureType sType; || VkStructureType sType; inputAspectCreateInfo.get(), // const void* pNext; || const void* pNext; (VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags; || VkRenderPassCreateFlags flags; (deUint32)attachments.size(), // deUint32 attachmentCount; || deUint32 attachmentCount; (attachments.empty() ? DE_NULL : &attachments[0]), // const VkAttachmentDescription* pAttachments; || const VkAttachmentDescription2KHR* pAttachments; (deUint32)subpasses.size(), // deUint32 subpassCount; || deUint32 subpassCount; (subpasses.empty() ? DE_NULL : &subpasses[0]), // const VkSubpassDescription* pSubpasses; || const VkSubpassDescription2KHR* pSubpasses; (deUint32)dependencies.size(), // deUint32 dependencyCount; || deUint32 dependencyCount; (dependencies.empty() ? DE_NULL : &dependencies[0]), // const VkSubpassDependency* pDependencies; || const VkSubpassDependency2KHR* pDependencies; 0u, // || deUint32 correlatedViewMaskCount; DE_NULL // || const deUint32* pCorrelatedViewMasks; ); return renderPassCreator.createRenderPass(vk, device); } Move createRenderPass (const DeviceInterface& vk, VkDevice device, const RenderPass& renderPassInfo, const RenderingType renderPassType) { switch (renderPassType) { case RENDERING_TYPE_RENDERPASS_LEGACY: return createRenderPass(vk, device, renderPassInfo); case RENDERING_TYPE_RENDERPASS2: return createRenderPass(vk, device, renderPassInfo); default: TCU_THROW(InternalError, "Impossible"); } } 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, deBool useFormatCompCount, const DepthValuesArray& depthValues) { 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 = float(depthValues[rng.getBool() ? 1 : 0]) / 255.0f; return clearValue; } else { VkClearValue clearValue; clearValue.color = randomColorClearValue(attachment, rng, useFormatCompCount); 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, VkDeviceSize nonCoherentAtomSize) { // Expand the range to flush to account for the nonCoherentAtomSize const VkDeviceSize roundedOffset = de::roundDown(memory.getOffset(), nonCoherentAtomSize); const VkDeviceSize roundedSize = de::roundUp(memory.getOffset() - roundedOffset + static_cast(size), nonCoherentAtomSize); const VkMappedMemoryRange range = { VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // sType; DE_NULL, // pNext; memory.getMemory(), // mem; roundedOffset, // offset; roundedSize, // 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 == 22); 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; } } deUint32 getAttachmentNdx (const vector& colorAttachments, size_t ndx) { return (colorAttachments[ndx].getAttachment() == VK_ATTACHMENT_UNUSED) ? (deUint32)ndx : colorAttachments[ndx].getAttachment(); } 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, deUint32 drawStartNdx, bool isSecondary_, bool omitBlendState_, 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_drawStartNdx (drawStartNdx) , m_isSecondary (isSecondary_) , m_omitBlendState (omitBlendState_) , 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()[getAttachmentNdx(m_colorAttachments, attachmentNdx)]); 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; } deUint32 getDrawStartNdx (void) const { return m_drawStartNdx; } bool isSecondary (void) const { return m_isSecondary; } bool getOmitBlendState (void) const { return m_omitBlendState; } 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; deUint32 m_drawStartNdx; bool m_isSecondary; bool m_omitBlendState; 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; }; 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 SubpassRenderInfo* pRenderInfo = 0, bool dynamicRenderPass = false ) { VkCommandBufferInheritanceInfo pInheritanceInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO, DE_NULL, pInheritanceInfo_renderPass, pInheritanceInfo_subpass, pInheritanceInfo_framebuffer, pInheritanceInfo_occlusionQueryEnable, pInheritanceInfo_queryFlags, pInheritanceInfo_pipelineStatistics, }; std::vector colorAttachmentFormats; VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo { VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR, DE_NULL, 0u, 0u, 0u, DE_NULL, VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT, }; if (pRenderInfo) { for (deUint32 i = 0; i < pRenderInfo->getColorAttachmentCount(); ++i) colorAttachmentFormats.push_back(pRenderInfo->getColorAttachment(i).getFormat()); inheritanceRenderingInfo.colorAttachmentCount = static_cast(colorAttachmentFormats.size()); inheritanceRenderingInfo.pColorAttachmentFormats = colorAttachmentFormats.data(); if (pRenderInfo->getDepthStencilAttachment()) { inheritanceRenderingInfo.depthAttachmentFormat = pRenderInfo->getDepthStencilAttachment()->getFormat(); inheritanceRenderingInfo.stencilAttachmentFormat = pRenderInfo->getDepthStencilAttachment()->getFormat(); } if (pRenderInfo->getColorAttachmentCount()) inheritanceRenderingInfo.rasterizationSamples = pRenderInfo->getColorAttachment(0).getSamples(); else if (pRenderInfo->getDepthStencilAttachment()) inheritanceRenderingInfo.rasterizationSamples = pRenderInfo->getDepthStencilAttachment()->getSamples(); if (dynamicRenderPass) pInheritanceInfo.pNext = &inheritanceRenderingInfo; } const VkCommandBufferBeginInfo pBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, DE_NULL, pBeginInfo_flags, &pInheritanceInfo, }; VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &pBeginInfo)); } Move createSubpassPipeline (const DeviceInterface& vk, VkDevice device, VkRenderPass renderPass, VkShaderModule vertexShaderModule, VkShaderModule fragmentShaderModule, VkPipelineLayout pipelineLayout, const SubpassRenderInfo& renderInfo) { 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 (attachmentNdx < renderInfo.getDrawStartNdx() ? (deUint32)0 : 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 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, // VkStructureType sType DE_NULL, // const void* pNext 0u, // VkPipelineInputAssemblyStateCreateFlags flags VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology VK_FALSE // VkBool32 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, // VkStructureType sType DE_NULL, // const void* pNext (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags 1u, // deUint32 viewportCount &viewport, // const VkViewport* pViewports 1u, // deUint32 scissorCount &scissor // const VkRect2D* pScissors }; const VkPipelineRasterizationStateCreateInfo rasterizationState = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext 0u, // VkPipelineRasterizationStateCreateFlags flags VK_FALSE, // VkBool32 depthClampEnable VK_FALSE, // VkBool32 rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode VK_CULL_MODE_NONE, // VkCullModeFlags cullMode VK_FRONT_FACE_COUNTER_CLOCKWISE, // VkFrontFace frontFace VK_FALSE, // VkBool32 depthBiasEnable 0.0f, // float depthBiasConstantFactor 0.0f, // float depthBiasClamp 0.0f, // float depthBiasSlopeFactor 1.0f // float 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 ? 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 ? 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 }; std::vector colorAttachmentFormats; for (deUint32 i = 0; i < renderInfo.getColorAttachmentCount(); ++i) colorAttachmentFormats.push_back(renderInfo.getColorAttachment(i).getFormat()); vk::VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; if (renderInfo.getDepthStencilAttachment()) { const Attachment& attachment = *renderInfo.getDepthStencilAttachment(); depthStencilFormat = attachment.getFormat(); } VkPipelineRenderingCreateInfoKHR renderingCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR, DE_NULL, 0u, static_cast(colorAttachmentFormats.size()), colorAttachmentFormats.data(), depthStencilFormat, depthStencilFormat }; return makeGraphicsPipeline(vk, // const DeviceInterface& vk device, // const VkDevice device pipelineLayout, // const VkPipelineLayout pipelineLayout vertexShaderModule, // const VkShaderModule vertexShaderModule DE_NULL, // const VkShaderModule tessellationControlShaderModule DE_NULL, // const VkShaderModule tessellationEvalShaderModule DE_NULL, // const VkShaderModule geometryShaderModule fragmentShaderModule, // const VkShaderModule fragmentShaderModule renderPass, // const VkRenderPass renderPass renderInfo.getSubpassIndex(), // const deUint32 subpass &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo &inputAssemblyState, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo &viewportState, // const VkPipelineViewportStateCreateInfo* pViewportStat; &rasterizationState, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState &multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo &depthStencilState, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo renderInfo.getOmitBlendState() ? DE_NULL : &blendState, // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo DE_NULL, // const VkPipelineDynamicStateCreateInfo* dynamicStateCreateInfo (renderPass == DE_NULL) ? &renderingCreateInfo : DE_NULL); // const void* pNext) } 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, const bool dynamicRendering) : 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++) { const deUint32 attachmentNdx = (renderInfo.getColorAttachmentIndex(colorAttachmentNdx) == VK_ATTACHMENT_UNUSED) ? colorAttachmentNdx : renderInfo.getColorAttachmentIndex(colorAttachmentNdx); m_colorAttachmentImages.push_back(attachmentImages[attachmentNdx]); } 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) && (isStencilFormat && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) ? 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); // Round up the vertex buffer size to honor nonCoherentAtomSize. const auto properties = vk::getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()); const auto vertexBufferSize = de::roundUp(static_cast(renderQuad.getVertexDataSize()), properties.limits.nonCoherentAtomSize); m_vertexBuffer = createBuffer(vk, device, 0u, vertexBufferSize, 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(), properties.limits.nonCoherentAtomSize); 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) { 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) { 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, &renderInfo, dynamicRendering); 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 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ? 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) || (tcu::hasStencilComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL)) { 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 m_renderInfo.getInputAttachmentLayout(inputAttachmentNdx), // oldLayout m_renderInfo.getInputAttachmentLayout(inputAttachmentNdx), // 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_ALL_COMMANDS_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; getMemoryFlagsForLayout(oldLayout), // 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_ALL_COMMANDS_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)renderPassLayouts.size(), &renderPassLayouts[0]); } } template 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; const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); 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; const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, contents); const VkRenderPassBeginInfo renderPassBeginInfo = createRenderPassBeginInfo(renderPass, framebuffer, renderArea, (deUint32)attachmentClearValues.size(), attachmentClearValues.empty() ? DE_NULL : &attachmentClearValues[0]); if (subpassNdx == 0) RenderpassSubpass::cmdBeginRenderPass(vk, commandBuffer, &renderPassBeginInfo, &subpassBeginInfo); else RenderpassSubpass::cmdNextSubpass(vk, commandBuffer, &subpassBeginInfo, &subpassEndInfo); 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"); } } RenderpassSubpass::cmdEndRenderPass(vk, commandBuffer, &subpassEndInfo); } } void pushDynamicRenderingCommands (const DeviceInterface& vk, VkCommandBuffer commandBuffer, const RenderPass& renderPassInfo, const vector >& attachmentResources, const vector >& subpassRenderers, const UVec2& renderPos, const UVec2& renderSize, const vector >& renderPassClearValues, deUint32 queueIndex, TestConfig::RenderTypes render) { const float clearNan = tcu::Float32::nan().asFloat(); const VkClearValue clearValueNan = makeClearValueColorF32(clearNan, clearNan, clearNan, clearNan); DE_ASSERT(subpassRenderers.size() == 1); VkRenderingFlagsKHR renderingFlags = 0u; if (subpassRenderers[0]->isSecondary()) renderingFlags = VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT_KHR; const VkRect2D renderArea { { (deInt32)renderPos.x(), (deInt32)renderPos.y() }, { renderSize.x(), renderSize.y() } }; // translate structures that were prepared to construct renderpass to structures needed for dynamic rendering vector imageBarriersBeforeRendering; vector imageBarriersAfterRendering; std::vector colorAttachmentVect; const Subpass& subpassInfo = renderPassInfo.getSubpasses()[0]; const vector& colorAttachmentsInfo = subpassInfo.getColorAttachments(); const vector& resolveAttachmentsInfo = subpassInfo.getResolveAttachments(); for (deUint32 i = 0 ; i < colorAttachmentsInfo.size() ; ++i) { const AttachmentReference& colorAttachmentReference = colorAttachmentsInfo[i]; const deUint32 colorAttachmentIndex = colorAttachmentReference.getAttachment(); const Attachment& colorAttachmentInfo = renderPassInfo.getAttachments()[colorAttachmentIndex]; VkResolveModeFlagBits resolveMode = VK_RESOLVE_MODE_NONE; VkImageView resolveImageView = DE_NULL; VkImageLayout resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; // handle resolve attachments if they were specified if (!resolveAttachmentsInfo.empty()) { const AttachmentReference& resolveAttachmentReference = resolveAttachmentsInfo[i]; const deUint32 resolveAttachmentIndex = resolveAttachmentReference.getAttachment(); const Attachment& resolveAttachmentInfo = renderPassInfo.getAttachments()[resolveAttachmentIndex]; resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT; resolveImageView = attachmentResources[resolveAttachmentIndex]->getAttachmentView(); resolveImageLayout = resolveAttachmentInfo.getInitialLayout(); } colorAttachmentVect.push_back({ vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType DE_NULL, // const void* pNext attachmentResources[colorAttachmentIndex]->getAttachmentView(), // VkImageView imageView colorAttachmentReference.getImageLayout(), // VkImageLayout imageLayout resolveMode, // VkResolveModeFlagBits resolveMode resolveImageView, // VkImageView resolveImageView resolveImageLayout, // VkImageLayout resolveImageLayout colorAttachmentInfo.getLoadOp(), // VkAttachmentLoadOp loadOp colorAttachmentInfo.getStoreOp(), // VkAttachmentStoreOp storeOp (renderPassClearValues[colorAttachmentIndex] ? *renderPassClearValues[colorAttachmentIndex] : clearValueNan) // VkClearValue clearValue }); const VkImageLayout initialLayout = colorAttachmentInfo.getInitialLayout(); const VkImageLayout renderingLayout = colorAttachmentReference.getImageLayout(); const VkImageLayout finalLayout = colorAttachmentInfo.getFinalLayout(); const VkImageMemoryBarrier barrierBeforeRendering { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext getAllMemoryWriteFlags() | getMemoryFlagsForLayout(initialLayout), // srcAccessMask getMemoryFlagsForLayout(renderingLayout), // dstAccessMask initialLayout, // oldLayout renderingLayout, // newLayout queueIndex, // srcQueueFamilyIndex queueIndex, // destQueueFamilyIndex attachmentResources[colorAttachmentIndex]->getImage(), // image { // subresourceRange getImageAspectFlags(colorAttachmentInfo.getFormat()), // aspect; 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; imageBarriersBeforeRendering.push_back(barrierBeforeRendering); const VkImageMemoryBarrier barrierAfterRendering { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext getMemoryFlagsForLayout(renderingLayout), // srcAccessMask getAllMemoryReadFlags() | getMemoryFlagsForLayout(finalLayout), // dstAccessMask renderingLayout, // oldLayout finalLayout, // newLayout queueIndex, // srcQueueFamilyIndex queueIndex, // destQueueFamilyIndex attachmentResources[colorAttachmentIndex]->getImage(), // image { // subresourceRange getImageAspectFlags(colorAttachmentInfo.getFormat()), // aspect; 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; imageBarriersAfterRendering.push_back(barrierAfterRendering); } VkRenderingAttachmentInfoKHR* pDepthAttachment = DE_NULL; VkRenderingAttachmentInfoKHR* pStencilAttachment = DE_NULL; VkRenderingAttachmentInfoKHR depthAttachment { vk::VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; DE_NULL, // VkImageView imageView; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout imageLayout; VK_RESOLVE_MODE_NONE, // VkResolveModeFlagBits resolveMode; DE_NULL, // VkImageView resolveImageView; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout resolveImageLayout; VK_ATTACHMENT_LOAD_OP_LOAD, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; clearValueNan // VkClearValue clearValue; }; VkRenderingAttachmentInfoKHR stencilAttachment = depthAttachment; const AttachmentReference& depthStencilAttachmentReference = subpassInfo.getDepthStencilAttachment(); const deUint32 dsAttachmentIndex = depthStencilAttachmentReference.getAttachment(); if (dsAttachmentIndex != VK_ATTACHMENT_UNUSED) { const Attachment& dsAttachmentInfo = renderPassInfo.getAttachments()[dsAttachmentIndex]; const tcu::TextureFormat format = mapVkFormat(dsAttachmentInfo.getFormat()); if (tcu::hasDepthComponent(format.order)) { depthAttachment.imageView = attachmentResources[dsAttachmentIndex]->getAttachmentView(); depthAttachment.imageLayout = depthStencilAttachmentReference.getImageLayout(); depthAttachment.loadOp = dsAttachmentInfo.getLoadOp(); depthAttachment.storeOp = dsAttachmentInfo.getStoreOp(); if (renderPassClearValues[dsAttachmentIndex]) depthAttachment.clearValue = *renderPassClearValues[dsAttachmentIndex]; pDepthAttachment = &depthAttachment; } if (tcu::hasStencilComponent(format.order)) { stencilAttachment.imageView = attachmentResources[dsAttachmentIndex]->getAttachmentView(); stencilAttachment.imageLayout = depthStencilAttachmentReference.getImageLayout(); stencilAttachment.loadOp = dsAttachmentInfo.getStencilLoadOp(); stencilAttachment.storeOp = dsAttachmentInfo.getStencilStoreOp(); if (renderPassClearValues[dsAttachmentIndex]) stencilAttachment.clearValue = *renderPassClearValues[dsAttachmentIndex]; pStencilAttachment = &stencilAttachment; } const VkImageLayout initialLayout = dsAttachmentInfo.getInitialLayout(); const VkImageLayout renderingLayout = depthStencilAttachmentReference.getImageLayout(); const VkImageLayout finalLayout = dsAttachmentInfo.getFinalLayout(); const VkImageMemoryBarrier barrierBeforeRendering { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext getAllMemoryWriteFlags() | getMemoryFlagsForLayout(initialLayout), // srcAccessMask getMemoryFlagsForLayout(renderingLayout), // dstAccessMask initialLayout, // oldLayout renderingLayout, // newLayout queueIndex, // srcQueueFamilyIndex queueIndex, // destQueueFamilyIndex attachmentResources[dsAttachmentIndex]->getImage(), // image { // subresourceRange getImageAspectFlags(dsAttachmentInfo.getFormat()), // aspect; 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; imageBarriersBeforeRendering.push_back(barrierBeforeRendering); const VkImageMemoryBarrier barrierAfterRendering { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext getMemoryFlagsForLayout(renderingLayout), // srcAccessMask getAllMemoryReadFlags() | getMemoryFlagsForLayout(finalLayout), // dstAccessMask renderingLayout, // oldLayout finalLayout, // newLayout queueIndex, // srcQueueFamilyIndex queueIndex, // destQueueFamilyIndex attachmentResources[dsAttachmentIndex]->getImage(), // image { // subresourceRange getImageAspectFlags(dsAttachmentInfo.getFormat()), // aspect; 0, // baseMipLevel 1, // mipLevels 0, // baseArraySlice 1 // arraySize } }; imageBarriersAfterRendering.push_back(barrierAfterRendering); } if (!imageBarriersBeforeRendering.empty()) vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(), getAllPipelineStageFlags(), (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)imageBarriersBeforeRendering.size(), &imageBarriersBeforeRendering[0]); vk::VkRenderingInfoKHR renderingInfo { vk::VK_STRUCTURE_TYPE_RENDERING_INFO_KHR, DE_NULL, renderingFlags, // VkRenderingFlagsKHR flags; renderArea, // VkRect2D renderArea; 1u, // deUint32 layerCount; 0u, // deUint32 viewMask; static_cast(colorAttachmentVect.size()), // deUint32 colorAttachmentCount; colorAttachmentVect.empty() ? DE_NULL : &colorAttachmentVect[0], // const VkRenderingAttachmentInfoKHR* pColorAttachments; pDepthAttachment, // const VkRenderingAttachmentInfoKHR* pDepthAttachment; pStencilAttachment // const VkRenderingAttachmentInfoKHR* pStencilAttachment; }; vk.cmdBeginRenderingKHR(commandBuffer, &renderingInfo); if (render) { if (subpassRenderers[0]->isSecondary()) { const VkCommandBuffer cmd = subpassRenderers[0]->getCommandBuffer(); vk.cmdExecuteCommands(commandBuffer, 1, &cmd); } else subpassRenderers[0]->pushRenderCommands(vk, commandBuffer); } vk.cmdEndRenderingKHR(commandBuffer); if (!imageBarriersAfterRendering.empty()) vk.cmdPipelineBarrier(commandBuffer, getAllPipelineStageFlags(), getAllPipelineStageFlags(), (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 0, (const VkBufferMemoryBarrier*)DE_NULL, (deUint32)imageBarriersAfterRendering.size(), &imageBarriersAfterRendering[0]); } void pushRenderPassCommands (const DeviceInterface& vk, VkCommandBuffer commandBuffer, VkRenderPass renderPass, const RenderPass& renderPassInfo, const vector >& attachmentResources, VkFramebuffer framebuffer, const vector >& subpassRenderers, const UVec2& renderPos, const UVec2& renderSize, const vector >& renderPassClearValues, deUint32 queueIndex, TestConfig::RenderTypes render, RenderingType renderingType) { switch (renderingType) { case RENDERING_TYPE_RENDERPASS_LEGACY: return pushRenderPassCommands(vk, commandBuffer, renderPass, framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, render); case RENDERING_TYPE_RENDERPASS2: return pushRenderPassCommands(vk, commandBuffer, renderPass, framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, render); case RENDERING_TYPE_DYNAMIC_RENDERING: return pushDynamicRenderingCommands(vk, commandBuffer, renderPassInfo, attachmentResources, subpassRenderers, renderPos, renderSize, renderPassClearValues, queueIndex, render); default: TCU_THROW(InternalError, "Impossible"); } } 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 = tcu::Nothing, const Maybe& y = tcu::Nothing, const Maybe& z = tcu::Nothing, const Maybe& w = tcu::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 tcu::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 DepthValuesArray& depthValues) { 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 == float(depthValues[1]) / 255.0f) pixelValue.setValue(0, true); else if (value.depthStencil.depth == float(depthValues[0]) / 255.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 deUint32 drawStartNdx, const DepthValuesArray& depthValues) { 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, depthValues)); } 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 = getAttachmentNdx(colorAttachments, attachmentNdx); if (!attachmentUsed[attachmentIndex] && colorAttachments[attachmentNdx].getAttachment() != VK_ATTACHMENT_UNUSED) { 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, depthValues)); 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, depthValues)); 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, depthValues)); 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, depthValues)); } 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; const bool hasDepth = tcu::hasDepthComponent(format.order) && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; 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, depthValues)); } 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 = drawStartNdx; attachmentRefNdx < subpass.getColorAttachments().size(); attachmentRefNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentRefNdx].getAttachment(); if (attachmentIndex == VK_ATTACHMENT_UNUSED) continue; 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) { 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) { 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) { 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) && (compNdx != 1 || layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)) { 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) { 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) { 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, const DepthValuesArray& depthValues) { 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(float(depthValues[1]) / 255.0f, x, y); else depthAccess.setPixDepth(float(depthValues[0]) / 255.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 deBool useFormatCompCount) { 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; const deUint32 componentCount = useFormatCompCount ? (deUint32)tcu::getNumUsedChannels(result.getFormat().order) : 4; for (deUint32 compNdx = 0; compNdx < componentCount; 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; } // Setting the alpha value to 1.0f by default helps visualization when the alpha channel is not used. const tcu::Vec4 kDefaultColorForLog {0.0f, 0.0f, 0.0f, 1.0f}; const float kTrueComponent = 1.0f; const float kFalseComponent = 0.5f; const float kUnsetComponentLow = 0.0f; const float kUnsetComponentHigh = 0.25f; std::unique_ptr renderColorImageForLog (const ConstPixelBufferAccess& image, int numChannels) { // Same channel order, but using UNORM_INT8 for the color format. const auto order = image.getFormat().order; const tcu::TextureFormat loggableFormat {order, tcu::TextureFormat::UNORM_INT8}; const int width = image.getWidth(); const int height = image.getHeight(); std::unique_ptr result {new tcu::TextureLevel{loggableFormat, width, height}}; auto access = result->getAccess(); tcu::Vec4 outColor = kDefaultColorForLog; for (int x = 0; x < width; ++x) for (int y = 0; y < height; ++y) { const auto value = image.getPixel(x, y); for (int c = 0; c < numChannels; ++c) { if (value[c] == 0.0f) outColor[c] = kFalseComponent; else if (value[c] == 1.0f) outColor[c] = kTrueComponent; else DE_ASSERT(false); } access.setPixel(outColor, x, y); } return result; } std::unique_ptr renderColorImageForLog (const vector& reference, const UVec2& targetSize, int numChannels) { const tcu::TextureFormat loggableFormat {tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8}; const int width = static_cast(targetSize.x()); const int height = static_cast(targetSize.y()); std::unique_ptr result {new tcu::TextureLevel{loggableFormat, width, height}}; auto access = result->getAccess(); tcu::Vec4 outColor = kDefaultColorForLog; for (int x = 0; x < width; ++x) for (int y = 0; y < height; ++y) { const int index = x + y * width; for (int c = 0; c < numChannels; ++c) { const auto maybeValue = reference[index].getValue(c); if (maybeValue) outColor[c] = ((*maybeValue) ? kTrueComponent : kFalseComponent); else outColor[c] = ((((x / 3) % 2) == ((y / 3) % 2)) ? kUnsetComponentLow : kUnsetComponentHigh); } access.setPixel(outColor, x, y); } return result; } bool verifyDepthAttachment (const vector& reference, const ConstPixelBufferAccess& result, const PixelBufferAccess& errorImage, const DepthValuesArray& depthValues, float epsilon) { 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 && !depthsEqual(resultDepth, float(depthValues[1]) / 255.0f, epsilon)) || (!value && !depthsEqual(resultDepth, float(depthValues[0]) / 255.0f, epsilon))) 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, config.drawStartNdx, config.depthValues); renderReferenceImagesFromValues(referenceAttachments, referenceValues, targetSize, renderPassInfo, config.depthValues); for (size_t attachmentNdx = 0; attachmentNdx < renderPassInfo.getAttachments().size(); attachmentNdx++) { if (!attachmentIsLazy[attachmentNdx]) { bool attachmentOK = true; 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()); void* const depthPtr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr(); const tcu::TextureFormat stencilFormat = getStencilCopyFormat(attachment.getFormat()); void* const stencilPtr = attachmentResources[attachmentNdx]->getSecondaryResultMemory().getHostPtr(); invalidateAlloc(vk, device, attachmentResources[attachmentNdx]->getResultMemory()); invalidateAlloc(vk, device, attachmentResources[attachmentNdx]->getSecondaryResultMemory()); { bool depthOK = true; bool stencilOK = true; 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()); if (renderPassInfo.getAttachments()[attachmentNdx].getStoreOp() == VK_ATTACHMENT_STORE_OP_STORE && !verifyDepthAttachment(referenceValues[attachmentNdx], depthAccess, depthErrorImage.getAccess(), config.depthValues, requiredDepthEpsilon(attachment.getFormat()))) { depthOK = false; } if (renderPassInfo.getAttachments()[attachmentNdx].getStencilStoreOp() == VK_ATTACHMENT_STORE_OP_STORE && !verifyStencilAttachment(referenceValues[attachmentNdx], stencilAccess, stencilErrorImage.getAccess())) { stencilOK = false; } if (!depthOK || !stencilOK) { const auto attachmentNdxStr = de::toString(attachmentNdx); // Output images. log << TestLog::ImageSet("OutputAttachments" + attachmentNdxStr, "Output depth and stencil attachments " + attachmentNdxStr); log << TestLog::Image("Attachment" + attachmentNdxStr + "Depth", "Attachment " + attachmentNdxStr + " Depth", depthAccess); log << TestLog::Image("Attachment" + attachmentNdxStr + "Stencil", "Attachment " + attachmentNdxStr + " Stencil", stencilAccess); log << TestLog::EndImageSet; // Reference images. These will be logged as image sets due to having depth and stencil aspects. log << TestLog::Image("AttachmentReferences" + attachmentNdxStr, "Reference images " + attachmentNdxStr, referenceAttachments[attachmentNdx].getAccess()); // Error masks. log << TestLog::ImageSet("ErrorMasks" + attachmentNdxStr, "Error masks " + attachmentNdxStr); if (!depthOK) log << TestLog::Image("DepthAttachmentError" + attachmentNdxStr, "Depth Attachment Error " + attachmentNdxStr, depthErrorImage.getAccess()); if (!stencilOK) log << TestLog::Image("StencilAttachmentError" + attachmentNdxStr, "Stencil Attachment Error " + attachmentNdxStr, stencilErrorImage.getAccess()); log << TestLog::EndImageSet; attachmentOK = false; } } } else { void* const ptr = attachmentResources[attachmentNdx]->getResultMemory().getHostPtr(); invalidateAlloc(vk, device, attachmentResources[attachmentNdx]->getResultMemory()); bool depthOK = true; bool stencilOK = true; bool colorOK = true; 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()); if (tcu::hasDepthComponent(format.order)) { 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(), config.depthValues, requiredDepthEpsilon(attachment.getFormat()))) { depthOK = false; } } else if (tcu::hasStencilComponent(format.order)) { 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())) { stencilOK = false; } } else { 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(), config.useFormatCompCount)) { colorOK = false; } } if (!depthOK || !stencilOK || !colorOK) { log << TestLog::ImageSet("TestImages", "Output attachment, reference image and error mask"); if (!depthOK || !stencilOK) { // Log without conversions. 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()); } else { // Convert color images to better reflect test status and output in any format. const auto numChannels = tcu::getNumUsedChannels(access.getFormat().order); const auto attachmentForLog = renderColorImageForLog(access, numChannels); const auto referenceForLog = renderColorImageForLog(referenceValues[attachmentNdx], targetSize, numChannels); log << TestLog::Message << "Check the attachment formats and test data to verify which components affect the test result." << TestLog::EndMessage; log << TestLog::Message << "In the reference image, unset pixel components are marked with a 3x3 grid storing values 0.0 and 0.25, pixel components set to false are stored as 0.5 and pixel components set to true are stored as 1.0." << TestLog::EndMessage; log << TestLog::Message << "Output attachment pixel components are always set to 0.5 or 1.0 but may not be taken into account if not set in the reference image." << TestLog::EndMessage; log << TestLog::Image("Attachment" + de::toString(attachmentNdx), "Attachment " + de::toString(attachmentNdx), attachmentForLog->getAccess()); log << TestLog::Image("AttachmentReference" + de::toString(attachmentNdx), "Attachment reference " + de::toString(attachmentNdx), referenceForLog->getAccess()); } log << TestLog::Image("AttachmentError" + de::toString(attachmentNdx), "Attachment Error " + de::toString(attachmentNdx), errorImage.getAccess()); log << TestLog::EndImageSet; attachmentOK = false; } } if (!attachmentOK) 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, deBool useFormatCompCount) { const tcu::TextureFormat format = mapVkFormat(vkFormat); const tcu::TextureChannelClass channelClass = tcu::getTextureChannelClass(format.type); const size_t componentCount = (size_t)tcu::getNumUsedChannels(format.order); switch (channelClass) { case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: if (useFormatCompCount) return (componentCount == 1 ? "int" : "ivec" + de::toString(componentCount)); else return "ivec4"; case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: if (useFormatCompCount) return (componentCount == 1 ? "uint" : "uvec" + de::toString(componentCount)); else return "uvec4"; case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: if (useFormatCompCount) return (componentCount == 1 ? "float" : "vec" + de::toString(componentCount)); else 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"; bool hasAnyDepthFormats = false; for (size_t attachmentNdx = config.drawStartNdx; 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) { hasAnyDepthFormats = true; 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) { 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 = config.drawStartNdx; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const std::string attachmentType = getAttachmentType(config.renderPass.getAttachments()[getAttachmentNdx(subpass.getColorAttachments(), attachmentNdx)].getFormat(), config.useFormatCompCount); fragmentShader << "layout(location = " << attachmentNdx << ") out highp " << attachmentType << " o_color" << attachmentNdx << ";\n"; } if (hasAnyDepthFormats) fragmentShader << "\nbool depthsEqual(float a, float b, float epsilon) {\n" << "\treturn abs(a - b) <= epsilon;\n}\n\n"; fragmentShader << "void main (void) {\n"; if (subpass.getInputAttachments().empty()) { for (size_t attachmentNdx = config.drawStartNdx; attachmentNdx < subpass.getColorAttachments().size(); attachmentNdx++) { const deUint32 attachmentIndex = subpass.getColorAttachments()[attachmentNdx].getAttachment(); if (attachmentIndex == VK_ATTACHMENT_UNUSED) continue; const Attachment attachment = config.renderPass.getAttachments()[attachmentIndex]; const tcu::TextureFormat format = mapVkFormat(attachment.getFormat()); const size_t componentCount = config.useFormatCompCount ? (size_t)tcu::getNumUsedChannels(format.order) : 4; const std::string attachmentType = getAttachmentType(attachment.getFormat(), config.useFormatCompCount); fragmentShader << "\to_color" << attachmentNdx << " = " << attachmentType << "(" << attachmentType + "("; for (size_t compNdx = 0; compNdx < componentCount; 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) { 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) << ") ? " << deUint32(config.depthValues[1]) << ".0f/255.0f : " << deUint32(config.depthValues[0]) << ".0f/255.0f);\n"; } } else { size_t inputComponentCount = 0; size_t outputComponentCount = 0; for (size_t attachmentNdx = config.drawStartNdx; 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) inputComponentCount += 1; else if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) inputComponentCount += 1; else inputComponentCount += componentCount; } for (size_t attachmentNdx = config.drawStartNdx; 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) { 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 = config.drawStartNdx; 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) { fragmentShader << "\tinputs[" << inputValueNdx << "] = depthsEqual(" << deUint32(config.depthValues[1]) << ".0f/255.0f, float(subpassLoad(i_depth" << attachmentNdx << ").x), " << std::fixed << std::setprecision(12) << requiredDepthEpsilon(attachment.getFormat()) << ");\n"; inputValueNdx++; } if (isStencilFormat && layout != VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { 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 = config.drawStartNdx; 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(), config.useFormatCompCount); 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 < (config.useFormatCompCount ? componentCount : 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) { 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 << "] ? " << deUint32(config.depthValues[1]) << ".0f/255.0f : " << deUint32(config.depthValues[0]) << ".0f/255.0f;\n"; } } } 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, deBool useFormatCompCount, const DepthValuesArray& depthValues) { for (size_t attachmentNdx = 0; attachmentNdx < attachments.size(); attachmentNdx++) { if (!isLazy[attachmentNdx]) clearValues.push_back(just(randomClearValue(attachments[attachmentNdx], rng, useFormatCompCount, depthValues))); else clearValues.push_back(tcu::Nothing); } } void initializeRenderPassClearValues (de::Random& rng, vector >& clearValues, const vector& attachments, deBool useFormatCompCount, const DepthValuesArray& depthValues) { 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, useFormatCompCount, depthValues))); } else clearValues.push_back(tcu::Nothing); } } void logSubpassRenderInfo (TestLog& log, const SubpassRenderInfo& info, TestConfig config) { 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(), config.useFormatCompCount) << 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], config.useFormatCompCount) << " 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], config.useFormatCompCount) << " 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], config); } } 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 bool omitBlendState = subpass.getOmitBlendState(); 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, config.useFormatCompCount); 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, config.useFormatCompCount, config.depthValues); 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, config.drawStartNdx, subpassIsSecondary, omitBlendState, 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; if (config.renderingType == RENDERING_TYPE_RENDERPASS2) context.requireDeviceFunctionality("VK_KHR_create_renderpass2"); if (config.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) context.requireDeviceFunctionality("VK_KHR_dynamic_rendering"); if (config.allocationKind == ALLOCATION_KIND_DEDICATED) { if (!context.isDeviceFunctionalitySupported("VK_KHR_dedicated_allocation")) TCU_THROW(NotSupportedError, "VK_KHR_dedicated_allocation is not supported"); } if (!renderPassInfo.getInputAspects().empty()) { if (!context.isDeviceFunctionalitySupported("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 || renderPassInfo.getAttachments()[attachmentNdx].getInitialLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL || renderPassInfo.getAttachments()[attachmentNdx].getFinalLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || renderPassInfo.getAttachments()[attachmentNdx].getFinalLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { 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 || subpass.getColorAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { 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 || subpass.getInputAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { 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 || subpass.getResolveAttachments()[attachmentNdx].getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { requireDepthStencilLayout = true; break; } } if (subpass.getDepthStencilAttachment().getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL || subpass.getDepthStencilAttachment().getImageLayout() == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) { requireDepthStencilLayout = true; break; } } if (requireDepthStencilLayout && !context.isDeviceFunctionalitySupported("VK_KHR_maintenance2")) TCU_THROW(NotSupportedError, "VK_KHR_maintenance2 is not supported"); } initializeAttachmentIsLazy(attachmentIsLazy, renderPassInfo.getAttachments(), config.imageMemory); initializeImageClearValues(rng, imageClearValues, renderPassInfo.getAttachments(), attachmentIsLazy, config.useFormatCompCount, config.depthValues); initializeAttachmentImageUsage(context, attachmentImageUsage, renderPassInfo, attachmentIsLazy, imageClearValues); initializeRenderPassClearValues(rng, renderPassClearValues, renderPassInfo.getAttachments(), config.useFormatCompCount, config.depthValues); initializeSubpassIsSecondary(subpassIsSecondary, renderPassInfo.getSubpasses(), config.commandBufferTypes); 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 commandBufferPool (createCommandPool(vk, device, 0, queueIndex)); 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; Move renderPass; if (config.renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) renderPass = createRenderPass(vk, device, renderPassInfo, config.renderingType); 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); { Move framebuffer; if (config.renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) 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, config.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING))); beginCommandBuffer(vk, *renderCommandBuffer, (VkCommandBufferUsageFlags)0, DE_NULL, 0, DE_NULL, VK_FALSE, (VkQueryControlFlags)0, (VkQueryPipelineStatisticFlags)0); pushRenderPassCommands(vk, *renderCommandBuffer, *renderPass, renderPassInfo, attachmentResources, *framebuffer, subpassRenderers, renderPos, renderSize, renderPassClearValues, queueIndex, config.renderTypes, config.renderingType); 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, const TestConfigExternal testConfigExternal) { 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 initialAndFinalColorLayoutsLazy[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_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 initialAndFinalDepthStencilLayoutsLazy[] = { 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 }; 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()); bool useDynamicRendering (testConfigExternal.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING); 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(); const TestConfig::ImageMemory imageMemory = rng.choose(DE_ARRAY_BEGIN(imageMemories), DE_ARRAY_END(imageMemories)); VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_GENERAL; vector attachments; vector colorAttachmentReferences; // we want to make sure that dynamic rendering test cases have corresponding renderpass // cases as this will allow drivers to easily compare GPU batches; since configurations // for those tests are generated we need to generate configurations for all cases // even when we know earlier that for dynamic rendering we will skip it bool executeForDynamicRendering = true; 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 = (imageMemory == TestConfig::IMAGEMEMORY_STRICT) ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayoutsLazy), DE_ARRAY_END(initialAndFinalColorLayoutsLazy)); VkImageLayout finalizeLayout = (imageMemory == TestConfig::IMAGEMEMORY_STRICT) ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayouts), DE_ARRAY_END(initialAndFinalColorLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalColorLayoutsLazy), DE_ARRAY_END(initialAndFinalColorLayoutsLazy)); 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)); if (useDynamicRendering) { // with renderpass we can have automatic layout transitions; to do the same with dynamic rendering cases // we would need to add addtional barries but since those tests won't add coverage we are skipping them if ((initialLayout == VK_IMAGE_LAYOUT_GENERAL) || (initialLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)) finalizeLayout = initialLayout; else executeForDynamicRendering = false; } 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 = (imageMemory == TestConfig::IMAGEMEMORY_STRICT) ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayoutsLazy), DE_ARRAY_END(initialAndFinalDepthStencilLayoutsLazy)); VkImageLayout finalizeLayout = (imageMemory == TestConfig::IMAGEMEMORY_STRICT) ? rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayouts), DE_ARRAY_END(initialAndFinalDepthStencilLayouts)) : rng.choose(DE_ARRAY_BEGIN(initialAndFinalDepthStencilLayoutsLazy), DE_ARRAY_END(initialAndFinalDepthStencilLayoutsLazy)); 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 (useDynamicRendering) { if ((initialLayout == VK_IMAGE_LAYOUT_GENERAL) || (initialLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) || (initialLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) finalizeLayout = initialLayout; else executeForDynamicRendering = false; } 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 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)); // skip dynamic rendering cases (that don't add coverage) // this can be done not earlier than after grabbing all random numbers as // we need to make sure that those tests that will be created for dynamic // rendering have corresponding renderpass tests with the same name if (useDynamicRendering && !executeForDynamicRendering) continue; const TestConfig testConfig (renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, DE_FALSE, 1293809, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, testConfig); } } group->addChild(attachmentCountGroup.release()); } } void addAttachmentWriteMaskTests (tcu::TestCaseGroup* group, const TestConfigExternal testConfigExternal) { const deUint32 attachmentCounts[] = { 1, 2, 3, 4, 8 }; const VkFormat attachmentFormats[] = { VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R5G6B5_UNORM_PACK16, VK_FORMAT_R8G8_UNORM }; tcu::TestContext& testCtx = group->getTestContext(); for (deUint32 attachmentCountNdx = 0; attachmentCountNdx < DE_LENGTH_OF_ARRAY(attachmentCounts); attachmentCountNdx++) { const deUint32 attachmentCount = attachmentCounts[attachmentCountNdx]; const string groupName = "attachment_count_" + de::toString(attachmentCount); de::MovePtr attachmentCountGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), de::toString(attachmentCount).c_str())); for (deUint32 drawStartNdx = 0; drawStartNdx < (attachmentCount); drawStartNdx++) { deUint32 formatNdx = 0; vector attachments; vector colorAttachmentReferences; for (deUint32 attachmentNdx = 0; attachmentNdx < attachmentCount; attachmentNdx++) { const VkFormat format = attachmentFormats[formatNdx]; const VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; const VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; const VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE; const VkAttachmentLoadOp stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; const VkAttachmentStoreOp stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; const VkImageLayout initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; const VkImageLayout finalizeLayout = (testConfigExternal.renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) ? initialLayout : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; const VkImageLayout subpassLayout = VK_IMAGE_LAYOUT_GENERAL; attachments.push_back(Attachment(format, sampleCount, loadOp, storeOp, stencilLoadOp, stencilStoreOp, initialLayout, finalizeLayout)); colorAttachmentReferences.push_back(AttachmentReference((deUint32)attachmentNdx, subpassLayout)); if (++formatNdx == DE_LENGTH_OF_ARRAY(attachmentFormats)) formatNdx = 0; } { const VkImageLayout depthStencilLayout = VK_IMAGE_LAYOUT_GENERAL; const vector subpass (1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), colorAttachmentReferences, vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, depthStencilLayout), vector())); const vector deps; const string testCaseName = "start_index_" + de::toString(drawStartNdx); const RenderPass renderPass (attachments, subpass, deps); const TestConfig::RenderTypes render = TestConfig::RENDERTYPES_DRAW; const TestConfig::CommandBufferTypes commandBuffer = TestConfig::COMMANDBUFFERTYPES_INLINE; const TestConfig::ImageMemory imageMemory = TestConfig::IMAGEMEMORY_LAZY; const UVec2 targetSize = UVec2(64, 64); const UVec2 renderPos = UVec2(0, 0); const UVec2 renderSize = UVec2(64, 64); const deBool useFormatCompCount = DE_TRUE; const vector requiredFeatures = {DEVICE_CORE_FEATURE_INDEPENDENT_BLEND}; const TestConfig testConfig (renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, useFormatCompCount, 1293809, drawStartNdx, testConfigExternal.allocationKind, testConfigExternal.renderingType, requiredFeatures); addFunctionCaseWithPrograms(attachmentCountGroup.get(), testCaseName.c_str(), testCaseName.c_str(), checkSupport, createTestShaders, renderPassTest, testConfig); } } 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, const TestConfigExternal testConfigExternal) { 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 subpassLayoutsColor[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; const VkImageLayout subpassLayoutsDepthStencil[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; const VkImageLayout subpassLayoutsInput[] = { VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_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(), tcu::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)) : tcu::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]; if (lastUseOfAttachment[colorAttachmentIndex]) { deBool foundDuplicate = false; const deUint32 srcPass = *lastUseOfAttachment[colorAttachmentIndex]; const deUint32 dstPass = subpassIndex; const VkDependencyFlags dependencyFlags = rng.getBool() ? (VkDependencyFlags) VK_DEPENDENCY_BY_REGION_BIT : 0u; const SubpassDependency newDependency(srcPass, dstPass, 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, dependencyFlags); for (SubpassDependency& dependency : deps) { if (dependency.getSrcPass() == srcPass && dependency.getDstPass() == dstPass) { const VkAccessFlags newDstFlags = dependency.getDstAccessMask() | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; dependency.setDstAccessMask(newDstFlags); foundDuplicate = true; break; } } if (!foundDuplicate) { deps.push_back(newDependency); } } lastUseOfAttachment[colorAttachmentIndex] = just(subpassIndex); colorAttachmentReferences.push_back(AttachmentReference((deUint32)subpassColorAttachments[colorAttachmentNdx], VK_IMAGE_LAYOUT_GENERAL)); } for (size_t inputAttachmentNdx = 0; inputAttachmentNdx < subpassInputAttachments.size(); inputAttachmentNdx++) { const deUint32 inputAttachmentIndex = subpassInputAttachments[inputAttachmentNdx]; if(lastUseOfAttachment[inputAttachmentIndex]) { deBool foundDuplicate = false; const deUint32 srcPass = *lastUseOfAttachment[inputAttachmentIndex]; const deUint32 dstPass = subpassIndex; const VkDependencyFlags dependencyFlags = ((srcPass == subpassIndex) || rng.getBool()) ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u; const SubpassDependency newDependency(srcPass, dstPass, 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, dependencyFlags); for (SubpassDependency& dependency : deps) { if (dependency.getSrcPass() == srcPass && dependency.getDstPass() == dstPass) { const VkAccessFlags newSrcFlags = dependency.getSrcAccessMask() | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; const VkAccessFlags newDstFlags = dependency.getDstAccessMask() | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; dependency.setDstAccessMask(newSrcFlags); dependency.setDstAccessMask(newDstFlags); foundDuplicate = true; break; } } if (!foundDuplicate) { deps.push_back(newDependency); } lastUseOfAttachment[inputAttachmentIndex] = just(subpassIndex); VkImageAspectFlags aspect = 0u; if (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2) { bool col = colorAttachments.find(inputAttachmentIndex) != colorAttachments.end(); aspect = col ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; } inputAttachmentReferences.push_back(AttachmentReference((deUint32)subpassInputAttachments[inputAttachmentNdx], VK_IMAGE_LAYOUT_GENERAL, aspect)); } } if (depthStencilAttachment) { if (lastUseOfAttachment[*depthStencilAttachment]) { deBool foundDuplicate = false; const deUint32 srcPass = *lastUseOfAttachment[*depthStencilAttachment]; const deUint32 dstPass = subpassIndex; const VkDependencyFlags dependencyFlags = ((srcPass == subpassIndex) || rng.getBool()) ? (VkDependencyFlags)VK_DEPENDENCY_BY_REGION_BIT : 0u; const SubpassDependency newDependency(srcPass, dstPass, 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_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, dependencyFlags); for (SubpassDependency& dependency : deps) { if (dependency.getSrcPass() == srcPass && dependency.getDstPass() == dstPass) { const VkAccessFlags newSrcFlags = dependency.getSrcAccessMask() | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; const VkAccessFlags newDstFlags = dependency.getDstAccessMask() | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; dependency.setDstAccessMask(newSrcFlags); dependency.setDstAccessMask(newDstFlags); foundDuplicate = true; break; } } if (!foundDuplicate) { deps.push_back(newDependency); } } 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); } // Use random image layout when possible for (size_t colorRefIdx = 0; colorRefIdx < colorAttachmentReferences.size(); ++colorRefIdx) { bool usedAsInput = false; for (size_t inputRefIdx = 0; inputRefIdx < inputAttachmentReferences.size(); ++inputRefIdx) if (colorAttachmentReferences[colorRefIdx].getAttachment() == inputAttachmentReferences[inputRefIdx].getAttachment()) usedAsInput = true; if (!usedAsInput) colorAttachmentReferences[colorRefIdx].setImageLayout(rng.choose(DE_ARRAY_BEGIN(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor))); } for (size_t inputRefIdx = 0; inputRefIdx < inputAttachmentReferences.size(); ++inputRefIdx) { bool usedAsDepthStencil = inputAttachmentReferences[inputRefIdx].getAttachment() == depthStencilAttachmentReference.getAttachment(); bool usedAsColor = false; for (size_t colorRefIdx = 0; colorRefIdx < colorAttachmentReferences.size(); ++colorRefIdx) if (inputAttachmentReferences[inputRefIdx].getAttachment() == colorAttachmentReferences[colorRefIdx].getAttachment()) usedAsColor = true; if (!usedAsColor && !usedAsDepthStencil) inputAttachmentReferences[inputRefIdx].setImageLayout(rng.choose(DE_ARRAY_BEGIN(subpassLayoutsInput), DE_ARRAY_END(subpassLayoutsInput))); } { bool usedAsInput = false; for (size_t inputRefIdx = 0; inputRefIdx < inputAttachmentReferences.size(); ++inputRefIdx) if (depthStencilAttachmentReference.getAttachment() == inputAttachmentReferences[inputRefIdx].getAttachment()) usedAsInput = true; if (!usedAsInput) depthStencilAttachmentReference.setImageLayout(rng.choose(DE_ARRAY_BEGIN(subpassLayoutsDepthStencil), DE_ARRAY_END(subpassLayoutsDepthStencil))); } 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); const TestConfig testConfig (renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, DE_FALSE, 80329, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, testConfig); } } 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)); 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)); 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)); 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)); 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)); 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(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)))), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())); for (size_t subpassNdx = 1; subpassNdx < attachmentCount; subpassNdx++) { const VkImageAspectFlags inputAttachmentAspectMask = (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2) ? VK_IMAGE_ASPECT_COLOR_BIT : static_cast(0); subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(1, AttachmentReference((deUint32)(subpassNdx - 1), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, inputAttachmentAspectMask)), vector(1, AttachmentReference((deUint32)(subpassNdx), rng.choose(DE_ARRAY_BEGIN(subpassLayoutsColor), DE_ARRAY_END(subpassLayoutsColor)))), 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); const TestConfig testConfig (renderPass, render, commandBuffer, imageMemory, targetSize, renderPos, renderSize, DE_FALSE, 80329, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(allocationTypeGroup.get(), testCaseName.c_str(), testCaseName.c_str(), createTestShaders, renderPassTest, testConfig); } } } group->addChild(allocationTypeGroup.release()); } } void addSimpleTests (tcu::TestCaseGroup* group, const TestConfigExternal testConfigExternal) { 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "color", "Single color attachment case.", createTestShaders, renderPassTest, testConfig); } // 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "depth", "Single depth attachment case.", createTestShaders, renderPassTest, testConfig); } // 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "stencil", "Single stencil attachment case.", createTestShaders, renderPassTest, testConfig); } // 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "depth_stencil", "Single depth stencil attachment case.", createTestShaders, renderPassTest, testConfig); } // 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "color_depth", "Color and depth attachment case.", createTestShaders, renderPassTest, testConfig); } // 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_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), }; 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "color_stencil", "Color and stencil attachment case.", createTestShaders, renderPassTest, testConfig); } // 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()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "color_depth_stencil", "Color, depth and stencil attachment case.", createTestShaders, renderPassTest, testConfig); } // no attachments { const RenderPass renderPass (vector(), vector(1, Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector())), vector()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "no_attachments", "No attachments case.", createTestShaders, renderPassTest, testConfig); } // color_unused_omit_blend_state if (testConfigExternal.renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) { vector subpasses; // First subpass: use color attachment, create pipeline with color blend state 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(), false)); // Second subpass: don't use color attachment, create pipeline without color blend state subpasses.push_back(Subpass(VK_PIPELINE_BIND_POINT_GRAPHICS, 0u, vector(), vector(1, AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)), vector(), AttachmentReference(VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_GENERAL), vector(), true)); 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)), subpasses, vector()); const TestConfig testConfig (renderPass, TestConfig::RENDERTYPES_DRAW, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(group, "color_unused_omit_blend_state", "Two unused color attachment case without blend state", createTestShaders, renderPassTest, testConfig); } } 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, const TestConfigExternal testConfigExternal) { 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()); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } formatGroup->addChild(loadOpGroup.release()); } if (testConfigExternal.renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) { 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 VkImageAspectFlags inputAttachmentAspectMask = (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2) ? static_cast(VK_IMAGE_ASPECT_COLOR_BIT) : static_cast(0); 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; if (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2 && useInputAspect) continue; 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, inputAttachmentAspectMask)), 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 VkInputAttachmentAspectReference inputAspect = { 1u, 0u, VK_IMAGE_ASPECT_COLOR_BIT }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "")); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } { 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, inputAttachmentAspectMask)), 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)); 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 VkInputAttachmentAspectReference inputAspect = { 1u, 0u, VK_IMAGE_ASPECT_COLOR_BIT }; inputAspects.push_back(inputAspect); } { const RenderPass renderPass (attachments, subpasses, deps, inputAspects); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "")); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } } } 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); const VkImageAspectFlags formatAspectFlags = (isDepthAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : 0u) | (isStencilAttachment ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : 0u); 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()); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); addFunctionCaseWithPrograms(loadOpGroup.get(), renderTypes[renderTypeNdx].str, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } if (isStencilAttachment && isDepthAttachment && loadOp != VK_ATTACHMENT_LOAD_OP_CLEAR) { { 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), vector())), vector()); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string(renderTypes[renderTypeNdx].str) + "_depth_read_only"); addFunctionCaseWithPrograms(loadOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } { 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), vector())), vector()); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 90239, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string(renderTypes[renderTypeNdx].str) + "_stencil_read_only"); addFunctionCaseWithPrograms(loadOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } } formatGroup->addChild(loadOpGroup.release()); } if (testConfigExternal.renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) { 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 VkImageAspectFlags inputAttachmentAspectMask = (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2) ? formatAspectFlags : static_cast(0); 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; if (testConfigExternal.renderingType == RENDERING_TYPE_RENDERPASS2 && useInputAspect) continue; 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, inputAttachmentAspectMask)), 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_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 0u)); if (useInputAspect) { const VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "")); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } { 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, inputAttachmentAspectMask)), 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)); deps.push_back(SubpassDependency(1, 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 VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "")); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } 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, inputAttachmentAspectMask)), 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_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, 0u)); if (useInputAspect) { const VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "") + "_depth_read_only"); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } { 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, inputAttachmentAspectMask)), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL), 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_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 VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "") + "_depth_read_only"); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } // 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, inputAttachmentAspectMask)), 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_COLOR_ATTACHMENT_OUTPUT_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 VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (renderTypes[renderTypeNdx].str + string(useInputAspect ? "_use_input_aspect" : "") + "_stencil_read_only"); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } { 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, inputAttachmentAspectMask)), vector(), vector(), AttachmentReference(0, VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL), 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_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 VkInputAttachmentAspectReference inputAspect = { 1u, 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); const TestConfig testConfig (renderPass, renderTypes[renderTypeNdx].types, TestConfig::COMMANDBUFFERTYPES_INLINE, TestConfig::IMAGEMEMORY_STRICT, targetSize, renderPos, renderSize, DE_FALSE, 89246, 0, testConfigExternal.allocationKind, testConfigExternal.renderingType); const string testName (string("self_dep_") + renderTypes[renderTypeNdx].str + (useInputAspect ? "_use_input_aspect" : "") + "_stencil_read_only"); addFunctionCaseWithPrograms(storeOpGroup.get(), testName, string("self_dep_") + renderTypes[renderTypeNdx].str, createTestShaders, renderPassTest, testConfig); } } } } } loadOpGroup->addChild(storeOpGroup.release()); } inputGroup->addChild(loadOpGroup.release()); } formatGroup->addChild(inputGroup.release()); } group->addChild(formatGroup.release()); } } void addRenderPassTests (tcu::TestCaseGroup* group, const AllocationKind allocationKind, const RenderingType renderingType) { const TestConfigExternal testConfigExternal (allocationKind, renderingType); addTestGroup(group, "simple", "Simple basic render pass tests", addSimpleTests, testConfigExternal); addTestGroup(group, "formats", "Tests for different image formats.", addFormatTests, testConfigExternal); addTestGroup(group, "attachment", "Attachment format and count tests with load and store ops and image layouts", addAttachmentTests, testConfigExternal); addTestGroup(group, "attachment_write_mask", "Attachment write mask tests", addAttachmentWriteMaskTests, testConfigExternal); if (renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) addTestGroup(group, "attachment_allocation", "Attachment allocation tests", addAttachmentAllocationTests, testConfigExternal); } de::MovePtr createSuballocationTests(tcu::TestContext& testCtx, RenderingType renderingType) { de::MovePtr suballocationTestsGroup(new tcu::TestCaseGroup(testCtx, "suballocation", "Suballocation RenderPass Tests")); addRenderPassTests(suballocationTestsGroup.get(), ALLOCATION_KIND_SUBALLOCATED, renderingType); return suballocationTestsGroup; } de::MovePtr createDedicatedAllocationTests(tcu::TestContext& testCtx, RenderingType renderingType) { de::MovePtr dedicatedAllocationTestsGroup(new tcu::TestCaseGroup(testCtx, "dedicated_allocation", "RenderPass Tests For Dedicated Allocation")); addRenderPassTests(dedicatedAllocationTestsGroup.get(), ALLOCATION_KIND_DEDICATED, renderingType); return dedicatedAllocationTestsGroup; } tcu::TestCaseGroup* createRenderPassTestsInternal (tcu::TestContext& testCtx, RenderingType renderingType) { const char* renderingTestsGroupName = (renderingType == RENDERING_TYPE_RENDERPASS_LEGACY) ? "renderpass" : (renderingType == RENDERING_TYPE_RENDERPASS2) ? "renderpass2" : (renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) ? "dynamic_rendering" : ""; const char* renderingTestsGroupDescription = (renderingType == RENDERING_TYPE_RENDERPASS_LEGACY) ? "RenderPass Tests" : (renderingType == RENDERING_TYPE_RENDERPASS2) ? "RenderPass2 Tests" : (renderingType == RENDERING_TYPE_DYNAMIC_RENDERING) ? "Dynamic Rendering Tests" : ""; de::MovePtr renderingTests (new tcu::TestCaseGroup(testCtx, renderingTestsGroupName, renderingTestsGroupDescription)); de::MovePtr suballocationTestGroup = createSuballocationTests(testCtx, renderingType); de::MovePtr dedicatedAllocationTestGroup = createDedicatedAllocationTests(testCtx, renderingType); switch (renderingType) { case RENDERING_TYPE_RENDERPASS_LEGACY: suballocationTestGroup->addChild(createRenderPassMultisampleTests(testCtx)); suballocationTestGroup->addChild(createRenderPassMultisampleResolveTests(testCtx)); suballocationTestGroup->addChild(createRenderPassSubpassDependencyTests(testCtx)); suballocationTestGroup->addChild(createRenderPassSampleReadTests(testCtx)); suballocationTestGroup->addChild(createRenderPassSparseRenderTargetTests(testCtx)); renderingTests->addChild(createRenderPassMultipleSubpassesMultipleCommandBuffersTests(testCtx)); break; case RENDERING_TYPE_RENDERPASS2: suballocationTestGroup->addChild(createRenderPass2MultisampleTests(testCtx)); suballocationTestGroup->addChild(createRenderPass2MultisampleResolveTests(testCtx)); suballocationTestGroup->addChild(createRenderPass2SubpassDependencyTests(testCtx)); suballocationTestGroup->addChild(createRenderPass2SampleReadTests(testCtx)); suballocationTestGroup->addChild(createRenderPass2SparseRenderTargetTests(testCtx)); renderingTests->addChild(createRenderPass2DepthStencilResolveTests(testCtx)); break; case RENDERING_TYPE_DYNAMIC_RENDERING: suballocationTestGroup->addChild(createDynamicRenderingMultisampleResolveTests(testCtx)); suballocationTestGroup->addChild(createDynamicRenderingSparseRenderTargetTests(testCtx)); renderingTests->addChild(createDynamicRenderingBasicTests(testCtx)); break; } if (renderingType != RENDERING_TYPE_DYNAMIC_RENDERING) { suballocationTestGroup->addChild(createRenderPassUnusedAttachmentTests(testCtx, renderingType)); suballocationTestGroup->addChild(createRenderPassUnusedAttachmentSparseFillingTests(testCtx, renderingType)); } suballocationTestGroup->addChild(createRenderPassUnusedClearAttachmentTests(testCtx, renderingType)); suballocationTestGroup->addChild(createRenderPassLoadStoreOpNoneTests(testCtx, renderingType)); renderingTests->addChild(suballocationTestGroup.release()); renderingTests->addChild(dedicatedAllocationTestGroup.release()); renderingTests->addChild(createFragmentDensityMapTests(testCtx, renderingType)); return renderingTests.release(); } } // anonymous tcu::TestCaseGroup* createRenderPassTests (tcu::TestContext& testCtx) { return createRenderPassTestsInternal(testCtx, RENDERING_TYPE_RENDERPASS_LEGACY); } tcu::TestCaseGroup* createRenderPass2Tests (tcu::TestContext& testCtx) { return createRenderPassTestsInternal(testCtx, RENDERING_TYPE_RENDERPASS2); } tcu::TestCaseGroup* createDynamicRenderingTests(tcu::TestContext& testCtx) { return createRenderPassTestsInternal(testCtx, RENDERING_TYPE_DYNAMIC_RENDERING); } } // vkt