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