/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 Advanced Micro Devices, Inc. * Copyright (c) 2019 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 * \brief Tests for VK_AMD_mixed_attachment_samples *//*--------------------------------------------------------------------*/ #include "vktPipelineMultisampleMixedAttachmentSamplesTests.hpp" #include "vktPipelineSampleLocationsUtil.hpp" #include "vktPipelineMakeUtil.hpp" #include "vktTestCase.hpp" #include "vktTestCaseUtil.hpp" #include "vktTestGroupUtil.hpp" #include "vkCmdUtil.hpp" #include "vkObjUtil.hpp" #include "vkPlatform.hpp" #include "vkMemUtil.hpp" #include "vkQueryUtil.hpp" #include "vkTypeUtil.hpp" #include "vkRefUtil.hpp" #include "vkBuilderUtil.hpp" #include "vkPrograms.hpp" #include "vkImageUtil.hpp" #include "deUniquePtr.hpp" #include "deSharedPtr.hpp" #include "deRandom.hpp" #include "deMath.h" #include "tcuVector.hpp" #include "tcuTestLog.hpp" #include "tcuImageCompare.hpp" #include "tcuTextureUtil.hpp" #include "tcuRGBA.hpp" #include #include namespace vkt { namespace pipeline { namespace { using namespace vk; using de::UniquePtr; using de::MovePtr; using de::SharedPtr; using tcu::UVec2; using tcu::Vec2; using tcu::Vec4; bool compareGreenImage (tcu::TestLog& log, const char* name, const char* description, const tcu::ConstPixelBufferAccess& image) { tcu::TextureLevel greenImage(image.getFormat(), image.getWidth(), image.getHeight()); tcu::clear(greenImage.getAccess(), tcu::RGBA::green().toIVec()); return tcu::intThresholdCompare(log, name, description, greenImage.getAccess(), image, tcu::UVec4(2u), tcu::COMPARE_LOG_RESULT); } VkImageAspectFlags getImageAspectFlags (const VkFormat format) { const tcu::TextureFormat tcuFormat = mapVkFormat(format); if (tcuFormat.order == tcu::TextureFormat::DS) return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; else if (tcuFormat.order == tcu::TextureFormat::D) return VK_IMAGE_ASPECT_DEPTH_BIT; else if (tcuFormat.order == tcu::TextureFormat::S) return VK_IMAGE_ASPECT_STENCIL_BIT; DE_ASSERT(false); return 0u; } struct CompareData { Vec4 color; float depth; deUint32 stencil; // Pad to 2*16 bytes, in the shader the base alignment of this structure is 16 due to vec4 deUint32 padding[2]; CompareData() : color(Vec4(0.0f)), depth(0.0f), stencil(0u) { padding[0] = 0u; padding[1] = 0u; static_assert(sizeof(CompareData) == (2 * 16), "Wrong structure size, expected 16 bytes"); } }; //! Make a dummy sampler. Move makeSampler (const DeviceInterface& vk, const VkDevice device) { const VkSamplerCreateInfo samplerParams = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkSamplerCreateFlags)0, // VkSamplerCreateFlags flags; VK_FILTER_NEAREST, // VkFilter magFilter; VK_FILTER_NEAREST, // VkFilter minFilter; VK_SAMPLER_MIPMAP_MODE_NEAREST, // VkSamplerMipmapMode mipmapMode; VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeU; VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeV; VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW; 0.0f, // float mipLodBias; VK_FALSE, // VkBool32 anisotropyEnable; 1.0f, // float maxAnisotropy; VK_FALSE, // VkBool32 compareEnable; VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp; 0.0f, // float minLod; 0.0f, // float maxLod; VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor; VK_FALSE, // VkBool32 unnormalizedCoordinates; }; return createSampler(vk, device, &samplerParams); } Move makeImage (const DeviceInterface& vk, const VkDevice device, const VkFormat format, const UVec2& size, const VkSampleCountFlagBits samples, const VkImageUsageFlags usage) { const VkImageCreateInfo imageParams = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkImageCreateFlags)0, // VkImageCreateFlags flags; VK_IMAGE_TYPE_2D, // VkImageType imageType; format, // VkFormat format; makeExtent3D(size.x(), size.y(), 1), // VkExtent3D extent; 1u, // deUint32 mipLevels; 1u, // deUint32 arrayLayers; samples, // VkSampleCountFlagBits samples; VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling; usage, // VkImageUsageFlags usage; VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode; 0u, // deUint32 queueFamilyIndexCount; DE_NULL, // const deUint32* pQueueFamilyIndices; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; }; return createImage(vk, device, &imageParams); } inline bool isDepthFormat (const VkFormat format) { return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_DEPTH_BIT) != 0; } inline bool isStencilFormat (const VkFormat format) { return (getImageAspectFlags(format) & VK_IMAGE_ASPECT_STENCIL_BIT) != 0; } //! Create a test-specific MSAA pipeline Move makeGraphicsPipeline (const DeviceInterface& vk, const VkDevice device, const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass, const VkShaderModule vertexModule, const VkShaderModule fragmentModule, const bool useVertexInput, const deUint32 subpassNdx, const UVec2& renderSize, const VkImageAspectFlags depthStencilAspect, //!< Used to determine which D/S tests to turn on const VkSampleCountFlagBits numSamples, const bool sampleShadingEnable, const bool useFragmentShadingRate, const VkSampleLocationsInfoEXT* pSampleLocationsInfo = DE_NULL) { std::vector vertexInputBindingDescriptions; std::vector vertexInputAttributeDescriptions; // Vertex attributes: position and color if (useVertexInput) { vertexInputBindingDescriptions.push_back (makeVertexInputBindingDescription (0u, 2 * sizeof(Vec4), VK_VERTEX_INPUT_RATE_VERTEX)); vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, 0u)); vertexInputAttributeDescriptions.push_back(makeVertexInputAttributeDescription(1u, 0u, VK_FORMAT_R32G32B32A32_SFLOAT, sizeof(Vec4))); } const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineVertexInputStateCreateFlags)0, // VkPipelineVertexInputStateCreateFlags flags; static_cast(vertexInputBindingDescriptions.size()), // uint32_t vertexBindingDescriptionCount; dataOrNullPtr(vertexInputBindingDescriptions), // const VkVertexInputBindingDescription* pVertexBindingDescriptions; static_cast(vertexInputAttributeDescriptions.size()), // uint32_t vertexAttributeDescriptionCount; dataOrNullPtr(vertexInputAttributeDescriptions), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; }; const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineInputAssemblyStateCreateFlags)0, // VkPipelineInputAssemblyStateCreateFlags flags; VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, // VkPrimitiveTopology topology; VK_FALSE, // VkBool32 primitiveRestartEnable; }; const VkViewport viewport = { 0.0f, 0.0f, // x, y static_cast(renderSize.x()), static_cast(renderSize.y()), // widht, height 0.0f, 1.0f // minDepth, maxDepth }; const VkRect2D scissor = { makeOffset2D(0, 0), makeExtent2D(renderSize.x(), renderSize.y()), }; const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineViewportStateCreateFlags)0, // VkPipelineViewportStateCreateFlags flags; 1u, // uint32_t viewportCount; &viewport, // const VkViewport* pViewports; 1u, // uint32_t scissorCount; &scissor, // const VkRect2D* pScissors; }; const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineRasterizationStateCreateFlags)0, // 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; }; VkPipelineSampleLocationsStateCreateInfoEXT pipelineSampleLocationsCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT, // VkStructureType sType; DE_NULL, // const void* pNext; VK_TRUE, // VkBool32 sampleLocationsEnable; VkSampleLocationsInfoEXT(), // VkSampleLocationsInfoEXT sampleLocationsInfo; }; VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineMultisampleStateCreateFlags)0, // VkPipelineMultisampleStateCreateFlags flags; numSamples, // VkSampleCountFlagBits rasterizationSamples; sampleShadingEnable, // VkBool32 sampleShadingEnable; 1.0f, // float minSampleShading; DE_NULL, // const VkSampleMask* pSampleMask; VK_FALSE, // VkBool32 alphaToCoverageEnable; VK_FALSE // VkBool32 alphaToOneEnable; }; if (pSampleLocationsInfo) { pipelineSampleLocationsCreateInfo.sampleLocationsInfo = *pSampleLocationsInfo; pipelineMultisampleStateInfo.pNext = &pipelineSampleLocationsCreateInfo; } // Simply increment the buffer const VkStencilOpState stencilOpState = makeStencilOpState( VK_STENCIL_OP_KEEP, // stencil fail VK_STENCIL_OP_INCREMENT_AND_CLAMP, // depth & stencil pass VK_STENCIL_OP_KEEP, // depth only fail VK_COMPARE_OP_ALWAYS, // compare op ~0u, // compare mask ~0u, // write mask 0u); // reference // Always pass the depth test VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineDepthStencilStateCreateFlags)0, // VkPipelineDepthStencilStateCreateFlags flags; (depthStencilAspect & VK_IMAGE_ASPECT_DEPTH_BIT) != 0u, // VkBool32 depthTestEnable; VK_TRUE, // VkBool32 depthWriteEnable; VK_COMPARE_OP_ALWAYS, // VkCompareOp depthCompareOp; VK_FALSE, // VkBool32 depthBoundsTestEnable; (depthStencilAspect & VK_IMAGE_ASPECT_STENCIL_BIT) != 0u, // 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 defaultBlendAttachmentState = { VK_FALSE, // VkBool32 blendEnable; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp; VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor; VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor; VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp; colorComponentsAll, // VkColorComponentFlags colorWriteMask; }; const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineColorBlendStateCreateFlags)0, // VkPipelineColorBlendStateCreateFlags flags; VK_FALSE, // VkBool32 logicOpEnable; VK_LOGIC_OP_COPY, // VkLogicOp logicOp; 1u, // deUint32 attachmentCount; &defaultBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments; { 0.0f, 0.0f, 0.0f, 0.0f }, // float blendConstants[4]; }; const VkPipelineShaderStageCreateInfo pShaderStages[] = { { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage; vertexModule, // VkShaderModule module; "main", // const char* pName; DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; }, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkPipelineShaderStageCreateFlags)0, // VkPipelineShaderStageCreateFlags flags; VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage; fragmentModule, // VkShaderModule module; "main", // const char* pName; DE_NULL, // const VkSpecializationInfo* pSpecializationInfo; } }; VkPipelineFragmentShadingRateStateCreateInfoKHR shadingRateStateCreateInfo { VK_STRUCTURE_TYPE_PIPELINE_FRAGMENT_SHADING_RATE_STATE_CREATE_INFO_KHR, // VkStructureType sType; DE_NULL, // const void* pNext; { 2, 2 }, // VkExtent2D fragmentSize; { VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR, VK_FRAGMENT_SHADING_RATE_COMBINER_OP_KEEP_KHR }, // VkFragmentShadingRateCombinerOpKHR combinerOps[2]; }; const VkGraphicsPipelineCreateInfo graphicsPipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType; useFragmentShadingRate ? &shadingRateStateCreateInfo : DE_NULL, // const void* pNext; (VkPipelineCreateFlags)0, // VkPipelineCreateFlags flags; DE_LENGTH_OF_ARRAY(pShaderStages), // deUint32 stageCount; pShaderStages, // const VkPipelineShaderStageCreateInfo* pStages; &vertexInputStateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState; &pipelineInputAssemblyStateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState; DE_NULL, // const VkPipelineTessellationStateCreateInfo* pTessellationState; &pipelineViewportStateInfo, // const VkPipelineViewportStateCreateInfo* pViewportState; &pipelineRasterizationStateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState; &pipelineMultisampleStateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState; &pipelineDepthStencilStateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState; &pipelineColorBlendStateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState; DE_NULL, // const VkPipelineDynamicStateCreateInfo* pDynamicState; pipelineLayout, // VkPipelineLayout layout; renderPass, // VkRenderPass renderPass; subpassNdx, // deUint32 subpass; DE_NULL, // VkPipeline basePipelineHandle; -1, // deInt32 basePipelineIndex; }; return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo); } //! Wrap float after an increment inline float wrapIncFloat (float a, float min, float max) { return deFloatMax(min, deFloatMod(a, max)); } //! Generate expected data for color, depth, and stencil samples of a given image. //! Samples are ordered starting at pixel (0, 0) - see compute shader source for reference. std::vector generateCompareData (const deUint32 seed, const UVec2& imageSize, const deUint32 numCoverageSamples, const deUint32 numColorSamples, const deUint32 numDepthStencilSamples) { std::vector allData; de::Random rng (seed); for (deUint32 y = 0u; y < imageSize.y(); ++y) for (deUint32 x = 0u; x < imageSize.x(); ++x) for (deUint32 sample = 0u; sample < numCoverageSamples; ++sample) { CompareData cd; if (sample < numColorSamples) { for (int i = 0; i < 3; ++i) cd.color[i] = 0.1f * static_cast(rng.getInt(1, 10)); cd.color.w() = 1.0f; } if (sample < numDepthStencilSamples) { const deUint32 globalSample = sample + numColorSamples * (x + imageSize.x() * y); cd.depth = wrapIncFloat(0.05f * static_cast(1 + globalSample), 0.05f, 1.0f); cd.stencil = 1 + globalSample % numCoverageSamples; } allData.push_back(cd); } return allData; } //! NDC transformation algorithm for sample locations template std::vector ndcTransformEachSampleInPixel (const UVec2& framebufferSize, const deUint32 numSamplesPerPixel, const SampleAccessor& access) { std::vector locations; for (deUint32 y = 0; y < framebufferSize.y(); ++y) for (deUint32 x = 0; x < framebufferSize.x(); ++x) for (deUint32 sampleNdx = 0; sampleNdx < numSamplesPerPixel; ++sampleNdx) { const Vec2& sp = access(x, y, sampleNdx); const float globalX = sp.x() + static_cast(x); const float globalY = sp.y() + static_cast(y); // Transform to [-1, 1] space locations.push_back(Vec2(-1.0f + 2.0f * (globalX / static_cast(framebufferSize.x())), -1.0f + 2.0f * (globalY / static_cast(framebufferSize.y())))); } return locations; } class AccessStandardSampleLocationsArray { public: AccessStandardSampleLocationsArray (const Vec2* ptr) : m_pData (ptr) {} const Vec2& operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const { DE_UNREF(x); DE_UNREF(y); return m_pData[sampleNdx]; } private: const Vec2* m_pData; }; class AccessMultisamplePixelGrid { public: AccessMultisamplePixelGrid (const MultisamplePixelGrid* ptr) : m_pGrid (ptr) {} Vec2 operator ()(const deUint32 x, const deUint32 y, const deUint32 sampleNdx) const { const VkSampleLocationEXT& sp = m_pGrid->getSample(x, y, sampleNdx); return Vec2(sp.x, sp.y); } private: const MultisamplePixelGrid* m_pGrid; }; //! Generate NDC space standard sample locations at each framebuffer pixel //! Data is filled starting at pixel (0,0) and for each pixel there are numSamples samples std::vector genFramebufferStandardSampleLocations (const VkSampleCountFlagBits numSamples, const UVec2& framebufferSize) { static const Vec2 s_location_samples_1[] = { Vec2(0.5f, 0.5f), }; static const Vec2 s_location_samples_2[] = { Vec2(0.75f, 0.75f), Vec2(0.25f, 0.25f), }; static const Vec2 s_location_samples_4[] = { Vec2(0.375f, 0.125f), Vec2(0.875f, 0.375f), Vec2(0.125f, 0.625f), Vec2(0.625f, 0.875f), }; static const Vec2 s_location_samples_8[] = { Vec2(0.5625f, 0.3125f), Vec2(0.4375f, 0.6875f), Vec2(0.8125f, 0.5625f), Vec2(0.3125f, 0.1875f), Vec2(0.1875f, 0.8125f), Vec2(0.0625f, 0.4375f), Vec2(0.6875f, 0.9375f), Vec2(0.9375f, 0.0625f), }; static const Vec2 s_location_samples_16[] = { Vec2(0.5625f, 0.5625f), Vec2(0.4375f, 0.3125f), Vec2(0.3125f, 0.6250f), Vec2(0.7500f, 0.4375f), Vec2(0.1875f, 0.3750f), Vec2(0.6250f, 0.8125f), Vec2(0.8125f, 0.6875f), Vec2(0.6875f, 0.1875f), Vec2(0.3750f, 0.8750f), Vec2(0.5000f, 0.0625f), Vec2(0.2500f, 0.1250f), Vec2(0.1250f, 0.7500f), Vec2(0.0000f, 0.5000f), Vec2(0.9375f, 0.2500f), Vec2(0.8750f, 0.9375f), Vec2(0.0625f, 0.0000f), }; const Vec2* pSampleLocation = DE_NULL; switch (numSamples) { case VK_SAMPLE_COUNT_1_BIT: pSampleLocation = s_location_samples_1; break; case VK_SAMPLE_COUNT_2_BIT: pSampleLocation = s_location_samples_2; break; case VK_SAMPLE_COUNT_4_BIT: pSampleLocation = s_location_samples_4; break; case VK_SAMPLE_COUNT_8_BIT: pSampleLocation = s_location_samples_8; break; case VK_SAMPLE_COUNT_16_BIT: pSampleLocation = s_location_samples_16; break; default: DE_ASSERT(0); return std::vector(); } return ndcTransformEachSampleInPixel(framebufferSize, static_cast(numSamples), AccessStandardSampleLocationsArray(pSampleLocation)); } //! Generate NDC space custom sample locations at each framebuffer pixel, based on the given pixel grid std::vector getSampleLocations (const MultisamplePixelGrid& pixelGrid, const UVec2& framebufferSize) { return ndcTransformEachSampleInPixel(framebufferSize, pixelGrid.samplesPerPixel(), AccessMultisamplePixelGrid(&pixelGrid)); } struct PositionColor { tcu::Vec4 position; tcu::Vec4 color; PositionColor (const tcu::Vec4& pos, const tcu::Vec4& col) : position(pos), color(col) {} }; //! Generate subpixel triangles containing the sample position, based on compare data. //! Stencil values are created by overlapping triangles, so the stencil pipeline state must be set up accordingly. std::vector generateSubpixelTriangles (const UVec2& renderSize, const std::vector& compareData, const std::vector& sampleLocations) { std::vector vertices; // For each sample location (in the whole framebuffer), create a sub-pixel triangle that contains it. // NDC viewport size is 2.0 in X and Y and NDC pixel width/height depends on the framebuffer resolution. const Vec2 pixelSize = Vec2(2.0f) / renderSize.cast(); const Vec2 offset = pixelSize / 16.0f; // 4 bits precision // Surround with a roughly centered triangle const float y1 = 0.5f * offset.y(); const float y2 = 0.35f * offset.y(); const float x1 = 0.5f * offset.x(); DE_ASSERT(compareData.size() == sampleLocations.size()); for (std::size_t globalSampleNdx = 0; globalSampleNdx < sampleLocations.size(); ++globalSampleNdx) { const Vec2& loc = sampleLocations[globalSampleNdx]; const CompareData& cd = compareData [globalSampleNdx]; // Overdraw at the same position to get the desired stencil // Draw at least once, if stencil is 0 for (deUint32 i = 0; i < deMaxu32(1u, cd.stencil); ++i) { vertices.push_back(PositionColor(Vec4(loc.x(), loc.y() - y1, cd.depth, 1.0f), cd.color)); vertices.push_back(PositionColor(Vec4(loc.x() - x1, loc.y() + y2, cd.depth, 1.0f), cd.color)); vertices.push_back(PositionColor(Vec4(loc.x() + x1, loc.y() + y2, cd.depth, 1.0f), cd.color)); } } return vertices; } void reportSampleError (tcu::TestLog& log, const std::string& sampleDesc, UVec2& renderSize, const deUint32 numCoverageSamples, const deUint32 globalSampleNdx) { const deUint32 pixelNdx = globalSampleNdx / numCoverageSamples; const deUint32 x = pixelNdx % renderSize.x(); const deUint32 y = pixelNdx / renderSize.x(); const deUint32 sample = globalSampleNdx % numCoverageSamples; log << tcu::TestLog::Message << "Incorrect " << sampleDesc << " sample (" << sample << ") at pixel (" << x << ", " << y << ")" << tcu::TestLog::EndMessage; } void checkSampleRequirements (Context& context, const VkSampleCountFlagBits numColorSamples, const VkSampleCountFlagBits numDepthStencilSamples, const bool requireStandardSampleLocations) { const VkPhysicalDeviceLimits& limits = context.getDeviceProperties().limits; if ((limits.framebufferColorSampleCounts & numColorSamples) == 0u) TCU_THROW(NotSupportedError, "framebufferColorSampleCounts: sample count not supported"); if ((limits.framebufferDepthSampleCounts & numDepthStencilSamples) == 0u) TCU_THROW(NotSupportedError, "framebufferDepthSampleCounts: sample count not supported"); if ((limits.framebufferStencilSampleCounts & numDepthStencilSamples) == 0u) TCU_THROW(NotSupportedError, "framebufferStencilSampleCounts: sample count not supported"); if ((limits.sampledImageColorSampleCounts & numColorSamples) == 0u) TCU_THROW(NotSupportedError, "sampledImageColorSampleCounts: sample count not supported"); if ((limits.sampledImageDepthSampleCounts & numDepthStencilSamples) == 0u) TCU_THROW(NotSupportedError, "sampledImageDepthSampleCounts: sample count not supported"); if ((limits.sampledImageStencilSampleCounts & numDepthStencilSamples) == 0u) TCU_THROW(NotSupportedError, "sampledImageStencilSampleCounts: sample count not supported"); // This is required to output geometry that is covering a specific sample if (requireStandardSampleLocations && !limits.standardSampleLocations) TCU_THROW(NotSupportedError, "standardSampleLocations: not supported"); } void checkImageRequirements (Context& context, const VkFormat format, const VkFormatFeatureFlags requiredFeatureFlags, const VkImageUsageFlags requiredUsageFlags, const VkSampleCountFlagBits requiredSampleCount = VK_SAMPLE_COUNT_1_BIT) { const InstanceInterface& vki = context.getInstanceInterface(); const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); VkImageFormatProperties imageProperties; const VkFormatProperties formatProperties = getPhysicalDeviceFormatProperties(vki, physicalDevice, format); if ((formatProperties.optimalTilingFeatures & requiredFeatureFlags) != requiredFeatureFlags) TCU_THROW(NotSupportedError, (de::toString(format) + ": format features not supported").c_str()); const VkResult result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, requiredUsageFlags, (VkImageCreateFlags)0, &imageProperties); if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) TCU_THROW(NotSupportedError, (de::toString(format) + ": format not supported").c_str()); if ((imageProperties.sampleCounts & requiredSampleCount) != requiredSampleCount) TCU_THROW(NotSupportedError, (de::toString(format) + ": sample count not supported").c_str()); } //! Used after a render pass color output (draw or resolve) void recordCopyOutputImageToBuffer (const DeviceInterface& vk, const VkCommandBuffer cmdBuffer, const UVec2& imageSize, const VkImage srcImage, const VkBuffer dstBuffer) { // Image read barrier after color output { const VkImageMemoryBarrier barrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_TRANSFER_READ_BIT, // VkAccessFlags dstAccessMask; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout oldLayout; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout newLayout; VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; srcImage, // VkImage image; makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u), // VkImageSubresourceRange subresourceRange; }; vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u, DE_NULL, 1u, &barrier); } // Resolve image -> host buffer { const VkBufferImageCopy region = { 0ull, // VkDeviceSize bufferOffset; 0u, // uint32_t bufferRowLength; 0u, // uint32_t bufferImageHeight; makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u), // VkImageSubresourceLayers imageSubresource; makeOffset3D(0, 0, 0), // VkOffset3D imageOffset; makeExtent3D(imageSize.x(), imageSize.y(), 1u), // VkExtent3D imageExtent; }; vk.cmdCopyImageToBuffer(cmdBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstBuffer, 1u, ®ion); } // Buffer write barrier { const VkBufferMemoryBarrier barrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; dstBuffer, // VkBuffer buffer; 0ull, // VkDeviceSize offset; VK_WHOLE_SIZE, // VkDeviceSize size; }; vk.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 1u, &barrier, DE_NULL, 0u); } } namespace VerifySamples { //! The parameters that define a test case struct TestParams { struct SampleCount { VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples }; VkFormat colorFormat; //!< Color attachment format VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format bool useProgrammableSampleLocations; //!< Try to use VK_EXT_sample_locations if available bool useFragmentShadingRate; //!< Try to use VK_KHR_fragment_shading_rate if available std::vector perSubpassSamples; //!< Will use multiple subpasses if more than one element TestParams (void) : colorFormat () , depthStencilFormat () , useProgrammableSampleLocations () , useFragmentShadingRate () { } }; //! Common data used by the test struct WorkingData { struct PerSubpass { deUint32 numVertices; //!< Number of vertices defined in the vertex buffer Move vertexBuffer; MovePtr vertexBufferAlloc; Move colorImage; //!< Color image Move colorImageView; //!< Color attachment MovePtr colorImageAlloc; Move depthStencilImage; //!< Depth stencil image Move depthStencilImageView; //!< Depth stencil attachment Move depthOnlyImageView; //!< Depth aspect for shader read Move stencilOnlyImageView; //!< Stencil aspect for shader read MovePtr depthStencilImageAlloc; Move compareBuffer; //!< Buffer used to verify the images - comparison data MovePtr compareBufferAlloc; VkDeviceSize compareBufferSize; Move resultBuffer; //!< Buffer used to verify the images - results MovePtr resultBufferAlloc; VkDeviceSize resultBufferSize; deUint32 numResultElements; //!< Number of checksums in the result buffer MovePtr pixelGrid; //!< Programmable locations PerSubpass (void) : numVertices () , compareBufferSize () , resultBufferSize () , numResultElements () { } }; UVec2 renderSize; //!< Size of the framebuffer VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationsProperties; //!< Used with VK_EXT_sample_locations std::vector > perSubpass; //!< Test may use more than one set of data WorkingData (void) : sampleLocationsProperties () { } }; void addVerificationComputeShader (SourceCollections& programCollection, const VkSampleCountFlagBits numCoverageSamples, const VkSampleCountFlagBits numColorSamples, const VkSampleCountFlagBits numDepthStencilSamples, const VkFormat depthStencilFormat, const std::string& nameSuffix) { const bool isColorMS = (numColorSamples != VK_SAMPLE_COUNT_1_BIT); const bool isDepthStencilMS = (numDepthStencilSamples != VK_SAMPLE_COUNT_1_BIT); const std::string colorBit = de::toString(static_cast(VK_IMAGE_ASPECT_COLOR_BIT)) + "u"; const std::string depthBit = de::toString(static_cast(VK_IMAGE_ASPECT_DEPTH_BIT)) + "u"; const std::string stencilBit = de::toString(static_cast(VK_IMAGE_ASPECT_STENCIL_BIT)) + "u"; std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "struct CompareData {\n" << " vec4 color;\n" << " float depth;\n" << " uint stencil;\n" << "};\n" << "\n" << "layout(local_size_x = " << static_cast(numCoverageSamples) << ") in;\n" // Always use this descriptor layout and ignore unused bindings << "layout(set = 0, binding = 0, std430) writeonly buffer Output {\n" << " uint values[];\n" << "} sb_out;\n" << "layout(set = 0, binding = 1, std430) readonly buffer InputCompare {\n" << " CompareData data[];\n" << "} sb_cmp;\n" << "layout(set = 0, binding = 2) uniform sampler2D" << (isColorMS ? "MS" : "") << " colorImage;\n" << "layout(set = 0, binding = 3) uniform sampler2D" << (isDepthStencilMS ? "MS" : "") <<" depthImage;\n" << "layout(set = 0, binding = 4) uniform usampler2D" << (isDepthStencilMS ? "MS" : "") <<" stencilImage;\n" << "\n" << "void main (void)\n" << "{\n" // Data for each sample in each pixel is laid out linearly (e.g 2 samples): // [pixel(0, 0) sample(0)][pixel(0, 0) sample(1)][pixel(1, 0) sample(0)][pixel(1, 0) sample(1)]... << " uint globalIndex = gl_LocalInvocationID.x + gl_WorkGroupSize.x * (gl_WorkGroupID.x + gl_WorkGroupID.y * gl_NumWorkGroups.x);\n" << " ivec2 position = ivec2(gl_WorkGroupID.x, gl_WorkGroupID.y);\n" << " int sampleNdx = int(gl_LocalInvocationID.x);\n" << " uint result = 0u;\n" << "\n" << " // Verify color samples\n" << " if (sampleNdx < " << static_cast(numColorSamples) << ")\n" << " {\n" << " vec4 color = texelFetch(colorImage, position, sampleNdx);\n" // for non-MS (1 sample) case, sampleNdx = 0 and will instead be LOD = 0 << " vec4 diff = abs(color - sb_cmp.data[globalIndex].color);\n" << " vec4 threshold = vec4(0.02);\n" << "\n" << " if (all(lessThan(diff, threshold)))\n" << " result |= " << colorBit << ";\n" << " }\n" << " else\n" << " result |= " << colorBit << ";\n" // Pass, if sample doesn't exist << "\n"; if (isDepthFormat(depthStencilFormat)) { src << " // Verify depth samples\n" << " if (sampleNdx < " << static_cast(numDepthStencilSamples) << ")\n" << " {\n" << " float depth = texelFetch(depthImage, position, sampleNdx).r;\n" << " float diff = abs(depth - sb_cmp.data[globalIndex].depth);\n" << " float threshold = 0.002;\n" << "\n" << " if (diff < threshold)\n" << " result |= " << depthBit << ";\n" << " }\n" << " else\n" << " result |= " << depthBit << ";\n" << "\n"; } if (isStencilFormat(depthStencilFormat)) { src << " // Verify stencil samples\n" << " if (sampleNdx < " << static_cast(numDepthStencilSamples) << ")\n" << " {\n" << " uint stencil = texelFetch(stencilImage, position, sampleNdx).r;\n" << " uint diff = stencil - sb_cmp.data[globalIndex].stencil;\n" << "\n" << " if (diff == 0u)\n" << " result |= " << stencilBit << ";\n" << " }\n" << " else\n" << " result |= " << stencilBit << ";\n" << "\n"; } src << " sb_out.values[globalIndex] = result;\n" << "}\n"; programCollection.glslSources.add("comp" + nameSuffix) << glu::ComputeSource(src.str()); } //! Get a compact sample count string in format X_Y_Z std::string getSampleCountString (const TestParams::SampleCount& samples) { std::ostringstream str; str << static_cast(samples.numCoverageSamples) << "_" << static_cast(samples.numColorSamples) << "_" << static_cast(samples.numDepthStencilSamples); return str.str(); } void initPrograms (SourceCollections& programCollection, const TestParams params) { // Vertex shader - position and color { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "layout(location = 0) in vec4 in_position;\n" << "layout(location = 1) in vec4 in_color;\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << "out gl_PerVertex {\n" << " vec4 gl_Position;\n" << "};\n" << "\n" << "void main(void)\n" << "{\n" << " gl_Position = in_position;\n" << " o_color = in_color;\n" << "}\n"; programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); } // Fragment shader - output color from VS { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "layout(location = 0) in vec4 in_color;\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << "void main(void)\n" << "{\n" << " o_color = in_color;\n" << "}\n"; programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); } // Compute shader - image verification for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) { const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx]; addVerificationComputeShader(programCollection, samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples, params.depthStencilFormat, "_" + getSampleCountString(samples)); } } //! A simple color, depth/stencil draw. Subpasses (if more than one) are independent void draw (Context& context, const TestParams& params, WorkingData& wd) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const deUint32 numSubpasses = static_cast(wd.perSubpass.size()); Move renderPass; Move framebuffer; std::vector perSubpassSampleLocationsInfo; std::vector attachmentSampleLocations; std::vector subpassSampleLocations; if (params.useProgrammableSampleLocations) for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx) { perSubpassSampleLocationsInfo.push_back(makeSampleLocationsInfo(*wd.perSubpass[subpassNdx]->pixelGrid)); } // Create a render pass and a framebuffer { std::vector subpasses; std::vector attachments; std::vector attachmentDescriptions; std::vector attachmentReferences; // Reserve capacity to avoid invalidating pointers to elements attachmentReferences.reserve(numSubpasses * 2); for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx) { attachments.push_back(wd.perSubpass[subpassNdx]->colorImageView.get()); attachments.push_back(wd.perSubpass[subpassNdx]->depthStencilImageView.get()); attachmentDescriptions.push_back(makeAttachmentDescription( (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; params.colorFormat, // VkFormat format; params.perSubpassSamples[subpassNdx].numColorSamples, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL // VkImageLayout finalLayout; )); attachmentDescriptions.push_back(makeAttachmentDescription( (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; params.depthStencilFormat, // VkFormat format; params.perSubpassSamples[subpassNdx].numDepthStencilSamples, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL // VkImageLayout finalLayout; )); attachmentReferences.push_back(makeAttachmentReference(static_cast(attachmentReferences.size()), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); const VkAttachmentReference* colorRef = &attachmentReferences.back(); attachmentReferences.push_back(makeAttachmentReference(static_cast(attachmentReferences.size()), VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); const VkAttachmentReference* depthStencilRef = &attachmentReferences.back(); if (params.useProgrammableSampleLocations) { const VkAttachmentSampleLocationsEXT newAttachmentSampleLocations = { attachmentReferences.back().attachment, // uint32_t attachmentIndex; perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo; }; attachmentSampleLocations.push_back(newAttachmentSampleLocations); const VkSubpassSampleLocationsEXT newSubpassSampleLocations = { subpassNdx, // uint32_t subpassIndex; perSubpassSampleLocationsInfo[subpassNdx], // VkSampleLocationsInfoEXT sampleLocationsInfo; }; subpassSampleLocations.push_back(newSubpassSampleLocations); } const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 0u, // uint32_t inputAttachmentCount; DE_NULL, // const VkAttachmentReference* pInputAttachments; 1u, // uint32_t colorAttachmentCount; colorRef, // const VkAttachmentReference* pColorAttachments; DE_NULL, // const VkAttachmentReference* pResolveAttachments; depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment; 0u, // uint32_t preserveAttachmentCount; DE_NULL, // const uint32_t* pPreserveAttachments; }; subpasses.push_back(subpassDescription); } // Assume there are no dependencies between subpasses const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; static_cast(attachmentDescriptions.size()), // deUint32 attachmentCount; dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments; static_cast(subpasses.size()), // deUint32 subpassCount; dataOrNullPtr(subpasses), // const VkSubpassDescription* pSubpasses; 0u, // deUint32 dependencyCount; DE_NULL, // const VkSubpassDependency* pDependencies; }; renderPass = createRenderPass(vk, device, &renderPassInfo); framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y()); } const Unique vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u)); const Unique fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u)); const Unique pipelineLayout (makePipelineLayout(vk, device)); typedef SharedPtr > PipelineSp; std::vector pipelines; for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx) { const VkSampleLocationsInfoEXT* pSampleLocationsInfo = (params.useProgrammableSampleLocations ? &perSubpassSampleLocationsInfo[subpassNdx] : DE_NULL); pipelines.push_back(PipelineSp(new Unique( makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, /*use vertex input*/ true, subpassNdx, wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.perSubpassSamples[subpassNdx].numCoverageSamples, /*use sample shading*/ true, params.useFragmentShadingRate, pSampleLocationsInfo)))); } const Unique cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex())); const Unique cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); beginCommandBuffer(vk, *cmdBuffer); { std::vector clearValues; for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx) { clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f)); clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u)); } const VkRect2D renderArea = { { 0u, 0u }, { wd.renderSize.x(), wd.renderSize.y() } }; 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(clearValues.size()), // uint32_t clearValueCount; dataOrNullPtr(clearValues), // const VkClearValue* pClearValues; }; if (params.useProgrammableSampleLocations) { const VkRenderPassSampleLocationsBeginInfoEXT renderPassSampleLocationsBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT, // VkStructureType sType; DE_NULL, // const void* pNext; static_cast(attachmentSampleLocations.size()), // uint32_t attachmentInitialSampleLocationsCount; dataOrNullPtr(attachmentSampleLocations), // const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations; static_cast(subpassSampleLocations.size()), // uint32_t postSubpassSampleLocationsCount; dataOrNullPtr(subpassSampleLocations), // const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations; }; renderPassBeginInfo.pNext = &renderPassSampleLocationsBeginInfo; vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); } else vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); } for (deUint32 subpassNdx = 0; subpassNdx < numSubpasses; ++subpassNdx) { if (subpassNdx != 0) vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE); const VkDeviceSize vertexBufferOffset = 0ull; vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &wd.perSubpass[subpassNdx]->vertexBuffer.get(), &vertexBufferOffset); vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[subpassNdx]); vk.cmdDraw(*cmdBuffer, wd.perSubpass[subpassNdx]->numVertices, 1u, 0u, 0u); } vk.cmdEndRenderPass(*cmdBuffer); VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer); } void dispatchImageCheck (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx]; const Unique defaultSampler (makeSampler(vk, device)); // Create descriptor set const Unique descriptorSetLayout( DescriptorSetLayoutBuilder() .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleBinding (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT) .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get()) .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get()) .addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_COMPUTE_BIT, &defaultSampler.get()) .build(vk, device)); const Unique descriptorPool( DescriptorPoolBuilder() .addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2u) .addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 3u) .build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u)); const Unique descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout)); { const VkDescriptorBufferInfo compareBufferInfo = makeDescriptorBufferInfo(*subpassData.compareBuffer, 0ull, subpassData.compareBufferSize); const VkDescriptorBufferInfo resultBufferInfo = makeDescriptorBufferInfo(*subpassData.resultBuffer, 0ull, subpassData.resultBufferSize); const VkDescriptorImageInfo colorImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); const VkDescriptorImageInfo depthImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.depthOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); const VkDescriptorImageInfo stencilImageInfo = makeDescriptorImageInfo(DE_NULL, *subpassData.stencilOnlyImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); DescriptorSetUpdateBuilder builder; builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &resultBufferInfo); builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &compareBufferInfo); builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &colorImageInfo); if (subpassData.depthOnlyImageView) builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(3u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &depthImageInfo); if (subpassData.stencilOnlyImageView) builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(4u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &stencilImageInfo); builder.update(vk, device); } // Pipeline const std::string shaderName ("comp_" + getSampleCountString(params.perSubpassSamples[subpassNdx])); const Unique shaderModule (createShaderModule(vk, device, context.getBinaryCollection().get(shaderName), 0u)); const Unique pipelineLayout (makePipelineLayout(vk, device, *descriptorSetLayout)); const Unique pipeline (makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, DE_NULL)); const Unique cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex())); const Unique cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); beginCommandBuffer(vk, *cmdBuffer); vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline); vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL); vk.cmdDispatch(*cmdBuffer, wd.renderSize.x(), wd.renderSize.y(), 1u); { const VkBufferMemoryBarrier barrier = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, // VkStructureType sType; DE_NULL, // const void* pNext; VK_ACCESS_SHADER_WRITE_BIT, // VkAccessFlags srcAccessMask; VK_ACCESS_HOST_READ_BIT, // VkAccessFlags dstAccessMask; VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex; VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex; *subpassData.resultBuffer, // VkBuffer buffer; 0ull, // VkDeviceSize offset; VK_WHOLE_SIZE, // VkDeviceSize size; }; vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags)0, 0, (const VkMemoryBarrier*)DE_NULL, 1u, &barrier, 0u, (const VkImageMemoryBarrier*)DE_NULL); } VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer); invalidateMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE); } void createPerSubpassData (Context& context, const TestParams& params, WorkingData& wd, const deUint32 subpassNdx) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); MovePtr allocator = MovePtr(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))); const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx]; WorkingData::PerSubpass& subpassData = *wd.perSubpass[subpassNdx]; // Create images { const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; checkImageRequirements (context, params.colorFormat, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, colorImageUsageFlags, samples.numColorSamples); subpassData.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, samples.numColorSamples, colorImageUsageFlags); subpassData.colorImageAlloc = bindImage(vk, device, *allocator, *subpassData.colorImage, MemoryRequirement::Any); subpassData.colorImageView = makeImageView(vk, device, *subpassData.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)); checkImageRequirements (context, params.depthStencilFormat, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, depthStencilImageUsageFlags, samples.numDepthStencilSamples); subpassData.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, samples.numDepthStencilSamples, depthStencilImageUsageFlags); subpassData.depthStencilImageAlloc = bindImage(vk, device, *allocator, *subpassData.depthStencilImage, MemoryRequirement::Any); subpassData.depthStencilImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u)); if (isDepthFormat(params.depthStencilFormat)) subpassData.depthOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u)); if (isStencilFormat(params.depthStencilFormat)) subpassData.stencilOnlyImageView = makeImageView(vk, device, *subpassData.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u)); } // Create vertex and comparison buffers { const deUint32 seed = 123 + 19 * subpassNdx; const std::vector compareData = generateCompareData(seed, wd.renderSize, samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples); subpassData.compareBufferSize = static_cast(sizeof(CompareData) * compareData.size()); subpassData.compareBuffer = makeBuffer(vk, device, subpassData.compareBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); subpassData.compareBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.compareBuffer, MemoryRequirement::HostVisible); deMemcpy(subpassData.compareBufferAlloc->getHostPtr(), dataOrNullPtr(compareData), static_cast(subpassData.compareBufferSize)); flushMappedMemoryRange(vk, device, subpassData.compareBufferAlloc->getMemory(), subpassData.compareBufferAlloc->getOffset(), VK_WHOLE_SIZE); subpassData.numResultElements = static_cast(compareData.size()); subpassData.resultBufferSize = static_cast(sizeof(deUint32) * compareData.size()); subpassData.resultBuffer = makeBuffer(vk, device, subpassData.resultBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); subpassData.resultBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.resultBuffer, MemoryRequirement::HostVisible); deMemset(subpassData.resultBufferAlloc->getHostPtr(), 0, static_cast(subpassData.resultBufferSize)); flushMappedMemoryRange(vk, device, subpassData.resultBufferAlloc->getMemory(), subpassData.resultBufferAlloc->getOffset(), VK_WHOLE_SIZE); std::vector vertices; if (params.useProgrammableSampleLocations) { subpassData.pixelGrid = MovePtr(new MultisamplePixelGrid(UVec2(wd.sampleLocationsProperties.maxSampleLocationGridSize.width, wd.sampleLocationsProperties.maxSampleLocationGridSize.height), samples.numCoverageSamples)); const deUint32 locationsSeed = 211 + 4 * subpassNdx; fillSampleLocationsRandom(*subpassData.pixelGrid, wd.sampleLocationsProperties.sampleLocationSubPixelBits, locationsSeed); vertices = generateSubpixelTriangles(wd.renderSize, compareData, getSampleLocations(*subpassData.pixelGrid, wd.renderSize)); } else { const std::vector locations = genFramebufferStandardSampleLocations(samples.numCoverageSamples, wd.renderSize); vertices = generateSubpixelTriangles(wd.renderSize, compareData, locations); } const VkDeviceSize vertexBufferSize = static_cast(sizeof(vertices[0]) * vertices.size()); subpassData.numVertices = static_cast(vertices.size()); subpassData.vertexBuffer = makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); subpassData.vertexBufferAlloc = bindBuffer(vk, device, *allocator, *subpassData.vertexBuffer, MemoryRequirement::HostVisible); deMemcpy(subpassData.vertexBufferAlloc->getHostPtr(), dataOrNullPtr(vertices), static_cast(vertexBufferSize)); flushMappedMemoryRange(vk, device, subpassData.vertexBufferAlloc->getMemory(), subpassData.vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE); } } void checkRequirements (Context& context, TestParams params) { context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples"); if (params.useProgrammableSampleLocations) context.requireDeviceFunctionality("VK_EXT_sample_locations"); for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) { const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx]; checkSampleRequirements(context, samples.numColorSamples, samples.numDepthStencilSamples, !params.useProgrammableSampleLocations); } if (params.useFragmentShadingRate) { const auto& vki = context.getInstanceInterface(); const auto physicalDevice = context.getPhysicalDevice(); context.requireDeviceFunctionality("VK_KHR_fragment_shading_rate"); if (!context.getFragmentShadingRateFeatures().pipelineFragmentShadingRate) TCU_THROW(NotSupportedError, "pipelineFragmentShadingRate not supported"); // Fetch information about supported fragment shading rates deUint32 supportedFragmentShadingRateCount = 0; vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, DE_NULL); std::vector supportedFragmentShadingRates(supportedFragmentShadingRateCount, { vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, DE_NULL, vk::VK_SAMPLE_COUNT_1_BIT, {1, 1} }); vki.getPhysicalDeviceFragmentShadingRatesKHR(physicalDevice, &supportedFragmentShadingRateCount, supportedFragmentShadingRates.data()); deUint32 cumulativeNeededSamples = 0; for (const TestParams::SampleCount& samples : params.perSubpassSamples) cumulativeNeededSamples |= samples.numColorSamples; bool requiredRateFound = false; for (const auto& rate : supportedFragmentShadingRates) { if ((rate.fragmentSize.width == 2u) && (rate.fragmentSize.height == 2u) && (rate.sampleCounts & cumulativeNeededSamples)) { requiredRateFound = true; break; } } if (!requiredRateFound) TCU_THROW(NotSupportedError, "Required FragmentShadingRate not supported"); } } //! Verify the values of all samples in all attachments. tcu::TestStatus test (Context& context, const TestParams params) { WorkingData wd; wd.renderSize = UVec2(2, 2); // Use a very small image, as we will verify all samples for all pixels // Query state related to programmable sample locations if (params.useProgrammableSampleLocations) { const InstanceInterface& vki = context.getInstanceInterface(); const VkPhysicalDevice physicalDevice = context.getPhysicalDevice(); wd.sampleLocationsProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT; wd.sampleLocationsProperties.pNext = DE_NULL; VkPhysicalDeviceProperties2 properties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR, // VkStructureType sType; &wd.sampleLocationsProperties, // void* pNext; VkPhysicalDeviceProperties(), // VkPhysicalDeviceProperties properties; }; vki.getPhysicalDeviceProperties2(physicalDevice, &properties); for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) { if ((wd.sampleLocationsProperties.sampleLocationSampleCounts & params.perSubpassSamples[subpassNdx].numCoverageSamples) == 0u) TCU_THROW(NotSupportedError, "VkSampleLocationsPropertiesAMD: sample count not supported"); } } // Create subpass data for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) { wd.perSubpass.push_back(SharedPtr(new WorkingData::PerSubpass())); createPerSubpassData(context, params, wd, subpassNdx); } // Draw test geometry draw (context, params, wd); // Verify images with a compute shader for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) dispatchImageCheck (context, params, wd, subpassNdx); // Test checksums for (deUint32 subpassNdx = 0; subpassNdx < static_cast(params.perSubpassSamples.size()); ++subpassNdx) { const deUint32* const pSampleChecksumBase = static_cast(wd.perSubpass[subpassNdx]->resultBufferAlloc->getHostPtr()); const bool hasDepth = isDepthFormat(params.depthStencilFormat); const bool hasStencil = isStencilFormat(params.depthStencilFormat); bool allOk = true; context.getTestContext().getLog() << tcu::TestLog::Message << "Verify images in subpass " << subpassNdx << tcu::TestLog::EndMessage; for (deUint32 globalSampleNdx = 0; globalSampleNdx < wd.perSubpass[subpassNdx]->numResultElements; ++globalSampleNdx) { const TestParams::SampleCount& samples = params.perSubpassSamples[subpassNdx]; const deUint32 checksum = pSampleChecksumBase[globalSampleNdx]; if ((checksum & VK_IMAGE_ASPECT_COLOR_BIT) == 0u) { reportSampleError(context.getTestContext().getLog(), "color", wd.renderSize, samples.numCoverageSamples, globalSampleNdx); allOk = false; } if (hasDepth && ((checksum & VK_IMAGE_ASPECT_DEPTH_BIT) == 0u)) { reportSampleError(context.getTestContext().getLog(), "depth", wd.renderSize, samples.numCoverageSamples, globalSampleNdx); allOk = false; } if (hasStencil && ((checksum & VK_IMAGE_ASPECT_STENCIL_BIT) == 0u)) { reportSampleError(context.getTestContext().getLog(), "stencil", wd.renderSize, samples.numCoverageSamples, globalSampleNdx); allOk = false; } } if (!allOk) return tcu::TestStatus::fail("Multisampled image has incorrect samples"); } return tcu::TestStatus::pass("Pass"); } } // VerifySamples namespace ShaderBuiltins { struct TestParams { VkSampleCountFlagBits numCoverageSamples; //!< VkPipelineMultisampleStateCreateInfo::rasterizationSamples VkSampleCountFlagBits numColorSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples VkSampleCountFlagBits numDepthStencilSamples; //!< VkAttachmentDescription::samples and VkImageCreateInfo::samples VkFormat colorFormat; //!< Color attachment format VkFormat depthStencilFormat; //!< D/S attachment format. Will test both aspects if it's a mixed format }; struct WorkingData { UVec2 renderSize; //!< Size of the framebuffer deUint32 numVertices; //!< Number of vertices defined in the vertex buffer Move vertexBuffer; MovePtr vertexBufferAlloc; Move colorImage; //!< Color image Move colorImageView; //!< Color attachment MovePtr colorImageAlloc; Move depthStencilImage; //!< Depth stencil image Move depthStencilImageView; //!< Depth stencil attachment Move depthOnlyImageView; //!< Depth aspect for shader read Move stencilOnlyImageView; //!< Stencil aspect for shader read MovePtr depthStencilImageAlloc; Move resolveImage; //!< Resolve image Move resolveImageView; //!< Resolve attachment MovePtr resolveImageAlloc; Move colorBuffer; //!< Buffer used to copy resolve output MovePtr colorBufferAlloc; VkDeviceSize colorBufferSize; WorkingData (void) : numVertices () , colorBufferSize (0) { } }; void initPrograms (SourceCollections& programCollection, const TestParams params) { // Vertex shader - no vertex data { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "out gl_PerVertex {\n" << " vec4 gl_Position;\n" << "};\n" << "\n" << "void main(void)\n" << "{\n" // Specify an oversized triangle covering the whole viewport. << " switch (gl_VertexIndex)\n" << " {\n" << " case 0:\n" << " gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n" << " break;\n" << " case 1:\n" << " gl_Position = vec4(-1.0, 3.0, 0.0, 1.0);\n" << " break;\n" << " case 2:\n" << " gl_Position = vec4( 3.0, -1.0, 0.0, 1.0);\n" << " break;\n" << " }\n" << "}\n"; programCollection.glslSources.add("vert") << glu::VertexSource(src.str()); } // Fragment shader { std::ostringstream src; src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n" << "\n" << "layout(location = 0) out vec4 o_color;\n" << "\n" << "void main(void)\n" << "{\n" << " vec4 col = vec4(0.0, 0.0, 0.0, 1.0);\n" << "\n"; if (params.numColorSamples == VK_SAMPLE_COUNT_1_BIT) { const deUint32 expectedMask = ((1u << static_cast(params.numCoverageSamples)) - 1u); // Expect all covered samples to be lit, the rest is zero src << " if (gl_SampleMaskIn[0] == " << expectedMask << ")\n" << " col.g = 1.0;\n" << " else\n" << " col.r = 1.0;\n"; } else { // Expect only a matching sample to be lit src << " if (gl_SampleMaskIn[0] == (1 << gl_SampleID))\n" << " col.g = 1.0;\n" << " else\n" << " col.r = 1.0;\n" << "\n" << " if (gl_SampleID >= " << static_cast(params.numColorSamples) << ") // number of color samples, should not happen\n" << " col.b = 1.0;\n"; } src << "\n" << " o_color = col;\n" << "}\n"; programCollection.glslSources.add("frag") << glu::FragmentSource(src.str()); } } //! A simple color, depth/stencil draw. Single subpass, no vertex input void drawResolve (Context& context, const TestParams& params, WorkingData& wd) { const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); const bool needResolve = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT); Move renderPass; Move framebuffer; // Create a render pass and a framebuffer { std::vector attachments; std::vector attachmentDescriptions; attachments.push_back(*wd.colorImageView); attachments.push_back(*wd.depthStencilImageView); attachmentDescriptions.push_back(makeAttachmentDescription( (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; params.colorFormat, // VkFormat format; params.numColorSamples, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; )); attachmentDescriptions.push_back(makeAttachmentDescription( (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; params.depthStencilFormat, // VkFormat format; params.numDepthStencilSamples, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout; )); if (needResolve) { attachments.push_back(*wd.resolveImageView); attachmentDescriptions.push_back(makeAttachmentDescription( (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags; params.colorFormat, // VkFormat format; VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp; VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp; VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp; VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp; VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout; VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout; )); } const VkAttachmentReference colorRef = makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); const VkAttachmentReference depthStencilRef = makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); const VkAttachmentReference resolveRef = makeAttachmentReference(2u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags; VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint; 0u, // uint32_t inputAttachmentCount; DE_NULL, // const VkAttachmentReference* pInputAttachments; 1u, // uint32_t colorAttachmentCount; &colorRef, // const VkAttachmentReference* pColorAttachments; (needResolve ? &resolveRef : DE_NULL), // const VkAttachmentReference* pResolveAttachments; &depthStencilRef, // const VkAttachmentReference* pDepthStencilAttachment; 0u, // uint32_t preserveAttachmentCount; DE_NULL, // const uint32_t* pPreserveAttachments; }; // Assume there are no dependencies between subpasses VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType; DE_NULL, // const void* pNext; (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags; static_cast(attachmentDescriptions.size()), // deUint32 attachmentCount; dataOrNullPtr(attachmentDescriptions), // const VkAttachmentDescription* pAttachments; 1u, // deUint32 subpassCount; &subpassDescription, // const VkSubpassDescription* pSubpasses; 0u, // deUint32 dependencyCount; DE_NULL, // const VkSubpassDependency* pDependencies; }; renderPass = createRenderPass(vk, device, &renderPassInfo); framebuffer = makeFramebuffer (vk, device, *renderPass, static_cast(attachments.size()), dataOrNullPtr(attachments), wd.renderSize.x(), wd.renderSize.y()); } const Unique vertexModule (createShaderModule(vk, device, context.getBinaryCollection().get("vert"), 0u)); const Unique fragmentModule (createShaderModule(vk, device, context.getBinaryCollection().get("frag"), 0u)); const Unique pipelineLayout (makePipelineLayout(vk, device)); const bool useVertexInput = false; const bool sampleShading = (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT); const deUint32 subpassNdx = 0u; const Unique pipeline (makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule, useVertexInput, subpassNdx, wd.renderSize, getImageAspectFlags(params.depthStencilFormat), params.numCoverageSamples, sampleShading, false)); const Unique cmdPool (createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, context.getUniversalQueueFamilyIndex())); const Unique cmdBuffer (makeCommandBuffer(vk, device, *cmdPool)); beginCommandBuffer(vk, *cmdBuffer); { std::vector clearValues; clearValues.push_back(makeClearValueColorF32(0.0f, 0.0f, 0.0f, 1.0f)); clearValues.push_back(makeClearValueDepthStencil(1.0f, 0u)); const VkRect2D renderArea = { { 0u, 0u }, { wd.renderSize.x(), wd.renderSize.y() } }; 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(clearValues.size()), // uint32_t clearValueCount; dataOrNullPtr(clearValues), // const VkClearValue* pClearValues; }; vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); } vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); vk.cmdDraw(*cmdBuffer, 3u, 1u, 0u, 0u); vk.cmdEndRenderPass(*cmdBuffer); if (needResolve) recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.resolveImage, *wd.colorBuffer); else recordCopyOutputImageToBuffer(vk, *cmdBuffer, wd.renderSize, *wd.colorImage, *wd.colorBuffer); VK_CHECK(vk.endCommandBuffer(*cmdBuffer)); submitCommandsAndWait(vk, device, context.getUniversalQueue(), *cmdBuffer); } void checkRequirements (Context& context, TestParams params) { context.requireDeviceFunctionality("VK_AMD_mixed_attachment_samples"); checkSampleRequirements(context, params.numColorSamples, params.numDepthStencilSamples, false /* require standard sample locations */); } //! Verify the values of shader builtins tcu::TestStatus test (Context& context, const TestParams params) { WorkingData wd; const DeviceInterface& vk = context.getDeviceInterface(); const VkDevice device = context.getDevice(); MovePtr allocator = MovePtr(new SimpleAllocator(vk, device, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()))); wd.renderSize = UVec2(16, 16); // Create images and a color buffer { const VkImageUsageFlags colorImageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; const VkImageUsageFlags depthStencilImageUsageFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; checkImageRequirements (context, params.colorFormat, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, colorImageUsageFlags, params.numColorSamples); wd.colorImage = makeImage(vk, device, params.colorFormat, wd.renderSize, params.numColorSamples, colorImageUsageFlags); wd.colorImageAlloc = bindImage(vk, device, *allocator, *wd.colorImage, MemoryRequirement::Any); wd.colorImageView = makeImageView(vk, device, *wd.colorImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)); if (params.numColorSamples != VK_SAMPLE_COUNT_1_BIT) { wd.resolveImage = makeImage(vk, device, params.colorFormat, wd.renderSize, VK_SAMPLE_COUNT_1_BIT, colorImageUsageFlags); wd.resolveImageAlloc = bindImage(vk, device, *allocator, *wd.resolveImage, MemoryRequirement::Any); wd.resolveImageView = makeImageView(vk, device, *wd.resolveImage, VK_IMAGE_VIEW_TYPE_2D, params.colorFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u)); } // Resolve result wd.colorBufferSize = static_cast(tcu::getPixelSize(mapVkFormat(params.colorFormat)) * wd.renderSize.x() * wd.renderSize.y()); wd.colorBuffer = makeBuffer(vk, device, wd.colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); wd.colorBufferAlloc = bindBuffer(vk, device, *allocator, *wd.colorBuffer, MemoryRequirement::HostVisible); deMemset(wd.colorBufferAlloc->getHostPtr(), 0, static_cast(wd.colorBufferSize)); flushMappedMemoryRange(vk, device, wd.colorBufferAlloc->getMemory(), wd.colorBufferAlloc->getOffset(), VK_WHOLE_SIZE); checkImageRequirements (context, params.depthStencilFormat, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, depthStencilImageUsageFlags, params.numDepthStencilSamples); wd.depthStencilImage = makeImage(vk, device, params.depthStencilFormat, wd.renderSize, params.numDepthStencilSamples, depthStencilImageUsageFlags); wd.depthStencilImageAlloc = bindImage(vk, device, *allocator, *wd.depthStencilImage, MemoryRequirement::Any); wd.depthStencilImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(getImageAspectFlags(params.depthStencilFormat), 0u, 1u, 0u, 1u)); if (isDepthFormat(params.depthStencilFormat)) wd.depthOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u)); if (isStencilFormat(params.depthStencilFormat)) wd.stencilOnlyImageView = makeImageView(vk, device, *wd.depthStencilImage, VK_IMAGE_VIEW_TYPE_2D, params.depthStencilFormat, makeImageSubresourceRange(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, 1u, 0u, 1u)); } // Draw, resolve, and copy to color buffer (see the fragment shader for details) drawResolve(context, params, wd); // Verify resolved image { const tcu::ConstPixelBufferAccess image (tcu::ConstPixelBufferAccess(mapVkFormat(params.colorFormat), tcu::IVec3(wd.renderSize.x(), wd.renderSize.y(), 1),wd.colorBufferAlloc->getHostPtr())); if (compareGreenImage(context.getTestContext().getLog(), "resolve0", "Resolved test image", image)) return tcu::TestStatus::pass("Pass"); else return tcu::TestStatus::fail("Some samples were incorrect"); } } } // ShaderBuiltins std::string getSampleCountGroupName(const VkSampleCountFlagBits coverageCount, const VkSampleCountFlagBits colorCount, const VkSampleCountFlagBits depthStencilCount) { std::ostringstream str; str << "coverage_" << static_cast(coverageCount) << "_color_" << static_cast(colorCount) << "_depth_stencil_" << static_cast(depthStencilCount); return str.str(); } std::string getFormatShortString (const VkFormat format) { std::string s(de::toLower(getFormatName(format))); return s.substr(10); } std::string getFormatCaseName (const VkFormat colorFormat, const VkFormat depthStencilFormat) { std::ostringstream str; str << getFormatShortString(colorFormat) << "_" << getFormatShortString(depthStencilFormat); return str.str(); } void createMixedAttachmentSamplesTestsInGroup (tcu::TestCaseGroup* rootGroup, bool useFragmentShadingRate) { const VkFormat colorFormatRange[] = { VK_FORMAT_R8G8B8A8_UNORM, // If you add more, make sure it is handled in the test/shader }; const VkFormat depthStencilFormatRange[] = { 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, }; // Minimal set of formats to cover depth and stencil const VkFormat depthStencilReducedFormatRange[] = { VK_FORMAT_D16_UNORM, //!< Must be supported VK_FORMAT_D24_UNORM_S8_UINT, //!< Either this, or the next one must be supported VK_FORMAT_D32_SFLOAT_S8_UINT, }; struct SampleCase { VkSampleCountFlagBits colorSamples; VkSampleCountFlagBits depthStencilSamples; }; // Currently supported EQAA cases static const SampleCase singlePassCases[] = { // Less color than depth/stencil { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_16_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_16_BIT }, { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_16_BIT }, { VK_SAMPLE_COUNT_8_BIT, VK_SAMPLE_COUNT_16_BIT }, }; // Multi-subpass cases static const SampleCase caseSubpassIncreaseColor_1[] = { { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, }; static const SampleCase caseSubpassIncreaseColor_2[] = { { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT }, }; static const SampleCase caseSubpassDecreaseColor_1[] = { { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_4_BIT }, }; static const SampleCase caseSubpassDecreaseColor_2[] = { { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_8_BIT }, }; static const SampleCase caseSubpassIncreaseCoverage_1[] = { { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, }; static const SampleCase caseSubpassIncreaseCoverage_2[] = { { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT }, }; static const SampleCase caseSubpassDecreaseCoverage_1[] = { { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT }, }; static const SampleCase caseSubpassDecreaseCoverage_2[] = { { VK_SAMPLE_COUNT_4_BIT, VK_SAMPLE_COUNT_8_BIT }, { VK_SAMPLE_COUNT_2_BIT, VK_SAMPLE_COUNT_4_BIT }, { VK_SAMPLE_COUNT_1_BIT, VK_SAMPLE_COUNT_2_BIT }, }; static const struct { const char* const caseName; const deUint32 numSampleCases; const SampleCase* pSampleCase; } subpassCases[] = { { "multi_subpass_decrease_color_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_1), caseSubpassDecreaseColor_1 }, { "multi_subpass_decrease_color_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseColor_2), caseSubpassDecreaseColor_2 }, { "multi_subpass_decrease_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_1), caseSubpassDecreaseCoverage_1 }, { "multi_subpass_decrease_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassDecreaseCoverage_2), caseSubpassDecreaseCoverage_2 }, { "multi_subpass_increase_color_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_1), caseSubpassIncreaseColor_1 }, { "multi_subpass_increase_color_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseColor_2), caseSubpassIncreaseColor_2 }, { "multi_subpass_increase_coverage_4", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_1), caseSubpassIncreaseCoverage_1 }, { "multi_subpass_increase_coverage_8", DE_LENGTH_OF_ARRAY(caseSubpassIncreaseCoverage_2), caseSubpassIncreaseCoverage_2 }, }; // Test 1: Per-sample expected value check { MovePtr standardLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_standard_locations", "")); MovePtr programmableLocationsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "verify_programmable_locations", "")); tcu::TestCaseGroup* locationsGroups[2] = { standardLocationsGroup.get(), programmableLocationsGroup.get() }; for (deUint32 groupNdx = 0u; groupNdx < DE_LENGTH_OF_ARRAY(locationsGroups); ++groupNdx) { // Single subpass cases for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx) { VerifySamples::TestParams::SampleCount samples; samples.numColorSamples = singlePassCases[caseNdx].colorSamples; samples.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples; samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples); VerifySamples::TestParams params; params.perSubpassSamples.push_back(samples); params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get()); params.useFragmentShadingRate = useFragmentShadingRate; MovePtr sampleCaseGroup(new tcu::TestCaseGroup( rootGroup->getTestContext(), getSampleCountGroupName(samples.numCoverageSamples, samples.numColorSamples, samples.numDepthStencilSamples).c_str(), "")); for (const VkFormat *pDepthStencilFormat = depthStencilFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilFormatRange); ++pDepthStencilFormat) for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat) { params.colorFormat = *pColorFormat; params.depthStencilFormat = *pDepthStencilFormat; addFunctionCaseWithPrograms( sampleCaseGroup.get(), getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(), "", VerifySamples::checkRequirements, VerifySamples::initPrograms, VerifySamples::test, params); } locationsGroups[groupNdx]->addChild(sampleCaseGroup.release()); } // Multi subpass cases for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(subpassCases); ++caseNdx) { VerifySamples::TestParams params; params.useProgrammableSampleLocations = (locationsGroups[groupNdx] == programmableLocationsGroup.get()); params.useFragmentShadingRate = useFragmentShadingRate; for (deUint32 subpassNdx = 0; subpassNdx < subpassCases[caseNdx].numSampleCases; ++subpassNdx) { VerifySamples::TestParams::SampleCount samples; samples.numColorSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].colorSamples; samples.numDepthStencilSamples = subpassCases[caseNdx].pSampleCase[subpassNdx].depthStencilSamples; samples.numCoverageSamples = de::max(samples.numColorSamples, samples.numDepthStencilSamples); params.perSubpassSamples.push_back(samples); } MovePtr sampleCaseGroup(new tcu::TestCaseGroup(rootGroup->getTestContext(), subpassCases[caseNdx].caseName, "")); for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat) for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat) { params.colorFormat = *pColorFormat; params.depthStencilFormat = *pDepthStencilFormat; addFunctionCaseWithPrograms( sampleCaseGroup.get(), getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(), "", VerifySamples::checkRequirements, VerifySamples::initPrograms, VerifySamples::test, params); } locationsGroups[groupNdx]->addChild(sampleCaseGroup.release()); } } rootGroup->addChild(standardLocationsGroup.release()); rootGroup->addChild(programmableLocationsGroup.release()); } // Test 2: Shader built-ins check if (!useFragmentShadingRate) { MovePtr builtinsGroup (new tcu::TestCaseGroup(rootGroup->getTestContext(), "shader_builtins", "")); for (deUint32 caseNdx = 0u; caseNdx < DE_LENGTH_OF_ARRAY(singlePassCases); ++caseNdx) { ShaderBuiltins::TestParams params; params.numColorSamples = singlePassCases[caseNdx].colorSamples; params.numDepthStencilSamples = singlePassCases[caseNdx].depthStencilSamples; params.numCoverageSamples = de::max(params.numColorSamples, params.numDepthStencilSamples); MovePtr sampleCaseGroup(new tcu::TestCaseGroup( rootGroup->getTestContext(), getSampleCountGroupName(params.numCoverageSamples, params.numColorSamples, params.numDepthStencilSamples).c_str(), "")); for (const VkFormat *pDepthStencilFormat = depthStencilReducedFormatRange; pDepthStencilFormat != DE_ARRAY_END(depthStencilReducedFormatRange); ++pDepthStencilFormat) for (const VkFormat *pColorFormat = colorFormatRange; pColorFormat != DE_ARRAY_END(colorFormatRange); ++pColorFormat) { params.colorFormat = *pColorFormat; params.depthStencilFormat = *pDepthStencilFormat; addFunctionCaseWithPrograms( sampleCaseGroup.get(), getFormatCaseName(params.colorFormat, params.depthStencilFormat).c_str(), "", ShaderBuiltins::checkRequirements, ShaderBuiltins::initPrograms, ShaderBuiltins::test, params); } builtinsGroup->addChild(sampleCaseGroup.release()); } rootGroup->addChild(builtinsGroup.release()); } } } // anonymous ns tcu::TestCaseGroup* createMultisampleMixedAttachmentSamplesTests (tcu::TestContext& testCtx, bool useFragmentShadingRate) { return createTestGroup(testCtx, "mixed_attachment_samples", "Test a graphics pipeline with varying sample count per color and depth/stencil attachments", createMixedAttachmentSamplesTestsInGroup, useFragmentShadingRate); } } // pipeline } // vkt