/*------------------------------------------------------------------------ * Vulkan Conformance Tests * ------------------------ * * Copyright (c) 2019 The Khronos Group Inc. * Copyright (c) 2019 Google LLC. * * 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 provoking vertex *//*--------------------------------------------------------------------*/ #include "vktRasterizationProvokingVertexTests.hpp" #include "vkBarrierUtil.hpp" #include "vkCmdUtil.hpp" #include "vkImageUtil.hpp" #include "vkObjUtil.hpp" #include "vkQueryUtil.hpp" #include "vkRefUtil.hpp" #include "vkTypeUtil.hpp" #include "vktTestGroupUtil.hpp" #include "tcuRGBA.hpp" #include "tcuSurface.hpp" #include "tcuTextureUtil.hpp" #include "tcuTestLog.hpp" using namespace vk; namespace vkt { namespace rasterization { namespace { enum ProvokingVertexMode { PROVOKING_VERTEX_DEFAULT, PROVOKING_VERTEX_FIRST, PROVOKING_VERTEX_LAST, PROVOKING_VERTEX_PER_PIPELINE }; struct Params { VkFormat format; tcu::UVec2 size; VkPrimitiveTopology primitiveTopology; bool requireGeometryShader; bool transformFeedback; ProvokingVertexMode provokingVertexMode; }; static VkDeviceSize getXfbBufferSize (deUint32 vertexCount, VkPrimitiveTopology topology) { switch (topology) { case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: return vertexCount * sizeof(tcu::Vec4); case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: return (vertexCount - 1) * 2 * sizeof(tcu::Vec4); case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: return (vertexCount - 2) * 3 * sizeof(tcu::Vec4); case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: return vertexCount / 2 * sizeof(tcu::Vec4); case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: return (vertexCount - 3) * 2 * sizeof(tcu::Vec4); case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: return (vertexCount / 2 - 2) * 3 * sizeof(tcu::Vec4); default: DE_FATAL("Unknown primitive topology"); return 0; } } static bool verifyXfbBuffer (const tcu::Vec4* const xfbResults, deUint32 count, VkPrimitiveTopology topology, ProvokingVertexMode mode, std::string& errorMessage) { const deUint32 primitiveSize = ((topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) || (topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) || (topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY) || (topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY)) ? 2 : 3; const tcu::Vec4 expected (1.0f, 0.0f, 0.0f, 1.0f); const deUint32 start = (mode == PROVOKING_VERTEX_LAST) ? primitiveSize - 1 : 0; DE_ASSERT(count % primitiveSize == 0); for (deUint32 ndx = start; ndx < count; ndx += primitiveSize) { if (xfbResults[ndx] != expected) { errorMessage = "Vertex " + de::toString(ndx) + ": Expected red, got " + de::toString(xfbResults[ndx]); return false; } } errorMessage = ""; return true; } class ProvokingVertexTestInstance : public TestInstance { public: ProvokingVertexTestInstance (Context& context, Params params); tcu::TestStatus iterate (void); Move makeRenderPass (const DeviceInterface& vk, const VkDevice device); private: Params m_params; }; ProvokingVertexTestInstance::ProvokingVertexTestInstance (Context& context, Params params) : TestInstance (context) , m_params (params) { } class ProvokingVertexTestCase : public TestCase { public: ProvokingVertexTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Params params); virtual void initPrograms (SourceCollections& programCollection) const; virtual void checkSupport (Context& context) const; virtual TestInstance* createInstance (Context& context) const; private: const Params m_params; }; ProvokingVertexTestCase::ProvokingVertexTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Params params) : TestCase (testCtx, name, description) , m_params (params) { } void ProvokingVertexTestCase::initPrograms (SourceCollections& programCollection) const { std::ostringstream vertShader; vertShader << "#version 450\n" << "layout(location = 0) in vec4 in_position;\n" << "layout(location = 1) in vec4 in_color;\n" << "layout(location = 0) flat out vec4 out_color;\n"; if (m_params.transformFeedback) vertShader << "layout(xfb_buffer = 0, xfb_offset = 0, location = 1) out vec4 out_xfb;\n"; vertShader << "void main()\n" << "{\n"; if (m_params.transformFeedback) vertShader << " out_xfb = in_color;\n"; vertShader << " out_color = in_color;\n" << " gl_Position = in_position;\n" << "}\n"; const std::string fragShader ( "#version 450\n" "layout(location = 0) flat in vec4 in_color;\n" "layout(location = 0) out vec4 out_color;\n" "void main()\n" "{\n" " out_color = in_color;\n" "}\n"); programCollection.glslSources.add("vert") << glu::VertexSource(vertShader.str()); programCollection.glslSources.add("frag") << glu::FragmentSource(fragShader); } void ProvokingVertexTestCase::checkSupport (Context& context) const { if (m_params.requireGeometryShader) context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER); if (m_params.transformFeedback) context.requireDeviceFunctionality("VK_EXT_transform_feedback"); if (m_params.provokingVertexMode != PROVOKING_VERTEX_DEFAULT) { const VkPhysicalDeviceProvokingVertexFeaturesEXT& features = context.getProvokingVertexFeaturesEXT(); const VkPhysicalDeviceProvokingVertexPropertiesEXT& properties = context.getProvokingVertexPropertiesEXT(); context.requireDeviceFunctionality("VK_EXT_provoking_vertex"); if (m_params.transformFeedback && features.transformFeedbackPreservesProvokingVertex != VK_TRUE) TCU_THROW(NotSupportedError, "transformFeedbackPreservesProvokingVertex not supported"); if (m_params.transformFeedback && (m_params.primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) && (properties.transformFeedbackPreservesTriangleFanProvokingVertex != VK_TRUE)) TCU_THROW(NotSupportedError, "transformFeedbackPreservesTriangleFanProvokingVertex not supported"); if (m_params.provokingVertexMode != PROVOKING_VERTEX_FIRST) { if (features.provokingVertexLast != VK_TRUE) TCU_THROW(NotSupportedError, "VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT not supported"); if ((m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE) && (properties.provokingVertexModePerPipeline != VK_TRUE)) TCU_THROW(NotSupportedError, "provokingVertexModePerPipeline not supported"); } } if (m_params.primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getPortabilitySubsetFeatures().triangleFans) { TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation"); } } TestInstance* ProvokingVertexTestCase::createInstance (Context& context) const { return new ProvokingVertexTestInstance(context, m_params); } tcu::TestStatus ProvokingVertexTestInstance::iterate (void) { const bool useProvokingVertexExt = (m_params.provokingVertexMode != PROVOKING_VERTEX_DEFAULT); const DeviceInterface& vk = m_context.getDeviceInterface(); const VkDevice device = m_context.getDevice(); const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex(); const tcu::TextureFormat textureFormat = vk::mapVkFormat(m_params.format); const VkDeviceSize counterBufferOffset = 0u; Allocator& allocator = m_context.getDefaultAllocator(); Move image; Move imageView; de::MovePtr imageMemory; Move resultBuffer; de::MovePtr resultBufferMemory; Move xfbBuffer; de::MovePtr xfbBufferMemory; VkDeviceSize xfbBufferSize = 0; Move counterBuffer; de::MovePtr counterBufferMemory; Move vertexBuffer; de::MovePtr vertexBufferMemory; Move renderPass; Move framebuffer; Move pipeline; Move altPipeline; deUint32 vertexCount = 0; // Image { const VkExtent3D extent = makeExtent3D(m_params.size.x(), m_params.size.y(), 1u); const VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; const VkImageCreateInfo createInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType DE_NULL, // pNext 0u, // flags VK_IMAGE_TYPE_2D, // imageType m_params.format, // format extent, // extent 1u, // mipLevels 1u, // arrayLayers VK_SAMPLE_COUNT_1_BIT, // samples VK_IMAGE_TILING_OPTIMAL, // tiling usage, // usage VK_SHARING_MODE_EXCLUSIVE, // sharingMode 1u, // queueFamilyIndexCount &queueFamilyIndex, // pQueueFamilyIndices VK_IMAGE_LAYOUT_UNDEFINED // initialLayout }; image = createImage(vk, device, &createInfo, DE_NULL); imageMemory = allocator.allocate(getImageMemoryRequirements(vk, device, *image), MemoryRequirement::Any); VK_CHECK(vk.bindImageMemory(device, *image, imageMemory->getMemory(), imageMemory->getOffset())); } // Image view { const VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 0u, // baseMipLevel 1u, // mipLevels 0u, // baseArrayLayer 1u // arraySize }; imageView = makeImageView(vk, device, *image, VK_IMAGE_VIEW_TYPE_2D, m_params.format, subresourceRange, DE_NULL); } // Result Buffer { const VkDeviceSize bufferSize = textureFormat.getPixelSize() * m_params.size.x() * m_params.size.y(); const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT); resultBuffer = createBuffer(vk, device, &createInfo); resultBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset())); } // Render pass, framebuffer and pipelines { const Unique vertexShader (createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0)); const Unique fragmentShader (createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0)); const std::vector viewports (1, makeViewport(tcu::UVec2(m_params.size))); const std::vector scissors (1, makeRect2D(tcu::UVec2(m_params.size))); const Move pipelineLayout = makePipelineLayout(vk, device, 0, DE_NULL); const VkVertexInputBindingDescription vertexInputBindingDescription = { 0, // binding sizeof(tcu::Vec4) * 2, // strideInBytes VK_VERTEX_INPUT_RATE_VERTEX // stepRate }; const VkVertexInputAttributeDescription vertexAttributeDescriptions[2] = { // Position { 0u, // location 0u, // binding VK_FORMAT_R32G32B32A32_SFLOAT, // format 0u // offsetInBytes }, // Color { 1u, // location 0u, // binding VK_FORMAT_R32G32B32A32_SFLOAT, // format sizeof(tcu::Vec4) // offsetInBytes } }; const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType DE_NULL, // pNext 0, // flags 1u, // bindingCount &vertexInputBindingDescription, // pVertexBindingDescriptions 2u, // attributeCount vertexAttributeDescriptions // pVertexAttributeDescriptions }; const VkProvokingVertexModeEXT provokingVertexMode = m_params.provokingVertexMode == PROVOKING_VERTEX_LAST ? VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT : VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT; const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, // sType DE_NULL, // pNext provokingVertexMode // provokingVertexMode }; const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType useProvokingVertexExt ? &provokingVertexCreateInfo : DE_NULL, // pNext 0, // flags false, // depthClipEnable false, // rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // fillMode VK_CULL_MODE_NONE, // cullMode VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace VK_FALSE, // depthBiasEnable 0.0f, // depthBias 0.0f, // depthBiasClamp 0.0f, // slopeScaledDepthBias 1.0f // lineWidth }; renderPass = ProvokingVertexTestInstance::makeRenderPass(vk, device); framebuffer = makeFramebuffer(vk, device, *renderPass, *imageView, m_params.size.x(), m_params.size.y(), 1u); pipeline = makeGraphicsPipeline(vk, device, *pipelineLayout, *vertexShader, DE_NULL, // tessellationControlShaderModule DE_NULL, // tessellationEvalShaderModule DE_NULL, // geometryShaderModule *fragmentShader, *renderPass, viewports, scissors, m_params.primitiveTopology, 0u, // subpass 0u, // patchControlPoints &vertexInputStateParams, &rasterizationStateCreateInfo, DE_NULL, // multisampleStateCreateInfo DE_NULL, // depthStencilStateCreateInfo DE_NULL, // colorBlendStateCreateInfo DE_NULL); // dynamicStateCreateInfo if (m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE) { const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT altProvokingVertexCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, // sType DE_NULL, // pNext VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT // provokingVertexMode }; const VkPipelineRasterizationStateCreateInfo altRasterizationStateCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType &altProvokingVertexCreateInfo, // pNext 0, // flags false, // depthClipEnable false, // rasterizerDiscardEnable VK_POLYGON_MODE_FILL, // fillMode VK_CULL_MODE_NONE, // cullMode VK_FRONT_FACE_COUNTER_CLOCKWISE, // frontFace VK_FALSE, // depthBiasEnable 0.0f, // depthBias 0.0f, // depthBiasClamp 0.0f, // slopeScaledDepthBias 1.0f, // lineWidth }; altPipeline = makeGraphicsPipeline(vk, device, *pipelineLayout, *vertexShader, DE_NULL, // tessellationControlShaderModule DE_NULL, // tessellationEvalShaderModule DE_NULL, // geometryShaderModule *fragmentShader, *renderPass, viewports, scissors, m_params.primitiveTopology, 0u, // subpass 0u, // patchControlPoints &vertexInputStateParams, &altRasterizationStateCreateInfo, DE_NULL, // multisampleStateCreateInfo DE_NULL, // depthStencilStateCreateInfo DE_NULL, // colorBlendStateCreateInfo DE_NULL); // dynamicStateCreateInfo } } // Vertex buffer { const tcu::Vec4 red (1.0f, 0.0f, 0.0f, 1.0f); const tcu::Vec4 green (0.0f, 1.0f, 0.0f, 1.0f); const tcu::Vec4 blue (0.0f, 0.0f, 1.0f, 1.0f); const tcu::Vec4 yellow (1.0f, 1.0f, 0.0f, 1.0f); const tcu::Vec4 white (1.0f, 1.0f, 1.0f, 1.0f); std::vector vertices; switch (m_params.primitiveTopology) { case VK_PRIMITIVE_TOPOLOGY_LINE_LIST: // Position //Color vertices.push_back(tcu::Vec4(-1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); // line 0 vertices.push_back(tcu::Vec4( 1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); // line 1 vertices.push_back(tcu::Vec4( 1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // line 1 reverse vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // line 0 reverse vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); break; case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP: // Position // Color vertices.push_back(tcu::Vec4(-1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); // line strip vertices.push_back(tcu::Vec4( 1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); // line strip reverse vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: // Position // Color vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle 0 vertices.push_back(tcu::Vec4(-0.6f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4(-0.2f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.2f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle 1 vertices.push_back(tcu::Vec4( 0.6f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle 1 reverse vertices.push_back(tcu::Vec4(-0.6f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4(-0.2f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.2f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle 0 reverse vertices.push_back(tcu::Vec4( 0.6f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP: // Position // Color vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle strip vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle strip reverse vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN: // Position // Color vertices.push_back(tcu::Vec4( 0.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); // triangle fan vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); // triangle fan reverse vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); break; case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY: // Position // Color vertices.push_back(tcu::Vec4(-1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(green); // line 0 vertices.push_back(tcu::Vec4(-0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(yellow); vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(green); // line 1 vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(yellow); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(yellow); // line 1 reverse vertices.push_back(tcu::Vec4(-0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(yellow); // line 0 reverse vertices.push_back(tcu::Vec4( 0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); break; case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY: // Position // Color vertices.push_back(tcu::Vec4(-1.0f,-0.5f, 0.0f, 1.0f)); vertices.push_back(green); // line strip vertices.push_back(tcu::Vec4(-0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 1.0f, 0.5f, 0.0f, 1.0f)); vertices.push_back(yellow); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(yellow); // line strip reverse vertices.push_back(tcu::Vec4(-0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f,-0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 0.5f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY: // Position // Color vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle 0 vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.6f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.2f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.2f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle 1 vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.6f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle 1 reverse vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.6f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.2f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.2f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle 0 reverse vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.6f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); break; case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY: // Position // Color vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); // triangle strip vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.5f,-1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 1.0f, 1.0f, 0.0f, 1.0f)); vertices.push_back(blue); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(blue); // triangle strip reverse vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(green); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 0.5f, 1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); vertices.push_back(tcu::Vec4( 1.0f,-1.0f, 0.0f, 1.0f)); vertices.push_back(red); vertices.push_back(tcu::Vec4( 0.0f, 0.0f, 0.0f, 1.0f)); vertices.push_back(white); break; default: DE_FATAL("Unknown primitive topology"); } const size_t bufferSize = vertices.size() * sizeof(tcu::Vec4); const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); vertexCount = (deUint32)vertices.size() / 4; vertexBuffer = createBuffer(vk, device, &createInfo); vertexBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *vertexBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(device, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset())); deMemcpy(vertexBufferMemory->getHostPtr(), &vertices[0], bufferSize); flushAlloc(vk, device, *vertexBufferMemory); } // Transform feedback and counter buffers if (m_params.transformFeedback) { xfbBufferSize = getXfbBufferSize(vertexCount, m_params.primitiveTopology); if (m_params.provokingVertexMode ==PROVOKING_VERTEX_PER_PIPELINE) xfbBufferSize = xfbBufferSize * 2; const int xfbBufferUsage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; const VkBufferCreateInfo xfbCreateInfo = makeBufferCreateInfo(xfbBufferSize, xfbBufferUsage); const VkDeviceSize counterBufferSize = 16 * sizeof(deUint32); const VkBufferCreateInfo counterBufferInfo = makeBufferCreateInfo(counterBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT); xfbBuffer = createBuffer(vk, device, &xfbCreateInfo); xfbBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *xfbBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(device, *xfbBuffer, xfbBufferMemory->getMemory(), xfbBufferMemory->getOffset())); counterBuffer = createBuffer(vk, device, &counterBufferInfo); counterBufferMemory = allocator.allocate(getBufferMemoryRequirements(vk, device, *counterBuffer), MemoryRequirement::HostVisible); VK_CHECK(vk.bindBufferMemory(device, *counterBuffer, counterBufferMemory->getMemory(), counterBufferMemory->getOffset())); // Make sure uninitialized values are not read when starting XFB for the first time. deMemset(counterBufferMemory->getHostPtr(), 0, static_cast(counterBufferSize)); flushAlloc(vk, device, *counterBufferMemory); } // Clear the color buffer to red and check the drawing doesn't add any // other colors from non-provoking vertices { const VkQueue queue = m_context.getUniversalQueue(); const VkRect2D renderArea = makeRect2D(m_params.size.x(), m_params.size.y()); const VkDeviceSize vertexBufferOffset = 0; const VkClearValue clearValue = makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f)); const VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; const VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; const VkImageSubresourceRange subResourcerange = { VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 0, // baseMipLevel 1, // levelCount 0, // baseArrayLayer 1 // layerCount }; const VkImageMemoryBarrier imageBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType DE_NULL, // pNext 0, // srcAccessMask VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout VK_QUEUE_FAMILY_IGNORED, // srcQueueFamilyIndex VK_QUEUE_FAMILY_IGNORED, // destQueueFamilyIndex *image, // image subResourcerange // subresourceRange }; const VkMemoryBarrier xfbMemoryBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT); const VkMemoryBarrier counterBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT); // The first half of the vertex buffer is for PROVOKING_VERTEX_FIRST, // the second half for PROVOKING_VERTEX_LAST const deUint32 firstVertex = m_params.provokingVertexMode == PROVOKING_VERTEX_LAST ? vertexCount : 0u; Move commandPool = makeCommandPool(vk, device, queueFamilyIndex); Move commandBuffer = allocateCommandBuffer(vk, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY); beginCommandBuffer(vk, *commandBuffer, 0u); { vk.cmdPipelineBarrier(*commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier); beginRenderPass(vk, *commandBuffer, *renderPass, *framebuffer, renderArea, 1, &clearValue); { vk.cmdBindVertexBuffers(*commandBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset); vk.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); if (m_params.transformFeedback) { const VkDeviceSize xfbBufferOffset = 0; vk.cmdBindTransformFeedbackBuffersEXT(*commandBuffer, 0, 1, &*xfbBuffer, &xfbBufferOffset, &xfbBufferSize); vk.cmdBeginTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset); } vk.cmdDraw(*commandBuffer, vertexCount, 1u, firstVertex, 0u); if (m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE) { // vkCmdBindPipeline must not be recorded when transform feedback is active. if (m_params.transformFeedback) { vk.cmdEndTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset); vk.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, 0u, 1u, &counterBarrier, 0u, DE_NULL, 0u, DE_NULL); } vk.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *altPipeline); if (m_params.transformFeedback) vk.cmdBeginTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset); vk.cmdDraw(*commandBuffer, vertexCount, 1u, vertexCount, 0u); } if (m_params.transformFeedback) vk.cmdEndTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset); } endRenderPass(vk, *commandBuffer); if (m_params.transformFeedback) vk.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &xfbMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL); copyImageToBuffer(vk, *commandBuffer, *image, *resultBuffer, tcu::IVec2(m_params.size.x(), m_params.size.y())); } endCommandBuffer(vk, *commandBuffer); submitCommandsAndWait(vk, device, queue, commandBuffer.get()); invalidateAlloc(vk, device, *resultBufferMemory); if (m_params.transformFeedback) invalidateAlloc(vk, device, *xfbBufferMemory); } // Verify result { tcu::TestLog& log = m_context.getTestContext().getLog(); const size_t bufferSize = textureFormat.getPixelSize() * m_params.size.x() * m_params.size.y(); tcu::Surface referenceSurface (m_params.size.x(), m_params.size.y()); tcu::ConstPixelBufferAccess referenceAccess = referenceSurface.getAccess(); tcu::Surface resultSurface (m_params.size.x(), m_params.size.y()); tcu::ConstPixelBufferAccess resultAccess (textureFormat, tcu::IVec3(m_params.size.x(), m_params.size.y(), 1), resultBufferMemory->getHostPtr()); // Verify transform feedback buffer if (m_params.transformFeedback) { const tcu::Vec4* const xfbResults = static_cast(xfbBufferMemory->getHostPtr()); const deUint32 count = static_cast(xfbBufferSize / sizeof(tcu::Vec4)); std::string errorMessage = ""; log << tcu::TestLog::Section("XFB Vertex colors", "vertex colors"); for (deUint32 i = 0; i < count; i++) { log << tcu::TestLog::Message << "[" << de::toString(i) << "]\t" << de::toString(xfbResults[i]) << tcu::TestLog::EndMessage; } log << tcu::TestLog::EndSection; if (m_params.provokingVertexMode != PROVOKING_VERTEX_PER_PIPELINE) { if (!verifyXfbBuffer(xfbResults, count, m_params.primitiveTopology, m_params.provokingVertexMode, errorMessage)) return tcu::TestStatus::fail(errorMessage); } else { const deUint32 halfCount = count / 2; if (!verifyXfbBuffer(xfbResults, halfCount, m_params.primitiveTopology, PROVOKING_VERTEX_FIRST, errorMessage)) return tcu::TestStatus::fail(errorMessage); if (!verifyXfbBuffer(&xfbResults[halfCount], halfCount, m_params.primitiveTopology, PROVOKING_VERTEX_LAST, errorMessage)) return tcu::TestStatus::fail(errorMessage); } } // Create reference for (deUint32 y = 0; y < m_params.size.y(); y++) for (deUint32 x = 0; x < m_params.size.x(); x++) referenceSurface.setPixel(x, y, tcu::RGBA::red()); // Copy result tcu::copy(resultSurface.getAccess(), resultAccess); // Compare if (deMemCmp(referenceAccess.getDataPtr(), resultAccess.getDataPtr(), bufferSize) != 0) { log << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering") << tcu::TestLog::Image("Result", "Result", resultSurface) << tcu::TestLog::EndImageSet; return tcu::TestStatus::fail("Incorrect rendering"); } } return tcu::TestStatus::pass("Solid red"); } // Copied from vkObjUtil.cpp with an additional subpass. Move ProvokingVertexTestInstance::makeRenderPass (const DeviceInterface& vk, const VkDevice device) { const VkAttachmentDescription colorAttachmentDescription = { (VkAttachmentDescriptionFlags)0, // VkAttachmentDescriptionFlags flags m_params.format, // VkFormat format VK_SAMPLE_COUNT_1_BIT, // 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_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout }; const VkAttachmentReference colorAttachmentRef = { 0u, // deUint32 attachment VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout }; const VkSubpassDescription subpassDescription = { (VkSubpassDescriptionFlags)0, // VkSubpassDescriptionFlags flags VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint 0u, // deUint32 inputAttachmentCount DE_NULL, // const VkAttachmentReference* pInputAttachments 1u, // deUint32 colorAttachmentCount &colorAttachmentRef, // const VkAttachmentReference* pColorAttachments DE_NULL, // const VkAttachmentReference* pResolveAttachments DE_NULL, // const VkAttachmentReference* pDepthStencilAttachment 0u, // deUint32 preserveAttachmentCount DE_NULL // const deUint32* pPreserveAttachments }; const VkSubpassDependency selfDependency = { 0u, // deUint32 srcSubpass 0u, // deUint32 dstSubpass VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, // VkPipelineStageFlags srcStageMask VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, // VkPipelineStageFlags dstStageMask VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, // VkAccessFlags srcAccessMask VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, // VkAccessFlags dstAccessMask 0u // VkDependencyFlags dependencyFlags }; const bool xfbPerPipeline = m_params.transformFeedback && m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE; const VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType DE_NULL, // const void* pNext (VkRenderPassCreateFlags)0, // VkRenderPassCreateFlags flags 1u, // deUint32 attachmentCount &colorAttachmentDescription, // const VkAttachmentDescription* pAttachments 1u, // deUint32 subpassCount &subpassDescription, // const VkSubpassDescription* pSubpasses xfbPerPipeline ? 1u : 0u, // deUint32 dependencyCount xfbPerPipeline ? &selfDependency : DE_NULL // const VkSubpassDependency* pDependencies }; return createRenderPass(vk, device, &renderPassInfo, DE_NULL); } void createTests (tcu::TestCaseGroup* testGroup) { tcu::TestContext& testCtx = testGroup->getTestContext(); const struct Provoking { const char* name; const char* desc; ProvokingVertexMode mode; } provokingVertexModes[] = { { "default", "Default provoking vertex convention", PROVOKING_VERTEX_DEFAULT, }, { "first", "VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT", PROVOKING_VERTEX_FIRST, }, { "last", "VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT", PROVOKING_VERTEX_LAST, }, { "per_pipeline", "Pipelines with different provokingVertexModes", PROVOKING_VERTEX_PER_PIPELINE } }; const struct Topology { std::string name; VkPrimitiveTopology type; bool requiresGeometryShader; } topologies[] = { { "line_list", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, false }, { "line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, false }, { "triangle_list", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, false }, { "triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, false }, { "triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, false }, { "line_list_with_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, true }, { "line_strip_with_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, true }, { "triangle_list_with_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, true }, { "triangle_strip_with_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, true } }; const struct TestType { const char* name; const char* desc; bool transformFeedback; } testTypes[] = { { "draw", "Test that primitives are flat shaded with the provoking vertex color", false }, { "transform_feedback", "Test that transform feedback preserves the position of the provoking vertex", true } }; for (const TestType& testType: testTypes) { tcu::TestCaseGroup* const typeGroup = new tcu::TestCaseGroup(testCtx, testType.name, testType.desc); for (const Provoking& provoking : provokingVertexModes) { // Only test transformFeedbackPreservesProvokingVertex with VK_EXT_provoking_vertex if (testType.transformFeedback && (provoking.mode == PROVOKING_VERTEX_DEFAULT)) continue; tcu::TestCaseGroup* const provokingGroup = new tcu::TestCaseGroup(testCtx, provoking.name, provoking.desc); for (const Topology& topology : topologies) { const std::string caseName = topology.name; const std::string caseDesc = getPrimitiveTopologyName(topology.type); const Params params = { VK_FORMAT_R8G8B8A8_UNORM, // format tcu::UVec2(32, 32), // size topology.type, // primitiveTopology topology.requiresGeometryShader, // requireGeometryShader testType.transformFeedback, // transformFeedback provoking.mode // provokingVertexMode }; provokingGroup->addChild(new ProvokingVertexTestCase(testCtx, caseName, caseDesc, params)); } typeGroup->addChild(provokingGroup); } testGroup->addChild(typeGroup); } } } // anonymous tcu::TestCaseGroup* createProvokingVertexTests (tcu::TestContext& testCtx) { return createTestGroup(testCtx, "provoking_vertex", "Tests for provoking vertex", createTests); } } // rasterization } // vkt