1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 The Khronos Group Inc.
6  * Copyright (c) 2019 Google LLC.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tests for provoking vertex
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktRasterizationProvokingVertexTests.hpp"
26 
27 #include "deDefs.h"
28 #include "deStringUtil.hpp"
29 #include "vkBarrierUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vktTestGroupUtil.hpp"
37 #include "tcuRGBA.hpp"
38 #include "tcuSurface.hpp"
39 #include "tcuTextureUtil.hpp"
40 #include "tcuTestLog.hpp"
41 
42 using namespace vk;
43 
44 namespace vkt
45 {
46 namespace rasterization
47 {
48 namespace
49 {
50 
51 enum ProvokingVertexMode
52 {
53     PROVOKING_VERTEX_DEFAULT,
54     PROVOKING_VERTEX_FIRST,
55     PROVOKING_VERTEX_LAST,
56     PROVOKING_VERTEX_PER_PIPELINE
57 };
58 
59 struct Params
60 {
61     VkFormat format;
62     tcu::UVec2 size;
63     VkPrimitiveTopology primitiveTopology;
64     bool requireGeometryShader;
65     bool transformFeedback;
66     ProvokingVertexMode provokingVertexMode;
67 };
68 
getXfbBufferSize(uint32_t vertexCount,VkPrimitiveTopology topology)69 static VkDeviceSize getXfbBufferSize(uint32_t vertexCount, VkPrimitiveTopology topology)
70 {
71     switch (topology)
72     {
73     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
74     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
75         return vertexCount * sizeof(tcu::Vec4);
76     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
77         return (vertexCount - 1) * 2 * sizeof(tcu::Vec4);
78     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
79     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
80         return (vertexCount - 2) * 3 * sizeof(tcu::Vec4);
81     case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
82     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
83         return vertexCount / 2 * sizeof(tcu::Vec4);
84     case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
85         return (vertexCount - 3) * 2 * sizeof(tcu::Vec4);
86     case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
87         return (vertexCount / 2 - 2) * 3 * sizeof(tcu::Vec4);
88     default:
89         DE_FATAL("Unknown primitive topology");
90         return 0;
91     }
92 }
93 
verifyXfbBuffer(const tcu::Vec4 * const xfbResults,const std::vector<tcu::Vec4> & vertices,const std::vector<size_t> & provoking,uint32_t count,VkPrimitiveTopology topology,ProvokingVertexMode mode,std::string & errorMessage)94 static bool verifyXfbBuffer(const tcu::Vec4 *const xfbResults, const std::vector<tcu::Vec4> &vertices,
95                             const std::vector<size_t> &provoking, uint32_t count, VkPrimitiveTopology topology,
96                             ProvokingVertexMode mode, std::string &errorMessage)
97 {
98     const uint32_t primitiveSize =
99         ((topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) || (topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP) ||
100          (topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY) ||
101          (topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY)) ?
102             2 :
103             3;
104 
105     const uint32_t start = (mode == PROVOKING_VERTEX_LAST) ? primitiveSize - 1 : 0;
106     const uint32_t provStart =
107         (mode == PROVOKING_VERTEX_LAST) ?
108             ((topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST) || (topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST) ||
109              (topology == VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY) ||
110              (topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY)) ?
111             2 :
112             3 :
113             0;
114 
115     DE_ASSERT(count % primitiveSize == 0);
116 
117     uint32_t i = 0;
118     for (uint32_t ndx = start; ndx < count; ndx += primitiveSize)
119     {
120         if (xfbResults[ndx] != vertices[provoking[i + provStart]])
121         {
122             errorMessage = "Vertex " + de::toString(ndx) + ": Expected " +
123                            de::toString(vertices[provoking[i + provStart]]) + ", got " + de::toString(xfbResults[ndx]);
124             return false;
125         }
126         i++;
127     }
128     errorMessage = "";
129     return true;
130 }
131 
132 class ProvokingVertexTestInstance : public TestInstance
133 {
134 public:
135     ProvokingVertexTestInstance(Context &context, Params params);
136     tcu::TestStatus iterate(void);
137     Move<VkRenderPass> makeRenderPass(const DeviceInterface &vk, const VkDevice device);
138 
139 private:
140     Params m_params;
141 };
142 
ProvokingVertexTestInstance(Context & context,Params params)143 ProvokingVertexTestInstance::ProvokingVertexTestInstance(Context &context, Params params)
144     : TestInstance(context)
145     , m_params(params)
146 {
147 }
148 
149 class ProvokingVertexTestCase : public TestCase
150 {
151 public:
152     ProvokingVertexTestCase(tcu::TestContext &testCtx, const std::string &name, const Params params);
153     virtual void initPrograms(SourceCollections &programCollection) const;
154     virtual void checkSupport(Context &context) const;
155     virtual TestInstance *createInstance(Context &context) const;
156 
157 private:
158     const Params m_params;
159 };
160 
ProvokingVertexTestCase(tcu::TestContext & testCtx,const std::string & name,const Params params)161 ProvokingVertexTestCase::ProvokingVertexTestCase(tcu::TestContext &testCtx, const std::string &name,
162                                                  const Params params)
163     : TestCase(testCtx, name)
164     , m_params(params)
165 {
166 }
167 
initPrograms(SourceCollections & programCollection) const168 void ProvokingVertexTestCase::initPrograms(SourceCollections &programCollection) const
169 {
170     std::ostringstream vertShader;
171 
172     vertShader << "#version 450\n"
173                << "layout(location = 0) in vec4 in_position;\n"
174                << "layout(location = 1) in vec4 in_color;\n"
175                << "layout(location = 0) flat out vec4 out_color;\n";
176 
177     if (m_params.transformFeedback)
178         vertShader << "layout(xfb_buffer = 0, xfb_offset = 0, location = 1) out vec4 out_xfb;\n";
179 
180     vertShader << "void main()\n"
181                << "{\n";
182 
183     if (m_params.transformFeedback)
184         vertShader << "    out_xfb = in_position;\n";
185 
186     vertShader << "    out_color = in_color;\n"
187                << "    gl_Position = in_position;\n"
188                << "}\n";
189 
190     const std::string fragShader("#version 450\n"
191                                  "layout(location = 0) flat in vec4 in_color;\n"
192                                  "layout(location = 0) out vec4 out_color;\n"
193                                  "void main()\n"
194                                  "{\n"
195                                  "    out_color = in_color;\n"
196                                  "}\n");
197 
198     programCollection.glslSources.add("vert") << glu::VertexSource(vertShader.str());
199     programCollection.glslSources.add("frag") << glu::FragmentSource(fragShader);
200 }
201 
checkSupport(Context & context) const202 void ProvokingVertexTestCase::checkSupport(Context &context) const
203 {
204     if (m_params.requireGeometryShader)
205         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
206 
207     if (m_params.transformFeedback)
208         context.requireDeviceFunctionality("VK_EXT_transform_feedback");
209 
210     if (m_params.provokingVertexMode != PROVOKING_VERTEX_DEFAULT)
211     {
212         const VkPhysicalDeviceProvokingVertexFeaturesEXT &features     = context.getProvokingVertexFeaturesEXT();
213         const VkPhysicalDeviceProvokingVertexPropertiesEXT &properties = context.getProvokingVertexPropertiesEXT();
214 
215         context.requireDeviceFunctionality("VK_EXT_provoking_vertex");
216 
217         if (m_params.transformFeedback && features.transformFeedbackPreservesProvokingVertex != VK_TRUE)
218             TCU_THROW(NotSupportedError, "transformFeedbackPreservesProvokingVertex not supported");
219 
220         if (m_params.transformFeedback && (m_params.primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) &&
221             (properties.transformFeedbackPreservesTriangleFanProvokingVertex != VK_TRUE))
222             TCU_THROW(NotSupportedError, "transformFeedbackPreservesTriangleFanProvokingVertex not supported");
223 
224         if (m_params.provokingVertexMode != PROVOKING_VERTEX_FIRST)
225         {
226             if (features.provokingVertexLast != VK_TRUE)
227                 TCU_THROW(NotSupportedError, "VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT not supported");
228 
229             if ((m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE) &&
230                 (properties.provokingVertexModePerPipeline != VK_TRUE))
231                 TCU_THROW(NotSupportedError, "provokingVertexModePerPipeline not supported");
232         }
233     }
234 
235     if (m_params.primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
236         context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
237         !context.getPortabilitySubsetFeatures().triangleFans)
238     {
239         TCU_THROW(NotSupportedError,
240                   "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
241     }
242 }
243 
createInstance(Context & context) const244 TestInstance *ProvokingVertexTestCase::createInstance(Context &context) const
245 {
246     return new ProvokingVertexTestInstance(context, m_params);
247 }
248 
iterate(void)249 tcu::TestStatus ProvokingVertexTestInstance::iterate(void)
250 {
251     const bool useProvokingVertexExt       = (m_params.provokingVertexMode != PROVOKING_VERTEX_DEFAULT);
252     const DeviceInterface &vk              = m_context.getDeviceInterface();
253     const VkDevice device                  = m_context.getDevice();
254     const uint32_t queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
255     const tcu::TextureFormat textureFormat = vk::mapVkFormat(m_params.format);
256     const VkDeviceSize counterBufferOffset = 0u;
257     Allocator &allocator                   = m_context.getDefaultAllocator();
258     Move<VkImage> image;
259     Move<VkImageView> imageView;
260     de::MovePtr<Allocation> imageMemory;
261     Move<VkBuffer> resultBuffer;
262     de::MovePtr<Allocation> resultBufferMemory;
263     Move<VkBuffer> xfbBuffer;
264     de::MovePtr<Allocation> xfbBufferMemory;
265     VkDeviceSize xfbBufferSize = 0;
266     Move<VkBuffer> counterBuffer;
267     de::MovePtr<Allocation> counterBufferMemory;
268     Move<VkBuffer> vertexBuffer;
269     de::MovePtr<Allocation> vertexBufferMemory;
270     Move<VkRenderPass> renderPass;
271     Move<VkFramebuffer> framebuffer;
272     Move<VkPipeline> pipeline;
273     Move<VkPipeline> altPipeline;
274     uint32_t vertexCount = 0;
275 
276     // Image
277     {
278         const VkExtent3D extent       = makeExtent3D(m_params.size.x(), m_params.size.y(), 1u);
279         const VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
280 
281         const VkImageCreateInfo createInfo = {
282             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
283             DE_NULL,                             // pNext
284             0u,                                  // flags
285             VK_IMAGE_TYPE_2D,                    // imageType
286             m_params.format,                     // format
287             extent,                              // extent
288             1u,                                  // mipLevels
289             1u,                                  // arrayLayers
290             VK_SAMPLE_COUNT_1_BIT,               // samples
291             VK_IMAGE_TILING_OPTIMAL,             // tiling
292             usage,                               // usage
293             VK_SHARING_MODE_EXCLUSIVE,           // sharingMode
294             1u,                                  // queueFamilyIndexCount
295             &queueFamilyIndex,                   // pQueueFamilyIndices
296             VK_IMAGE_LAYOUT_UNDEFINED            // initialLayout
297         };
298 
299         image = createImage(vk, device, &createInfo, DE_NULL);
300 
301         imageMemory = allocator.allocate(getImageMemoryRequirements(vk, device, *image), MemoryRequirement::Any);
302         VK_CHECK(vk.bindImageMemory(device, *image, imageMemory->getMemory(), imageMemory->getOffset()));
303     }
304 
305     // Image view
306     {
307         const VkImageSubresourceRange subresourceRange = {
308             VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
309             0u,                        // baseMipLevel
310             1u,                        // mipLevels
311             0u,                        // baseArrayLayer
312             1u                         // arraySize
313         };
314 
315         imageView =
316             makeImageView(vk, device, *image, VK_IMAGE_VIEW_TYPE_2D, m_params.format, subresourceRange, DE_NULL);
317     }
318 
319     // Result Buffer
320     {
321         const VkDeviceSize bufferSize       = textureFormat.getPixelSize() * m_params.size.x() * m_params.size.y();
322         const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
323 
324         resultBuffer = createBuffer(vk, device, &createInfo);
325         resultBufferMemory =
326             allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);
327 
328         VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(),
329                                      resultBufferMemory->getOffset()));
330     }
331 
332     // Render pass, framebuffer and pipelines
333     {
334         const Unique<VkShaderModule> vertexShader(
335             createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0));
336         const Unique<VkShaderModule> fragmentShader(
337             createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0));
338         const std::vector<VkViewport> viewports(1, makeViewport(tcu::UVec2(m_params.size)));
339         const std::vector<VkRect2D> scissors(1, makeRect2D(tcu::UVec2(m_params.size)));
340         const Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device, 0, DE_NULL);
341 
342         const VkVertexInputBindingDescription vertexInputBindingDescription = {
343             0,                          // binding
344             sizeof(tcu::Vec4) * 2,      // strideInBytes
345             VK_VERTEX_INPUT_RATE_VERTEX // stepRate
346         };
347 
348         const VkVertexInputAttributeDescription vertexAttributeDescriptions[2] = {
349             // Position
350             {
351                 0u,                            // location
352                 0u,                            // binding
353                 VK_FORMAT_R32G32B32A32_SFLOAT, // format
354                 0u                             // offsetInBytes
355             },
356             // Color
357             {
358                 1u,                            // location
359                 0u,                            // binding
360                 VK_FORMAT_R32G32B32A32_SFLOAT, // format
361                 sizeof(tcu::Vec4)              // offsetInBytes
362             }};
363 
364         const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
365             VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // sType
366             DE_NULL,                                                   // pNext
367             0,                                                         // flags
368             1u,                                                        // bindingCount
369             &vertexInputBindingDescription,                            // pVertexBindingDescriptions
370             2u,                                                        // attributeCount
371             vertexAttributeDescriptions                                // pVertexAttributeDescriptions
372         };
373 
374         const VkProvokingVertexModeEXT provokingVertexMode = m_params.provokingVertexMode == PROVOKING_VERTEX_LAST ?
375                                                                  VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT :
376                                                                  VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT;
377 
378         const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provokingVertexCreateInfo = {
379             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, // sType
380             DE_NULL,                                                                         // pNext
381             provokingVertexMode                                                              // provokingVertexMode
382         };
383 
384         const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
385             VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,   // sType
386             useProvokingVertexExt ? &provokingVertexCreateInfo : DE_NULL, // pNext
387             0,                                                            // flags
388             false,                                                        // depthClipEnable
389             false,                                                        // rasterizerDiscardEnable
390             VK_POLYGON_MODE_FILL,                                         // fillMode
391             VK_CULL_MODE_NONE,                                            // cullMode
392             VK_FRONT_FACE_COUNTER_CLOCKWISE,                              // frontFace
393             VK_FALSE,                                                     // depthBiasEnable
394             0.0f,                                                         // depthBias
395             0.0f,                                                         // depthBiasClamp
396             0.0f,                                                         // slopeScaledDepthBias
397             1.0f                                                          // lineWidth
398         };
399 
400         renderPass  = ProvokingVertexTestInstance::makeRenderPass(vk, device);
401         framebuffer = makeFramebuffer(vk, device, *renderPass, *imageView, m_params.size.x(), m_params.size.y(), 1u);
402         pipeline    = makeGraphicsPipeline(vk, device, *pipelineLayout, *vertexShader,
403                                            DE_NULL, // tessellationControlShaderModule
404                                            DE_NULL, // tessellationEvalShaderModule
405                                            DE_NULL, // geometryShaderModule
406                                            *fragmentShader, *renderPass, viewports, scissors, m_params.primitiveTopology,
407                                            0u, // subpass
408                                            0u, // patchControlPoints
409                                            &vertexInputStateParams, &rasterizationStateCreateInfo,
410                                            DE_NULL,  // multisampleStateCreateInfo
411                                            DE_NULL,  // depthStencilStateCreateInfo
412                                            DE_NULL,  // colorBlendStateCreateInfo
413                                            DE_NULL); // dynamicStateCreateInfo
414 
415         if (m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE)
416         {
417             const VkPipelineRasterizationProvokingVertexStateCreateInfoEXT altProvokingVertexCreateInfo = {
418                 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT, // sType
419                 DE_NULL,                                                                         // pNext
420                 VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT                                         // provokingVertexMode
421             };
422 
423             const VkPipelineRasterizationStateCreateInfo altRasterizationStateCreateInfo = {
424                 VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // sType
425                 &altProvokingVertexCreateInfo,                              // pNext
426                 0,                                                          // flags
427                 false,                                                      // depthClipEnable
428                 false,                                                      // rasterizerDiscardEnable
429                 VK_POLYGON_MODE_FILL,                                       // fillMode
430                 VK_CULL_MODE_NONE,                                          // cullMode
431                 VK_FRONT_FACE_COUNTER_CLOCKWISE,                            // frontFace
432                 VK_FALSE,                                                   // depthBiasEnable
433                 0.0f,                                                       // depthBias
434                 0.0f,                                                       // depthBiasClamp
435                 0.0f,                                                       // slopeScaledDepthBias
436                 1.0f,                                                       // lineWidth
437             };
438 
439             altPipeline =
440                 makeGraphicsPipeline(vk, device, *pipelineLayout, *vertexShader,
441                                      DE_NULL, // tessellationControlShaderModule
442                                      DE_NULL, // tessellationEvalShaderModule
443                                      DE_NULL, // geometryShaderModule
444                                      *fragmentShader, *renderPass, viewports, scissors, m_params.primitiveTopology,
445                                      0u, // subpass
446                                      0u, // patchControlPoints
447                                      &vertexInputStateParams, &altRasterizationStateCreateInfo,
448                                      DE_NULL,  // multisampleStateCreateInfo
449                                      DE_NULL,  // depthStencilStateCreateInfo
450                                      DE_NULL,  // colorBlendStateCreateInfo
451                                      DE_NULL); // dynamicStateCreateInfo
452         }
453     }
454 
455     std::vector<tcu::Vec4> vertices;
456     std::vector<size_t> provoking;
457     // Vertex buffer
458     {
459         const tcu::Vec4 red(1.0f, 0.0f, 0.0f, 1.0f);
460         const tcu::Vec4 green(0.0f, 1.0f, 0.0f, 1.0f);
461         const tcu::Vec4 blue(0.0f, 0.0f, 1.0f, 1.0f);
462         const tcu::Vec4 yellow(1.0f, 1.0f, 0.0f, 1.0f);
463         const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f);
464 
465         switch (m_params.primitiveTopology)
466         {
467         case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
468             // Position                                                //Color
469             vertices.push_back(tcu::Vec4(-1.0f, -0.5f, 0.0f, 1.0f));
470             vertices.push_back(red); // line 0
471             provoking.push_back(vertices.size() - 2);
472             vertices.push_back(tcu::Vec4(1.0f, -0.5f, 0.0f, 1.0f));
473             vertices.push_back(blue);
474             vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f));
475             vertices.push_back(red); // line 1
476             provoking.push_back(vertices.size() - 2);
477             vertices.push_back(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f));
478             vertices.push_back(blue);
479 
480             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
481             vertices.push_back(blue); // line 1 reverse
482             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
483             vertices.push_back(red);
484             provoking.push_back(vertices.size() - 2);
485             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
486             vertices.push_back(blue); // line 0 reverse
487             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
488             vertices.push_back(red);
489             provoking.push_back(vertices.size() - 2);
490             break;
491         case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
492             // Position                                                // Color
493             vertices.push_back(tcu::Vec4(-1.0f, -0.5f, 0.0f, 1.0f));
494             vertices.push_back(red); // line strip
495             provoking.push_back(vertices.size() - 2);
496             vertices.push_back(tcu::Vec4(1.0f, -0.5f, 0.0f, 1.0f));
497             vertices.push_back(red);
498             provoking.push_back(vertices.size() - 2);
499             vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f));
500             vertices.push_back(red);
501             provoking.push_back(vertices.size() - 2);
502             vertices.push_back(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f));
503             vertices.push_back(green);
504 
505             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
506             vertices.push_back(green); // line strip reverse
507             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
508             vertices.push_back(red);
509             provoking.push_back(vertices.size() - 2);
510             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
511             vertices.push_back(red);
512             provoking.push_back(vertices.size() - 2);
513             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
514             vertices.push_back(red);
515             provoking.push_back(vertices.size() - 2);
516             break;
517         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
518             // Position                                                // Color
519             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
520             vertices.push_back(red); // triangle 0
521             provoking.push_back(vertices.size() - 2);
522             vertices.push_back(tcu::Vec4(-0.6f, -1.0f, 0.0f, 1.0f));
523             vertices.push_back(green);
524             vertices.push_back(tcu::Vec4(-0.2f, 1.0f, 0.0f, 1.0f));
525             vertices.push_back(blue);
526             vertices.push_back(tcu::Vec4(0.2f, 1.0f, 0.0f, 1.0f));
527             vertices.push_back(red); // triangle 1
528             provoking.push_back(vertices.size() - 2);
529             vertices.push_back(tcu::Vec4(0.6f, -1.0f, 0.0f, 1.0f));
530             vertices.push_back(green);
531             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
532             vertices.push_back(blue);
533 
534             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
535             vertices.push_back(blue); // triangle 1 reverse
536             vertices.push_back(tcu::Vec4(-0.6f, 1.0f, 0.0f, 1.0f));
537             vertices.push_back(green);
538             vertices.push_back(tcu::Vec4(-0.2f, -1.0f, 0.0f, 1.0f));
539             vertices.push_back(red);
540             provoking.push_back(vertices.size() - 2);
541             vertices.push_back(tcu::Vec4(0.2f, -1.0f, 0.0f, 1.0f));
542             vertices.push_back(blue); // triangle 0 reverse
543             vertices.push_back(tcu::Vec4(0.6f, 1.0f, 0.0f, 1.0f));
544             vertices.push_back(green);
545             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
546             vertices.push_back(red);
547             provoking.push_back(vertices.size() - 2);
548             break;
549         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
550             // Position                                                // Color
551             vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
552             vertices.push_back(red); // triangle strip
553             provoking.push_back(vertices.size() - 2);
554             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
555             vertices.push_back(red);
556             provoking.push_back(vertices.size() - 2);
557             vertices.push_back(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
558             vertices.push_back(red);
559             provoking.push_back(vertices.size() - 2);
560             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
561             vertices.push_back(green);
562             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
563             vertices.push_back(blue);
564 
565             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
566             vertices.push_back(blue); // triangle strip reverse
567             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
568             vertices.push_back(green);
569             vertices.push_back(tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f));
570             vertices.push_back(red);
571             provoking.push_back(vertices.size() - 2);
572             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
573             vertices.push_back(red);
574             provoking.push_back(vertices.size() - 2);
575             vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
576             vertices.push_back(red);
577             provoking.push_back(vertices.size() - 2);
578 
579             break;
580         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
581             // Position                                                // Color
582             vertices.push_back(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
583             vertices.push_back(green); // triangle fan
584             vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
585             vertices.push_back(red);
586             provoking.push_back(vertices.size() - 2);
587             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
588             vertices.push_back(red);
589             provoking.push_back(vertices.size() - 2);
590             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
591             vertices.push_back(red);
592             provoking.push_back(vertices.size() - 2);
593             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
594             vertices.push_back(blue);
595 
596             vertices.push_back(tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f));
597             vertices.push_back(green); // triangle fan reverse
598             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
599             vertices.push_back(blue);
600             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
601             vertices.push_back(red);
602             provoking.push_back(vertices.size() - 2);
603             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
604             vertices.push_back(red);
605             provoking.push_back(vertices.size() - 2);
606             vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
607             vertices.push_back(red);
608             provoking.push_back(vertices.size() - 2);
609             break;
610         case VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
611             // Position                                                // Color
612             vertices.push_back(tcu::Vec4(-1.0f, -0.5f, 0.0f, 1.0f));
613             vertices.push_back(green); // line 0
614             vertices.push_back(tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f));
615             vertices.push_back(red);
616             provoking.push_back(vertices.size() - 2);
617             vertices.push_back(tcu::Vec4(0.5f, -0.5f, 0.0f, 1.0f));
618             vertices.push_back(blue);
619             vertices.push_back(tcu::Vec4(1.0f, -0.5f, 0.0f, 1.0f));
620             vertices.push_back(yellow);
621             vertices.push_back(tcu::Vec4(-1.0f, 0.5f, 0.0f, 1.0f));
622             vertices.push_back(green); // line 1
623             vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f));
624             vertices.push_back(red);
625             provoking.push_back(vertices.size() - 2);
626             vertices.push_back(tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f));
627             vertices.push_back(blue);
628             vertices.push_back(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f));
629             vertices.push_back(yellow);
630 
631             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
632             vertices.push_back(yellow); // line 1 reverse
633             vertices.push_back(tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f));
634             vertices.push_back(blue);
635             vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f));
636             vertices.push_back(red);
637             provoking.push_back(vertices.size() - 2);
638             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
639             vertices.push_back(green);
640             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
641             vertices.push_back(yellow); // line 0 reverse
642             vertices.push_back(tcu::Vec4(0.5f, -0.5f, 0.0f, 1.0f));
643             vertices.push_back(blue);
644             vertices.push_back(tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f));
645             vertices.push_back(red);
646             provoking.push_back(vertices.size() - 2);
647             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
648             vertices.push_back(green);
649             break;
650         case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
651             // Position                                                // Color
652             vertices.push_back(tcu::Vec4(-1.0f, -0.5f, 0.0f, 1.0f));
653             vertices.push_back(green); // line strip
654             vertices.push_back(tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f));
655             vertices.push_back(red);
656             provoking.push_back(vertices.size() - 2);
657             vertices.push_back(tcu::Vec4(0.5f, -0.5f, 0.0f, 1.0f));
658             vertices.push_back(red);
659             provoking.push_back(vertices.size() - 2);
660             vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f));
661             vertices.push_back(red);
662             provoking.push_back(vertices.size() - 2);
663             vertices.push_back(tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f));
664             vertices.push_back(blue);
665             vertices.push_back(tcu::Vec4(1.0f, 0.5f, 0.0f, 1.0f));
666             vertices.push_back(yellow);
667 
668             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
669             vertices.push_back(yellow); // line strip reverse
670             vertices.push_back(tcu::Vec4(-0.5f, -0.5f, 0.0f, 1.0f));
671             vertices.push_back(blue);
672             vertices.push_back(tcu::Vec4(-0.5f, 0.5f, 0.0f, 1.0f));
673             vertices.push_back(red);
674             provoking.push_back(vertices.size() - 2);
675             vertices.push_back(tcu::Vec4(0.5f, -0.5f, 0.0f, 1.0f));
676             vertices.push_back(red);
677             provoking.push_back(vertices.size() - 2);
678             vertices.push_back(tcu::Vec4(0.5f, 0.5f, 0.0f, 1.0f));
679             vertices.push_back(red);
680             provoking.push_back(vertices.size() - 2);
681             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
682             vertices.push_back(green);
683             break;
684         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
685             // Position                                                // Color
686             vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
687             vertices.push_back(red); // triangle 0
688             provoking.push_back(vertices.size() - 2);
689             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
690             vertices.push_back(white);
691             vertices.push_back(tcu::Vec4(-0.6f, -1.0f, 0.0f, 1.0f));
692             vertices.push_back(green);
693             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
694             vertices.push_back(white);
695             vertices.push_back(tcu::Vec4(-0.2f, 1.0f, 0.0f, 1.0f));
696             vertices.push_back(blue);
697             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
698             vertices.push_back(white);
699             vertices.push_back(tcu::Vec4(0.2f, 1.0f, 0.0f, 1.0f));
700             vertices.push_back(red); // triangle 1
701             provoking.push_back(vertices.size() - 2);
702             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
703             vertices.push_back(white);
704             vertices.push_back(tcu::Vec4(0.6f, -1.0f, 0.0f, 1.0f));
705             vertices.push_back(green);
706             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
707             vertices.push_back(white);
708             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
709             vertices.push_back(blue);
710             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
711             vertices.push_back(white);
712 
713             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
714             vertices.push_back(blue); // triangle 1 reverse
715             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
716             vertices.push_back(white);
717             vertices.push_back(tcu::Vec4(-0.6f, 1.0f, 0.0f, 1.0f));
718             vertices.push_back(green);
719             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
720             vertices.push_back(white);
721             vertices.push_back(tcu::Vec4(-0.2f, -1.0f, 0.0f, 1.0f));
722             vertices.push_back(red);
723             provoking.push_back(vertices.size() - 2);
724             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
725             vertices.push_back(white);
726             vertices.push_back(tcu::Vec4(0.2f, -1.0f, 0.0f, 1.0f));
727             vertices.push_back(blue); // triangle 0 reverse
728             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
729             vertices.push_back(white);
730             vertices.push_back(tcu::Vec4(0.6f, 1.0f, 0.0f, 1.0f));
731             vertices.push_back(green);
732             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
733             vertices.push_back(white);
734             vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
735             vertices.push_back(red);
736             provoking.push_back(vertices.size() - 2);
737             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
738             vertices.push_back(white);
739             break;
740         case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
741             // Position                                                // Color
742             vertices.push_back(tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f));
743             vertices.push_back(red); // triangle strip
744             provoking.push_back(vertices.size() - 2);
745             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
746             vertices.push_back(white);
747             vertices.push_back(tcu::Vec4(-0.5f, -1.0f, 0.0f, 1.0f));
748             vertices.push_back(red);
749             provoking.push_back(vertices.size() - 2);
750             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
751             vertices.push_back(white);
752             vertices.push_back(tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f));
753             vertices.push_back(red);
754             provoking.push_back(vertices.size() - 2);
755             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
756             vertices.push_back(white);
757             vertices.push_back(tcu::Vec4(0.5f, -1.0f, 0.0f, 1.0f));
758             vertices.push_back(green);
759             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
760             vertices.push_back(white);
761             vertices.push_back(tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f));
762             vertices.push_back(blue);
763             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
764             vertices.push_back(white);
765 
766             vertices.push_back(tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
767             vertices.push_back(blue); // triangle strip reverse
768             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
769             vertices.push_back(white);
770             vertices.push_back(tcu::Vec4(-0.5f, 1.0f, 0.0f, 1.0f));
771             vertices.push_back(green);
772             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
773             vertices.push_back(white);
774             vertices.push_back(tcu::Vec4(0.0f, -1.0f, 0.0f, 1.0f));
775             vertices.push_back(red);
776             provoking.push_back(vertices.size() - 2);
777             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
778             vertices.push_back(white);
779             vertices.push_back(tcu::Vec4(0.5f, 1.0f, 0.0f, 1.0f));
780             vertices.push_back(red);
781             provoking.push_back(vertices.size() - 2);
782             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
783             vertices.push_back(white);
784             vertices.push_back(tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f));
785             vertices.push_back(red);
786             provoking.push_back(vertices.size() - 2);
787             vertices.push_back(tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
788             vertices.push_back(white);
789             break;
790         default:
791             DE_FATAL("Unknown primitive topology");
792         }
793 
794         const size_t bufferSize             = vertices.size() * sizeof(tcu::Vec4);
795         const VkBufferCreateInfo createInfo = makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
796 
797         vertexCount  = (uint32_t)vertices.size() / 4;
798         vertexBuffer = createBuffer(vk, device, &createInfo);
799         vertexBufferMemory =
800             allocator.allocate(getBufferMemoryRequirements(vk, device, *vertexBuffer), MemoryRequirement::HostVisible);
801         VK_CHECK(vk.bindBufferMemory(device, *vertexBuffer, vertexBufferMemory->getMemory(),
802                                      vertexBufferMemory->getOffset()));
803         deMemcpy(vertexBufferMemory->getHostPtr(), &vertices[0], bufferSize);
804         flushAlloc(vk, device, *vertexBufferMemory);
805     }
806 
807     // Transform feedback and counter buffers
808     if (m_params.transformFeedback)
809     {
810         xfbBufferSize = getXfbBufferSize(vertexCount, m_params.primitiveTopology);
811 
812         if (m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE)
813             xfbBufferSize = xfbBufferSize * 2;
814 
815         const int xfbBufferUsage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
816         const VkBufferCreateInfo xfbCreateInfo = makeBufferCreateInfo(xfbBufferSize, xfbBufferUsage);
817         const VkDeviceSize counterBufferSize   = 16 * sizeof(uint32_t);
818         const VkBufferCreateInfo counterBufferInfo =
819             makeBufferCreateInfo(counterBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT);
820 
821         xfbBuffer = createBuffer(vk, device, &xfbCreateInfo);
822         xfbBufferMemory =
823             allocator.allocate(getBufferMemoryRequirements(vk, device, *xfbBuffer), MemoryRequirement::HostVisible);
824         VK_CHECK(vk.bindBufferMemory(device, *xfbBuffer, xfbBufferMemory->getMemory(), xfbBufferMemory->getOffset()));
825 
826         counterBuffer = createBuffer(vk, device, &counterBufferInfo);
827         counterBufferMemory =
828             allocator.allocate(getBufferMemoryRequirements(vk, device, *counterBuffer), MemoryRequirement::HostVisible);
829         VK_CHECK(vk.bindBufferMemory(device, *counterBuffer, counterBufferMemory->getMemory(),
830                                      counterBufferMemory->getOffset()));
831         // Make sure uninitialized values are not read when starting XFB for the first time.
832         deMemset(counterBufferMemory->getHostPtr(), 0, static_cast<size_t>(counterBufferSize));
833         flushAlloc(vk, device, *counterBufferMemory);
834     }
835 
836     // Clear the color buffer to red and check the drawing doesn't add any
837     // other colors from non-provoking vertices
838     {
839         const VkQueue queue                     = m_context.getUniversalQueue();
840         const VkRect2D renderArea               = makeRect2D(m_params.size.x(), m_params.size.y());
841         const VkDeviceSize vertexBufferOffset   = 0;
842         const VkClearValue clearValue           = makeClearValueColor(tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
843         const VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
844         const VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
845 
846         const VkImageSubresourceRange subResourcerange = {
847             VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
848             0,                         // baseMipLevel
849             1,                         // levelCount
850             0,                         // baseArrayLayer
851             1                          // layerCount
852         };
853 
854         const VkImageMemoryBarrier imageBarrier = {
855             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // sType
856             DE_NULL,                                  // pNext
857             0,                                        // srcAccessMask
858             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,     // dstAccessMask
859             VK_IMAGE_LAYOUT_UNDEFINED,                // oldLayout
860             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
861             VK_QUEUE_FAMILY_IGNORED,                  // srcQueueFamilyIndex
862             VK_QUEUE_FAMILY_IGNORED,                  // destQueueFamilyIndex
863             *image,                                   // image
864             subResourcerange                          // subresourceRange
865         };
866 
867         const VkMemoryBarrier xfbMemoryBarrier =
868             makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
869         const VkMemoryBarrier counterBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
870                                                                  VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT);
871 
872         // The first half of the vertex buffer is for PROVOKING_VERTEX_FIRST,
873         // the second half for PROVOKING_VERTEX_LAST
874         const uint32_t firstVertex = m_params.provokingVertexMode == PROVOKING_VERTEX_LAST ? vertexCount : 0u;
875 
876         Move<VkCommandPool> commandPool = makeCommandPool(vk, device, queueFamilyIndex);
877         Move<VkCommandBuffer> commandBuffer =
878             allocateCommandBuffer(vk, device, *commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
879 
880         beginCommandBuffer(vk, *commandBuffer, 0u);
881         {
882             vk.cmdPipelineBarrier(*commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1,
883                                   &imageBarrier);
884 
885             beginRenderPass(vk, *commandBuffer, *renderPass, *framebuffer, renderArea, 1, &clearValue);
886             {
887                 vk.cmdBindVertexBuffers(*commandBuffer, 0, 1, &*vertexBuffer, &vertexBufferOffset);
888                 vk.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
889 
890                 if (m_params.transformFeedback)
891                 {
892                     const VkDeviceSize xfbBufferOffset = 0;
893 
894                     vk.cmdBindTransformFeedbackBuffersEXT(*commandBuffer, 0, 1, &*xfbBuffer, &xfbBufferOffset,
895                                                           &xfbBufferSize);
896                     vk.cmdBeginTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset);
897                 }
898 
899                 vk.cmdDraw(*commandBuffer, vertexCount, 1u, firstVertex, 0u);
900 
901                 if (m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE)
902                 {
903                     // vkCmdBindPipeline must not be recorded when transform feedback is active.
904                     if (m_params.transformFeedback)
905                     {
906                         vk.cmdEndTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset);
907                         vk.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
908                                               VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, 0u, 1u, &counterBarrier, 0u,
909                                               DE_NULL, 0u, DE_NULL);
910                     }
911 
912                     vk.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *altPipeline);
913 
914                     if (m_params.transformFeedback)
915                         vk.cmdBeginTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset);
916 
917                     vk.cmdDraw(*commandBuffer, vertexCount, 1u, vertexCount, 0u);
918                 }
919 
920                 if (m_params.transformFeedback)
921                     vk.cmdEndTransformFeedbackEXT(*commandBuffer, 0, 1, &*counterBuffer, &counterBufferOffset);
922             }
923             endRenderPass(vk, *commandBuffer);
924 
925             if (m_params.transformFeedback)
926                 vk.cmdPipelineBarrier(*commandBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,
927                                       VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &xfbMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
928 
929             copyImageToBuffer(vk, *commandBuffer, *image, *resultBuffer,
930                               tcu::IVec2(m_params.size.x(), m_params.size.y()));
931         }
932         endCommandBuffer(vk, *commandBuffer);
933 
934         submitCommandsAndWait(vk, device, queue, commandBuffer.get());
935         invalidateAlloc(vk, device, *resultBufferMemory);
936 
937         if (m_params.transformFeedback)
938             invalidateAlloc(vk, device, *xfbBufferMemory);
939     }
940 
941     // Verify result
942     {
943         tcu::TestLog &log       = m_context.getTestContext().getLog();
944         const size_t bufferSize = textureFormat.getPixelSize() * m_params.size.x() * m_params.size.y();
945         tcu::Surface referenceSurface(m_params.size.x(), m_params.size.y());
946         tcu::ConstPixelBufferAccess referenceAccess = referenceSurface.getAccess();
947         tcu::Surface resultSurface(m_params.size.x(), m_params.size.y());
948         tcu::ConstPixelBufferAccess resultAccess(textureFormat, tcu::IVec3(m_params.size.x(), m_params.size.y(), 1),
949                                                  resultBufferMemory->getHostPtr());
950 
951         // Verify transform feedback buffer
952         if (m_params.transformFeedback)
953         {
954             const tcu::Vec4 *const xfbResults = static_cast<tcu::Vec4 *>(xfbBufferMemory->getHostPtr());
955             const uint32_t count              = static_cast<uint32_t>(xfbBufferSize / sizeof(tcu::Vec4));
956             std::string errorMessage          = "";
957 
958             log << tcu::TestLog::Section("XFB Vertex colors", "vertex colors");
959 
960             for (uint32_t i = 0; i < count; i++)
961             {
962                 log << tcu::TestLog::Message << "[" << de::toString(i) << "]\t" << de::toString(xfbResults[i])
963                     << tcu::TestLog::EndMessage;
964             }
965 
966             log << tcu::TestLog::EndSection;
967 
968             if (m_params.provokingVertexMode != PROVOKING_VERTEX_PER_PIPELINE)
969             {
970                 if (!verifyXfbBuffer(xfbResults, vertices, provoking, count, m_params.primitiveTopology,
971                                      m_params.provokingVertexMode, errorMessage))
972                     return tcu::TestStatus::fail(errorMessage);
973             }
974             else
975             {
976                 const uint32_t halfCount = count / 2;
977 
978                 if (!verifyXfbBuffer(xfbResults, vertices, provoking, halfCount, m_params.primitiveTopology,
979                                      PROVOKING_VERTEX_FIRST, errorMessage))
980                     return tcu::TestStatus::fail(errorMessage);
981 
982                 if (!verifyXfbBuffer(&xfbResults[halfCount], vertices, provoking, halfCount, m_params.primitiveTopology,
983                                      PROVOKING_VERTEX_LAST, errorMessage))
984                     return tcu::TestStatus::fail(errorMessage);
985             }
986         }
987 
988         // Create reference
989         for (uint32_t y = 0; y < m_params.size.y(); y++)
990             for (uint32_t x = 0; x < m_params.size.x(); x++)
991                 referenceSurface.setPixel(x, y, tcu::RGBA::red());
992 
993         // Copy result
994         tcu::copy(resultSurface.getAccess(), resultAccess);
995 
996         // Compare
997         if (deMemCmp(referenceAccess.getDataPtr(), resultAccess.getDataPtr(), bufferSize) != 0)
998         {
999             log << tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
1000                 << tcu::TestLog::Image("Result", "Result", resultSurface) << tcu::TestLog::EndImageSet;
1001             return tcu::TestStatus::fail("Incorrect rendering");
1002         }
1003     }
1004 
1005     return tcu::TestStatus::pass("Solid red");
1006 }
1007 
1008 // Copied from vkObjUtil.cpp with an additional subpass.
makeRenderPass(const DeviceInterface & vk,const VkDevice device)1009 Move<VkRenderPass> ProvokingVertexTestInstance::makeRenderPass(const DeviceInterface &vk, const VkDevice device)
1010 {
1011     const VkAttachmentDescription colorAttachmentDescription = {
1012         (VkAttachmentDescriptionFlags)0,          // VkAttachmentDescriptionFlags    flags
1013         m_params.format,                          // VkFormat                        format
1014         VK_SAMPLE_COUNT_1_BIT,                    // VkSampleCountFlagBits           samples
1015         VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp              loadOp
1016         VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp             storeOp
1017         VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp              stencilLoadOp
1018         VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp             stencilStoreOp
1019         VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout                   initialLayout
1020         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout                   finalLayout
1021     };
1022 
1023     const VkAttachmentReference colorAttachmentRef = {
1024         0u,                                      // uint32_t         attachment
1025         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout    layout
1026     };
1027 
1028     const VkSubpassDescription subpassDescription = {
1029         (VkSubpassDescriptionFlags)0,    // VkSubpassDescriptionFlags       flags
1030         VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint             pipelineBindPoint
1031         0u,                              // uint32_t                        inputAttachmentCount
1032         DE_NULL,                         // const VkAttachmentReference*    pInputAttachments
1033         1u,                              // uint32_t                        colorAttachmentCount
1034         &colorAttachmentRef,             // const VkAttachmentReference*    pColorAttachments
1035         DE_NULL,                         // const VkAttachmentReference*    pResolveAttachments
1036         DE_NULL,                         // const VkAttachmentReference*    pDepthStencilAttachment
1037         0u,                              // uint32_t                        preserveAttachmentCount
1038         DE_NULL                          // const uint32_t*                 pPreserveAttachments
1039     };
1040 
1041     const VkSubpassDependency selfDependency = {
1042         0u,                                                 // uint32_t                srcSubpass
1043         0u,                                                 // uint32_t                dstSubpass
1044         VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,       // VkPipelineStageFlags    srcStageMask
1045         VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,       // VkPipelineStageFlags    dstStageMask
1046         VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, // VkAccessFlags           srcAccessMask
1047         VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,  // VkAccessFlags           dstAccessMask
1048         0u                                                  // VkDependencyFlags       dependencyFlags
1049     };
1050 
1051     const bool xfbPerPipeline =
1052         m_params.transformFeedback && m_params.provokingVertexMode == PROVOKING_VERTEX_PER_PIPELINE;
1053 
1054     const VkRenderPassCreateInfo renderPassInfo = {
1055         VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType                   sType
1056         DE_NULL,                                   // const void*                       pNext
1057         (VkRenderPassCreateFlags)0,                // VkRenderPassCreateFlags           flags
1058         1u,                                        // uint32_t                          attachmentCount
1059         &colorAttachmentDescription,               // const VkAttachmentDescription*    pAttachments
1060         1u,                                        // uint32_t                          subpassCount
1061         &subpassDescription,                       // const VkSubpassDescription*       pSubpasses
1062         xfbPerPipeline ? 1u : 0u,                  // uint32_t                          dependencyCount
1063         xfbPerPipeline ? &selfDependency : DE_NULL // const VkSubpassDependency*        pDependencies
1064     };
1065 
1066     return createRenderPass(vk, device, &renderPassInfo, DE_NULL);
1067 }
1068 
createTests(tcu::TestCaseGroup * testGroup)1069 void createTests(tcu::TestCaseGroup *testGroup)
1070 {
1071     tcu::TestContext &testCtx = testGroup->getTestContext();
1072 
1073     const struct Provoking
1074     {
1075         const char *name;
1076         ProvokingVertexMode mode;
1077     } provokingVertexModes[] = {// Default provoking vertex convention
1078                                 {
1079                                     "default",
1080                                     PROVOKING_VERTEX_DEFAULT,
1081                                 },
1082                                 // VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT
1083                                 {
1084                                     "first",
1085                                     PROVOKING_VERTEX_FIRST,
1086                                 },
1087                                 // VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT
1088                                 {
1089                                     "last",
1090                                     PROVOKING_VERTEX_LAST,
1091                                 },
1092                                 // Pipelines with different provokingVertexModes
1093                                 {"per_pipeline", PROVOKING_VERTEX_PER_PIPELINE}};
1094 
1095     const struct Topology
1096     {
1097         std::string name;
1098         VkPrimitiveTopology type;
1099         bool requiresGeometryShader;
1100     } topologies[] = {{"line_list", VK_PRIMITIVE_TOPOLOGY_LINE_LIST, false},
1101                       {"line_strip", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, false},
1102                       {"triangle_list", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, false},
1103                       {"triangle_strip", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, false},
1104                       {"triangle_fan", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, false},
1105                       {"line_list_with_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY, true},
1106                       {"line_strip_with_adjacency", VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY, true},
1107                       {"triangle_list_with_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY, true},
1108                       {"triangle_strip_with_adjacency", VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, true}};
1109 
1110     const struct TestType
1111     {
1112         const char *name;
1113         bool transformFeedback;
1114     } testTypes[] = {// Test that primitives are flat shaded with the provoking vertex color
1115                      {"draw", false},
1116                      // Test that transform feedback preserves the position of the provoking vertex
1117                      {"transform_feedback", true}};
1118 
1119     for (const TestType &testType : testTypes)
1120     {
1121         tcu::TestCaseGroup *const typeGroup = new tcu::TestCaseGroup(testCtx, testType.name);
1122 
1123         for (const Provoking &provoking : provokingVertexModes)
1124         {
1125             // Only test transformFeedbackPreservesProvokingVertex with VK_EXT_provoking_vertex
1126             if (testType.transformFeedback && (provoking.mode == PROVOKING_VERTEX_DEFAULT))
1127                 continue;
1128 
1129             tcu::TestCaseGroup *const provokingGroup = new tcu::TestCaseGroup(testCtx, provoking.name);
1130 
1131             for (const Topology &topology : topologies)
1132             {
1133                 const std::string caseName = topology.name;
1134 
1135                 const Params params = {
1136                     VK_FORMAT_R8G8B8A8_UNORM,        // format
1137                     tcu::UVec2(32, 32),              // size
1138                     topology.type,                   // primitiveTopology
1139                     topology.requiresGeometryShader, // requireGeometryShader
1140                     testType.transformFeedback,      // transformFeedback
1141                     provoking.mode                   // provokingVertexMode
1142                 };
1143 
1144                 provokingGroup->addChild(new ProvokingVertexTestCase(testCtx, caseName, params));
1145             }
1146 
1147             typeGroup->addChild(provokingGroup);
1148         }
1149 
1150         testGroup->addChild(typeGroup);
1151     }
1152 }
1153 
1154 } // namespace
1155 
createProvokingVertexTests(tcu::TestContext & testCtx)1156 tcu::TestCaseGroup *createProvokingVertexTests(tcu::TestContext &testCtx)
1157 {
1158     return createTestGroup(testCtx, "provoking_vertex", createTests);
1159 }
1160 
1161 } // namespace rasterization
1162 } // namespace vkt
1163