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