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