--- /dev/null
+/*------------------------------------------------------------------------
+* Vulkan Conformance Tests
+* ------------------------
+*
+* Copyright (c) 2016 The Khronos Group 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 vktPipelineMultisampleInterpolationTests.cpp
+* \brief Multisample Interpolation Tests
+*//*--------------------------------------------------------------------*/
+
+#include "vktPipelineMultisampleInterpolationTests.hpp"
+#include "vktPipelineMultisampleTestsUtil.hpp"
+#include "vktPipelineMakeUtil.hpp"
+#include "vkQueryUtil.hpp"
+
+#include <set>
+
+namespace vkt
+{
+namespace pipeline
+{
+namespace multisample
+{
+
+using namespace vk;
+
+struct ImageMSParams
+{
+ ImageMSParams(const VkSampleCountFlagBits samples, const tcu::UVec3& size) : numSamples(samples), imageSize(size) {}
+
+ VkSampleCountFlagBits numSamples;
+ tcu::UVec3 imageSize;
+};
+
+class MSInterpolationCaseBase : public TestCase
+{
+public:
+ MSInterpolationCaseBase (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : TestCase(testCtx, name, "")
+ , m_imageMSParams(imageMSParams)
+ {}
+
+protected:
+ const ImageMSParams m_imageMSParams;
+};
+
+typedef MSInterpolationCaseBase* (*MSInterpolationCaseFuncPtr)(tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams);
+
+class MSInterpolationInstanceBase : public TestInstance
+{
+public:
+ MSInterpolationInstanceBase (Context& context,
+ const ImageMSParams& imageMSParams)
+ : TestInstance (context)
+ , m_imageMSParams (imageMSParams)
+ , m_imageType (IMAGE_TYPE_2D)
+ , m_imageFormat (tcu::TextureFormat(tcu::TextureFormat::RG, tcu::TextureFormat::UNORM_INT8))
+ {}
+
+ tcu::TestStatus iterate (void);
+
+protected:
+
+ typedef std::vector<VkVertexInputAttributeDescription> VertexAttribDescVec;
+
+ struct VertexDataDesc
+ {
+ VkPrimitiveTopology primitiveTopology;
+ deUint32 verticesCount;
+ deUint32 dataStride;
+ VkDeviceSize dataSize;
+ VertexAttribDescVec vertexAttribDescVec;
+ };
+
+ void validateImageSize (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const ImageType imageType,
+ const tcu::UVec3& imageSize) const;
+
+ void validateImageFeatureFlags (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const VkFormat format,
+ const VkFormatFeatureFlags featureFlags) const;
+
+ void validateImageInfo (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const VkImageCreateInfo& imageInfo) const;
+
+ virtual VertexDataDesc getVertexDataDescripton (void) const = 0;
+
+ virtual void uploadVertexData (const Allocation& vertexBufferAllocation,
+ const VertexDataDesc& vertexDataDescripton) const = 0;
+
+ virtual tcu::TestStatus verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const = 0;
+protected:
+ const ImageMSParams m_imageMSParams;
+ const ImageType m_imageType;
+ const tcu::TextureFormat m_imageFormat;
+};
+
+void MSInterpolationInstanceBase::validateImageSize (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const ImageType imageType,
+ const tcu::UVec3& imageSize) const
+{
+ const VkPhysicalDeviceProperties deviceProperties = getPhysicalDeviceProperties(instance, physicalDevice);
+
+ bool isImageSizeValid = true;
+
+ switch (imageType)
+ {
+ case IMAGE_TYPE_1D:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimension1D;
+ break;
+ case IMAGE_TYPE_1D_ARRAY:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimension1D &&
+ imageSize.z() <= deviceProperties.limits.maxImageArrayLayers;
+ break;
+ case IMAGE_TYPE_2D:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimension2D &&
+ imageSize.y() <= deviceProperties.limits.maxImageDimension2D;
+ break;
+ case IMAGE_TYPE_2D_ARRAY:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimension2D &&
+ imageSize.y() <= deviceProperties.limits.maxImageDimension2D &&
+ imageSize.z() <= deviceProperties.limits.maxImageArrayLayers;
+ break;
+ case IMAGE_TYPE_CUBE:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimensionCube &&
+ imageSize.y() <= deviceProperties.limits.maxImageDimensionCube;
+ break;
+ case IMAGE_TYPE_CUBE_ARRAY:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimensionCube &&
+ imageSize.y() <= deviceProperties.limits.maxImageDimensionCube &&
+ imageSize.z() <= deviceProperties.limits.maxImageArrayLayers;
+ break;
+ case IMAGE_TYPE_3D:
+ isImageSizeValid = imageSize.x() <= deviceProperties.limits.maxImageDimension3D &&
+ imageSize.y() <= deviceProperties.limits.maxImageDimension3D &&
+ imageSize.z() <= deviceProperties.limits.maxImageDimension3D;
+ break;
+ default:
+ DE_FATAL("Unknown image type");
+ }
+
+ if (!isImageSizeValid)
+ {
+ std::ostringstream notSupportedStream;
+
+ notSupportedStream << "Image type (" << getImageTypeName(imageType) << ") with size (" << imageSize.x() << ", " << imageSize.y() << ", " << imageSize.z() << ") not supported by device" << std::endl;
+
+ const std::string notSupportedString = notSupportedStream.str();
+
+ TCU_THROW(NotSupportedError, notSupportedString.c_str());
+ }
+}
+
+void MSInterpolationInstanceBase::validateImageFeatureFlags (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const VkFormat format,
+ const VkFormatFeatureFlags featureFlags) const
+{
+ const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(instance, physicalDevice, format);
+
+ if ((formatProperties.optimalTilingFeatures & featureFlags) != featureFlags)
+ {
+ std::ostringstream notSupportedStream;
+
+ notSupportedStream << "Device does not support image format " << format << " for feature flags " << featureFlags << std::endl;
+
+ const std::string notSupportedString = notSupportedStream.str();
+
+ TCU_THROW(NotSupportedError, notSupportedString.c_str());
+ }
+}
+
+void MSInterpolationInstanceBase::validateImageInfo (const InstanceInterface& instance,
+ const VkPhysicalDevice physicalDevice,
+ const VkImageCreateInfo& imageInfo) const
+{
+ VkImageFormatProperties imageFormatProps;
+ instance.getPhysicalDeviceImageFormatProperties(physicalDevice, imageInfo.format, imageInfo.imageType, imageInfo.tiling, imageInfo.usage, imageInfo.flags, &imageFormatProps);
+
+ if (imageFormatProps.maxExtent.width < imageInfo.extent.width ||
+ imageFormatProps.maxExtent.height < imageInfo.extent.height ||
+ imageFormatProps.maxExtent.depth < imageInfo.extent.depth)
+ {
+ std::ostringstream notSupportedStream;
+
+ notSupportedStream << "Image extent ("
+ << imageInfo.extent.width << ", "
+ << imageInfo.extent.height << ", "
+ << imageInfo.extent.depth
+ << ") exceeds allowed maximum ("
+ << imageFormatProps.maxExtent.width << ", "
+ << imageFormatProps.maxExtent.height << ", "
+ << imageFormatProps.maxExtent.depth
+ << ")"
+ << std::endl;
+
+ const std::string notSupportedString = notSupportedStream.str();
+
+ TCU_THROW(NotSupportedError, notSupportedString.c_str());
+ }
+
+ if (imageFormatProps.maxArrayLayers < imageInfo.arrayLayers)
+ {
+ std::ostringstream notSupportedStream;
+
+ notSupportedStream << "Image layers count of " << imageInfo.arrayLayers << " exceeds allowed maximum which is " << imageFormatProps.maxArrayLayers << std::endl;
+
+ const std::string notSupportedString = notSupportedStream.str();
+
+ TCU_THROW(NotSupportedError, notSupportedString.c_str());
+ }
+
+ if (!(imageFormatProps.sampleCounts & imageInfo.samples))
+ {
+ std::ostringstream notSupportedStream;
+
+ notSupportedStream << "Samples count of " << imageInfo.samples << " not supported for image" << std::endl;
+
+ const std::string notSupportedString = notSupportedStream.str();
+
+ TCU_THROW(NotSupportedError, notSupportedString.c_str());
+ }
+}
+
+tcu::TestStatus MSInterpolationInstanceBase::iterate (void)
+{
+ const InstanceInterface& instance = m_context.getInstanceInterface();
+ const DeviceInterface& deviceInterface = m_context.getDeviceInterface();
+ const VkDevice device = m_context.getDevice();
+ const VkPhysicalDevice physicalDevice = m_context.getPhysicalDevice();
+ Allocator& allocator = m_context.getDefaultAllocator();
+ const VkQueue queue = m_context.getUniversalQueue();
+ const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
+
+ VkImageCreateInfo imageMSInfo;
+ VkImageCreateInfo imageRSInfo;
+
+ // Check if image size does not exceed device limits
+ validateImageSize(instance, physicalDevice, m_imageType, m_imageMSParams.imageSize);
+
+ // Check if device supports image format as color attachment
+ validateImageFeatureFlags(instance, physicalDevice, mapTextureFormat(m_imageFormat), VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
+
+ imageMSInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+ imageMSInfo.pNext = DE_NULL;
+ imageMSInfo.flags = 0u;
+ imageMSInfo.imageType = mapImageType(m_imageType);
+ imageMSInfo.format = mapTextureFormat(m_imageFormat);
+ imageMSInfo.extent = makeExtent3D(getLayerSize(m_imageType, m_imageMSParams.imageSize));
+ imageMSInfo.arrayLayers = getNumLayers(m_imageType, m_imageMSParams.imageSize);
+ imageMSInfo.mipLevels = 1u;
+ imageMSInfo.samples = m_imageMSParams.numSamples;
+ imageMSInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ imageMSInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ imageMSInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ imageMSInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ imageMSInfo.queueFamilyIndexCount = 0u;
+ imageMSInfo.pQueueFamilyIndices = DE_NULL;
+
+ if (m_imageType == IMAGE_TYPE_CUBE || m_imageType == IMAGE_TYPE_CUBE_ARRAY)
+ {
+ imageMSInfo.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
+ }
+
+ validateImageInfo(instance, physicalDevice, imageMSInfo);
+
+ const de::UniquePtr<Image> imageMS(new Image(deviceInterface, device, allocator, imageMSInfo, MemoryRequirement::Any));
+
+ imageRSInfo = imageMSInfo;
+ imageRSInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+
+ validateImageInfo(instance, physicalDevice, imageRSInfo);
+
+ const de::UniquePtr<Image> imageRS(new Image(deviceInterface, device, allocator, imageRSInfo, MemoryRequirement::Any));
+
+ // Create render pass
+ const VkAttachmentDescription attachmentMSDesc =
+ {
+ (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
+ imageMSInfo.format, // VkFormat format;
+ imageMSInfo.samples, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentDescription attachmentRSDesc =
+ {
+ (VkAttachmentDescriptionFlags)0u, // VkAttachmentDescriptionFlags flags;
+ imageRSInfo.format, // VkFormat format;
+ imageRSInfo.samples, // VkSampleCountFlagBits samples;
+ VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
+ VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
+ VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
+ VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout;
+ };
+
+ const VkAttachmentDescription attachments[] = { attachmentMSDesc, attachmentRSDesc };
+
+ const VkAttachmentReference attachmentMSRef =
+ {
+ 0u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkAttachmentReference attachmentRSRef =
+ {
+ 1u, // deUint32 attachment;
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout;
+ };
+
+ const VkAttachmentReference* resolveAttachment = m_imageMSParams.numSamples == VK_SAMPLE_COUNT_1_BIT ? DE_NULL : &attachmentRSRef;
+
+ const VkSubpassDescription subpassDescription =
+ {
+ (VkSubpassDescriptionFlags)0u, // VkSubpassDescriptionFlags flags;
+ VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
+ 0u, // deUint32 inputAttachmentCount;
+ DE_NULL, // const VkAttachmentReference* pInputAttachments;
+ 1u, // deUint32 colorAttachmentCount;
+ &attachmentMSRef, // const VkAttachmentReference* pColorAttachments;
+ resolveAttachment, // const VkAttachmentReference* pResolveAttachments;
+ DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment;
+ 0u, // deUint32 preserveAttachmentCount;
+ DE_NULL // const deUint32* pPreserveAttachments;
+ };
+
+ const VkRenderPassCreateInfo renderPassInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkRenderPassCreateFlags)0u, // VkRenderPassCreateFlags flags;
+ 2u, // deUint32 attachmentCount;
+ attachments, // const VkAttachmentDescription* pAttachments;
+ 1u, // deUint32 subpassCount;
+ &subpassDescription, // const VkSubpassDescription* pSubpasses;
+ 0u, // deUint32 dependencyCount;
+ DE_NULL // const VkSubpassDependency* pDependencies;
+ };
+
+ const Unique<VkRenderPass> renderPass(createRenderPass(deviceInterface, device, &renderPassInfo));
+
+ const VkImageSubresourceRange fullImageRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, imageMSInfo.mipLevels, 0u, imageMSInfo.arrayLayers);
+
+ // Create color attachments image views
+ const Unique<VkImageView> imageMSView(makeImageView(deviceInterface, device, **imageMS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
+ const Unique<VkImageView> imageRSView(makeImageView(deviceInterface, device, **imageRS, mapImageViewType(m_imageType), imageMSInfo.format, fullImageRange));
+
+ const VkImageView attachmentsViews[] = { *imageMSView, *imageRSView };
+
+ // Create framebuffer
+ const VkFramebufferCreateInfo framebufferInfo =
+ {
+ VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkFramebufferCreateFlags)0u, // VkFramebufferCreateFlags flags;
+ *renderPass, // VkRenderPass renderPass;
+ 2u, // uint32_t attachmentCount;
+ attachmentsViews, // const VkImageView* pAttachments;
+ imageMSInfo.extent.width, // uint32_t width;
+ imageMSInfo.extent.height, // uint32_t height;
+ imageMSInfo.arrayLayers, // uint32_t layers;
+ };
+
+ const Unique<VkFramebuffer> framebuffer(createFramebuffer(deviceInterface, device, &framebufferInfo));
+
+ // Create pipeline layout
+ const VkPipelineLayoutCreateInfo pipelineLayoutParams =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineLayoutCreateFlags)0u, // VkPipelineLayoutCreateFlags flags;
+ 0u, // deUint32 setLayoutCount;
+ DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
+ 0u, // deUint32 pushConstantRangeCount;
+ DE_NULL, // const VkPushConstantRange* pPushConstantRanges;
+ };
+
+ const Unique<VkPipelineLayout> pipelineLayout(createPipelineLayout(deviceInterface, device, &pipelineLayoutParams));
+
+ // Create vertex attributes data
+ const VertexDataDesc vertexDataDesc = getVertexDataDescripton();
+
+ de::SharedPtr<Buffer> vertexBuffer = de::SharedPtr<Buffer>(new Buffer(deviceInterface, device, allocator, makeBufferCreateInfo(vertexDataDesc.dataSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible));
+ const Allocation& vertexBufferAllocation = vertexBuffer->getAllocation();
+
+ uploadVertexData(vertexBufferAllocation, vertexDataDesc);
+
+ flushMappedMemoryRange(deviceInterface, device, vertexBufferAllocation.getMemory(), vertexBufferAllocation.getOffset(), vertexDataDesc.dataSize);
+
+ const VkVertexInputBindingDescription vertexBinding =
+ {
+ 0u, // deUint32 binding;
+ vertexDataDesc.dataStride, // deUint32 stride;
+ VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
+ };
+
+ const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineVertexInputStateCreateFlags)0u, // VkPipelineVertexInputStateCreateFlags flags;
+ 1u, // uint32_t vertexBindingDescriptionCount;
+ &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
+ static_cast<deUint32>(vertexDataDesc.vertexAttribDescVec.size()), // uint32_t vertexAttributeDescriptionCount;
+ dataPointer(vertexDataDesc.vertexAttribDescVec), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
+ };
+
+ const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineInputAssemblyStateCreateFlags)0u, // VkPipelineInputAssemblyStateCreateFlags flags;
+ vertexDataDesc.primitiveTopology, // VkPrimitiveTopology topology;
+ VK_FALSE, // VkBool32 primitiveRestartEnable;
+ };
+
+ const VkViewport viewport =
+ {
+ 0.0f, 0.0f,
+ static_cast<float>(imageMSInfo.extent.width), static_cast<float>(imageMSInfo.extent.height),
+ 0.0f, 1.0f
+ };
+
+ const VkRect2D scissor =
+ {
+ makeOffset2D(0, 0),
+ makeExtent2D(imageMSInfo.extent.width, imageMSInfo.extent.height),
+ };
+
+ const VkPipelineViewportStateCreateInfo viewportStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineViewportStateCreateFlags)0u, // VkPipelineViewportStateCreateFlags flags;
+ 1u, // uint32_t viewportCount;
+ &viewport, // const VkViewport* pViewports;
+ 1u, // uint32_t scissorCount;
+ &scissor, // const VkRect2D* pScissors;
+ };
+
+ const VkPipelineRasterizationStateCreateInfo rasterizationStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineRasterizationStateCreateFlags)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 multisampleStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineMultisampleStateCreateFlags)0u, // VkPipelineMultisampleStateCreateFlags flags;
+ imageMSInfo.samples, // VkSampleCountFlagBits rasterizationSamples;
+ VK_TRUE, // VkBool32 sampleShadingEnable;
+ 1.0f, // float minSampleShading;
+ DE_NULL, // const VkSampleMask* pSampleMask;
+ VK_FALSE, // VkBool32 alphaToCoverageEnable;
+ VK_FALSE, // VkBool32 alphaToOneEnable;
+ };
+
+ const VkStencilOpState stencilOpState = makeStencilOpState
+ (
+ VK_STENCIL_OP_KEEP, // stencil fail
+ VK_STENCIL_OP_KEEP, // depth & stencil pass
+ VK_STENCIL_OP_KEEP, // depth only fail
+ VK_COMPARE_OP_ALWAYS, // compare op
+ 0u, // compare mask
+ 0u, // write mask
+ 0u // reference
+ );
+
+ const VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineDepthStencilStateCreateFlags)0u, // VkPipelineDepthStencilStateCreateFlags flags;
+ VK_FALSE, // VkBool32 depthTestEnable;
+ VK_FALSE, // VkBool32 depthWriteEnable;
+ VK_COMPARE_OP_LESS, // VkCompareOp depthCompareOp;
+ VK_FALSE, // VkBool32 depthBoundsTestEnable;
+ VK_FALSE, // VkBool32 stencilTestEnable;
+ stencilOpState, // VkStencilOpState front;
+ stencilOpState, // VkStencilOpState back;
+ 0.0f, // float minDepthBounds;
+ 1.0f, // float maxDepthBounds;
+ };
+
+ const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
+
+ const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
+ {
+ VK_FALSE, // VkBool32 blendEnable;
+ VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcColorBlendFactor;
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor dstColorBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
+ VK_BLEND_FACTOR_SRC_ALPHA, // VkBlendFactor srcAlphaBlendFactor;
+ VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, // VkBlendFactor dstAlphaBlendFactor;
+ VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
+ colorComponentsAll, // VkColorComponentFlags colorWriteMask;
+ };
+
+ const VkPipelineColorBlendStateCreateInfo colorBlendStateInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineColorBlendStateCreateFlags)0u, // VkPipelineColorBlendStateCreateFlags flags;
+ VK_FALSE, // VkBool32 logicOpEnable;
+ VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
+ 1u, // deUint32 attachmentCount;
+ &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
+ { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4];
+ };
+
+ const Unique<VkShaderModule> vsModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("vertex_shader"), (VkShaderModuleCreateFlags)0));
+
+ const VkPipelineShaderStageCreateInfo vsShaderStageInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineShaderStageCreateFlags)0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
+ *vsModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
+ };
+
+ const Unique<VkShaderModule> fsModule(createShaderModule(deviceInterface, device, m_context.getBinaryCollection().get("fragment_shader"), (VkShaderModuleCreateFlags)0));
+
+ const VkPipelineShaderStageCreateInfo fsShaderStageInfo =
+ {
+ VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineShaderStageCreateFlags)0u, // VkPipelineShaderStageCreateFlags flags;
+ VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
+ *fsModule, // VkShaderModule module;
+ "main", // const char* pName;
+ DE_NULL, // const VkSpecializationInfo* pSpecializationInfo;
+ };
+
+ const VkPipelineShaderStageCreateInfo shaderStageInfos[] = { vsShaderStageInfo, fsShaderStageInfo };
+
+ const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
+ {
+ VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags;
+ 2u, // deUint32 stageCount;
+ shaderStageInfos, // const VkPipelineShaderStageCreateInfo* pStages;
+ &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
+ &inputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
+ DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
+ &viewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState;
+ &rasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
+ &multisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
+ &depthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
+ &colorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
+ DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
+ *pipelineLayout, // VkPipelineLayout layout;
+ *renderPass, // VkRenderPass renderPass;
+ 0u, // deUint32 subpass;
+ DE_NULL, // VkPipeline basePipelineHandle;
+ 0u, // deInt32 basePipelineIndex;
+ };
+
+ // Create graphics pipeline
+ const Unique<VkPipeline> graphicsPipeline(createGraphicsPipeline(deviceInterface, device, DE_NULL, &graphicsPipelineInfo));
+
+ // Create command buffer for compute and transfer oparations
+ const Unique<VkCommandPool> commandPool(makeCommandPool(deviceInterface, device, queueFamilyIndex));
+ const Unique<VkCommandBuffer> commandBuffer(makeCommandBuffer(deviceInterface, device, *commandPool));
+
+ // Start recording commands
+ beginCommandBuffer(deviceInterface, *commandBuffer);
+
+ {
+ VkImageMemoryBarrier imageOutputAttachmentBarriers[2];
+
+ imageOutputAttachmentBarriers[0] = makeImageMemoryBarrier
+ (
+ 0u,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ **imageMS,
+ fullImageRange
+ );
+
+ imageOutputAttachmentBarriers[1] = makeImageMemoryBarrier
+ (
+ 0u,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_IMAGE_LAYOUT_UNDEFINED,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ **imageRS,
+ fullImageRange
+ );
+
+ deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 2u, imageOutputAttachmentBarriers);
+ }
+
+ {
+ const VkDeviceSize vertexStartOffset = 0u;
+
+ std::vector<VkClearValue> clearValues;
+ clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
+ clearValues.push_back(makeClearValueColor(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f)));
+
+ const vk::VkRect2D renderArea =
+ {
+ makeOffset2D(0u, 0u),
+ makeExtent2D(imageMSInfo.extent.width, imageMSInfo.extent.height),
+ };
+
+ // Begin render pass
+ const VkRenderPassBeginInfo renderPassBeginInfo =
+ {
+ VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, // VkStructureType sType;
+ DE_NULL, // const void* pNext;
+ *renderPass, // VkRenderPass renderPass;
+ *framebuffer, // VkFramebuffer framebuffer;
+ renderArea, // VkRect2D renderArea;
+ static_cast<deUint32>(clearValues.size()), // deUint32 clearValueCount;
+ &clearValues[0], // const VkClearValue* pClearValues;
+ };
+
+ deviceInterface.cmdBeginRenderPass(*commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
+
+ // Bind graphics pipeline
+ deviceInterface.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
+
+ // Bind vertex buffer
+ deviceInterface.cmdBindVertexBuffers(*commandBuffer, 0u, 1u, &vertexBuffer->get(), &vertexStartOffset);
+
+ // Draw full screen quad
+ deviceInterface.cmdDraw(*commandBuffer, vertexDataDesc.verticesCount, 1u, 0u, 0u);
+
+ // End render pass
+ deviceInterface.cmdEndRenderPass(*commandBuffer);
+ }
+
+ const VkImage sourceImage = m_imageMSParams.numSamples == VK_SAMPLE_COUNT_1_BIT ? **imageMS : **imageRS;
+
+ {
+ const VkImageMemoryBarrier imageTransferSrcBarrier = makeImageMemoryBarrier
+ (
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ VK_ACCESS_TRANSFER_READ_BIT,
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+ sourceImage,
+ fullImageRange
+ );
+
+ deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &imageTransferSrcBarrier);
+ }
+
+ // Copy data from resolve image to buffer
+ const deUint32 imageRSSizeInBytes = getImageSizeInBytes(imageRSInfo.extent, imageRSInfo.arrayLayers, m_imageFormat, imageRSInfo.mipLevels);
+
+ const VkBufferCreateInfo bufferRSInfo = makeBufferCreateInfo(imageRSSizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+ const de::UniquePtr<Buffer> bufferRS(new Buffer(deviceInterface, device, allocator, bufferRSInfo, MemoryRequirement::HostVisible));
+
+ {
+ const VkBufferImageCopy bufferImageCopy =
+ {
+ 0u, // VkDeviceSize bufferOffset;
+ 0u, // deUint32 bufferRowLength;
+ 0u, // deUint32 bufferImageHeight;
+ makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, imageRSInfo.arrayLayers), // VkImageSubresourceLayers imageSubresource;
+ makeOffset3D(0, 0, 0), // VkOffset3D imageOffset;
+ imageRSInfo.extent, // VkExtent3D imageExtent;
+ };
+
+ deviceInterface.cmdCopyImageToBuffer(*commandBuffer, sourceImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, bufferRS->get(), 1u, &bufferImageCopy);
+ }
+
+ {
+ const VkBufferMemoryBarrier bufferRSHostReadBarrier = makeBufferMemoryBarrier
+ (
+ VK_ACCESS_TRANSFER_WRITE_BIT,
+ VK_ACCESS_HOST_READ_BIT,
+ bufferRS->get(),
+ 0u,
+ imageRSSizeInBytes
+ );
+
+ deviceInterface.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferRSHostReadBarrier, 0u, DE_NULL);
+ }
+
+ // End recording commands
+ VK_CHECK(deviceInterface.endCommandBuffer(*commandBuffer));
+
+ // Submit commands for execution and wait for completion
+ submitCommandsAndWait(deviceInterface, device, queue, *commandBuffer);
+
+ // Retrieve data from buffer to host memory
+ const Allocation& bufferRSAllocation = bufferRS->getAllocation();
+
+ invalidateMappedMemoryRange(deviceInterface, device, bufferRSAllocation.getMemory(), bufferRSAllocation.getOffset(), imageRSSizeInBytes);
+
+ const tcu::ConstPixelBufferAccess bufferRSData (m_imageFormat,
+ imageRSInfo.extent.width,
+ imageRSInfo.extent.height,
+ imageRSInfo.extent.depth * imageRSInfo.arrayLayers,
+ bufferRSAllocation.getHostPtr());
+
+ std::stringstream imageName;
+ imageName << getImageTypeName(m_imageType) << "_" << bufferRSData.getWidth() << "_" << bufferRSData.getHeight() << "_" << bufferRSData.getDepth() << std::endl;
+
+ m_context.getTestContext().getLog()
+ << tcu::TestLog::Section(imageName.str(), imageName.str())
+ << tcu::LogImage("image", "", bufferRSData)
+ << tcu::TestLog::EndSection;
+
+ return verifyResolvedImage(bufferRSData);
+}
+
+class MSInstanceDistinctValues : public MSInterpolationInstanceBase
+{
+public:
+ MSInstanceDistinctValues(Context& context,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationInstanceBase(context, imageMSParams) {}
+
+ VertexDataDesc getVertexDataDescripton (void) const;
+ void uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const;
+ tcu::TestStatus verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const;
+
+protected:
+ struct VertexData
+ {
+ VertexData(const tcu::Vec4& posNdc) : positionNdc(posNdc) {}
+
+ tcu::Vec4 positionNdc;
+ };
+};
+
+MSInterpolationInstanceBase::VertexDataDesc MSInstanceDistinctValues::getVertexDataDescripton (void) const
+{
+ VertexDataDesc vertexDataDesc;
+
+ vertexDataDesc.verticesCount = 3u;
+ vertexDataDesc.dataStride = sizeof(VertexData);
+ vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
+ vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+ const VkVertexInputAttributeDescription vertexAttribPositionNdc =
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(VertexData, positionNdc), // deUint32 offset;
+ };
+
+ vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
+
+ return vertexDataDesc;
+}
+
+void MSInstanceDistinctValues::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
+{
+ std::vector<VertexData> vertices;
+
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)));
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f, 4.0f, 0.0f, 1.0f)));
+ vertices.push_back(VertexData(tcu::Vec4( 4.0f,-1.0f, 0.0f, 1.0f)));
+
+ deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
+}
+
+tcu::TestStatus MSInstanceDistinctValues::verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const
+{
+ const deUint32 distinctValuesExpected = static_cast<deUint32>(m_imageMSParams.numSamples) + 1u;
+
+ std::vector<tcu::IVec4> distinctValues;
+
+ for (deInt32 z = 0u; z < imageData.getDepth(); ++z)
+ for (deInt32 y = 0u; y < imageData.getHeight(); ++y)
+ for (deInt32 x = 0u; x < imageData.getWidth(); ++x)
+ {
+ const tcu::IVec4 pixel = imageData.getPixelInt(x, y, z);
+
+ if (std::find(distinctValues.begin(), distinctValues.end(), pixel) == distinctValues.end())
+ distinctValues.push_back(pixel);
+ }
+
+ if (distinctValues.size() >= distinctValuesExpected)
+ return tcu::TestStatus::pass("Passed");
+ else
+ return tcu::TestStatus::fail("Failed");
+}
+
+class MSCaseSampleQualifierDistinctValues : public MSInterpolationCaseBase
+{
+public:
+ MSCaseSampleQualifierDistinctValues (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseSampleQualifierDistinctValues (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseSampleQualifierDistinctValues(testCtx, name, imageMSParams);
+}
+
+void MSCaseSampleQualifierDistinctValues::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that a sample qualified varying is given different values for different samples.\n"
+ << " Render full screen traingle with quadratic function defining red/green color pattern division.\n"
+ << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseSampleQualifierDistinctValues::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "\n"
+ << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_position_ndc = vs_in_position_ndc;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) sample in vec4 fs_in_position_ndc;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " if(fs_in_position_ndc.y < -2.0*pow(0.5*(fs_in_position_ndc.x + 1.0), 2.0) + 1.0)\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseSampleQualifierDistinctValues::createInstance (Context& context) const
+{
+ return new MSInstanceDistinctValues(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtSampleDistinctValues : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtSampleDistinctValues (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtSampleDistinctValues (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtSampleDistinctValues(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtSampleDistinctValues::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that a interpolateAtSample returns different values for different samples.\n"
+ << " Render full screen traingle with quadratic function defining red/green color pattern division.\n"
+ << " => Resulting image should contain n+1 different colors, where n = sample count.\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtSampleDistinctValues::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "\n"
+ << "layout(location = 0) out vec4 vs_out_position_ndc;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_position_ndc = vs_in_position_ndc;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) in vec4 fs_in_position_ndc;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const vec4 position_ndc_at_sample = interpolateAtSample(fs_in_position_ndc, gl_SampleID);\n"
+ << " if(position_ndc_at_sample.y < -2.0*pow(0.5*(position_ndc_at_sample.x + 1.0), 2.0) + 1.0)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtSampleDistinctValues::createInstance (Context& context) const
+{
+ return new MSInstanceDistinctValues(context, m_imageMSParams);
+}
+
+class MSInstanceInterpolateScreenPosition : public MSInterpolationInstanceBase
+{
+public:
+ MSInstanceInterpolateScreenPosition (Context& context,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationInstanceBase(context, imageMSParams) {}
+
+ VertexDataDesc getVertexDataDescripton (void) const;
+ void uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const;
+ tcu::TestStatus verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const;
+
+protected:
+ struct VertexData
+ {
+ VertexData(const tcu::Vec4& posNdc, const tcu::Vec2& posScreen) : positionNdc(posNdc), positionScreen(posScreen) {}
+
+ tcu::Vec4 positionNdc;
+ tcu::Vec2 positionScreen;
+ };
+};
+
+MSInterpolationInstanceBase::VertexDataDesc MSInstanceInterpolateScreenPosition::getVertexDataDescripton (void) const
+{
+ VertexDataDesc vertexDataDesc;
+
+ vertexDataDesc.verticesCount = 4u;
+ vertexDataDesc.dataStride = sizeof(VertexData);
+ vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
+ vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
+
+ const VkVertexInputAttributeDescription vertexAttribPositionNdc =
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(VertexData, positionNdc), // deUint32 offset;
+ };
+
+ vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
+
+ const VkVertexInputAttributeDescription vertexAttribPositionScreen =
+ {
+ 1u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(VertexData, positionScreen), // deUint32 offset;
+ };
+
+ vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionScreen);
+
+ return vertexDataDesc;
+}
+
+void MSInstanceInterpolateScreenPosition::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
+{
+ const tcu::UVec3 layerSize = getLayerSize(IMAGE_TYPE_2D, m_imageMSParams.imageSize);
+ const float screenSizeX = static_cast<float>(layerSize.x());
+ const float screenSizeY = static_cast<float>(layerSize.y());
+
+ std::vector<VertexData> vertices;
+
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, 0.0f)));
+ vertices.push_back(VertexData(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, 0.0f)));
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(0.0f, screenSizeY)));
+ vertices.push_back(VertexData(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec2(screenSizeX, screenSizeY)));
+
+ deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
+}
+
+tcu::TestStatus MSInstanceInterpolateScreenPosition::verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const
+{
+ for (deInt32 z = 0u; z < imageData.getDepth(); ++z)
+ for (deInt32 y = 0u; y < imageData.getHeight(); ++y)
+ for (deInt32 x = 0u; x < imageData.getWidth(); ++x)
+ {
+ const deInt32 firstComponent = imageData.getPixelInt(x, y, z).x();
+
+ if (firstComponent > 0)
+ return tcu::TestStatus::fail("Failed");
+ }
+ return tcu::TestStatus::pass("Passed");
+}
+
+class MSCaseInterpolateAtSampleSingleSample : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtSampleSingleSample (tcu::TestContext& testCtx,
+ const std::string& name,
+ tcu::UVec3 imageSize)
+ : MSInterpolationCaseBase(testCtx, name, ImageMSParams(VK_SAMPLE_COUNT_1_BIT, imageSize)) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+void MSCaseInterpolateAtSampleSingleSample::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that using interpolateAtSample with multisample buffers not available returns sample evaluated at the center of the pixel.\n"
+ << " Interpolate varying containing screen space location.\n"
+ << " => fract(screen space location) should be (about) (0.5, 0.5)\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtSampleSingleSample::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_position_screen;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_position_screen = vs_in_position_screen;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) in vec2 fs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.15625;\n"
+ << " const vec2 position_screen_at_sample = interpolateAtSample(fs_in_position_screen, 0);\n"
+ << " const vec2 position_inside_pixel = fract(position_screen_at_sample);\n"
+ << "\n"
+ << " if (abs(position_inside_pixel.x - 0.5) <= threshold && abs(position_inside_pixel.y - 0.5) <= threshold)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtSampleSingleSample::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtSampleIgnoresCentroid : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtSampleIgnoresCentroid(tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtSampleIgnoresCentroid (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtSampleIgnoresCentroid(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtSampleIgnoresCentroid::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that interpolateAtSample ignores centroid qualifier.\n"
+ << " Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
+ << " => interpolateAtSample(screenSample, n) ~= interpolateAtSample(screenCentroid, n)\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtSampleIgnoresCentroid::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
+ << "layout(location = 1) out vec2 vs_out_pos_screen_fragment;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
+ << " vs_out_pos_screen_fragment = vs_in_position_screen;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
+ << "layout(location = 1) in vec2 fs_in_pos_screen_fragment;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.0005;\n"
+ << "\n"
+ << " const vec2 position_a = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
+ << " const vec2 position_b = interpolateAtSample(fs_in_pos_screen_fragment, gl_SampleID);\n"
+ << " const bool valuesEqual = all(lessThan(abs(position_a - position_b), vec2(threshold)));\n"
+ << "\n"
+ << " if (valuesEqual)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtSampleIgnoresCentroid::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtSampleConsistency : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtSampleConsistency (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtSampleConsistency (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtSampleConsistency(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtSampleConsistency::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that interpolateAtSample with the sample set to the current sampleID returns consistent values.\n"
+ << " Interpolate varying containing screen space location with centroid and sample qualifiers.\n"
+ << " => interpolateAtSample(screenCentroid, sampleID) = screenSample\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtSampleConsistency::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_pos_screen_centroid;\n"
+ << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
+ << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) centroid in vec2 fs_in_pos_screen_centroid;\n"
+ << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.15625;\n"
+ << "\n"
+ << " const vec2 pos_interpolated_at_sample = interpolateAtSample(fs_in_pos_screen_centroid, gl_SampleID);\n"
+ << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_sample - fs_in_pos_screen_sample), vec2(threshold)));\n"
+ << "\n"
+ << " if (valuesEqual)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtSampleConsistency::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtCentroidConsistency : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtCentroidConsistency (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtCentroidConsistency (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtCentroidConsistency(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtCentroidConsistency::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that interpolateAtCentroid does not return different values than a corresponding centroid qualified varying.\n"
+ << " Interpolate varying containing screen space location with sample and centroid qualifiers.\n"
+ << " => interpolateAtCentroid(screenSample) = screenCentroid\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtCentroidConsistency::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_pos_screen_sample;\n"
+ << "layout(location = 1) out vec2 vs_out_pos_screen_centroid;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
+ << " vs_out_pos_screen_centroid = vs_in_position_screen;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) sample in vec2 fs_in_pos_screen_sample;\n"
+ << "layout(location = 1) centroid in vec2 fs_in_pos_screen_centroid;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.0005;\n"
+ << "\n"
+ << " const vec2 pos_interpolated_at_centroid = interpolateAtCentroid(fs_in_pos_screen_sample);\n"
+ << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_centroid - fs_in_pos_screen_centroid), vec2(threshold)));\n"
+ << "\n"
+ << " if (valuesEqual)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtCentroidConsistency::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtOffsetPixelCenter : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtOffsetPixelCenter(tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtOffsetPixelCenter (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtOffsetPixelCenter(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtOffsetPixelCenter::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that interpolateAtOffset returns value sampled at an offset from the center of the pixel.\n"
+ << " Interpolate varying containing screen space location.\n"
+ << " => interpolateAtOffset(screen, offset) should be \"varying value at the pixel center\" + offset"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtOffsetPixelCenter::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_pos_screen;\n"
+ << "layout(location = 1) out vec2 vs_out_offset;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_pos_screen = vs_in_position_screen;\n"
+ << " vs_out_offset = vs_in_position_ndc.xy * 0.5;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) in vec2 fs_in_pos_screen;\n"
+ << "layout(location = 1) in vec2 fs_in_offset;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.15625;\n"
+ << "\n"
+ << " const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen, fs_in_offset);\n"
+ << " const vec2 pixel_center = floor(fs_in_pos_screen) + vec2(0.5, 0.5);\n"
+ << " const vec2 reference_value = pixel_center + fs_in_offset;\n"
+ << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - reference_value), vec2(threshold)));\n"
+ << "\n"
+ << " if (valuesEqual)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtOffsetPixelCenter::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSCaseInterpolateAtOffsetSamplePosition : public MSInterpolationCaseBase
+{
+public:
+ MSCaseInterpolateAtOffsetSamplePosition (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseInterpolateAtOffsetSamplePosition (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseInterpolateAtOffsetSamplePosition(testCtx, name, imageMSParams);
+}
+
+void MSCaseInterpolateAtOffsetSamplePosition::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that interpolateAtOffset of screen position with the offset of current sample position returns value "
+ << "similar to screen position interpolated at sample.\n"
+ << " Interpolate varying containing screen space location with and without sample qualifier.\n"
+ << " => interpolateAtOffset(screenFragment, samplePosition - (0.5,0.5)) = screenSample"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseInterpolateAtOffsetSamplePosition::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec2 vs_in_position_screen;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 vs_out_pos_screen_fragment;\n"
+ << "layout(location = 1) out vec2 vs_out_pos_screen_sample;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_pos_screen_fragment = vs_in_position_screen;\n"
+ << " vs_out_pos_screen_sample = vs_in_position_screen;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) in vec2 fs_in_pos_screen_fragment;\n"
+ << "layout(location = 1) sample in vec2 fs_in_pos_screen_sample;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " const float threshold = 0.15625;\n"
+ << "\n"
+ << " const vec2 offset = gl_SamplePosition - vec2(0.5, 0.5);\n"
+ << " const vec2 pos_interpolated_at_offset = interpolateAtOffset(fs_in_pos_screen_fragment, offset);\n"
+ << " const bool valuesEqual = all(lessThan(abs(pos_interpolated_at_offset - fs_in_pos_screen_sample), vec2(threshold)));\n"
+ << "\n"
+ << " if (valuesEqual)\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseInterpolateAtOffsetSamplePosition::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateScreenPosition(context, m_imageMSParams);
+}
+
+class MSInstanceInterpolateBarycentricCoordinates : public MSInterpolationInstanceBase
+{
+public:
+ MSInstanceInterpolateBarycentricCoordinates (Context& context,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationInstanceBase(context, imageMSParams) {}
+
+ VertexDataDesc getVertexDataDescripton (void) const;
+ void uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const;
+ tcu::TestStatus verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const;
+
+protected:
+ struct VertexData
+ {
+ VertexData(const tcu::Vec4& posNdc, const tcu::Vec3& barCoord) : positionNdc(posNdc), barycentricCoord(barCoord) {}
+
+ tcu::Vec4 positionNdc;
+ tcu::Vec3 barycentricCoord;
+ };
+};
+
+MSInterpolationInstanceBase::VertexDataDesc MSInstanceInterpolateBarycentricCoordinates::getVertexDataDescripton (void) const
+{
+ VertexDataDesc vertexDataDesc;
+
+ vertexDataDesc.verticesCount = 3u;
+ vertexDataDesc.dataStride = sizeof(VertexData);
+ vertexDataDesc.dataSize = vertexDataDesc.verticesCount * vertexDataDesc.dataStride;
+ vertexDataDesc.primitiveTopology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
+
+ const VkVertexInputAttributeDescription vertexAttribPositionNdc =
+ {
+ 0u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32A32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(VertexData, positionNdc), // deUint32 offset;
+ };
+
+ vertexDataDesc.vertexAttribDescVec.push_back(vertexAttribPositionNdc);
+
+ const VkVertexInputAttributeDescription vertexAttrBarCoord =
+ {
+ 1u, // deUint32 location;
+ 0u, // deUint32 binding;
+ VK_FORMAT_R32G32B32_SFLOAT, // VkFormat format;
+ DE_OFFSET_OF(VertexData, barycentricCoord), // deUint32 offset;
+ };
+
+ vertexDataDesc.vertexAttribDescVec.push_back(vertexAttrBarCoord);
+
+ return vertexDataDesc;
+}
+
+void MSInstanceInterpolateBarycentricCoordinates::uploadVertexData (const Allocation& vertexBufferAllocation, const VertexDataDesc& vertexDataDescripton) const
+{
+ // Create buffer storing vertex data
+ std::vector<VertexData> vertices;
+
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 0.0f, 1.0f)));
+ vertices.push_back(VertexData(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), tcu::Vec3(1.0f, 0.0f, 0.0f)));
+ vertices.push_back(VertexData(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f), tcu::Vec3(0.0f, 1.0f, 0.0f)));
+
+ deMemcpy(vertexBufferAllocation.getHostPtr(), dataPointer(vertices), static_cast<std::size_t>(vertexDataDescripton.dataSize));
+}
+
+tcu::TestStatus MSInstanceInterpolateBarycentricCoordinates::verifyResolvedImage (const tcu::ConstPixelBufferAccess& imageData) const
+{
+ for (deInt32 z = 0u; z < imageData.getDepth(); ++z)
+ for (deInt32 y = 0u; y < imageData.getHeight(); ++y)
+ for (deInt32 x = 0u; x < imageData.getWidth(); ++x)
+ {
+ const deInt32 firstComponent = imageData.getPixelInt(x, y, z).x();
+
+ if (firstComponent > 0)
+ return tcu::TestStatus::fail("Failed");
+ }
+
+ return tcu::TestStatus::pass("Passed");
+}
+
+class MSCaseCentroidQualifierInsidePrimitive : public MSInterpolationCaseBase
+{
+public:
+ MSCaseCentroidQualifierInsidePrimitive (tcu::TestContext& testCtx,
+ const std::string& name,
+ const ImageMSParams& imageMSParams)
+ : MSInterpolationCaseBase(testCtx, name, imageMSParams) {}
+
+ void init (void);
+ void initPrograms (vk::SourceCollections& programCollection) const;
+ TestInstance* createInstance (Context& context) const;
+};
+
+MSInterpolationCaseBase* createMSCaseCentroidQualifierInsidePrimitive (tcu::TestContext& testCtx, const std::string& name, const ImageMSParams& imageMSParams)
+{
+ return new MSCaseCentroidQualifierInsidePrimitive(testCtx, name, imageMSParams);
+}
+
+void MSCaseCentroidQualifierInsidePrimitive::init (void)
+{
+ m_testCtx.getLog()
+ << tcu::TestLog::Message
+ << "Verifying that varying qualified with centroid is interpolated at location inside both the pixel and the primitive being processed.\n"
+ << " Interpolate triangle's barycentric coordinates with centroid qualifier.\n"
+ << " => After interpolation we expect barycentric.xyz >= 0.0 && barycentric.xyz <= 1.0\n"
+ << tcu::TestLog::EndMessage;
+
+ MSInterpolationCaseBase::init();
+}
+
+void MSCaseCentroidQualifierInsidePrimitive::initPrograms (vk::SourceCollections& programCollection) const
+{
+ // Create vertex shader
+ std::ostringstream vs;
+
+ vs << "#version 440\n"
+ << "layout(location = 0) in vec4 vs_in_position_ndc;\n"
+ << "layout(location = 1) in vec3 vs_in_barCoord;\n"
+ << "\n"
+ << "layout(location = 0) out vec3 vs_out_barCoord;\n"
+ << "\n"
+ << "out gl_PerVertex {\n"
+ << " vec4 gl_Position;\n"
+ << "};\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " gl_Position = vs_in_position_ndc;\n"
+ << " vs_out_barCoord = vs_in_barCoord;\n"
+ << "}\n";
+
+ programCollection.glslSources.add("vertex_shader") << glu::VertexSource(vs.str());
+
+ // Create fragment shader
+ std::ostringstream fs;
+
+ fs << "#version 440\n"
+ << "layout(location = 0) centroid in vec3 fs_in_barCoord;\n"
+ << "\n"
+ << "layout(location = 0) out vec2 fs_out_color;\n"
+ << "\n"
+ << "void main (void)\n"
+ << "{\n"
+ << " if( all(greaterThanEqual(fs_in_barCoord, vec3(0.0))) && all(lessThanEqual(fs_in_barCoord, vec3(1.0))) )\n"
+ << " fs_out_color = vec2(0.0, 1.0);\n"
+ << " else\n"
+ << " fs_out_color = vec2(1.0, 0.0);\n"
+ << "}\n";
+
+ programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fs.str());
+}
+
+TestInstance* MSCaseCentroidQualifierInsidePrimitive::createInstance (Context& context) const
+{
+ return new MSInstanceInterpolateBarycentricCoordinates(context, m_imageMSParams);
+}
+
+} // multisample
+
+tcu::TestCaseGroup* makeGroup( multisample::MSInterpolationCaseFuncPtr createCaseFuncPtr,
+ tcu::TestContext& testCtx,
+ const std::string groupName,
+ const tcu::UVec3 imageSizes[],
+ const deUint32 imageSizesElemCount,
+ const vk::VkSampleCountFlagBits imageSamples[],
+ const deUint32 imageSamplesElemCount)
+{
+ de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, groupName.c_str(), ""));
+
+ for (deUint32 imageSizeNdx = 0u; imageSizeNdx < imageSizesElemCount; ++imageSizeNdx)
+ {
+ const tcu::UVec3 imageSize = imageSizes[imageSizeNdx];
+ std::ostringstream imageSizeStream;
+
+ imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
+
+ de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
+
+ for (deUint32 imageSamplesNdx = 0u; imageSamplesNdx < imageSamplesElemCount; ++imageSamplesNdx)
+ {
+ const vk::VkSampleCountFlagBits samples = imageSamples[imageSamplesNdx];
+ const multisample::ImageMSParams imageMSParams = multisample::ImageMSParams(samples, imageSize);
+
+ sizeGroup->addChild(createCaseFuncPtr(testCtx, "samples_" + de::toString(samples), imageMSParams));
+ }
+
+ caseGroup->addChild(sizeGroup.release());
+ }
+ return caseGroup.release();
+}
+
+tcu::TestCaseGroup* createMultisampleInterpolationTests (tcu::TestContext& testCtx)
+{
+ de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multisample_interpolation", "Multisample Interpolation"));
+
+ const tcu::UVec3 imageSizes[] =
+ {
+ tcu::UVec3(128u, 128u, 1u),
+ tcu::UVec3(137u, 191u, 1u),
+ };
+
+ const deUint32 sizesElemCount = static_cast<deUint32>(sizeof(imageSizes) / sizeof(tcu::UVec3));
+
+ const vk::VkSampleCountFlagBits imageSamples[] =
+ {
+ vk::VK_SAMPLE_COUNT_2_BIT,
+ vk::VK_SAMPLE_COUNT_4_BIT,
+ vk::VK_SAMPLE_COUNT_8_BIT,
+ vk::VK_SAMPLE_COUNT_16_BIT,
+ vk::VK_SAMPLE_COUNT_32_BIT,
+ vk::VK_SAMPLE_COUNT_64_BIT,
+ };
+
+ const deUint32 samplesElemCount = static_cast<deUint32>(sizeof(imageSamples) / sizeof(vk::VkSampleCountFlagBits));
+
+ de::MovePtr<tcu::TestCaseGroup> caseGroup(new tcu::TestCaseGroup(testCtx, "sample_interpolate_at_single_sample_", ""));
+
+ for (deUint32 imageSizeNdx = 0u; imageSizeNdx < sizesElemCount; ++imageSizeNdx)
+ {
+ const tcu::UVec3 imageSize = imageSizes[imageSizeNdx];
+ std::ostringstream imageSizeStream;
+
+ imageSizeStream << imageSize.x() << "_" << imageSize.y() << "_" << imageSize.z();
+
+ de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, imageSizeStream.str().c_str(), ""));
+
+ sizeGroup->addChild(new multisample::MSCaseInterpolateAtSampleSingleSample(testCtx, "samples_" + de::toString(1), imageSize));
+
+ caseGroup->addChild(sizeGroup.release());
+ }
+
+ testGroup->addChild(caseGroup.release());
+
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtSampleDistinctValues, testCtx, "sample_interpolate_at_distinct_values", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtSampleIgnoresCentroid, testCtx, "sample_interpolate_at_ignores_centroid", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtSampleConsistency, testCtx, "sample_interpolate_at_consistency", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseSampleQualifierDistinctValues, testCtx, "sample_qualifier_distinct_values", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtCentroidConsistency, testCtx, "centroid_interpolate_at_consistency", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseCentroidQualifierInsidePrimitive, testCtx, "centroid_qualifier_inside_primitive", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtOffsetPixelCenter, testCtx, "offset_interpolate_at_pixel_center", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+ testGroup->addChild(makeGroup(multisample::createMSCaseInterpolateAtOffsetSamplePosition, testCtx, "offset_interpolate_at_sample_position", imageSizes, sizesElemCount, imageSamples, samplesElemCount));
+
+ return testGroup.release();
+}
+
+} // pipeline
+} // vkt