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