/*------------------------------------------------------------------------- * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Tests for render passses with multisample attachments *//*--------------------------------------------------------------------*/ #include "vktRenderPassMultisampleTests.hpp" #include "vktRenderPassTestsUtil.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 "vkTypeUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "tcuFloat.hpp" #include "tcuImageCompare.hpp" #include "tcuFormatUtil.hpp" #include "tcuMaybe.hpp" #include "tcuResultCollector.hpp" #include "tcuTestLog.hpp" #include "tcuTextureUtil.hpp" #include "tcuVectorUtil.hpp" #include "deUniquePtr.hpp" #include "deSharedPtr.hpp" 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 std::pair; using std::string; using std::vector; typedef de::SharedPtr > VkImageSp; typedef de::SharedPtr > VkImageViewSp; typedef de::SharedPtr > VkBufferSp; typedef de::SharedPtr > VkPipelineSp; namespace vkt { namespace { using namespace renderpass; enum { MAX_COLOR_ATTACHMENT_COUNT = 4u }; enum TestSeparateUsage { TEST_DEPTH = (1 << 0), TEST_STENCIL = (1 << 1) }; template de::SharedPtr safeSharedPtr (T* ptr) { try { return de::SharedPtr(ptr); } catch (...) { delete ptr; throw; } } VkImageAspectFlags getImageAspectFlags (VkFormat vkFormat) { const tcu::TextureFormat format (mapVkFormat(vkFormat)); const bool hasDepth (tcu::hasDepthComponent(format.order)); const bool hasStencil (tcu::hasStencilComponent(format.order)); if (hasDepth || hasStencil) { return (hasDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : (VkImageAspectFlagBits)0u) | (hasStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : (VkImageAspectFlagBits)0u); } else return VK_IMAGE_ASPECT_COLOR_BIT; } 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)); } de::MovePtr createBufferMemory (const DeviceInterface& vk, VkDevice device, Allocator& allocator, VkBuffer buffer) { de::MovePtr allocation (allocator.allocate(getBufferMemoryRequirements(vk, device, buffer), MemoryRequirement::HostVisible)); bindBufferMemory(vk, device, buffer, allocation->getMemory(), allocation->getOffset()); return allocation; } de::MovePtr createImageMemory (const DeviceInterface& vk, VkDevice device, Allocator& allocator, VkImage image) { de::MovePtr allocation (allocator.allocate(getImageMemoryRequirements(vk, device, image), MemoryRequirement::Any)); bindImageMemory(vk, device, image, allocation->getMemory(), allocation->getOffset()); return allocation; } Move createImage (const DeviceInterface& vk, VkDevice device, VkImageCreateFlags flags, VkImageType imageType, VkFormat format, VkExtent3D extent, deUint32 mipLevels, deUint32 arrayLayers, VkSampleCountFlagBits samples, VkImageTiling tiling, VkImageUsageFlags usage, VkSharingMode sharingMode, deUint32 queueFamilyCount, const deUint32* pQueueFamilyIndices, VkImageLayout initialLayout, TestSeparateUsage separateStencilUsage) { VkImageUsageFlags depthUsage = (separateStencilUsage == TEST_DEPTH) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; VkImageUsageFlags stencilUsage = (separateStencilUsage == TEST_STENCIL) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; const VkImageStencilUsageCreateInfo stencilUsageInfo = { VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, DE_NULL, stencilUsage }; const VkImageCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, separateStencilUsage ? &stencilUsageInfo : DE_NULL, flags, imageType, format, extent, mipLevels, arrayLayers, samples, tiling, separateStencilUsage ? depthUsage : usage, sharingMode, queueFamilyCount, pQueueFamilyIndices, initialLayout }; return createImage(vk, device, &pCreateInfo); } Move createImageView (const DeviceInterface& vk, VkDevice device, VkImageViewCreateFlags flags, VkImage image, VkImageViewType viewType, VkFormat format, VkComponentMapping components, VkImageSubresourceRange subresourceRange) { const VkImageViewCreateInfo pCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, DE_NULL, flags, image, viewType, format, components, subresourceRange, }; return createImageView(vk, device, &pCreateInfo); } Move createImage (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const DeviceInterface& vkd, VkDevice device, VkFormat vkFormat, VkSampleCountFlagBits sampleCountBit, VkImageUsageFlags usage, deUint32 width, deUint32 height, TestSeparateUsage separateStencilUsage = (TestSeparateUsage)0u) { try { const tcu::TextureFormat format (mapVkFormat(vkFormat)); const VkImageType imageType (VK_IMAGE_TYPE_2D); const VkImageTiling imageTiling (VK_IMAGE_TILING_OPTIMAL); const VkFormatProperties formatProperties (getPhysicalDeviceFormatProperties(vki, physicalDevice, vkFormat)); const VkImageFormatProperties imageFormatProperties (getPhysicalDeviceImageFormatProperties(vki, physicalDevice, vkFormat, imageType, imageTiling, usage, 0u)); const VkImageUsageFlags depthUsage = (separateStencilUsage == TEST_DEPTH) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; const VkImageUsageFlags stencilUsage = (separateStencilUsage == TEST_STENCIL) ? usage : (VkImageUsageFlags)VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; const VkExtent3D imageExtent = { width, height, 1u }; if ((tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) TCU_THROW(NotSupportedError, "Format can't be used as depth stencil attachment"); if (!(tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) && (formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) == 0) TCU_THROW(NotSupportedError, "Format can't be used as color attachment"); if (imageFormatProperties.maxExtent.width < imageExtent.width || imageFormatProperties.maxExtent.height < imageExtent.height || ((imageFormatProperties.sampleCounts & sampleCountBit) == 0)) { TCU_THROW(NotSupportedError, "Image type not supported"); } if (separateStencilUsage) { const VkImageStencilUsageCreateInfo stencilUsageInfo = { VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext stencilUsage // VkImageUsageFlags stencilUsage }; const VkPhysicalDeviceImageFormatInfo2 formatInfo2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, // VkStructureType sType &stencilUsageInfo, // const void* pNext vkFormat, // VkFormat format imageType, // VkImageType type imageTiling, // VkImageTiling tiling depthUsage, // VkImageUsageFlags usage (VkImageCreateFlags)0u // VkImageCreateFlags flags }; VkImageFormatProperties2 extProperties = { VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, DE_NULL, { { 0, // width 0, // height 0, // depth }, 0u, // maxMipLevels 0u, // maxArrayLayers 0, // sampleCounts 0u, // maxResourceSize }, }; if ((vki.getPhysicalDeviceImageFormatProperties2(physicalDevice, &formatInfo2, &extProperties) == VK_ERROR_FORMAT_NOT_SUPPORTED) || extProperties.imageFormatProperties.maxExtent.width < imageExtent.width || extProperties.imageFormatProperties.maxExtent.height < imageExtent.height || ((extProperties.imageFormatProperties.sampleCounts & sampleCountBit) == 0)) { TCU_THROW(NotSupportedError, "Image format not supported"); } } return createImage(vkd, device, 0u, imageType, vkFormat, imageExtent, 1u, 1u, sampleCountBit, imageTiling, usage, VK_SHARING_MODE_EXCLUSIVE, 0u, DE_NULL, VK_IMAGE_LAYOUT_UNDEFINED, separateStencilUsage); } catch (const vk::Error& error) { if (error.getError() == VK_ERROR_FORMAT_NOT_SUPPORTED) TCU_THROW(NotSupportedError, "Image format not supported"); throw; } } Move createImageAttachmentView (const DeviceInterface& vkd, VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect) { const VkImageSubresourceRange range = { aspect, 0u, 1u, 0u, 1u }; return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range); } Move createSrcPrimaryInputImageView (const DeviceInterface& vkd, VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect, TestSeparateUsage testSeparateUsage) { VkImageAspectFlags primaryDepthStencilAspect = (testSeparateUsage == TEST_STENCIL) ? VK_IMAGE_ASPECT_STENCIL_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; const VkImageSubresourceRange range = { aspect == (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT) ? primaryDepthStencilAspect : aspect, 0u, 1u, 0u, 1u }; return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range); } Move createSrcSecondaryInputImageView (const DeviceInterface& vkd, VkDevice device, VkImage image, VkFormat format, VkImageAspectFlags aspect, TestSeparateUsage separateStencilUsage) { if ((aspect == (VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT)) && !separateStencilUsage) { const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u }; return createImageView(vkd, device, 0u, image, VK_IMAGE_VIEW_TYPE_2D, format, makeComponentMappingRGBA(), range); } else return Move(); } VkDeviceSize getPixelSize (VkFormat vkFormat) { const tcu::TextureFormat format (mapVkFormat(vkFormat)); return format.getPixelSize(); } Move createBuffer (const DeviceInterface& vkd, VkDevice device, VkFormat format, deUint32 width, deUint32 height) { const VkBufferUsageFlags bufferUsage (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT); const VkDeviceSize pixelSize (getPixelSize(format)); const VkBufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, DE_NULL, 0u, width * height * pixelSize, bufferUsage, VK_SHARING_MODE_EXCLUSIVE, 0u, DE_NULL }; return createBuffer(vkd, device, &createInfo); } VkSampleCountFlagBits sampleCountBitFromomSampleCount (deUint32 count) { switch (count) { case 1: return VK_SAMPLE_COUNT_1_BIT; case 2: return VK_SAMPLE_COUNT_2_BIT; case 4: return VK_SAMPLE_COUNT_4_BIT; case 8: return VK_SAMPLE_COUNT_8_BIT; case 16: return VK_SAMPLE_COUNT_16_BIT; case 32: return VK_SAMPLE_COUNT_32_BIT; case 64: return VK_SAMPLE_COUNT_64_BIT; default: DE_FATAL("Invalid sample count"); return (VkSampleCountFlagBits)(0x1u << count); } } std::vector createMultisampleImages (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const DeviceInterface& vkd, VkDevice device, VkFormat format, deUint32 sampleCount, deUint32 width, deUint32 height) { std::vector images (sampleCount); for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) images[imageNdx] = safeSharedPtr(new vk::Unique(createImage(vki, physicalDevice, vkd, device, format, sampleCountBitFromomSampleCount(sampleCount), VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, width, height))); return images; } std::vector createSingleSampleImages (const InstanceInterface& vki, VkPhysicalDevice physicalDevice, const DeviceInterface& vkd, VkDevice device, VkFormat format, deUint32 sampleCount, deUint32 width, deUint32 height) { std::vector images (sampleCount); for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) images[imageNdx] = safeSharedPtr(new vk::Unique(createImage(vki, physicalDevice, vkd, device, format, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, width, height))); return images; } std::vector > createImageMemory (const DeviceInterface& vkd, VkDevice device, Allocator& allocator, const std::vector images) { std::vector > memory (images.size()); for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) memory[memoryNdx] = safeSharedPtr(createImageMemory(vkd, device, allocator, **images[memoryNdx]).release()); return memory; } std::vector createImageAttachmentViews (const DeviceInterface& vkd, VkDevice device, const std::vector& images, VkFormat format, VkImageAspectFlagBits aspect) { std::vector views (images.size()); for (size_t imageNdx = 0; imageNdx < images.size(); imageNdx++) views[imageNdx] = safeSharedPtr(new vk::Unique(createImageAttachmentView(vkd, device, **images[imageNdx], format, aspect))); return views; } std::vector createBuffers (const DeviceInterface& vkd, VkDevice device, VkFormat format, deUint32 sampleCount, deUint32 width, deUint32 height) { std::vector buffers (sampleCount); for (size_t bufferNdx = 0; bufferNdx < buffers.size(); bufferNdx++) buffers[bufferNdx] = safeSharedPtr(new vk::Unique(createBuffer(vkd, device, format, width, height))); return buffers; } std::vector > createBufferMemory (const DeviceInterface& vkd, VkDevice device, Allocator& allocator, const std::vector buffers) { std::vector > memory (buffers.size()); for (size_t memoryNdx = 0; memoryNdx < memory.size(); memoryNdx++) memory[memoryNdx] = safeSharedPtr(createBufferMemory(vkd, device, allocator, **buffers[memoryNdx]).release()); return memory; } template Move createRenderPass (const DeviceInterface& vkd, VkDevice device, VkFormat srcFormat, VkFormat dstFormat, deUint32 sampleCount, RenderingType renderingType, TestSeparateUsage separateStencilUsage) { const VkSampleCountFlagBits samples (sampleCountBitFromomSampleCount(sampleCount)); const deUint32 splitSubpassCount (deDivRoundUp32(sampleCount, MAX_COLOR_ATTACHMENT_COUNT)); const tcu::TextureFormat format (mapVkFormat(srcFormat)); const bool isDepthStencilFormat (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)); const VkImageAspectFlags inputAspect (separateStencilUsage == TEST_DEPTH ? (VkImageAspectFlags)VK_IMAGE_ASPECT_DEPTH_BIT : separateStencilUsage == TEST_STENCIL ? (VkImageAspectFlags)VK_IMAGE_ASPECT_STENCIL_BIT : getImageAspectFlags(srcFormat)); vector subpasses; vector > dstAttachmentRefs (splitSubpassCount); vector > dstResolveAttachmentRefs (splitSubpassCount); vector attachments; vector dependencies; const AttachmentRef srcAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // deUint32 attachment; || deUint32 attachment; isDepthStencilFormat // VkImageLayout layout; || VkImageLayout layout; ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 0u // || VkImageAspectFlags aspectMask; ); const AttachmentRef srcAttachmentInputRef // VkAttachmentReference || VkAttachmentReference2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // deUint32 attachment; || deUint32 attachment; VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout; (renderingType == RENDERING_TYPE_RENDERPASS2) // || VkImageAspectFlags aspectMask; ? inputAspect : 0u ); { const AttachmentDesc srcAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags; srcFormat, // VkFormat format; || VkFormat format; samples, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout; VK_IMAGE_LAYOUT_GENERAL // VkImageLayout finalLayout; || VkImageLayout finalLayout; ); attachments.push_back(srcAttachment); } for (deUint32 splitSubpassIndex = 0; splitSubpassIndex < splitSubpassCount; splitSubpassIndex++) { for (deUint32 sampleNdx = 0; sampleNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, sampleCount - splitSubpassIndex * MAX_COLOR_ATTACHMENT_COUNT); sampleNdx++) { // Multisample color attachment { const AttachmentDesc dstAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags; dstFormat, // VkFormat format; || VkFormat format; samples, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; || VkImageLayout finalLayout; ); const AttachmentRef dstAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; (deUint32)attachments.size(), // deUint32 attachment; || deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout; 0u // || VkImageAspectFlags aspectMask; ); attachments.push_back(dstAttachment); dstAttachmentRefs[splitSubpassIndex].push_back(dstAttachmentRef); } // Resolve attachment { const AttachmentDesc dstAttachment // VkAttachmentDescription || VkAttachmentDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // VkAttachmentDescriptionFlags flags; || VkAttachmentDescriptionFlags flags; dstFormat, // VkFormat format; || VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; || VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; || VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; || VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; || VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp; || VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; || VkImageLayout initialLayout; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; || VkImageLayout finalLayout; ); const AttachmentRef dstAttachmentRef // VkAttachmentReference || VkAttachmentReference2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; (deUint32)attachments.size(), // deUint32 attachment; || deUint32 attachment; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout; || VkImageLayout layout; 0u // || VkImageAspectFlags aspectMask; ); attachments.push_back(dstAttachment); dstResolveAttachmentRefs[splitSubpassIndex].push_back(dstAttachmentRef); } } } { { const SubpassDesc subpass // VkSubpassDescription || VkSubpassDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; || VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; || VkPipelineBindPoint pipelineBindPoint; 0u, // || deUint32 viewMask; 0u, // deUint32 inputAttachmentCount; || deUint32 inputAttachmentCount; DE_NULL, // const VkAttachmentReference* pInputAttachments; || const VkAttachmentReference2KHR* pInputAttachments; isDepthStencilFormat ? 0u : 1u, // deUint32 colorAttachmentCount; || deUint32 colorAttachmentCount; isDepthStencilFormat ? DE_NULL : &srcAttachmentRef, // const VkAttachmentReference* pColorAttachments; || const VkAttachmentReference2KHR* pColorAttachments; DE_NULL, // const VkAttachmentReference* pResolveAttachments; || const VkAttachmentReference2KHR* pResolveAttachments; isDepthStencilFormat ? &srcAttachmentRef : DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; || const VkAttachmentReference2KHR* pDepthStencilAttachment; 0u, // deUint32 preserveAttachmentCount; || deUint32 preserveAttachmentCount; DE_NULL // const deUint32* pPreserveAttachments; || const deUint32* pPreserveAttachments; ); subpasses.push_back(subpass); } for (deUint32 splitSubpassIndex = 0; splitSubpassIndex < splitSubpassCount; splitSubpassIndex++) { { const SubpassDesc subpass // VkSubpassDescription || VkSubpassDescription2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; || VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; || VkPipelineBindPoint pipelineBindPoint; 0u, // || deUint32 viewMask; 1u, // deUint32 inputAttachmentCount; || deUint32 inputAttachmentCount; &srcAttachmentInputRef, // const VkAttachmentReference* pInputAttachments; || const VkAttachmentReference2KHR* pInputAttachments; (deUint32)dstAttachmentRefs[splitSubpassIndex].size(), // deUint32 colorAttachmentCount; || deUint32 colorAttachmentCount; &dstAttachmentRefs[splitSubpassIndex][0], // const VkAttachmentReference* pColorAttachments; || const VkAttachmentReference2KHR* pColorAttachments; &dstResolveAttachmentRefs[splitSubpassIndex][0], // const VkAttachmentReference* pResolveAttachments; || const VkAttachmentReference2KHR* pResolveAttachments; DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment; || const VkAttachmentReference2KHR* pDepthStencilAttachment; 0u, // deUint32 preserveAttachmentCount; || deUint32 preserveAttachmentCount; DE_NULL // const deUint32* pPreserveAttachments; || const deUint32* pPreserveAttachments; ); subpasses.push_back(subpass); } { const SubpassDep dependency // VkSubpassDependency || VkSubpassDependency2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; 0u, // deUint32 srcSubpass; || deUint32 srcSubpass; splitSubpassIndex + 1, // deUint32 dstSubpass; || deUint32 dstSubpass; VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask; || VkPipelineStageFlags srcStageMask; VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask; || VkPipelineStageFlags dstStageMask; VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask; || VkAccessFlags srcAccessMask; VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask; || VkAccessFlags dstAccessMask; VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags; || VkDependencyFlags dependencyFlags; 0u // || deInt32 viewOffset; ); dependencies.push_back(dependency); } } // the last subpass must synchronize with all prior subpasses for (deUint32 splitSubpassIndex = 0; splitSubpassIndex < (splitSubpassCount - 1); splitSubpassIndex++) { const SubpassDep dependency // VkSubpassDependency || VkSubpassDependency2KHR ( // || VkStructureType sType; DE_NULL, // || const void* pNext; splitSubpassIndex + 1, // deUint32 srcSubpass; || deUint32 srcSubpass; splitSubpassCount, // deUint32 dstSubpass; || deUint32 dstSubpass; VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // VkPipelineStageFlags srcStageMask; || VkPipelineStageFlags srcStageMask; VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // VkPipelineStageFlags dstStageMask; || VkPipelineStageFlags dstStageMask; VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask; || VkAccessFlags srcAccessMask; VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, // VkAccessFlags dstAccessMask; || VkAccessFlags dstAccessMask; VK_DEPENDENCY_BY_REGION_BIT, // VkDependencyFlags dependencyFlags; || VkDependencyFlags dependencyFlags; 0u // || deInt32 viewOffset; ); dependencies.push_back(dependency); } const RenderPassCreateInfo renderPassCreator // VkRenderPassCreateInfo || VkRenderPassCreateInfo2KHR ( // VkStructureType sType; || VkStructureType sType; DE_NULL, // const void* pNext; || const void* pNext; (VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags; || VkRenderPassCreateFlags flags; (deUint32)attachments.size(), // deUint32 attachmentCount; || deUint32 attachmentCount; &attachments[0], // const VkAttachmentDescription* pAttachments; || const VkAttachmentDescription2KHR* pAttachments; (deUint32)subpasses.size(), // deUint32 subpassCount; || deUint32 subpassCount; &subpasses[0], // const VkSubpassDescription* pSubpasses; || const VkSubpassDescription2KHR* pSubpasses; (deUint32)dependencies.size(), // deUint32 dependencyCount; || deUint32 dependencyCount; &dependencies[0], // const VkSubpassDependency* pDependencies; || const VkSubpassDependency2KHR* pDependencies; 0u, // || deUint32 correlatedViewMaskCount; DE_NULL // || const deUint32* pCorrelatedViewMasks; ); return renderPassCreator.createRenderPass(vkd, device); } } Move createRenderPass (const DeviceInterface& vkd, VkDevice device, VkFormat srcFormat, VkFormat dstFormat, deUint32 sampleCount, const RenderingType renderingType, const TestSeparateUsage separateStencilUsage) { switch (renderingType) { case RENDERING_TYPE_RENDERPASS_LEGACY: return createRenderPass(vkd, device, srcFormat, dstFormat, sampleCount, renderingType, separateStencilUsage); case RENDERING_TYPE_RENDERPASS2: return createRenderPass(vkd, device, srcFormat, dstFormat, sampleCount, renderingType, separateStencilUsage); default: TCU_THROW(InternalError, "Impossible"); } } Move createFramebuffer (const DeviceInterface& vkd, VkDevice device, VkRenderPass renderPass, VkImageView srcImageView, const std::vector& dstMultisampleImageViews, const std::vector& dstSinglesampleImageViews, deUint32 width, deUint32 height) { std::vector attachments; attachments.reserve(dstMultisampleImageViews.size() + dstSinglesampleImageViews.size() + 1u); attachments.push_back(srcImageView); DE_ASSERT(dstMultisampleImageViews.size() == dstSinglesampleImageViews.size()); for (size_t ndx = 0; ndx < dstMultisampleImageViews.size(); ndx++) { attachments.push_back(**dstMultisampleImageViews[ndx]); attachments.push_back(**dstSinglesampleImageViews[ndx]); } const VkFramebufferCreateInfo createInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, DE_NULL, 0u, renderPass, (deUint32)attachments.size(), &attachments[0], width, height, 1u }; return createFramebuffer(vkd, device, &createInfo); } Move createRenderPipelineLayout (const DeviceInterface& vkd, VkDevice device) { const VkPushConstantRange pushConstant = { VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u }; const VkPipelineLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, DE_NULL, (vk::VkPipelineLayoutCreateFlags)0, 0u, DE_NULL, 1u, &pushConstant }; return createPipelineLayout(vkd, device, &createInfo); } Move createRenderPipeline (const DeviceInterface& vkd, VkDevice device, VkFormat srcFormat, VkRenderPass renderPass, VkPipelineLayout pipelineLayout, const vk::BinaryCollection& binaryCollection, deUint32 width, deUint32 height, deUint32 sampleCount) { const tcu::TextureFormat format (mapVkFormat(srcFormat)); const bool isDepthStencilFormat (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)); const Unique vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u)); const Unique fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-frag"), 0u)); // Disable blending const VkPipelineColorBlendAttachmentState attachmentBlendState = { VK_FALSE, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT }; const VkPipelineVertexInputStateCreateInfo vertexInputState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, (VkPipelineVertexInputStateCreateFlags)0u, 0u, DE_NULL, 0u, DE_NULL }; const std::vector viewports (1, makeViewport(tcu::UVec2(width, height))); const std::vector scissors (1, makeRect2D(tcu::UVec2(width, height))); const VkPipelineMultisampleStateCreateInfo multisampleState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, DE_NULL, (VkPipelineMultisampleStateCreateFlags)0u, sampleCountBitFromomSampleCount(sampleCount), VK_FALSE, 0.0f, DE_NULL, VK_FALSE, VK_FALSE, }; const VkPipelineDepthStencilStateCreateInfo depthStencilState = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, DE_NULL, (VkPipelineDepthStencilStateCreateFlags)0u, VK_TRUE, VK_TRUE, VK_COMPARE_OP_ALWAYS, VK_FALSE, VK_TRUE, { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_WRAP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, ~0u, ~0u, 0xFFu / (sampleCount + 1) }, { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_WRAP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, ~0u, ~0u, 0xFFu / (sampleCount + 1) }, 0.0f, 1.0f }; const VkPipelineColorBlendStateCreateInfo blendState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, DE_NULL, (VkPipelineColorBlendStateCreateFlags)0u, VK_FALSE, VK_LOGIC_OP_COPY, (isDepthStencilFormat ? 0u : 1u), (isDepthStencilFormat ? DE_NULL : &attachmentBlendState), { 0.0f, 0.0f, 0.0f, 0.0f } }; return makeGraphicsPipeline(vkd, // 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 viewports, // const std::vector& viewports scissors, // const std::vector& scissors VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology 0u, // const deUint32 subpass 0u, // const deUint32 patchControlPoints &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo &multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo &depthStencilState, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo &blendState); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo } Move createSplitDescriptorSetLayout (const DeviceInterface& vkd, VkDevice device, VkFormat vkFormat) { const tcu::TextureFormat format (mapVkFormat(vkFormat)); const bool hasDepth (tcu::hasDepthComponent(format.order)); const bool hasStencil (tcu::hasStencilComponent(format.order)); const VkDescriptorSetLayoutBinding bindings[] = { { 0u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u, VK_SHADER_STAGE_FRAGMENT_BIT, DE_NULL }, { 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1u, VK_SHADER_STAGE_FRAGMENT_BIT, DE_NULL } }; const VkDescriptorSetLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, DE_NULL, 0u, hasDepth && hasStencil ? 2u : 1u, bindings }; return createDescriptorSetLayout(vkd, device, &createInfo); } Move createSplitPipelineLayout (const DeviceInterface& vkd, VkDevice device, VkDescriptorSetLayout descriptorSetLayout) { const VkPushConstantRange pushConstant = { VK_SHADER_STAGE_FRAGMENT_BIT, 0u, 4u }; const VkPipelineLayoutCreateInfo createInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, DE_NULL, (vk::VkPipelineLayoutCreateFlags)0, 1u, &descriptorSetLayout, 1u, &pushConstant }; return createPipelineLayout(vkd, device, &createInfo); } Move createSplitPipeline (const DeviceInterface& vkd, VkDevice device, VkRenderPass renderPass, deUint32 subpassIndex, VkPipelineLayout pipelineLayout, const vk::BinaryCollection& binaryCollection, deUint32 width, deUint32 height, deUint32 sampleCount) { const Unique vertexShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-vert"), 0u)); const Unique fragmentShaderModule (createShaderModule(vkd, device, binaryCollection.get("quad-split-frag"), 0u)); // Disable blending const VkPipelineColorBlendAttachmentState attachmentBlendState = { VK_FALSE, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_OP_ADD, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ONE, VK_BLEND_OP_ADD, VK_COLOR_COMPONENT_R_BIT|VK_COLOR_COMPONENT_G_BIT|VK_COLOR_COMPONENT_B_BIT|VK_COLOR_COMPONENT_A_BIT }; const std::vector attachmentBlendStates (de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, sampleCount), attachmentBlendState); const VkPipelineVertexInputStateCreateInfo vertexInputState = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, DE_NULL, (VkPipelineVertexInputStateCreateFlags)0u, 0u, DE_NULL, 0u, DE_NULL }; const std::vector viewports (1, makeViewport(tcu::UVec2(width, height))); const std::vector scissors (1, makeRect2D(tcu::UVec2(width, height))); const VkPipelineMultisampleStateCreateInfo multisampleState = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, DE_NULL, (VkPipelineMultisampleStateCreateFlags)0u, sampleCountBitFromomSampleCount(sampleCount), VK_FALSE, 0.0f, DE_NULL, VK_FALSE, VK_FALSE, }; const VkPipelineColorBlendStateCreateInfo blendState = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, DE_NULL, (VkPipelineColorBlendStateCreateFlags)0u, VK_FALSE, VK_LOGIC_OP_COPY, (deUint32)attachmentBlendStates.size(), &attachmentBlendStates[0], { 0.0f, 0.0f, 0.0f, 0.0f } }; return makeGraphicsPipeline(vkd, // 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 viewports, // const std::vector& viewports scissors, // const std::vector& scissors VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // const VkPrimitiveTopology topology subpassIndex, // const deUint32 subpass 0u, // const deUint32 patchControlPoints &vertexInputState, // const VkPipelineVertexInputStateCreateInfo* vertexInputStateCreateInfo DE_NULL, // const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo &multisampleState, // const VkPipelineMultisampleStateCreateInfo* multisampleStateCreateInfo DE_NULL, // const VkPipelineDepthStencilStateCreateInfo* depthStencilStateCreateInfo &blendState); // const VkPipelineColorBlendStateCreateInfo* colorBlendStateCreateInfo } vector createSplitPipelines (const DeviceInterface& vkd, VkDevice device, VkRenderPass renderPass, VkPipelineLayout pipelineLayout, const vk::BinaryCollection& binaryCollection, deUint32 width, deUint32 height, deUint32 sampleCount) { std::vector pipelines (deDivRoundUp32(sampleCount, MAX_COLOR_ATTACHMENT_COUNT), (VkPipelineSp)0u); for (size_t ndx = 0; ndx < pipelines.size(); ndx++) pipelines[ndx] = safeSharedPtr(new Unique(createSplitPipeline(vkd, device, renderPass, (deUint32)(ndx + 1), pipelineLayout, binaryCollection, width, height, sampleCount))); return pipelines; } Move createSplitDescriptorPool (const DeviceInterface& vkd, VkDevice device) { const VkDescriptorPoolSize size = { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 2u }; const VkDescriptorPoolCreateInfo createInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, DE_NULL, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u, 1u, &size }; return createDescriptorPool(vkd, device, &createInfo); } Move createSplitDescriptorSet (const DeviceInterface& vkd, VkDevice device, VkDescriptorPool pool, VkDescriptorSetLayout layout, VkImageView primaryImageView, VkImageView secondaryImageView) { const VkDescriptorSetAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, DE_NULL, pool, 1u, &layout }; Move set (allocateDescriptorSet(vkd, device, &allocateInfo)); { const VkDescriptorImageInfo imageInfos[] = { { (VkSampler)0u, primaryImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL }, { (VkSampler)0u, secondaryImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } }; const VkWriteDescriptorSet writes[] = { { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, DE_NULL, *set, 0u, 0u, 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[0], DE_NULL, DE_NULL }, { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, DE_NULL, *set, 1u, 0u, 1u, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, &imageInfos[1], DE_NULL, DE_NULL } }; const deUint32 count = secondaryImageView != (VkImageView)0 ? 2u : 1u; vkd.updateDescriptorSets(device, count, writes, 0u, DE_NULL); } return set; } struct TestConfig { TestConfig (VkFormat format_, deUint32 sampleCount_, RenderingType renderingType_, TestSeparateUsage separateStencilUsage_ = (TestSeparateUsage)0u) : format (format_) , sampleCount (sampleCount_) , renderingType (renderingType_) , separateStencilUsage(separateStencilUsage_) { } VkFormat format; deUint32 sampleCount; RenderingType renderingType; TestSeparateUsage separateStencilUsage; }; VkImageUsageFlags getSrcImageUsage (VkFormat vkFormat) { const tcu::TextureFormat format (mapVkFormat(vkFormat)); const bool hasDepth (tcu::hasDepthComponent(format.order)); const bool hasStencil (tcu::hasStencilComponent(format.order)); if (hasDepth || hasStencil) return VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; else return VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; } VkFormat getDstFormat (VkFormat vkFormat, TestSeparateUsage separateStencilUsage) { const tcu::TextureFormat format (mapVkFormat(vkFormat)); const bool hasDepth (tcu::hasDepthComponent(format.order)); const bool hasStencil (tcu::hasStencilComponent(format.order)); if (hasDepth && hasStencil && !separateStencilUsage) return VK_FORMAT_R32G32_SFLOAT; else if (hasDepth || hasStencil) return VK_FORMAT_R32_SFLOAT; else return vkFormat; } bool isExtensionSupported(Context& context, RenderingType renderingType, TestSeparateUsage separateStencilUsage) { if (renderingType == RENDERING_TYPE_RENDERPASS2) context.requireDeviceFunctionality("VK_KHR_create_renderpass2"); if (separateStencilUsage) { context.requireDeviceFunctionality ("VK_EXT_separate_stencil_usage"); context.requireInstanceFunctionality("VK_KHR_get_physical_device_properties2"); } return true; } class MultisampleRenderPassTestInstance : public TestInstance { public: MultisampleRenderPassTestInstance (Context& context, TestConfig config); ~MultisampleRenderPassTestInstance (void); tcu::TestStatus iterate (void); template tcu::TestStatus iterateInternal (void); private: const bool m_extensionSupported; const RenderingType m_renderingType; const TestSeparateUsage m_separateStencilUsage; const VkFormat m_srcFormat; const VkFormat m_dstFormat; const deUint32 m_sampleCount; const deUint32 m_width; const deUint32 m_height; const VkImageAspectFlags m_srcImageAspect; const VkImageUsageFlags m_srcImageUsage; const Unique m_srcImage; const de::UniquePtr m_srcImageMemory; const Unique m_srcImageView; const Unique m_srcPrimaryInputImageView; const Unique m_srcSecondaryInputImageView; const std::vector m_dstMultisampleImages; const std::vector > m_dstMultisampleImageMemory; const std::vector m_dstMultisampleImageViews; const std::vector m_dstSinglesampleImages; const std::vector > m_dstSinglesampleImageMemory; const std::vector m_dstSinglesampleImageViews; const std::vector m_dstBuffers; const std::vector > m_dstBufferMemory; const Unique m_renderPass; const Unique m_framebuffer; const Unique m_renderPipelineLayout; const Unique m_renderPipeline; const Unique m_splitDescriptorSetLayout; const Unique m_splitPipelineLayout; const std::vector m_splitPipelines; const Unique m_splitDescriptorPool; const Unique m_splitDescriptorSet; const Unique m_commandPool; tcu::ResultCollector m_resultCollector; }; MultisampleRenderPassTestInstance::MultisampleRenderPassTestInstance (Context& context, TestConfig config) : TestInstance (context) , m_extensionSupported (isExtensionSupported(context, config.renderingType, config.separateStencilUsage)) , m_renderingType (config.renderingType) , m_separateStencilUsage (config.separateStencilUsage) , m_srcFormat (config.format) , m_dstFormat (getDstFormat(config.format, config.separateStencilUsage)) , m_sampleCount (config.sampleCount) , m_width (32u) , m_height (32u) , m_srcImageAspect (getImageAspectFlags(m_srcFormat)) , m_srcImageUsage (getSrcImageUsage(m_srcFormat)) , m_srcImage (createImage(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_srcFormat, sampleCountBitFromomSampleCount(m_sampleCount), m_srcImageUsage, m_width, m_height, m_separateStencilUsage)) , m_srcImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), *m_srcImage)) , m_srcImageView (createImageAttachmentView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect)) , m_srcPrimaryInputImageView (createSrcPrimaryInputImageView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect, m_separateStencilUsage)) , m_srcSecondaryInputImageView (createSrcSecondaryInputImageView(context.getDeviceInterface(), context.getDevice(), *m_srcImage, m_srcFormat, m_srcImageAspect, m_separateStencilUsage)) , m_dstMultisampleImages (createMultisampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height)) , m_dstMultisampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstMultisampleImages)) , m_dstMultisampleImageViews (createImageAttachmentViews(context.getDeviceInterface(), context.getDevice(), m_dstMultisampleImages, m_dstFormat, VK_IMAGE_ASPECT_COLOR_BIT)) , m_dstSinglesampleImages (createSingleSampleImages(context.getInstanceInterface(), context.getPhysicalDevice(), context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height)) , m_dstSinglesampleImageMemory (createImageMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstSinglesampleImages)) , m_dstSinglesampleImageViews (createImageAttachmentViews(context.getDeviceInterface(), context.getDevice(), m_dstSinglesampleImages, m_dstFormat, VK_IMAGE_ASPECT_COLOR_BIT)) , m_dstBuffers (createBuffers(context.getDeviceInterface(), context.getDevice(), m_dstFormat, m_sampleCount, m_width, m_height)) , m_dstBufferMemory (createBufferMemory(context.getDeviceInterface(), context.getDevice(), context.getDefaultAllocator(), m_dstBuffers)) , m_renderPass (createRenderPass(context.getDeviceInterface(), context.getDevice(), m_srcFormat, m_dstFormat, m_sampleCount, config.renderingType, m_separateStencilUsage)) , m_framebuffer (createFramebuffer(context.getDeviceInterface(), context.getDevice(), *m_renderPass, *m_srcImageView, m_dstMultisampleImageViews, m_dstSinglesampleImageViews, m_width, m_height)) , m_renderPipelineLayout (createRenderPipelineLayout(context.getDeviceInterface(), context.getDevice())) , m_renderPipeline (createRenderPipeline(context.getDeviceInterface(), context.getDevice(), m_srcFormat, *m_renderPass, *m_renderPipelineLayout, context.getBinaryCollection(), m_width, m_height, m_sampleCount)) , m_splitDescriptorSetLayout (createSplitDescriptorSetLayout(context.getDeviceInterface(), context.getDevice(), m_srcFormat)) , m_splitPipelineLayout (createSplitPipelineLayout(context.getDeviceInterface(), context.getDevice(), *m_splitDescriptorSetLayout)) , m_splitPipelines (createSplitPipelines(context.getDeviceInterface(), context.getDevice(), *m_renderPass, *m_splitPipelineLayout, context.getBinaryCollection(), m_width, m_height, m_sampleCount)) , m_splitDescriptorPool (createSplitDescriptorPool(context.getDeviceInterface(), context.getDevice())) , m_splitDescriptorSet (createSplitDescriptorSet(context.getDeviceInterface(), context.getDevice(), *m_splitDescriptorPool, *m_splitDescriptorSetLayout, *m_srcPrimaryInputImageView, *m_srcSecondaryInputImageView)) , m_commandPool (createCommandPool(context.getDeviceInterface(), context.getDevice(), VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, context.getUniversalQueueFamilyIndex())) { } MultisampleRenderPassTestInstance::~MultisampleRenderPassTestInstance (void) { } tcu::TestStatus MultisampleRenderPassTestInstance::iterate (void) { switch (m_renderingType) { case RENDERING_TYPE_RENDERPASS_LEGACY: return iterateInternal(); case RENDERING_TYPE_RENDERPASS2: return iterateInternal(); default: TCU_THROW(InternalError, "Impossible"); } } template tcu::TestStatus MultisampleRenderPassTestInstance::iterateInternal (void) { const DeviceInterface& vkd (m_context.getDeviceInterface()); const VkDevice device (m_context.getDevice()); const Unique commandBuffer (allocateCommandBuffer(vkd, device, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY)); const typename RenderpassSubpass::SubpassBeginInfo subpassBeginInfo (DE_NULL, VK_SUBPASS_CONTENTS_INLINE); const typename RenderpassSubpass::SubpassEndInfo subpassEndInfo (DE_NULL); beginCommandBuffer(vkd, *commandBuffer); { const VkRenderPassBeginInfo beginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, DE_NULL, *m_renderPass, *m_framebuffer, { { 0u, 0u }, { m_width, m_height } }, 0u, DE_NULL }; RenderpassSubpass::cmdBeginRenderPass(vkd, *commandBuffer, &beginInfo, &subpassBeginInfo); // Stencil needs to be cleared if it exists. if (tcu::hasStencilComponent(mapVkFormat(m_srcFormat).order)) { const VkClearAttachment clearAttachment = { VK_IMAGE_ASPECT_STENCIL_BIT, // VkImageAspectFlags aspectMask; 0, // deUint32 colorAttachment; makeClearValueDepthStencil(0, 0) // VkClearValue clearValue; }; const VkClearRect clearRect = { { { 0u, 0u }, { m_width, m_height } }, 0, // deUint32 baseArrayLayer; 1 // deUint32 layerCount; }; vkd.cmdClearAttachments(*commandBuffer, 1, &clearAttachment, 1, &clearRect); } } vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_renderPipeline); for (deUint32 sampleNdx = 0; sampleNdx < m_sampleCount; sampleNdx++) { vkd.cmdPushConstants(*commandBuffer, *m_renderPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(sampleNdx), &sampleNdx); vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); } for (deUint32 splitPipelineNdx = 0; splitPipelineNdx < m_splitPipelines.size(); splitPipelineNdx++) { RenderpassSubpass::cmdNextSubpass(vkd, *commandBuffer, &subpassBeginInfo, &subpassEndInfo); vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **m_splitPipelines[splitPipelineNdx]); vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_splitPipelineLayout, 0u, 1u, &*m_splitDescriptorSet, 0u, DE_NULL); vkd.cmdPushConstants(*commandBuffer, *m_splitPipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0u, sizeof(splitPipelineNdx), &splitPipelineNdx); vkd.cmdDraw(*commandBuffer, 6u, 1u, 0u, 0u); } RenderpassSubpass::cmdEndRenderPass(vkd, *commandBuffer, &subpassEndInfo); for (size_t dstNdx = 0; dstNdx < m_dstSinglesampleImages.size(); dstNdx++) copyImageToBuffer(vkd, *commandBuffer, **m_dstSinglesampleImages[dstNdx], **m_dstBuffers[dstNdx], tcu::IVec2(m_width, m_height), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); endCommandBuffer(vkd, *commandBuffer); submitCommandsAndWait(vkd, device, m_context.getUniversalQueue(), *commandBuffer); { const tcu::TextureFormat format (mapVkFormat(m_dstFormat)); const tcu::TextureFormat srcFormat (mapVkFormat(m_srcFormat)); const bool verifyDepth (m_separateStencilUsage ? (m_separateStencilUsage == TEST_DEPTH) : tcu::hasDepthComponent(srcFormat.order)); const bool verifyStencil (m_separateStencilUsage ? (m_separateStencilUsage == TEST_STENCIL) : tcu::hasStencilComponent(srcFormat.order)); for (deUint32 sampleNdx = 0; sampleNdx < m_sampleCount; sampleNdx++) { Allocation *dstBufMem = m_dstBufferMemory[sampleNdx].get(); invalidateAlloc(vkd, device, *dstBufMem); const std::string name ("Sample" + de::toString(sampleNdx)); const void* const ptr (dstBufMem->getHostPtr()); const tcu::ConstPixelBufferAccess access (format, m_width, m_height, 1, ptr); tcu::TextureLevel reference (format, m_width, m_height); if (verifyDepth || verifyStencil) { if (verifyDepth) { for (deUint32 y = 0; y < m_height; y++) for (deUint32 x = 0; x < m_width; x++) { const deUint32 x1 = x ^ sampleNdx; const deUint32 y1 = y ^ sampleNdx; const float range = 1.0f; float depth = 0.0f; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits for (size_t bitNdx = 0; bitNdx < 10; bitNdx++) { depth += (range / (float)divider) * (((bitNdx % 2 == 0 ? x1 : y1) & (0x1u << (bitNdx / 2u))) == 0u ? 0u : 1u); divider *= 2; } reference.getAccess().setPixel(Vec4(depth, 0.0f, 0.0f, 0.0f), x, y); } } if (verifyStencil) { for (deUint32 y = 0; y < m_height; y++) for (deUint32 x = 0; x < m_width; x++) { const deUint32 stencil = sampleNdx + 1u; if (verifyDepth) { const Vec4 src (reference.getAccess().getPixel(x, y)); reference.getAccess().setPixel(Vec4(src.x(), (float)stencil, 0.0f, 0.0f), x, y); } else reference.getAccess().setPixel(Vec4((float)stencil, 0.0f, 0.0f, 0.0f), x, y); } } { const Vec4 threshold (verifyDepth ? (1.0f / 1024.0f) : 0.0f, 0.0f, 0.0f, 0.0f); if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR)) m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx)); } } else { const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); switch (channelClass) { case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: { const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast()); const UVec4 minValue (0); const UVec4 range (UVec4(1u) << tcu::min(bits, UVec4(31))); const int componentCount (tcu::getNumUsedChannels(format.order)); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); for (deUint32 y = 0; y < m_height; y++) for (deUint32 x = 0; x < m_width; x++) { const deUint32 x1 = x ^ sampleNdx; const deUint32 y1 = y ^ sampleNdx; UVec4 color (minValue); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; color[compNdx] += (range[compNdx] / divider) * (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u); nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } reference.getAccess().setPixel(color, x, y); } if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, UVec4(0u), tcu::COMPARE_LOG_ON_ERROR)) m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx)); break; } case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: { const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast()); const IVec4 minValue (0); const IVec4 range ((UVec4(1u) << tcu::min(bits, UVec4(30))).cast()); const int componentCount (tcu::getNumUsedChannels(format.order)); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); for (deUint32 y = 0; y < m_height; y++) for (deUint32 x = 0; x < m_width; x++) { const deUint32 x1 = x ^ sampleNdx; const deUint32 y1 = y ^ sampleNdx; IVec4 color (minValue); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; color[compNdx] += (range[compNdx] / divider) * (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u); nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } reference.getAccess().setPixel(color, x, y); } if (!tcu::intThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, UVec4(0u), tcu::COMPARE_LOG_ON_ERROR)) m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx)); break; } case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: { const tcu::TextureFormatInfo info (tcu::getTextureFormatInfo(format)); const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast()); const Vec4 minLimit (-65536.0); const Vec4 maxLimit (65536.0); const Vec4 minValue (tcu::max(info.valueMin, minLimit)); const Vec4 range (tcu::min(info.valueMax, maxLimit) - minValue); const int componentCount (tcu::getNumUsedChannels(format.order)); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); for (deUint32 y = 0; y < m_height; y++) for (deUint32 x = 0; x < m_width; x++) { const deUint32 x1 = x ^ sampleNdx; const deUint32 y1 = y ^ sampleNdx; Vec4 color (minValue); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; color[compNdx] += (range[compNdx] / (float)divider) * (((nextSrcBit % 2 == 0 ? x1 : y1) & (0x1u << (nextSrcBit / 2u))) == 0u ? 0u : 1u); nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } if (tcu::isSRGB(format)) reference.getAccess().setPixel(tcu::linearToSRGB(color), x, y); else reference.getAccess().setPixel(color, x, y); } if (channelClass == tcu::TEXTURECHANNELCLASS_FLOATING_POINT) { // Convert target format ulps to float ulps and allow 64ulp differences const UVec4 threshold (64u * (UVec4(1u) << (UVec4(23) - tcu::getTextureFormatMantissaBitDepth(format).cast()))); if (!tcu::floatUlpThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR)) m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx)); } else { // Allow error of 4 times the minimum presentable difference const Vec4 threshold (4.0f * 1.0f / ((UVec4(1u) << tcu::getTextureFormatMantissaBitDepth(format).cast()) - 1u).cast()); if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), name.c_str(), name.c_str(), reference.getAccess(), access, threshold, tcu::COMPARE_LOG_ON_ERROR)) m_resultCollector.fail("Compare failed for sample " + de::toString(sampleNdx)); } break; } default: DE_FATAL("Unknown channel class"); } } } } return tcu::TestStatus(m_resultCollector.getResult(), m_resultCollector.getMessage()); } struct Programs { void init (vk::SourceCollections& dst, TestConfig config) const { const tcu::TextureFormat format (mapVkFormat(config.format)); const tcu::TextureChannelClass channelClass (tcu::getTextureChannelClass(format.type)); const bool testDepth (config.separateStencilUsage ? (config.separateStencilUsage == TEST_DEPTH) : tcu::hasDepthComponent(format.order)); const bool testStencil (config.separateStencilUsage ? (config.separateStencilUsage == TEST_STENCIL) : tcu::hasStencilComponent(format.order)); dst.glslSources.add("quad-vert") << glu::VertexSource( "#version 450\n" "out gl_PerVertex {\n" "\tvec4 gl_Position;\n" "};\n" "highp float;\n" "void main (void) {\n" "\tgl_Position = vec4(((gl_VertexIndex + 2) / 3) % 2 == 0 ? -1.0 : 1.0,\n" "\t ((gl_VertexIndex + 1) / 3) % 2 == 0 ? -1.0 : 1.0, 0.0, 1.0);\n" "}\n"); if (testDepth) { const Vec4 minValue (0.0f); const Vec4 range (1.0f); std::ostringstream fragmentShader; fragmentShader << "#version 450\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint sampleIndex;\n" "} pushConstants;\n" "void main (void)\n" "{\n" "\thighp uint sampleIndex = pushConstants.sampleIndex;\n" "\tgl_SampleMask[0] = int((~0x0u) << sampleIndex);\n" "\thighp float depth;\n" "\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n" "\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n"; fragmentShader << "\tdepth = " << minValue[0] << ";\n"; { deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits for (size_t bitNdx = 0; bitNdx < 10; bitNdx++) { fragmentShader << "\tdepth += " << (range[0] / (float)divider) << " * float(bitfieldExtract(" << (bitNdx % 2 == 0 ? "x" : "y") << ", " << (bitNdx / 2) << ", 1));\n"; divider *= 2; } } fragmentShader << "\tgl_FragDepth = depth;\n" "}\n"; dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str()); } else if (testStencil) { dst.glslSources.add("quad-frag") << glu::FragmentSource( "#version 450\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint sampleIndex;\n" "} pushConstants;\n" "void main (void)\n" "{\n" "\thighp uint sampleIndex = pushConstants.sampleIndex;\n" "\tgl_SampleMask[0] = int((~0x0u) << sampleIndex);\n" "}\n"); } else { switch (channelClass) { case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: { const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast()); const UVec4 minValue (0); const UVec4 range (UVec4(1u) << tcu::min(bits, UVec4(31))); std::ostringstream fragmentShader; fragmentShader << "#version 450\n" "layout(location = 0) out highp uvec4 o_color;\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint sampleIndex;\n" "} pushConstants;\n" "void main (void)\n" "{\n" "\thighp uint sampleIndex = pushConstants.sampleIndex;\n" "\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n" "\thighp uint color[4];\n" "\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n" "\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n"; for (int ndx = 0; ndx < 4; ndx++) fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n"; { const int componentCount = tcu::getNumUsedChannels(format.order); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; fragmentShader << "\tcolor[" << compNdx << "] += " << (range[compNdx] / divider) << " * bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1);\n"; nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } } fragmentShader << "\to_color = uvec4(color[0], color[1], color[2], color[3]);\n" "}\n"; dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str()); break; } case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: { const UVec4 bits (tcu::getTextureFormatBitDepth(format).cast()); const IVec4 minValue (0); const IVec4 range ((UVec4(1u) << tcu::min(bits, UVec4(30))).cast()); const IVec4 maxV ((UVec4(1u) << (bits - UVec4(1u))).cast()); const IVec4 clampMax (maxV - 1); const IVec4 clampMin (-maxV); std::ostringstream fragmentShader; fragmentShader << "#version 450\n" "layout(location = 0) out highp ivec4 o_color;\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint sampleIndex;\n" "} pushConstants;\n" "void main (void)\n" "{\n" "\thighp uint sampleIndex = pushConstants.sampleIndex;\n" "\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n" "\thighp int color[4];\n" "\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n" "\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n"; for (int ndx = 0; ndx < 4; ndx++) fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n"; { const int componentCount = tcu::getNumUsedChannels(format.order); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; fragmentShader << "\tcolor[" << compNdx << "] += " << (range[compNdx] / divider) << " * int(bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1));\n"; nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } } // The spec doesn't define whether signed-integers are clamped on output, // so we'll clamp them explicitly to have well-defined outputs. fragmentShader << "\to_color = clamp(ivec4(color[0], color[1], color[2], color[3]), " << "ivec4" << clampMin << ", ivec4" << clampMax << ");\n" << "}\n"; dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str()); break; } case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: { const tcu::TextureFormatInfo info (tcu::getTextureFormatInfo(format)); const UVec4 bits (tcu::getTextureFormatMantissaBitDepth(format).cast()); const Vec4 minLimit (-65536.0); const Vec4 maxLimit (65536.0); const Vec4 minValue (tcu::max(info.valueMin, minLimit)); const Vec4 range (tcu::min(info.valueMax, maxLimit) - minValue); std::ostringstream fragmentShader; fragmentShader << "#version 450\n" "layout(location = 0) out highp vec4 o_color;\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint sampleIndex;\n" "} pushConstants;\n" "void main (void)\n" "{\n" "\thighp uint sampleIndex = pushConstants.sampleIndex;\n" "\tgl_SampleMask[0] = int(0x1u << sampleIndex);\n" "\thighp float color[4];\n" "\thighp uint x = sampleIndex ^ uint(gl_FragCoord.x);\n" "\thighp uint y = sampleIndex ^ uint(gl_FragCoord.y);\n"; for (int ndx = 0; ndx < 4; ndx++) fragmentShader << "\tcolor[" << ndx << "] = " << minValue[ndx] << ";\n"; { const int componentCount = tcu::getNumUsedChannels(format.order); const deUint32 bitSize (bits[0] + bits[1] + bits[2] + bits[3]); deUint32 dstBitsUsed[4] = { 0u, 0u, 0u, 0u }; deUint32 nextSrcBit = 0; deUint32 divider = 2; // \note Limited to ten bits since the target is 32x32, so there are 10 input bits while (nextSrcBit < de::min(bitSize, 10u)) { for (int compNdx = 0; compNdx < componentCount; compNdx++) { if (dstBitsUsed[compNdx] > bits[compNdx]) continue; fragmentShader << "\tcolor[" << compNdx << "] += " << (range[compNdx] / (float)divider) << " * float(bitfieldExtract(" << (nextSrcBit % 2 == 0 ? "x" : "y") << ", " << (nextSrcBit / 2) << ", 1));\n"; nextSrcBit++; dstBitsUsed[compNdx]++; } divider *= 2; } } fragmentShader << "\to_color = vec4(color[0], color[1], color[2], color[3]);\n" "}\n"; dst.glslSources.add("quad-frag") << glu::FragmentSource(fragmentShader.str()); break; } default: DE_FATAL("Unknown channel class"); } } if (tcu::hasDepthComponent(format.order) || tcu::hasStencilComponent(format.order)) { std::ostringstream splitShader; splitShader << "#version 450\n"; if (testDepth && testStencil) { splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInputMS i_depth;\n" << "layout(input_attachment_index = 0, set = 0, binding = 1) uniform highp usubpassInputMS i_stencil;\n"; } else if (testDepth) splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInputMS i_depth;\n"; else if (testStencil) splitShader << "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp usubpassInputMS i_stencil;\n"; splitShader << "layout(push_constant) uniform PushConstant {\n" "\thighp uint splitSubpassIndex;\n" "} pushConstants;\n"; for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++) { if (testDepth && testStencil) splitShader << "layout(location = " << attachmentNdx << ") out highp vec2 o_color" << attachmentNdx << ";\n"; else splitShader << "layout(location = " << attachmentNdx << ") out highp float o_color" << attachmentNdx << ";\n"; } splitShader << "void main (void)\n" "{\n"; for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++) { if (testDepth) splitShader << "\thighp float depth" << attachmentNdx << " = subpassLoad(i_depth, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u)).x;\n"; if (testStencil) splitShader << "\thighp uint stencil" << attachmentNdx << " = subpassLoad(i_stencil, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u)).x;\n"; if (testDepth && testStencil) splitShader << "\to_color" << attachmentNdx << " = vec2(depth" << attachmentNdx << ", float(stencil" << attachmentNdx << "));\n"; else if (testDepth) splitShader << "\to_color" << attachmentNdx << " = float(depth" << attachmentNdx << ");\n"; else if (testStencil) splitShader << "\to_color" << attachmentNdx << " = float(stencil" << attachmentNdx << ");\n"; } splitShader << "}\n"; dst.glslSources.add("quad-split-frag") << glu::FragmentSource(splitShader.str()); } else { std::string subpassType; std::string outputType; switch (channelClass) { case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER: subpassType = "usubpassInputMS"; outputType = "uvec4"; break; case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER: subpassType = "isubpassInputMS"; outputType = "ivec4"; break; case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT: case tcu::TEXTURECHANNELCLASS_FLOATING_POINT: subpassType = "subpassInputMS"; outputType = "vec4"; break; default: DE_FATAL("Unknown channel class"); } std::ostringstream splitShader; splitShader << "#version 450\n" "layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp " << subpassType << " i_color;\n" "layout(push_constant) uniform PushConstant {\n" "\thighp uint splitSubpassIndex;\n" "} pushConstants;\n"; for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++) splitShader << "layout(location = " << attachmentNdx << ") out highp " << outputType << " o_color" << attachmentNdx << ";\n"; splitShader << "void main (void)\n" "{\n"; for (deUint32 attachmentNdx = 0; attachmentNdx < de::min((deUint32)MAX_COLOR_ATTACHMENT_COUNT, config.sampleCount); attachmentNdx++) splitShader << "\to_color" << attachmentNdx << " = subpassLoad(i_color, int(" << MAX_COLOR_ATTACHMENT_COUNT << " * pushConstants.splitSubpassIndex + " << attachmentNdx << "u));\n"; splitShader << "}\n"; dst.glslSources.add("quad-split-frag") << glu::FragmentSource(splitShader.str()); } } }; 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 initTests (tcu::TestCaseGroup* group, RenderingType renderingType) { static const VkFormat formats[] = { 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, VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16, VK_FORMAT_D16_UNORM, VK_FORMAT_X8_D24_UNORM_PACK32, VK_FORMAT_D32_SFLOAT, VK_FORMAT_S8_UINT, VK_FORMAT_D16_UNORM_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT, VK_FORMAT_D32_SFLOAT_S8_UINT }; const deUint32 sampleCounts[] = { 2u, 4u, 8u, 16u, 32u }; tcu::TestContext& testCtx (group->getTestContext()); de::MovePtr extGroup (new tcu::TestCaseGroup(testCtx, "separate_stencil_usage", "test VK_EXT_separate_stencil_usage")); for (size_t formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(formats); formatNdx++) { const VkFormat format (formats[formatNdx]); const std::string formatName (formatToName(format)); de::MovePtr formatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str())); de::MovePtr extFormatGroup (new tcu::TestCaseGroup(testCtx, formatName.c_str(), formatName.c_str())); for (size_t sampleCountNdx = 0; sampleCountNdx < DE_LENGTH_OF_ARRAY(sampleCounts); sampleCountNdx++) { const deUint32 sampleCount (sampleCounts[sampleCountNdx]); const TestConfig testConfig (format, sampleCount, renderingType); const std::string testName ("samples_" + de::toString(sampleCount)); formatGroup->addChild(new InstanceFactory1(testCtx, tcu::NODETYPE_SELF_VALIDATE, testName.c_str(), testName.c_str(), testConfig)); // create tests for VK_EXT_separate_stencil_usage if (tcu::hasDepthComponent(mapVkFormat(format).order) && tcu::hasStencilComponent(mapVkFormat(format).order)) { de::MovePtr sampleGroup (new tcu::TestCaseGroup(testCtx, testName.c_str(), testName.c_str())); { const TestConfig separateUsageDepthTestConfig (format, sampleCount, renderingType, TEST_DEPTH); sampleGroup->addChild(new InstanceFactory1(testCtx, tcu::NODETYPE_SELF_VALIDATE, "test_depth", "depth with input attachment bit", separateUsageDepthTestConfig)); const TestConfig separateUsageStencilTestConfig (format, sampleCount, renderingType, TEST_STENCIL); sampleGroup->addChild(new InstanceFactory1(testCtx, tcu::NODETYPE_SELF_VALIDATE, "test_stencil", "stencil with input attachment bit", separateUsageStencilTestConfig)); } extFormatGroup->addChild(sampleGroup.release()); } } group->addChild(formatGroup.release()); extGroup->addChild(extFormatGroup.release()); } group->addChild(extGroup.release()); } } // anonymous tcu::TestCaseGroup* createRenderPassMultisampleTests (tcu::TestContext& testCtx) { return createTestGroup(testCtx, "multisample", "Multisample render pass tests", initTests, RENDERING_TYPE_RENDERPASS_LEGACY); } tcu::TestCaseGroup* createRenderPass2MultisampleTests (tcu::TestContext& testCtx) { return createTestGroup(testCtx, "multisample", "Multisample render pass tests", initTests, RENDERING_TYPE_RENDERPASS2); } } // vkt