1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Vulkan Transform Feedback Simple Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktTransformFeedbackSimpleTests.hpp"
25 #include "vktTestGroupUtil.hpp"
26 #include "vktTestCase.hpp"
27 
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 
35 #include "deUniquePtr.hpp"
36 #include "deRandom.hpp"
37 
38 #include "tcuTextureUtil.hpp"
39 #include "tcuVectorUtil.hpp"
40 #include "tcuImageCompare.hpp"
41 #include "tcuRGBA.hpp"
42 #include "tcuTestLog.hpp"
43 #include "tcuCommandLine.hpp"
44 
45 #include <iostream>
46 #include <functional>
47 #include <set>
48 #include <algorithm>
49 #include <limits>
50 
51 namespace vkt
52 {
53 namespace TransformFeedback
54 {
55 namespace
56 {
57 using namespace vk;
58 using de::MovePtr;
59 using de::UniquePtr;
60 using de::SharedPtr;
61 
62 #define VALIDATE_MINIMUM(A,B) if ((A) < (B)) TCU_FAIL(#A "==" + de::toString(A) + " which is less than required by specification (" + de::toString(B) + ")")
63 #define VALIDATE_BOOL(A) if (! ( (A) == VK_TRUE || (A) == VK_FALSE) ) TCU_FAIL(#A " expected to be VK_TRUE or VK_FALSE. Received " + de::toString((deUint64)(A)))
64 
65 const deUint32				INVOCATION_COUNT	= 8u;
66 const std::vector<deUint32>	LINES_LIST			{ 2, 6, 3 };
67 const std::vector<deUint32>	TRIANGLES_LIST		{ 3, 8, 6, 5, 4 };
68 
69 enum TestType
70 {
71 	TEST_TYPE_BASIC,
72 	TEST_TYPE_RESUME,
73 	TEST_TYPE_STREAMS,
74 	TEST_TYPE_XFB_POINTSIZE,
75 	TEST_TYPE_XFB_CLIPDISTANCE,
76 	TEST_TYPE_XFB_CULLDISTANCE,
77 	TEST_TYPE_XFB_CLIP_AND_CULL,
78 	TEST_TYPE_WINDING,
79 	TEST_TYPE_STREAMS_POINTSIZE,
80 	TEST_TYPE_STREAMS_CLIPDISTANCE,
81 	TEST_TYPE_STREAMS_CULLDISTANCE,
82 	TEST_TYPE_MULTISTREAMS,
83 	TEST_TYPE_MULTISTREAMS_SAME_LOCATION,
84 	TEST_TYPE_DRAW_INDIRECT,
85 	TEST_TYPE_DRAW_INDIRECT_MULTIVIEW,
86 	TEST_TYPE_BACKWARD_DEPENDENCY,
87 	TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT,
88 	TEST_TYPE_QUERY_GET,
89 	TEST_TYPE_QUERY_COPY,
90 	TEST_TYPE_QUERY_COPY_STRIDE_ZERO,
91 	TEST_TYPE_QUERY_RESET,
92 	TEST_TYPE_MULTIQUERY,
93 	TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX,
94 	TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY,
95 	TEST_TYPE_DEPTH_CLIP_CONTROL_TESE,
96 	TEST_TYPE_LINES_TRIANGLES,
97 	TEST_TYPE_DRAW_OUTSIDE,
98 	TEST_TYPE_HOLES_VERTEX,
99 	TEST_TYPE_HOLES_GEOMETRY,
100 	TEST_TYPE_LAST
101 };
102 
103 enum StreamId0Mode
104 {
105 	STREAM_ID_0_NORMAL					= 0,
106 	STREAM_ID_0_BEGIN_QUERY_INDEXED		= 1,
107 	STREAM_ID_0_END_QUERY_INDEXED		= 2,
108 };
109 
110 struct TestParameters
111 {
112 	TestType			testType;
113 	deUint32			bufferSize;
114 	deUint32			partCount;
115 	deUint32			streamId;
116 	deUint32			pointSize;
117 	deUint32			vertexStride;
118 	StreamId0Mode		streamId0Mode;
119 	bool				query64bits;
120 	bool				noOffsetArray;
121 	bool				requireRastStreamSelect;
122 	bool				omitShaderWrite;
123 	bool				useMaintenance5;
124 	VkPrimitiveTopology	primTopology;
125 	bool				queryResultWithAvailability;
126 };
127 
128 struct TopologyInfo
129 {
130 	deUint32							primSize;			// The size of the on primitive.
131 	std::string							topologyName;		// The suffix for the name of test.
132 	std::function<deUint64(deUint64)>	getNumPrimitives;	// The number of primitives generated.
133 	std::function<deUint64(deUint64)>	getNumVertices;		// The number of vertices generated.
134 };
135 
136 const std::map<VkPrimitiveTopology, TopologyInfo> topologyData =
137 {
138 	{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST						, { 1, ""								,[](deUint64 vertexCount)	{	return vertexCount;				}	,[](deUint64 primCount)	{	return primCount;			}, } },
139 	{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST						, { 2, "line_list_"						,[](deUint64 vertexCount)	{	return vertexCount / 2u;		}	,[](deUint64 primCount) {	return primCount * 2u;		}, } },
140 	{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP						, { 2, "line_strip_"					,[](deUint64 vertexCount)	{	return vertexCount - 1u;		}	,[](deUint64 primCount) {	return primCount + 1u;		}, } },
141 	{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST					, { 3, "triangle_list_"					,[](deUint64 vertexCount)	{	return vertexCount / 3u;		}	,[](deUint64 primCount) {	return primCount * 3u;		}, } },
142 	{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP					, { 3, "triangle_strip_"				,[](deUint64 vertexCount)	{	return vertexCount - 2u;		}	,[](deUint64 primCount) {	return primCount + 2u;		}, } },
143 	{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN					, { 3, "triangle_fan_"					,[](deUint64 vertexCount)	{	return vertexCount - 2u;		}	,[](deUint64 primCount) {	return primCount + 2u;		}, } },
144 	{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY		, { 2, "line_list_with_adjacency_"		,[](deUint64 vertexCount)	{	return vertexCount / 4u;		}	,[](deUint64 primCount) {	return primCount * 4u;		}, } },
145 	{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY		, { 2, "line_strip_with_adjacency_"		,[](deUint64 vertexCount)	{	return vertexCount - 3u;		}	,[](deUint64 primCount) {	return primCount + 3u;		}, } },
146 	{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY	, { 3, "triangle_list_with_adjacency_"	,[](deUint64 vertexCount)	{	return vertexCount / 6u;		}	,[](deUint64 primCount) {	return primCount * 6u;		}, } },
147 	{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY	, { 3, "triangle_strip_with_adjacency_"	,[](deUint64 vertexCount)	{	return (vertexCount - 4u) / 2u;	}	,[](deUint64 primCount) {	return primCount * 2u + 4u;	}, } },
148 	{ VK_PRIMITIVE_TOPOLOGY_PATCH_LIST						, { 3, "patch_list_"					,[](deUint64 vertexCount)	{	return vertexCount / 3u;		}	,[](deUint64 primCount) {	return primCount * 3u;		}, } },
149 };
150 
151 struct TransformFeedbackQuery
152 {
153 	deUint32	written;
154 	deUint32	attempts;
155 };
156 
157 const deUint32	MINIMUM_TF_BUFFER_SIZE	= (1<<27);
158 const deUint32	IMAGE_SIZE				= 64u;
159 
160 template<typename T>
makeSharedPtr(Move<T> move)161 inline SharedPtr<Unique<T> > makeSharedPtr(Move<T> move)
162 {
163 	return SharedPtr<Unique<T> >(new Unique<T>(move));
164 }
165 
166 template<typename T>
getInvalidatedHostPtr(const DeviceInterface& vk, const VkDevice device, Allocation& bufAlloc)167 const T* getInvalidatedHostPtr (const DeviceInterface& vk, const VkDevice device, Allocation& bufAlloc)
168 {
169 	invalidateAlloc(vk, device, bufAlloc);
170 
171 	return static_cast<T*>(bufAlloc.getHostPtr());
172 }
173 
makePipelineLayout(const DeviceInterface& vk, const VkDevice device, const uint32_t pcSize = sizeof(uint32_t))174 Move<VkPipelineLayout> makePipelineLayout (const DeviceInterface&		vk,
175 										   const VkDevice				device,
176 										   const uint32_t				pcSize = sizeof(uint32_t))
177 {
178 	const VkPushConstantRange			pushConstantRanges			=
179 	{
180 		VK_SHADER_STAGE_VERTEX_BIT,						//  VkShaderStageFlags				stageFlags;
181 		0u,												//  deUint32						offset;
182 		pcSize,											//  deUint32						size;
183 	};
184 	const VkPipelineLayoutCreateInfo	pipelineLayoutCreateInfo	=
185 	{
186 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//  VkStructureType					sType;
187 		DE_NULL,										//  const void*						pNext;
188 		(VkPipelineLayoutCreateFlags)0,					//  VkPipelineLayoutCreateFlags		flags;
189 		0u,												//  deUint32						setLayoutCount;
190 		DE_NULL,										//  const VkDescriptorSetLayout*	pSetLayouts;
191 		1u,												//  deUint32						pushConstantRangeCount;
192 		&pushConstantRanges,							//  const VkPushConstantRange*		pPushConstantRanges;
193 	};
194 	return createPipelineLayout(vk, device, &pipelineLayoutCreateInfo);
195 }
196 
makeGraphicsPipeline(const DeviceInterface& vk, const VkDevice device, const VkPipelineLayout pipelineLayout, const VkRenderPass renderPass, const VkShaderModule vertexModule, const VkShaderModule tessellationControlModule, const VkShaderModule tessellationEvalModule, const VkShaderModule geometryModule, const VkShaderModule fragmentModule, const VkExtent2D renderSize, const deUint32 subpass, const deUint32* rasterizationStreamPtr = DE_NULL, const VkPrimitiveTopology topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST, const bool inputVertices = false, const bool depthClipControl = false)197 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
198 									   const VkDevice				device,
199 									   const VkPipelineLayout		pipelineLayout,
200 									   const VkRenderPass			renderPass,
201 									   const VkShaderModule			vertexModule,
202 									   const VkShaderModule			tessellationControlModule,
203 									   const VkShaderModule			tessellationEvalModule,
204 									   const VkShaderModule			geometryModule,
205 									   const VkShaderModule			fragmentModule,
206 									   const VkExtent2D				renderSize,
207 									   const deUint32				subpass,
208 									   const deUint32*				rasterizationStreamPtr	= DE_NULL,
209 									   const VkPrimitiveTopology	topology				= VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
210 									   const bool					inputVertices			= false,
211 									   const bool					depthClipControl		= false)
212 {
213 	VkViewport												viewport							= makeViewport(renderSize);
214 	VkRect2D												scissor								= makeRect2D(renderSize);
215 
216 	const VkPipelineViewportDepthClipControlCreateInfoEXT	depthClipControlCreateInfo			=
217 	{
218 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT,	// VkStructureType	sType;
219 		DE_NULL,																// const void*		pNext;
220 		VK_TRUE,																// VkBool32		negativeOneToOne;
221 	};
222 
223 	const VkPipelineViewportStateCreateInfo					viewportStateCreateInfo				=
224 	{
225 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,		// VkStructureType                             sType
226 		depthClipControl ? &depthClipControlCreateInfo : DE_NULL,	// const void*                                 pNext
227 		(VkPipelineViewportStateCreateFlags)0,						// VkPipelineViewportStateCreateFlags          flags
228 		1u,															// deUint32                                    viewportCount
229 		&viewport,													// const VkViewport*                           pViewports
230 		1u,															// deUint32                                    scissorCount
231 		&scissor													// const VkRect2D*                             pScissors
232 	};
233 
234 	const VkPipelineInputAssemblyStateCreateInfo			inputAssemblyStateCreateInfo		=
235 	{
236 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                            sType
237 		DE_NULL,														// const void*                                pNext
238 		0u,																// VkPipelineInputAssemblyStateCreateFlags    flags
239 		topology,														// VkPrimitiveTopology                        topology
240 		VK_FALSE														// VkBool32                                   primitiveRestartEnable
241 	};
242 
243 	const VkPipelineVertexInputStateCreateInfo				vertexInputStateCreateInfo			=
244 	{
245 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,									//  VkStructureType									sType
246 		DE_NULL,																					//  const void*										pNext
247 		(VkPipelineVertexInputStateCreateFlags)0,													//  VkPipelineVertexInputStateCreateFlags			flags
248 		0u,																							//  deUint32										vertexBindingDescriptionCount
249 		DE_NULL,																					//  const VkVertexInputBindingDescription*			pVertexBindingDescriptions
250 		0u,																							//  deUint32										vertexAttributeDescriptionCount
251 		DE_NULL,																					//  const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions
252 	};
253 
254 	const VkPipelineVertexInputStateCreateInfo*				vertexInputStateCreateInfoPtr		= (inputVertices) ? DE_NULL : &vertexInputStateCreateInfo;
255 	const VkBool32											disableRasterization				= (fragmentModule == DE_NULL);
256 	const deUint32											rasterizationStream					= (rasterizationStreamPtr == DE_NULL) ? 0 : *rasterizationStreamPtr;
257 
258 	const VkPipelineRasterizationStateStreamCreateInfoEXT	rasterizationStateStreamCreateInfo	=
259 	{
260 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT,						//  VkStructureType										sType;
261 		DE_NULL,																					//  const void*											pNext;
262 		0,																							//  VkPipelineRasterizationStateStreamCreateFlagsEXT	flags;
263 		rasterizationStream																			//  deUint32											rasterizationStream;
264 	};
265 
266 	const VkPipelineRasterizationStateCreateInfo			rasterizationStateCreateInfo		=
267 	{
268 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//  VkStructureType							sType
269 		&rasterizationStateStreamCreateInfo,						//  const void*								pNext
270 		0u,															//  VkPipelineRasterizationStateCreateFlags	flags
271 		VK_FALSE,													//  VkBool32								depthClampEnable
272 		disableRasterization,										//  VkBool32								rasterizerDiscardEnable
273 		VK_POLYGON_MODE_FILL,										//  VkPolygonMode							polygonMode
274 		VK_CULL_MODE_NONE,											//  VkCullModeFlags							cullMode
275 		VK_FRONT_FACE_COUNTER_CLOCKWISE,							//  VkFrontFace								frontFace
276 		VK_FALSE,													//  VkBool32								depthBiasEnable
277 		0.0f,														//  float									depthBiasConstantFactor
278 		0.0f,														//  float									depthBiasClamp
279 		0.0f,														//  float									depthBiasSlopeFactor
280 		1.0f														//  float									lineWidth
281 	};
282 
283 	const VkPipelineRasterizationStateCreateInfo*			rasterizationStateCreateInfoPtr		= (rasterizationStreamPtr == DE_NULL) ? DE_NULL : &rasterizationStateCreateInfo;
284 
285 	const VkPipelineTessellationStateCreateInfo				tessStateCreateInfo					=
286 	{
287 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,	// VkStructureType                           sType
288 		DE_NULL,													// const void*                               pNext
289 		0u,															// VkPipelineTessellationStateCreateFlags    flags
290 		3u															// deUint32                                  patchControlPoints
291 	};
292 
293 	return makeGraphicsPipeline(vk,									// const DeviceInterface&							vk
294 								device,								// const VkDevice									device
295 								pipelineLayout,						// const VkPipelineLayout							pipelineLayout
296 								vertexModule,						// const VkShaderModule								vertexShaderModule
297 								tessellationControlModule,			// const VkShaderModule								tessellationControlModule
298 								tessellationEvalModule,				// const VkShaderModule								tessellationEvalModule
299 								geometryModule,						// const VkShaderModule								geometryShaderModule
300 								fragmentModule,						// const VkShaderModule								fragmentShaderModule
301 								renderPass,							// const VkRenderPass								renderPass
302 								subpass,							// const deUint32									subpass
303 								vertexInputStateCreateInfoPtr,		// const VkPipelineVertexInputStateCreateInfo*		vertexInputStateCreateInfo
304 								&inputAssemblyStateCreateInfo,		// const VkPipelineInputAssemblyStateCreateInfo*	inputAssemblyStateCreateInfo
305 								&tessStateCreateInfo,				// const VkPipelineTessellationStateCreateInfo*		tessStateCreateInfo
306 								&viewportStateCreateInfo,			// const VkPipelineViewportStateCreateInfo*			viewportStateCreateInfo
307 								rasterizationStateCreateInfoPtr);	// const VkPipelineRasterizationStateCreateInfo*	rasterizationStateCreateInfo
308 }
309 
makeImageCreateInfo(const VkImageCreateFlags flags, const VkImageType type, const VkFormat format, const VkExtent2D size, const deUint32 numLayers, const VkImageUsageFlags usage)310 VkImageCreateInfo makeImageCreateInfo (const VkImageCreateFlags flags, const VkImageType type, const VkFormat format, const VkExtent2D size, const deUint32 numLayers, const VkImageUsageFlags usage)
311 {
312 	const VkExtent3D		extent		= { size.width, size.height, 1u };
313 	const VkImageCreateInfo imageParams =
314 	{
315 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
316 		DE_NULL,										// const void*				pNext;
317 		flags,											// VkImageCreateFlags		flags;
318 		type,											// VkImageType				imageType;
319 		format,											// VkFormat					format;
320 		extent,											// VkExtent3D				extent;
321 		1u,												// deUint32					mipLevels;
322 		numLayers,										// deUint32					arrayLayers;
323 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
324 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
325 		usage,											// VkImageUsageFlags		usage;
326 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
327 		0u,												// deUint32					queueFamilyIndexCount;
328 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
329 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
330 	};
331 	return imageParams;
332 }
333 
makeCustomRenderPass(const DeviceInterface& vk, const VkDevice device, const VkFormat format = VK_FORMAT_UNDEFINED)334 Move<VkRenderPass> makeCustomRenderPass (const DeviceInterface&		vk,
335 										 const VkDevice				device,
336 										 const VkFormat				format = VK_FORMAT_UNDEFINED)
337 {
338 	std::vector<VkSubpassDescription>	subpassDescriptions;
339 	std::vector<VkSubpassDependency>	subpassDependencies;
340 	const bool							hasColorAtt				= (format != VK_FORMAT_UNDEFINED);
341 
342 	std::vector<VkAttachmentDescription>	attachmentDescs;
343 	std::vector<VkAttachmentReference>		attachmentRefs;
344 
345 	if (hasColorAtt)
346 	{
347 		attachmentDescs.push_back(makeAttachmentDescription(
348 			0u,
349 			format,
350 			VK_SAMPLE_COUNT_1_BIT,
351 			VK_ATTACHMENT_LOAD_OP_CLEAR,
352 			VK_ATTACHMENT_STORE_OP_STORE,
353 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,
354 			VK_ATTACHMENT_STORE_OP_DONT_CARE,
355 			VK_IMAGE_LAYOUT_UNDEFINED,
356 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
357 		attachmentRefs.push_back(makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
358 	}
359 
360 	const VkSubpassDescription	description	=
361 	{
362 		(VkSubpassDescriptionFlags)0,		//  VkSubpassDescriptionFlags		flags;
363 		VK_PIPELINE_BIND_POINT_GRAPHICS,	//  VkPipelineBindPoint				pipelineBindPoint;
364 		0u,									//  deUint32						inputAttachmentCount;
365 		nullptr,							//  const VkAttachmentReference*	pInputAttachments;
366 		de::sizeU32(attachmentRefs),		//  deUint32						colorAttachmentCount;
367 		de::dataOrNull(attachmentRefs),		//  const VkAttachmentReference*	pColorAttachments;
368 		nullptr,							//  const VkAttachmentReference*	pResolveAttachments;
369 		nullptr,							//  const VkAttachmentReference*	pDepthStencilAttachment;
370 		0u,									//  deUint32						preserveAttachmentCount;
371 		nullptr,							//  const deUint32*					pPreserveAttachments;
372 	};
373 	subpassDescriptions.push_back(description);
374 
375 	const VkSubpassDependency	dependency	=
376 	{
377 		0u,													//  deUint32				srcSubpass;
378 		0u,													//  deUint32				dstSubpass;
379 		VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT,		//  VkPipelineStageFlags	srcStageMask;
380 		VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,				//  VkPipelineStageFlags	dstStageMask;
381 		VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,	//  VkAccessFlags			srcAccessMask;
382 		VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,	//  VkAccessFlags			dstAccessMask;
383 		0u													//  VkDependencyFlags		dependencyFlags;
384 	};
385 	subpassDependencies.push_back(dependency);
386 
387 	const VkRenderPassCreateInfo renderPassInfo =
388 	{
389 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			//  VkStructureType					sType;
390 		nullptr,											//  const void*						pNext;
391 		static_cast<VkRenderPassCreateFlags>(0u),			//  VkRenderPassCreateFlags			flags;
392 		de::sizeU32(attachmentDescs),						//  deUint32						attachmentCount;
393 		de::dataOrNull(attachmentDescs),					//  const VkAttachmentDescription*	pAttachments;
394 		de::sizeU32(subpassDescriptions),					//  deUint32						subpassCount;
395 		de::dataOrNull(subpassDescriptions),				//  const VkSubpassDescription*		pSubpasses;
396 		de::sizeU32(subpassDependencies),					//  deUint32						dependencyCount;
397 		de::dataOrNull(subpassDependencies),				//  const VkSubpassDependency*		pDependencies;
398 	};
399 
400 	return createRenderPass(vk, device, &renderPassInfo);
401 }
402 
makeImageMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask, const VkImageLayout oldLayout, const VkImageLayout newLayout, const VkImage image, const VkImageSubresourceRange subresourceRange)403 VkImageMemoryBarrier makeImageMemoryBarrier	(const VkAccessFlags			srcAccessMask,
404 											 const VkAccessFlags			dstAccessMask,
405 											 const VkImageLayout			oldLayout,
406 											 const VkImageLayout			newLayout,
407 											 const VkImage					image,
408 											 const VkImageSubresourceRange	subresourceRange)
409 {
410 	const VkImageMemoryBarrier barrier =
411 	{
412 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,			// VkStructureType			sType;
413 		DE_NULL,										// const void*				pNext;
414 		srcAccessMask,									// VkAccessFlags			outputMask;
415 		dstAccessMask,									// VkAccessFlags			inputMask;
416 		oldLayout,										// VkImageLayout			oldLayout;
417 		newLayout,										// VkImageLayout			newLayout;
418 		VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
419 		VK_QUEUE_FAMILY_IGNORED,						// deUint32					destQueueFamilyIndex;
420 		image,											// VkImage					image;
421 		subresourceRange,								// VkImageSubresourceRange	subresourceRange;
422 	};
423 	return barrier;
424 }
425 
makeBufferMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask, const VkBuffer buffer, const VkDeviceSize offset, const VkDeviceSize bufferSizeBytes)426 VkBufferMemoryBarrier makeBufferMemoryBarrier (const VkAccessFlags	srcAccessMask,
427 											   const VkAccessFlags	dstAccessMask,
428 											   const VkBuffer		buffer,
429 											   const VkDeviceSize	offset,
430 											   const VkDeviceSize	bufferSizeBytes)
431 {
432 	const VkBufferMemoryBarrier barrier =
433 	{
434 		VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	//  VkStructureType	sType;
435 		DE_NULL,									//  const void*		pNext;
436 		srcAccessMask,								//  VkAccessFlags	srcAccessMask;
437 		dstAccessMask,								//  VkAccessFlags	dstAccessMask;
438 		VK_QUEUE_FAMILY_IGNORED,					//  deUint32		srcQueueFamilyIndex;
439 		VK_QUEUE_FAMILY_IGNORED,					//  deUint32		destQueueFamilyIndex;
440 		buffer,										//  VkBuffer		buffer;
441 		offset,										//  VkDeviceSize	offset;
442 		bufferSizeBytes,							//  VkDeviceSize	size;
443 	};
444 	return barrier;
445 }
446 
makeMemoryBarrier(const VkAccessFlags srcAccessMask, const VkAccessFlags dstAccessMask)447 VkMemoryBarrier makeMemoryBarrier (const VkAccessFlags	srcAccessMask,
448 								   const VkAccessFlags	dstAccessMask)
449 {
450 	const VkMemoryBarrier barrier =
451 	{
452 		VK_STRUCTURE_TYPE_MEMORY_BARRIER,	// VkStructureType			sType;
453 		DE_NULL,							// const void*				pNext;
454 		srcAccessMask,						// VkAccessFlags			outputMask;
455 		dstAccessMask,						// VkAccessFlags			inputMask;
456 	};
457 	return barrier;
458 }
459 
makeQueryPoolCreateInfo(const deUint32 queryCountersNumber)460 VkQueryPoolCreateInfo makeQueryPoolCreateInfo (const deUint32 queryCountersNumber)
461 {
462 	const VkQueryPoolCreateInfo			queryPoolCreateInfo		=
463 	{
464 		VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,		//  VkStructureType					sType;
465 		DE_NULL,										//  const void*						pNext;
466 		(VkQueryPoolCreateFlags)0,						//  VkQueryPoolCreateFlags			flags;
467 		VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT,	//  VkQueryType						queryType;
468 		queryCountersNumber,							//  deUint32						queryCount;
469 		0u,												//  VkQueryPipelineStatisticFlags	pipelineStatistics;
470 	};
471 
472 	return queryPoolCreateInfo;
473 }
474 
fillBuffer(const DeviceInterface& vk, const VkDevice device, Allocation& bufferAlloc, VkDeviceSize bufferSize, const void* data, const VkDeviceSize dataSize)475 void fillBuffer (const DeviceInterface& vk, const VkDevice device, Allocation& bufferAlloc, VkDeviceSize bufferSize, const void* data, const VkDeviceSize dataSize)
476 {
477 	const VkMappedMemoryRange	memRange		=
478 	{
479 		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//  VkStructureType	sType;
480 		DE_NULL,								//  const void*		pNext;
481 		bufferAlloc.getMemory(),				//  VkDeviceMemory	memory;
482 		bufferAlloc.getOffset(),				//  VkDeviceSize	offset;
483 		VK_WHOLE_SIZE							//  VkDeviceSize	size;
484 	};
485 	std::vector<deUint8>		dataVec			(static_cast<deUint32>(bufferSize), 0u);
486 
487 	DE_ASSERT(bufferSize >= dataSize);
488 
489 	deMemcpy(&dataVec[0], data, static_cast<deUint32>(dataSize));
490 
491 	deMemcpy(bufferAlloc.getHostPtr(), &dataVec[0], dataVec.size());
492 	VK_CHECK(vk.flushMappedMemoryRanges(device, 1u, &memRange));
493 }
494 
destripedLineCount(const std::vector<deUint32>& lineStripeSizesList)495 deUint32 destripedLineCount (const std::vector<deUint32>& lineStripeSizesList)
496 {
497 	deUint32 result = 0;
498 
499 	DE_ASSERT(!lineStripeSizesList.empty());
500 
501 	for (auto x : lineStripeSizesList)
502 		result += x > 1 ? x - 1 : 0;
503 
504 	return result;
505 }
506 
destripedTriangleCount(const std::vector<deUint32>& triangleStripeSizesList)507 deUint32 destripedTriangleCount (const std::vector<deUint32>& triangleStripeSizesList)
508 {
509 	deUint32 result = 0;
510 
511 	DE_ASSERT(!triangleStripeSizesList.empty());
512 
513 	for (auto x : triangleStripeSizesList)
514 		result += x > 2 ? x - 2 : 0;
515 
516 	return result;
517 }
518 
519 class TransformFeedbackTestInstance : public TestInstance
520 {
521 public:
522 													TransformFeedbackTestInstance	(Context& context, const TestParameters& parameters);
523 protected:
524 	void											validateLimits					();
525 	std::vector<VkDeviceSize>						generateSizesList				(const size_t bufBytes, const size_t chunkCount);
526 	std::vector<VkDeviceSize>						generateOffsetsList				(const std::vector<VkDeviceSize>& sizesList);
527 	void											verifyTransformFeedbackBuffer	(const MovePtr<Allocation>& bufAlloc,
528 																					 const deUint32 bufBytes);
529 
530 	const VkExtent2D								m_imageExtent2D;
531 	const TestParameters							m_parameters;
532 	VkPhysicalDeviceTransformFeedbackPropertiesEXT	m_transformFeedbackProperties;
533 	de::Random										m_rnd;
534 };
535 
TransformFeedbackTestInstance(Context& context, const TestParameters& parameters)536 TransformFeedbackTestInstance::TransformFeedbackTestInstance (Context& context, const TestParameters& parameters)
537 	: TestInstance		(context)
538 	, m_imageExtent2D	(makeExtent2D(IMAGE_SIZE, IMAGE_SIZE))
539 	, m_parameters		(parameters)
540 	, m_rnd				(context.getTestContext().getCommandLine().getBaseSeed())
541 {
542 	VkPhysicalDeviceProperties2 deviceProperties2;
543 
544 	deMemset(&deviceProperties2, 0, sizeof(deviceProperties2));
545 	deMemset(&m_transformFeedbackProperties, 0, sizeof(m_transformFeedbackProperties));
546 
547 	deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
548 	deviceProperties2.pNext = &m_transformFeedbackProperties;
549 
550 	m_transformFeedbackProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
551 	m_transformFeedbackProperties.pNext = DE_NULL;
552 
553 	context.getInstanceInterface().getPhysicalDeviceProperties2(context.getPhysicalDevice(), &deviceProperties2);
554 
555 	validateLimits();
556 }
557 
validateLimits()558 void TransformFeedbackTestInstance::validateLimits ()
559 {
560 	VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBuffers, 1);
561 	VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferSize, MINIMUM_TF_BUFFER_SIZE);
562 	VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize, 512);
563 	VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize, 512);
564 	VALIDATE_MINIMUM(m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride, 512);
565 
566 	VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackQueries);
567 	VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackStreamsLinesTriangles);
568 	VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackRasterizationStreamSelect);
569 	VALIDATE_BOOL(m_transformFeedbackProperties.transformFeedbackDraw);
570 }
571 
generateSizesList(const size_t bufBytes, const size_t chunkCount)572 std::vector<VkDeviceSize> TransformFeedbackTestInstance::generateSizesList (const size_t bufBytes, const size_t chunkCount)
573 {
574 	const int					minChunkSlot	= static_cast<int>(1);
575 	const int					maxChunkSlot	= static_cast<int>(bufBytes / sizeof(deUint32));
576 	int							prevOffsetSlot	= 0;
577 	std::map<int, bool>			offsetsSet;
578 	std::vector<VkDeviceSize>	result;
579 
580 	DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
581 	DE_ASSERT(bufBytes % sizeof(deUint32) == 0);
582 	DE_ASSERT(minChunkSlot <= maxChunkSlot);
583 	DE_ASSERT(chunkCount > 0);
584 	// To be effective this algorithm requires that chunkCount is much less than amount of chunks possible
585 	DE_ASSERT(8 * chunkCount <= static_cast<size_t>(maxChunkSlot));
586 
587 	offsetsSet[0] = true;
588 
589 	// Create a list of unique offsets first
590 	for (size_t chunkNdx = 1; chunkNdx < chunkCount; ++chunkNdx)
591 	{
592 		int chunkSlot;
593 
594 		do
595 		{
596 			chunkSlot = m_rnd.getInt(minChunkSlot, maxChunkSlot - 1);
597 		} while (offsetsSet.find(chunkSlot) != offsetsSet.end());
598 
599 		offsetsSet[chunkSlot] = true;
600 	}
601 	offsetsSet[maxChunkSlot] = true;
602 
603 	// Calculate sizes of offsets list
604 	result.reserve(chunkCount);
605 	for (std::map<int, bool>::iterator mapIt = offsetsSet.begin(); mapIt != offsetsSet.end(); ++mapIt)
606 	{
607 		const int offsetSlot = mapIt->first;
608 
609 		if (offsetSlot == 0)
610 			continue;
611 
612 		DE_ASSERT(prevOffsetSlot < offsetSlot && offsetSlot > 0);
613 
614 		result.push_back(static_cast<VkDeviceSize>(static_cast<size_t>(offsetSlot - prevOffsetSlot) * sizeof(deUint32)));
615 
616 		prevOffsetSlot = offsetSlot;
617 	}
618 
619 	DE_ASSERT(result.size() == chunkCount);
620 
621 	return result;
622 }
623 
generateOffsetsList(const std::vector<VkDeviceSize>& sizesList)624 std::vector<VkDeviceSize> TransformFeedbackTestInstance::generateOffsetsList (const std::vector<VkDeviceSize>& sizesList)
625 {
626 	VkDeviceSize				offset	= 0ull;
627 	std::vector<VkDeviceSize>	result;
628 
629 	result.reserve(sizesList.size());
630 
631 	for (size_t chunkNdx = 0; chunkNdx < sizesList.size(); ++chunkNdx)
632 	{
633 		result.push_back(offset);
634 
635 		offset += sizesList[chunkNdx];
636 	}
637 
638 	DE_ASSERT(sizesList.size() == result.size());
639 
640 	return result;
641 }
642 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)643 void TransformFeedbackTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>&	bufAlloc,
644 																   const deUint32				bufBytes)
645 {
646 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
647 	const VkDevice			device		= m_context.getDevice();
648 	const deUint32			numPoints	= static_cast<deUint32>(bufBytes / sizeof(deUint32));
649 	const deUint32*			tfData		= getInvalidatedHostPtr<deUint32>(vk, device, *bufAlloc);
650 
651 	for (deUint32 i = 0; i < numPoints; ++i)
652 		if (tfData[i] != i)
653 			TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) + " expected:" + de::toString(i));
654 }
655 
656 class TransformFeedbackBasicTestInstance : public TransformFeedbackTestInstance
657 {
658 public:
659 						TransformFeedbackBasicTestInstance	(Context& context, const TestParameters& parameters);
660 
661 protected:
662 	tcu::TestStatus		iterate								(void);
663 };
664 
TransformFeedbackBasicTestInstance(Context& context, const TestParameters& parameters)665 TransformFeedbackBasicTestInstance::TransformFeedbackBasicTestInstance (Context& context, const TestParameters& parameters)
666 	: TransformFeedbackTestInstance	(context, parameters)
667 {
668 }
669 
iterate(void)670 tcu::TestStatus TransformFeedbackBasicTestInstance::iterate (void)
671 {
672 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
673 	const VkDevice						device					= m_context.getDevice();
674 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
675 	const VkQueue						queue					= m_context.getUniversalQueue();
676 	Allocator&							allocator				= m_context.getDefaultAllocator();
677 
678 	const Unique<VkShaderModule>		vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
679 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
680 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
681 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
682 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
683 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
684 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
685 
686 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
687 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
688 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
689 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
690 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
691 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
692 
693 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
694 
695 	beginCommandBuffer(vk, *cmdBuffer);
696 	{
697 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
698 		{
699 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
700 
701 			for (deUint32 drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
702 			{
703 				const deUint32	startValue	= static_cast<deUint32>(tfBufBindingOffsets[drawNdx] / sizeof(deUint32));
704 				const deUint32	numPoints	= static_cast<deUint32>(tfBufBindingSizes[drawNdx] / sizeof(deUint32));
705 
706 				vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[drawNdx], &tfBufBindingSizes[drawNdx]);
707 
708 				vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(startValue), &startValue);
709 
710 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
711 				{
712 					vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
713 				}
714 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
715 			}
716 		}
717 		endRenderPass(vk, *cmdBuffer);
718 
719 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
720 	}
721 	endCommandBuffer(vk, *cmdBuffer);
722 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
723 
724 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
725 
726 	return tcu::TestStatus::pass("Pass");
727 }
728 
729 class TransformFeedbackResumeTestInstance : public TransformFeedbackTestInstance
730 {
731 public:
732 						TransformFeedbackResumeTestInstance	(Context& context, const TestParameters& parameters);
733 
734 protected:
735 	tcu::TestStatus		iterate								(void);
736 };
737 
TransformFeedbackResumeTestInstance(Context& context, const TestParameters& parameters)738 TransformFeedbackResumeTestInstance::TransformFeedbackResumeTestInstance (Context& context, const TestParameters& parameters)
739 	: TransformFeedbackTestInstance	(context, parameters)
740 {
741 }
742 
iterate(void)743 tcu::TestStatus TransformFeedbackResumeTestInstance::iterate (void)
744 {
745 	const DeviceInterface&					vk						= m_context.getDeviceInterface();
746 	const VkDevice							device					= m_context.getDevice();
747 	const deUint32							queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
748 	const VkQueue							queue					= m_context.getUniversalQueue();
749 	Allocator&								allocator				= m_context.getDefaultAllocator();
750 
751 	const Unique<VkShaderModule>			vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
752 	const Unique<VkRenderPass>				renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
753 	const Unique<VkFramebuffer>				framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
754 	const Unique<VkPipelineLayout>			pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
755 	const Unique<VkPipeline>				pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
756 
757 	const Unique<VkCommandPool>				cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
758 	const Unique<VkCommandBuffer>			cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
759 
760 	VkBufferCreateInfo						tfBufCreateInfo			= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
761 
762 #ifndef CTS_USES_VULKANSC
763 	vk::VkBufferUsageFlags2CreateInfoKHR bufferUsageFlags2 = vk::initVulkanStructure();
764 	if (m_parameters.useMaintenance5)
765 	{
766 		bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)tfBufCreateInfo.usage;
767 		tfBufCreateInfo.pNext = &bufferUsageFlags2;
768 		tfBufCreateInfo.usage = 0;
769 	}
770 #endif // CTS_USES_VULKANSC
771 
772 	const Move<VkBuffer>					tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
773 	const MovePtr<Allocation>				tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
774 	const VkMemoryBarrier					tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
775 	const std::vector<VkDeviceSize>			tfBufBindingSizes		= std::vector<VkDeviceSize>(1, m_parameters.bufferSize);
776 	const std::vector<VkDeviceSize>			tfBufBindingOffsets		= std::vector<VkDeviceSize>(1, 0ull);
777 
778 	const size_t							tfcBufSize				= 16 * sizeof(deUint32) * m_parameters.partCount;
779 	VkBufferCreateInfo						tfcBufCreateInfo		= makeBufferCreateInfo(tfcBufSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT);
780 
781 #ifndef CTS_USES_VULKANSC
782 	if (m_parameters.useMaintenance5)
783 	{
784 		bufferUsageFlags2.usage = (VkBufferUsageFlagBits2KHR)tfcBufCreateInfo.usage;
785 		tfcBufCreateInfo.pNext = &bufferUsageFlags2;
786 		tfcBufCreateInfo.usage = 0;
787 	}
788 #endif // CTS_USES_VULKANSC
789 
790 	const Move<VkBuffer>					tfcBuf					= createBuffer(vk, device, &tfcBufCreateInfo);
791 	const MovePtr<Allocation>				tfcBufAllocation		= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfcBuf), MemoryRequirement::Any);
792 	const std::vector<VkDeviceSize>			tfcBufBindingOffsets	= generateOffsetsList(generateSizesList(tfcBufSize, m_parameters.partCount));
793 	const VkBufferMemoryBarrier				tfcBufBarrier			= makeBufferMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT, *tfcBuf, 0ull, VK_WHOLE_SIZE);
794 
795 	const std::vector<VkDeviceSize>			chunkSizesList			= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
796 	const std::vector<VkDeviceSize>			chunkOffsetsList		= generateOffsetsList(chunkSizesList);
797 
798 	DE_ASSERT(tfBufBindingSizes.size() == 1);
799 	DE_ASSERT(tfBufBindingOffsets.size() == 1);
800 
801 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
802 	VK_CHECK(vk.bindBufferMemory(device, *tfcBuf, tfcBufAllocation->getMemory(), tfcBufAllocation->getOffset()));
803 
804 	beginCommandBuffer(vk, *cmdBuffer);
805 	{
806 		for (size_t drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
807 		{
808 			const deUint32	startValue = static_cast<deUint32>(chunkOffsetsList[drawNdx] / sizeof(deUint32));
809 			const deUint32	numPoints = static_cast<deUint32>(chunkSizesList[drawNdx] / sizeof(deUint32));
810 			const deUint32	countBuffersCount = (drawNdx == 0) ? 0 : 1;
811 
812 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
813 			{
814 
815 				vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
816 
817 				vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
818 
819 				vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(startValue), &startValue);
820 
821 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, countBuffersCount, (drawNdx == 0) ? DE_NULL : &*tfcBuf, (drawNdx == 0) ? DE_NULL : &tfcBufBindingOffsets[drawNdx - 1]);
822 				{
823 					vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
824 				}
825 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf, &tfcBufBindingOffsets[drawNdx]);
826 			}
827 			endRenderPass(vk, *cmdBuffer);
828 
829 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 0u, DE_NULL, 1u, &tfcBufBarrier, 0u, DE_NULL);
830 		}
831 
832 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
833 	}
834 	endCommandBuffer(vk, *cmdBuffer);
835 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
836 
837 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
838 
839 	return tcu::TestStatus::pass("Pass");
840 }
841 
842 class TransformFeedbackWindingOrderTestInstance : public TransformFeedbackTestInstance
843 {
844 public:
845 	TransformFeedbackWindingOrderTestInstance(Context& context, const TestParameters& parameters);
846 
847 protected:
848 	struct TopologyParameters
849 	{
850 		// number of vertex in primitive; 2 for line, 3 for triangle
851 		deUint32 vertexPerPrimitive;
852 
853 		// pointer to function calculating number of points that
854 		// will be generated for given part count
855 		std::function<deUint32(deUint32)> getNumGeneratedPoints;
856 
857 		// pointer to function generating expected values; parameter is
858 		// primitive index, result array with expected data for primitive vertex
859 		std::function<std::vector<deUint32>(deUint32)> getExpectedValuesForPrimitive;
860 	};
861 	typedef const std::map<VkPrimitiveTopology, TopologyParameters> TopologyParametersMap;
862 
863 protected:
864 	const TopologyParametersMap&	getTopologyParametersMap					(void);
865 	tcu::TestStatus					iterate										(void);
866 	void							verifyTransformFeedbackBuffer				(const MovePtr<Allocation>& bufAlloc,
867 																				 const deUint32 bufBytes);
868 
869 private:
870 	TopologyParameters				m_tParameters;
871 	const bool						m_requiresTesselationStage;
872 };
873 
TransformFeedbackWindingOrderTestInstance(Context& context, const TestParameters& parameters)874 TransformFeedbackWindingOrderTestInstance::TransformFeedbackWindingOrderTestInstance(Context& context, const TestParameters& parameters)
875 	: TransformFeedbackTestInstance	(context, parameters)
876 	, m_requiresTesselationStage(parameters.primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
877 {
878 	if (m_requiresTesselationStage && !context.getDeviceFeatures().tessellationShader)
879 		throw tcu::NotSupportedError("Tessellation shader not supported");
880 
881 	TopologyParametersMap topologyParametersMap = getTopologyParametersMap();
882 	DE_ASSERT(topologyParametersMap.find(parameters.primTopology) != topologyParametersMap.end());
883 	m_tParameters = topologyParametersMap.at(parameters.primTopology);
884 }
885 
getTopologyParametersMap(void)886 const TransformFeedbackWindingOrderTestInstance::TopologyParametersMap& TransformFeedbackWindingOrderTestInstance::getTopologyParametersMap(void)
887 {
888 	static const TopologyParametersMap topologyParametersMap =
889 	{
890 		{
891 			VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
892 			{
893 				1u,
894 				[](deUint32 partCount)	{	return partCount;	},
895 				[](deUint32 i)			{	return std::vector<deUint32>{ i, i + 1u };	}
896 			}
897 		},
898 		{
899 			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
900 			{
901 				2u,
902 				[](deUint32 partCount)	{	return partCount;	},
903 				[](deUint32 i)			{	return std::vector<deUint32>{ 2 * i, 2 * i + 1u };	}
904 			}
905 		},
906 		{
907 			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
908 			{
909 				2u,
910 				[](deUint32 partCount)	{	return 2u * (partCount - 1);	},
911 				[](deUint32 i)			{	return std::vector<deUint32>{ i, i + 1u };	}
912 			}
913 		},
914 		{
915 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
916 			{
917 				3u,
918 				[](deUint32 partCount)	{	return partCount;	},
919 				[](deUint32 i)			{	return std::vector<deUint32>{ 3 * i, 3 * i + 1u, 3 * i + 2u };	}
920 			}
921 		},
922 		{
923 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
924 			{
925 				3u,
926 				[](deUint32 partCount)	{	return 3u * (partCount - 2);	},
927 				[](deUint32 i)
928 				{
929 					const deUint32	iMod2 = i % 2;
930 					return std::vector<deUint32>{ i, i + 1 + iMod2, i + 2 - iMod2 };
931 				}
932 			}
933 		},
934 		{
935 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
936 			{
937 				3u,
938 				[](deUint32 partCount)	{	return partCount;	},
939 				[](deUint32 i)			{	return std::vector<deUint32>{ i + 1, i + 2, 0 };	}
940 			}
941 		},
942 		{
943 			VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
944 			{
945 				2u,
946 				[](deUint32 partCount)	{	return partCount / 4u;	},		// note: this cant be replaced with partCount / 2 as for partCount=6 we will get 3 instead of 2
947 				[](deUint32 i)			{	return std::vector<deUint32>{ i + 1u, i + 2u };	}
948 			}
949 		},
950 		{
951 			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
952 			{
953 				2u,
954 				[](deUint32 partCount)	{	return 2u * (partCount - 3u);	},
955 				[](deUint32 i)			{	return std::vector<deUint32>{ i + 1u, i + 2u };	}
956 			}
957 		},
958 		{
959 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
960 			{
961 				3u,
962 				[](deUint32 partCount)	{	return partCount / 2u;	},
963 				[](deUint32 i)			{	return std::vector<deUint32>{ 6 * i, 6 * i + 2u, 6 * i + 4u	};	}
964 			}
965 		},
966 		{
967 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
968 			{
969 				3u,
970 				[](deUint32 partCount)	{	return 3u * (partCount / 2u - 2u);	},
971 				[](deUint32 i)
972 				{
973 					const bool even = (0 == i % 2);
974 					if (even)
975 						return std::vector<deUint32>{ 2 * i + 0, 2 * i + 2, 2 * i + 4 };
976 					return std::vector<deUint32>{ 2 * i + 0, 2 * i + 4, 2 * i + 2 };
977 				}
978 			}
979 		},
980 		{
981 			VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
982 			{
983 				9u,
984 				[](deUint32 partCount)	{	return partCount * 3u;	},
985 				[](deUint32 i)
986 				{
987 					// we cant generate vertex numbers in tesselation evaluation shader;
988 					// check if patch index is correct for every 9 generated vertex
989 					return std::vector<deUint32>(9, i);
990 				}
991 			}
992 		}
993 	};
994 
995 	return topologyParametersMap;
996 }
997 
iterate(void)998 tcu::TestStatus TransformFeedbackWindingOrderTestInstance::iterate (void)
999 {
1000 	DE_ASSERT(m_parameters.partCount >= 6);
1001 
1002 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
1003 	const VkDevice					device				= m_context.getDevice();
1004 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1005 	const VkQueue					queue				= m_context.getUniversalQueue();
1006 	Allocator&						allocator			= m_context.getDefaultAllocator();
1007 
1008 	const Move<VkShaderModule>		vertexModule(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1009 	Move<VkShaderModule>			tescModule;
1010 	Move<VkShaderModule>			teseModule;
1011 	if (m_requiresTesselationStage)
1012 	{
1013 		tescModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("tesc"), 0u);
1014 		teseModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("tese"), 0u);
1015 	}
1016 
1017 	const Unique<VkRenderPass>		renderPass			(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
1018 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1019 	const Unique<VkPipelineLayout>	pipelineLayout		(TransformFeedback::makePipelineLayout	(vk, device));
1020 	const Unique<VkPipeline>		pipeline			(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass,
1021 																								 *vertexModule,
1022 																								 m_requiresTesselationStage ? *tescModule : DE_NULL,
1023 																								 m_requiresTesselationStage ? *teseModule : DE_NULL,
1024 																								 DE_NULL,
1025 																								 DE_NULL,
1026 																								 m_imageExtent2D, 0u, DE_NULL, m_parameters.primTopology));
1027 	const Unique<VkCommandPool>		cmdPool				(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1028 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1029 	const VkDeviceSize				bufferSize			= m_tParameters.getNumGeneratedPoints	(m_parameters.partCount) * sizeof(deUint32);
1030 	const VkBufferCreateInfo		tfBufCreateInfo		= makeBufferCreateInfo					(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1031 	const Move<VkBuffer>			tfBuf				= createBuffer							(vk, device, &tfBufCreateInfo);
1032 	const MovePtr<Allocation>		tfBufAllocation		= allocator.allocate					(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1033 	const VkMemoryBarrier			tfMemoryBarrier		= makeMemoryBarrier						(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1034 	const VkDeviceSize				tfBufBindingSize	= bufferSize;
1035 	const VkDeviceSize				tfBufBindingOffset	= 0u;
1036 	const deUint32					startValue			= 0u;
1037 
1038 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1039 
1040 	beginCommandBuffer(vk, *cmdBuffer);
1041 	{
1042 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1043 		{
1044 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1045 
1046 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
1047 
1048 			vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(startValue), &startValue);
1049 
1050 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1051 			{
1052 				vk.cmdDraw(*cmdBuffer, m_parameters.partCount, 1u, 0u, 0u);
1053 			}
1054 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1055 		}
1056 		endRenderPass(vk, *cmdBuffer);
1057 
1058 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1059 	}
1060 	endCommandBuffer(vk, *cmdBuffer);
1061 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1062 
1063 	verifyTransformFeedbackBuffer(tfBufAllocation, static_cast<deUint32>(bufferSize));
1064 
1065 	return tcu::TestStatus::pass("Pass");
1066 }
1067 
1068 template <typename T, int Size>
operator >(const tcu::Vector<T, Size>& a, const tcu::Vector<T, Size>& b)1069 bool operator>(const tcu::Vector<T, Size>& a, const tcu::Vector<T, Size>& b)
1070 {
1071 	return tcu::boolAny(tcu::greaterThan(a, b));
1072 }
1073 
1074 template <typename T, int Size>
elemAbsDiff(const tcu::Vector<T, Size>& a, const tcu::Vector<T, Size>& b)1075 tcu::Vector<T, Size> elemAbsDiff (const tcu::Vector<T, Size>& a, const tcu::Vector<T, Size>& b)
1076 {
1077 	return tcu::absDiff(a, b);
1078 }
1079 
elemAbsDiff(uint32_t a, uint32_t b)1080 uint32_t elemAbsDiff (uint32_t a, uint32_t b)
1081 {
1082 	if (a > b)
1083 		return a - b;
1084 	return b - a;
1085 }
1086 
1087 template <typename T>
verifyVertexDataWithWinding(const std::vector<T>& reference, const T* result, const size_t vertexCount, const size_t verticesPerPrimitive, const T& threshold)1088 std::vector<std::string> verifyVertexDataWithWinding (const std::vector<T>& reference, const T* result, const size_t vertexCount, const size_t verticesPerPrimitive, const T& threshold)
1089 {
1090 	//DE_ASSERT(vertexCount % verticesPerPrimitive == 0);
1091 	//DE_ASSERT(reference.size() == vertexCount);
1092 	const size_t primitiveCount = vertexCount / verticesPerPrimitive;
1093 
1094 	std::vector<std::string> errors;
1095 
1096 	for (size_t primIdx = 0; primIdx < primitiveCount; ++primIdx)
1097 	{
1098 		const auto	pastVertexCount	= verticesPerPrimitive * primIdx;
1099 		const T*	resultPrim		= result + pastVertexCount;
1100 		const T*	referencePrim	= &reference.at(pastVertexCount);
1101 		bool		primitiveOK		= false;
1102 
1103 		// Vertices must be in the same winding order, but the first vertex may vary. We test every rotation below.
1104 		// E.g. vertices 0 1 2 could be stored as 0 1 2, 2 0 1 or 1 2 0.
1105 		for (size_t firstVertex = 0; firstVertex < verticesPerPrimitive; ++firstVertex)
1106 		{
1107 			bool match = true;
1108 			for (size_t vertIdx = 0; vertIdx < verticesPerPrimitive; ++vertIdx)
1109 			{
1110 				const auto& refVertex = referencePrim[(firstVertex + vertIdx) % verticesPerPrimitive]; // Rotation.
1111 				const auto& resVertex = resultPrim[vertIdx];
1112 
1113 				if (elemAbsDiff(refVertex, resVertex) > threshold)
1114 				{
1115 					match = false;
1116 					break;
1117 				}
1118 			}
1119 
1120 			if (match)
1121 			{
1122 				primitiveOK = true;
1123 				break;
1124 			}
1125 		}
1126 
1127 		if (!primitiveOK)
1128 		{
1129 			// Log error.
1130 			std::ostringstream err;
1131 			err << "Primitive " << primIdx << " failed: expected rotation of [";
1132 			for (size_t i = 0; i < verticesPerPrimitive; ++i)
1133 				err << ((i > 0) ? ", " : "") << referencePrim[i];
1134 			err << "] but found [";
1135 			for (size_t i = 0; i < verticesPerPrimitive; ++i)
1136 				err << ((i > 0) ? ", " : "") << resultPrim[i];
1137 			err << "]; threshold: " << threshold;
1138 			errors.push_back(err.str());
1139 		}
1140 	}
1141 
1142 	return errors;
1143 }
1144 
checkErrorVec(tcu::TestLog& log, const std::vector<std::string>& errors)1145 void checkErrorVec (tcu::TestLog& log, const std::vector<std::string>& errors)
1146 {
1147 	if (!errors.empty())
1148 	{
1149 		for (const auto& err : errors)
1150 			log << tcu::TestLog::Message << err << tcu::TestLog::EndMessage;
1151 		TCU_FAIL("Vertex data verification failed; check log for details");
1152 	}
1153 }
1154 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)1155 void TransformFeedbackWindingOrderTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>&	bufAlloc,
1156 																			   const deUint32				bufBytes)
1157 {
1158 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
1159 	const VkDevice			device				= m_context.getDevice();
1160 	const deUint32			numPoints			= static_cast<deUint32>(bufBytes / sizeof(deUint32));
1161 	const deUint32			vertexPerPrimitive	= m_tParameters.vertexPerPrimitive;
1162 	const deUint32			numPrimitives		= numPoints / vertexPerPrimitive;
1163 	const deUint32*			tfData				= getInvalidatedHostPtr<deUint32>(vk, device, *bufAlloc);
1164 
1165 	std::vector<uint32_t> referenceValues;
1166 	referenceValues.reserve(numPrimitives * vertexPerPrimitive);
1167 
1168 	for (uint32_t primIdx = 0; primIdx < numPrimitives; ++primIdx)
1169 	{
1170 		const auto expectedValues = m_tParameters.getExpectedValuesForPrimitive(primIdx);
1171 		for (const auto& value : expectedValues)
1172 			referenceValues.push_back(value);
1173 	}
1174 
1175 	const auto errors = verifyVertexDataWithWinding(referenceValues, tfData, numPoints, vertexPerPrimitive, 0u/*threshold*/);
1176 	checkErrorVec(m_context.getTestContext().getLog(), errors);
1177 }
1178 
1179 class TransformFeedbackBuiltinTestInstance : public TransformFeedbackTestInstance
1180 {
1181 public:
1182 						TransformFeedbackBuiltinTestInstance	(Context& context, const TestParameters& parameters);
1183 
1184 protected:
1185 	tcu::TestStatus		iterate									(void);
1186 	void				verifyTransformFeedbackBuffer			(const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes);
1187 };
1188 
TransformFeedbackBuiltinTestInstance(Context& context, const TestParameters& parameters)1189 TransformFeedbackBuiltinTestInstance::TransformFeedbackBuiltinTestInstance (Context& context, const TestParameters& parameters)
1190 	: TransformFeedbackTestInstance	(context, parameters)
1191 {
1192 	const InstanceInterface&		vki			= m_context.getInstanceInterface();
1193 	const VkPhysicalDevice			physDevice	= m_context.getPhysicalDevice();
1194 	const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(vki, physDevice);
1195 
1196 	const deUint32 tfBuffersSupported	= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1197 	const deUint32 tfBuffersRequired	= m_parameters.partCount;
1198 
1199 	if ((m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE || m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) && !features.shaderClipDistance)
1200 		TCU_THROW(NotSupportedError, std::string("shaderClipDistance feature is not supported"));
1201 	if ((m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE || m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) && !features.shaderCullDistance)
1202 		TCU_THROW(NotSupportedError, std::string("shaderCullDistance feature is not supported"));
1203 	if (tfBuffersSupported < tfBuffersRequired)
1204 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
1205 }
1206 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes)1207 void TransformFeedbackBuiltinTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes)
1208 {
1209 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
1210 	const VkDevice			device		= m_context.getDevice();
1211 	const deUint32			numPoints	= bufBytes / static_cast<deUint32>(sizeof(float));
1212 	const deUint8*			tfDataBytes	= getInvalidatedHostPtr<deUint8>(vk, device, *bufAlloc);
1213 	const float*			tfData		= (float*)&tfDataBytes[offset];
1214 
1215 	for (deUint32 i = 0; i < numPoints; ++i)
1216 	{
1217 		const deUint32	divisor		= 32768u;
1218 		const float		epsilon		= 1.0f / float(divisor);
1219 		const float		expected	= float(i) / float(divisor);
1220 
1221 		if (deAbs(tfData[i] - expected) > epsilon)
1222 			TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) + " expected:" + de::toString(expected));
1223 	}
1224 }
1225 
iterate(void)1226 tcu::TestStatus TransformFeedbackBuiltinTestInstance::iterate (void)
1227 {
1228 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
1229 	const VkDevice						device					= m_context.getDevice();
1230 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
1231 	const VkQueue						queue					= m_context.getUniversalQueue();
1232 	Allocator&							allocator				= m_context.getDefaultAllocator();
1233 
1234 	const Unique<VkShaderModule>		vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1235 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
1236 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1237 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
1238 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
1239 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1240 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1241 
1242 	const VkDeviceSize					tfBufSize				= m_parameters.bufferSize * m_parameters.partCount;
1243 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(tfBufSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1244 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
1245 	const std::vector<VkBuffer>			tfBufArray				= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1246 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1247 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1248 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= std::vector<VkDeviceSize>(m_parameters.partCount, m_parameters.bufferSize);
1249 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
1250 	const deUint32						perVertexDataSize		= (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)    ? static_cast<deUint32>(sizeof(float))
1251 																: (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE) ? static_cast<deUint32>(8u * sizeof(float))
1252 																: (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE) ? static_cast<deUint32>(8u * sizeof(float))
1253 																: (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ? static_cast<deUint32>(6u * sizeof(float))
1254 																: 0u;
1255 	const deUint32						numPoints				= m_parameters.bufferSize / perVertexDataSize;
1256 
1257 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1258 
1259 	beginCommandBuffer(vk, *cmdBuffer);
1260 	{
1261 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1262 		{
1263 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1264 
1265 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1266 
1267 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1268 			{
1269 				vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
1270 			}
1271 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1272 		}
1273 		endRenderPass(vk, *cmdBuffer);
1274 
1275 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1276 	}
1277 	endCommandBuffer(vk, *cmdBuffer);
1278 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1279 
1280 	verifyTransformFeedbackBuffer(tfBufAllocation, tfBufBindingOffsets[m_parameters.partCount - 1], numPoints * perVertexDataSize);
1281 
1282 	return tcu::TestStatus::pass("Pass");
1283 }
1284 
1285 class TransformFeedbackDepthClipControlTestInstance : public TransformFeedbackTestInstance
1286 {
1287 public:
1288 	TransformFeedbackDepthClipControlTestInstance		(Context& context, const TestParameters& parameters);
1289 
1290 protected:
1291 	tcu::TestStatus		iterate							(void);
1292 	void				verifyTransformFeedbackBuffer	(const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes);
1293 };
1294 
TransformFeedbackDepthClipControlTestInstance(Context& context, const TestParameters& parameters)1295 TransformFeedbackDepthClipControlTestInstance::TransformFeedbackDepthClipControlTestInstance (Context& context, const TestParameters& parameters)
1296 		: TransformFeedbackTestInstance	(context, parameters)
1297 {
1298 	const InstanceInterface&		vki			= m_context.getInstanceInterface();
1299 	const VkPhysicalDevice			physDevice	= m_context.getPhysicalDevice();
1300 	const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(vki, physDevice);
1301 
1302 	const deUint32 tfBuffersSupported	= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1303 	const deUint32 tfBuffersRequired	= m_parameters.partCount;
1304 
1305 	if (!context.isDeviceFunctionalitySupported("VK_EXT_depth_clip_control"))
1306 		TCU_THROW(NotSupportedError, "VK_EXT_depth_clip_control is not supported");
1307 
1308 	if (parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY && !features.geometryShader)
1309 		TCU_THROW(NotSupportedError, "Geometry shader not supported");
1310 
1311 	if (parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE && !features.tessellationShader)
1312 		TCU_THROW(NotSupportedError, "Tessellation shader not supported");
1313 
1314 	if (tfBuffersSupported < tfBuffersRequired)
1315 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
1316 }
1317 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes)1318 void TransformFeedbackDepthClipControlTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>& bufAlloc, const VkDeviceSize offset, const deUint32 bufBytes)
1319 {
1320 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
1321 	const VkDevice			device		= m_context.getDevice();
1322 	const deUint32			numVertices	= bufBytes / static_cast<deUint32>(sizeof(float) * 4);
1323 	const deUint8*			tfDataBytes	= getInvalidatedHostPtr<deUint8>(vk, device, *bufAlloc);
1324 	const float*			tfData		= (float*)&tfDataBytes[offset];
1325 	std::vector<float>		result;
1326 
1327 	// We only care about the depth (z) value.
1328 	for (deUint32 i = 0; i < numVertices; i++)
1329 		result.push_back(tfData[i * 4 + 2]);
1330 
1331 	// Tessellation generates triangles whose vertex data might be written into
1332 	// transform feedback buffer in a different order than generated by the vertex
1333 	// shader. Sort the values here to allow comparison.
1334 	if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
1335 	{
1336 		std::sort(result.begin(), result.end());
1337 	}
1338 
1339 	// Verify the vertex depth values match with the ones written by the shader.
1340 	for (deUint32 i = 0; i < numVertices; i++)
1341 	{
1342 		const float	expected	= (float)i / 3.0f - 1.0f;
1343 		const float	epsilon		= 0.0001f;
1344 
1345 		if (deAbs(result[i] - expected) > epsilon)
1346 			TCU_FAIL(std::string("Failed at vertex ") + de::toString(i) + " depth. Received:" + de::toString(result[i]) + " expected:" + de::toString(expected));
1347 	}
1348 }
1349 
iterate(void)1350 tcu::TestStatus TransformFeedbackDepthClipControlTestInstance::iterate (void)
1351 {
1352 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
1353 	const VkDevice						device					= m_context.getDevice();
1354 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
1355 	const VkQueue						queue					= m_context.getUniversalQueue();
1356 	Allocator&							allocator				= m_context.getDefaultAllocator();
1357 
1358 	const Unique<VkShaderModule>		vertexModule			(createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1359 	Move<VkShaderModule>				geomModule;
1360 	Move<VkShaderModule>				tescModule;
1361 	Move<VkShaderModule>				teseModule;
1362 	const bool							hasGeomShader			= m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY;
1363 	const bool							hasTessellation			= m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE;
1364 
1365 	if (hasGeomShader)
1366 		geomModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("geom"), 0u);
1367 
1368 	if (hasTessellation)
1369 	{
1370 		tescModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("tesc"), 0u);
1371 		teseModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("tese"), 0u);
1372 	}
1373 
1374 	const Unique<VkRenderPass>			renderPass				(makeRenderPass(vk, device, VK_FORMAT_UNDEFINED));
1375 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1376 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
1377 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline(vk, device, *pipelineLayout, *renderPass, *vertexModule, hasTessellation ? *tescModule : DE_NULL, hasTessellation ? *teseModule : DE_NULL, hasGeomShader ? *geomModule : DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId, m_parameters.primTopology, false, true));
1378 	const Unique<VkCommandPool>			cmdPool					(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1379 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1380 	const VkDeviceSize					tfBufSize				= m_parameters.bufferSize * m_parameters.partCount;
1381 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(tfBufSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1382 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
1383 	const std::vector<VkBuffer>			tfBufArray				= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1384 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1385 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1386 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= std::vector<VkDeviceSize>(m_parameters.partCount, m_parameters.bufferSize);
1387 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
1388 	const deUint32						perVertexDataSize		= static_cast<deUint32>(4u * sizeof(float));
1389 	const deUint32						numVertices				= m_parameters.bufferSize / perVertexDataSize;
1390 
1391 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1392 
1393 	beginCommandBuffer(vk, *cmdBuffer);
1394 	{
1395 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1396 		{
1397 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1398 
1399 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1400 
1401 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1402 			{
1403 				vk.cmdDraw(*cmdBuffer, numVertices, 1u, 0u, 0u);
1404 			}
1405 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1406 		}
1407 		endRenderPass(vk, *cmdBuffer);
1408 
1409 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1410 	}
1411 	endCommandBuffer(vk, *cmdBuffer);
1412 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1413 
1414 	verifyTransformFeedbackBuffer(tfBufAllocation, tfBufBindingOffsets[m_parameters.partCount - 1], m_parameters.bufferSize);
1415 
1416 	return tcu::TestStatus::pass("Pass");
1417 }
1418 
1419 class TransformFeedbackMultistreamTestInstance : public TransformFeedbackTestInstance
1420 {
1421 public:
1422 								TransformFeedbackMultistreamTestInstance	(Context& context, const TestParameters& parameters);
1423 
1424 protected:
1425 	std::vector<VkDeviceSize>	generateSizesList							(const size_t bufBytes, const size_t chunkCount);
1426 	void						verifyTransformFeedbackBuffer				(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes);
1427 	tcu::TestStatus				iterate										(void);
1428 };
1429 
TransformFeedbackMultistreamTestInstance(Context& context, const TestParameters& parameters)1430 TransformFeedbackMultistreamTestInstance::TransformFeedbackMultistreamTestInstance (Context& context, const TestParameters& parameters)
1431 	: TransformFeedbackTestInstance	(context, parameters)
1432 {
1433 	const InstanceInterface&								vki							= m_context.getInstanceInterface();
1434 	const VkPhysicalDevice									physDevice					= m_context.getPhysicalDevice();
1435 	const VkPhysicalDeviceFeatures							features					= getPhysicalDeviceFeatures(vki, physDevice);
1436 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&		transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
1437 	const deUint32											streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
1438 	const deUint32											streamsRequired				= m_parameters.streamId + 1;
1439 	const deUint32											tfBuffersSupported			= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1440 	const deUint32											tfBuffersRequired			= m_parameters.partCount;
1441 	const deUint32											bytesPerVertex				= m_parameters.bufferSize / m_parameters.partCount;
1442 	const deUint32											tfStreamDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
1443 	const deUint32											tfBufferDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
1444 	const deUint32											tfBufferDataStrideSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
1445 
1446 	DE_ASSERT(m_parameters.partCount == 2u);
1447 
1448 	if (!features.geometryShader)
1449 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
1450 
1451 	if (transformFeedbackFeatures.geometryStreams == DE_FALSE)
1452 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
1453 
1454 	if (streamsSupported < streamsRequired)
1455 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
1456 
1457 	if (tfBuffersSupported < tfBuffersRequired)
1458 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
1459 
1460 	if (tfStreamDataSizeSupported < bytesPerVertex)
1461 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1462 
1463 	if (tfBufferDataSizeSupported < bytesPerVertex)
1464 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1465 
1466 	if (tfBufferDataStrideSupported < bytesPerVertex)
1467 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1468 }
1469 
generateSizesList(const size_t bufBytes, const size_t chunkCount)1470 std::vector<VkDeviceSize> TransformFeedbackMultistreamTestInstance::generateSizesList (const size_t bufBytes, const size_t chunkCount)
1471 {
1472 	const VkDeviceSize			chunkSize	= bufBytes / chunkCount;
1473 	std::vector<VkDeviceSize>	result		(chunkCount, chunkSize);
1474 
1475 	DE_ASSERT(chunkSize * chunkCount == bufBytes);
1476 	DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
1477 	DE_ASSERT(bufBytes % sizeof(deUint32) == 0);
1478 	DE_ASSERT(chunkCount > 0);
1479 	DE_ASSERT(result.size() == chunkCount);
1480 
1481 	return result;
1482 }
1483 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)1484 void TransformFeedbackMultistreamTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)
1485 {
1486 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
1487 	const VkDevice			device		= m_context.getDevice();
1488 	const deUint32			numPoints	= static_cast<deUint32>(bufBytes / sizeof(deUint32));
1489 	const float*			tfData		= getInvalidatedHostPtr<float>(vk, device, *bufAlloc);
1490 
1491 	for (deUint32 i = 0; i < numPoints; ++i)
1492 		if (tfData[i] != float(i))
1493 			TCU_FAIL(std::string("Failed at item ") + de::toString(float(i)) + " received:" + de::toString(tfData[i]) + " expected:" + de::toString(i));
1494 }
1495 
iterate(void)1496 tcu::TestStatus TransformFeedbackMultistreamTestInstance::iterate (void)
1497 {
1498 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
1499 	const VkDevice						device					= m_context.getDevice();
1500 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
1501 	const VkQueue						queue					= m_context.getUniversalQueue();
1502 	Allocator&							allocator				= m_context.getDefaultAllocator();
1503 
1504 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
1505 
1506 	const Unique<VkShaderModule>		vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1507 	const Unique<VkShaderModule>		geomModule				(createShaderModule						(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
1508 
1509 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1510 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
1511 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, *geomModule, DE_NULL, m_imageExtent2D, 0u));
1512 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1513 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1514 
1515 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1516 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
1517 	const std::vector<VkBuffer>			tfBufArray				= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1518 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1519 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1520 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
1521 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
1522 
1523 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1524 
1525 	beginCommandBuffer(vk, *cmdBuffer);
1526 	{
1527 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1528 		{
1529 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1530 
1531 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1532 
1533 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1534 			{
1535 				vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
1536 			}
1537 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1538 		}
1539 		endRenderPass(vk, *cmdBuffer);
1540 
1541 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1542 	}
1543 	endCommandBuffer(vk, *cmdBuffer);
1544 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1545 
1546 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
1547 
1548 	return tcu::TestStatus::pass("Pass");
1549 }
1550 
1551 class TransformFeedbackMultistreamSameLocationTestInstance final : public TransformFeedbackTestInstance
1552 {
1553 public:
1554 	TransformFeedbackMultistreamSameLocationTestInstance(Context& context, const TestParameters& parameters);
1555 protected:
1556 	tcu::TestStatus		iterate							(void) override;
1557 	void				verifyTransformFeedbackBuffer	(const MovePtr<Allocation>& bufAlloc, deUint32 bufBytes);
1558 };
1559 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)1560 void TransformFeedbackMultistreamSameLocationTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes)
1561 {
1562 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
1563 	const VkDevice			device		= m_context.getDevice();
1564 	const auto			numPoints	= static_cast<deUint32>(bufBytes / sizeof(deUint32));
1565 	const auto*			tuData		= getInvalidatedHostPtr<deUint32>(vk, device, *bufAlloc);
1566 
1567 	for (deUint32 i = 0; i < numPoints; ++i)
1568 		if (tuData[i] != i*2 - ((i / 16) == 0 ? 0 : 31))
1569 			TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tuData[i]) + " expected:" + de::toString(i));
1570 
1571 	return;
1572 }
1573 
TransformFeedbackMultistreamSameLocationTestInstance(Context& context, const TestParameters& parameters)1574 TransformFeedbackMultistreamSameLocationTestInstance::TransformFeedbackMultistreamSameLocationTestInstance(Context& context, const TestParameters& parameters)
1575 	: TransformFeedbackTestInstance	(context, parameters)
1576 {
1577 	const InstanceInterface&								vki							= m_context.getInstanceInterface();
1578 	const VkPhysicalDevice									physDevice					= m_context.getPhysicalDevice();
1579 	const VkPhysicalDeviceFeatures							features					= getPhysicalDeviceFeatures(vki, physDevice);
1580 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&		transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
1581 	const deUint32											streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
1582 	const deUint32											streamsRequired				= m_parameters.streamId + 1;
1583 	const deUint32											tfBuffersSupported			= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
1584 	const deUint32											tfBuffersRequired			= 1;
1585 	const deUint32											bytesPerVertex				= 4;
1586 	const deUint32											tfStreamDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
1587 	const deUint32											tfBufferDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
1588 	const deUint32											tfBufferDataStrideSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
1589 
1590 	if (!features.geometryShader)
1591 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
1592 
1593 	if (transformFeedbackFeatures.geometryStreams == DE_FALSE)
1594 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
1595 
1596 	if (streamsSupported < streamsRequired)
1597 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
1598 
1599 	if (tfBuffersSupported < tfBuffersRequired)
1600 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
1601 
1602 	if (tfStreamDataSizeSupported < bytesPerVertex)
1603 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1604 
1605 	if (tfBufferDataSizeSupported < bytesPerVertex)
1606 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1607 
1608 	if (tfBufferDataStrideSupported < bytesPerVertex)
1609 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
1610 }
1611 
iterate(void)1612 tcu::TestStatus TransformFeedbackMultistreamSameLocationTestInstance::iterate (void)
1613 {
1614 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
1615 	const VkDevice						device					= m_context.getDevice();
1616 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
1617 	const VkQueue						queue					= m_context.getUniversalQueue();
1618 	Allocator&							allocator				= m_context.getDefaultAllocator();
1619 
1620 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
1621 
1622 	const Unique<VkShaderModule>		vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1623 	const Unique<VkShaderModule>		geomModule				(createShaderModule						(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
1624 
1625 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
1626 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
1627 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, *geomModule, DE_NULL, m_imageExtent2D, 0u));
1628 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1629 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1630 
1631 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
1632 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
1633 	const std::vector<VkBuffer>			tfBufArray				= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
1634 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
1635 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
1636 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= { m_parameters.bufferSize / 2, m_parameters.bufferSize / 2 };
1637 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= { 0, m_parameters.bufferSize / 2 };
1638 
1639 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
1640 
1641 	beginCommandBuffer(vk, *cmdBuffer);
1642 	{
1643 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
1644 		{
1645 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1646 
1647 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
1648 
1649 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1650 			{
1651 				vk.cmdDraw(*cmdBuffer, 16u, 1u, 0u, 0u);
1652 			}
1653 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
1654 		}
1655 		endRenderPass(vk, *cmdBuffer);
1656 
1657 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
1658 	}
1659 	endCommandBuffer(vk, *cmdBuffer);
1660 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1661 
1662 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
1663 
1664 	return tcu::TestStatus::pass("Pass");
1665 }
1666 
1667 class TransformFeedbackStreamsTestInstance : public TransformFeedbackTestInstance
1668 {
1669 public:
1670 						TransformFeedbackStreamsTestInstance	(Context& context, const TestParameters& parameters);
1671 
1672 protected:
1673 	tcu::TestStatus		iterate									(void);
1674 	bool				verifyImage								(const VkFormat imageFormat, const VkExtent2D& size, const void* resultData);
1675 };
1676 
TransformFeedbackStreamsTestInstance(Context& context, const TestParameters& parameters)1677 TransformFeedbackStreamsTestInstance::TransformFeedbackStreamsTestInstance (Context& context, const TestParameters& parameters)
1678 	: TransformFeedbackTestInstance	(context, parameters)
1679 {
1680 	const InstanceInterface&								vki							= m_context.getInstanceInterface();
1681 	const VkPhysicalDevice									physDevice					= m_context.getPhysicalDevice();
1682 	const VkPhysicalDeviceFeatures							features					= getPhysicalDeviceFeatures(vki, physDevice);
1683 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&		transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
1684 	const deUint32											streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
1685 	const deUint32											streamsRequired				= m_parameters.streamId + 1;
1686 	const bool												geomPointSizeRequired		= m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE;
1687 
1688 	if (!features.geometryShader)
1689 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
1690 
1691 	if (transformFeedbackFeatures.geometryStreams == DE_FALSE)
1692 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
1693 
1694 	if (streamsSupported < streamsRequired)
1695 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
1696 
1697 	if (geomPointSizeRequired && !features.shaderTessellationAndGeometryPointSize)
1698 		TCU_THROW(NotSupportedError, "shaderTessellationAndGeometryPointSize feature is not supported");
1699 }
1700 
verifyImage(const VkFormat imageFormat, const VkExtent2D& size, const void* resultData)1701 bool TransformFeedbackStreamsTestInstance::verifyImage (const VkFormat imageFormat, const VkExtent2D& size, const void* resultData)
1702 {
1703 	const tcu::RGBA				magentaRGBA		(tcu::RGBA(0xFF, 0x00, 0xFF, 0xFF));
1704 	const tcu::Vec4				magenta			(magentaRGBA.toVec());
1705 	const tcu::Vec4				black			(tcu::RGBA::black().toVec());
1706 	const tcu::TextureFormat	textureFormat	(mapVkFormat(imageFormat));
1707 	const int					dataSize		(size.width * size.height * textureFormat.getPixelSize());
1708 	tcu::TextureLevel			referenceImage	(textureFormat, size.width, size.height);
1709 	tcu::PixelBufferAccess		referenceAccess	(referenceImage.getAccess());
1710 
1711 	// Generate reference image
1712 	if (m_parameters.testType == TEST_TYPE_STREAMS)
1713 	{
1714 		for (int y = 0; y < referenceImage.getHeight(); ++y)
1715 		{
1716 			const tcu::Vec4&	validColor = y < referenceImage.getHeight() / 2 ? black : magenta;
1717 
1718 			for (int x = 0; x < referenceImage.getWidth(); ++x)
1719 				referenceAccess.setPixel(validColor, x, y);
1720 		}
1721 	}
1722 
1723 	if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE || m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
1724 	{
1725 		for (int y = 0; y < referenceImage.getHeight(); ++y)
1726 			for (int x = 0; x < referenceImage.getWidth(); ++x)
1727 			{
1728 				const tcu::Vec4&	validColor	= (y >= referenceImage.getHeight() / 2) && (x >= referenceImage.getWidth() / 2) ? magenta : black;
1729 
1730 				referenceAccess.setPixel(validColor, x, y);
1731 			}
1732 	}
1733 
1734 	if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
1735 	{
1736 		const int			pointSize	= static_cast<int>(m_parameters.pointSize);
1737 		const tcu::Vec4&	validColor	= black;
1738 
1739 		for (int y = 0; y < referenceImage.getHeight(); ++y)
1740 			for (int x = 0; x < referenceImage.getWidth(); ++x)
1741 				referenceAccess.setPixel(validColor, x, y);
1742 
1743 		referenceAccess.setPixel(magenta, (1 + referenceImage.getWidth()) / 4 - 1, (referenceImage.getHeight() * 3) / 4 - 1);
1744 
1745 		for (int y = 0; y < pointSize; ++y)
1746 			for (int x = 0; x < pointSize; ++x)
1747 				referenceAccess.setPixel(magenta, x + (referenceImage.getWidth() * 3) / 4 - 1, y + (referenceImage.getHeight() * 3) / 4 - 1);
1748 	}
1749 
1750 	if (deMemCmp(resultData, referenceAccess.getDataPtr(), dataSize) != 0)
1751 	{
1752 		const tcu::ConstPixelBufferAccess	resultImage	(textureFormat, size.width, size.height, 1, resultData);
1753 		bool								ok;
1754 
1755 		ok = tcu::intThresholdCompare(m_context.getTestContext().getLog(), "Image comparison", "", referenceAccess, resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
1756 
1757 		return ok;
1758 	}
1759 
1760 	return true;
1761 }
1762 
1763 tcu::TestStatus TransformFeedbackStreamsTestInstance::iterate (void)
1764 {
1765 	const DeviceInterface&				vk					= m_context.getDeviceInterface();
1766 	const VkDevice						device				= m_context.getDevice();
1767 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1768 	const VkQueue						queue				= m_context.getUniversalQueue();
1769 	Allocator&							allocator			= m_context.getDefaultAllocator();
1770 
1771 	const Unique<VkRenderPass>			renderPass			(makeRenderPass			(vk, device, VK_FORMAT_R8G8B8A8_UNORM));
1772 
1773 	const Unique<VkShaderModule>		vertModule			(createShaderModule		(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1774 	const Unique<VkShaderModule>		geomModule			(createShaderModule		(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
1775 	const Unique<VkShaderModule>		fragModule			(createShaderModule		(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1776 
1777 	const VkFormat						colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
1778 	const VkImageUsageFlags				imageUsageFlags		= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1779 	const tcu::RGBA						clearColor			(tcu::RGBA::black());
1780 	const VkImageSubresourceRange		colorSubresRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u));
1781 	const VkDeviceSize					colorBufferSize		(m_imageExtent2D.width * m_imageExtent2D.height * tcu::getPixelSize(mapVkFormat(colorFormat)));
1782 	const Unique<VkImage>				colorImage			(makeImage								(vk, device, makeImageCreateInfo(0u, VK_IMAGE_TYPE_2D, colorFormat, m_imageExtent2D, 1u, imageUsageFlags)));
1783 	const UniquePtr<Allocation>			colorImageAlloc		(bindImage								(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1784 	const Unique<VkImageView>			colorAttachment		(makeImageView							(vk, device, *colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresRange));
1785 	const Unique<VkBuffer>				colorBuffer			(makeBuffer								(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1786 	const UniquePtr<Allocation>			colorBufferAlloc	(bindBuffer								(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
1787 
1788 	const Unique<VkFramebuffer>			framebuffer			(makeFramebuffer						(vk, device, *renderPass, *colorAttachment, m_imageExtent2D.width, m_imageExtent2D.height));
1789 	const Unique<VkPipelineLayout>		pipelineLayout		(TransformFeedback::makePipelineLayout	(vk, device));
1790 	const Unique<VkPipeline>			pipeline			(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertModule, DE_NULL, DE_NULL, *geomModule, *fragModule, m_imageExtent2D, 0u, &m_parameters.streamId));
1791 	const Unique<VkCommandPool>			cmdPool				(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1792 	const Unique<VkCommandBuffer>		cmdBuffer			(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1793 
1794 	const VkImageMemoryBarrier			preCopyBarrier		= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1795 																					 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1796 																					 *colorImage, colorSubresRange);
1797 	const VkBufferImageCopy				region				= makeBufferImageCopy(makeExtent3D(m_imageExtent2D.width, m_imageExtent2D.height, 1u),
1798 																				  makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
1799 	const VkBufferMemoryBarrier			postCopyBarrier		= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, VK_WHOLE_SIZE);
1800 
1801 	beginCommandBuffer(vk, *cmdBuffer);
1802 	{
1803 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D), clearColor.toVec());
1804 		{
1805 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1806 
1807 			vk.cmdDraw(*cmdBuffer, 2u, 1u, 0u, 0u);
1808 		}
1809 		endRenderPass(vk, *cmdBuffer);
1810 
1811 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier);
1812 		vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
1813 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &postCopyBarrier, DE_NULL, 0u);
1814 
1815 		invalidateAlloc(vk, device, *colorBufferAlloc);
1816 	}
1817 	endCommandBuffer(vk, *cmdBuffer);
1818 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1819 
1820 	if (!verifyImage(colorFormat, m_imageExtent2D, colorBufferAlloc->getHostPtr()))
1821 		return tcu::TestStatus::fail("Fail");
1822 
1823 	return tcu::TestStatus::pass("Pass");
1824 }
1825 
1826 class TransformFeedbackIndirectDrawTestInstance : public TransformFeedbackTestInstance
1827 {
1828 public:
1829 						TransformFeedbackIndirectDrawTestInstance	(Context& context, const TestParameters& parameters, bool multiview);
1830 
1831 protected:
1832 	tcu::TestStatus		iterate										(void);
1833 	bool				verifyImage									(const VkFormat imageFormat, const VkExtent2D& size, const void* resultData, uint32_t layerIdx = std::numeric_limits<uint32_t>::max());
1834 
1835 	const bool			m_multiview;
1836 };
1837 
1838 TransformFeedbackIndirectDrawTestInstance::TransformFeedbackIndirectDrawTestInstance (Context& context, const TestParameters& parameters, bool multiview)
1839 	: TransformFeedbackTestInstance	(context, parameters)
1840 	, m_multiview					(multiview)
1841 {
1842 	const InstanceInterface&		vki							= m_context.getInstanceInterface();
1843 	const VkPhysicalDevice			physDevice					= m_context.getPhysicalDevice();
1844 	const VkPhysicalDeviceLimits	limits						= getPhysicalDeviceProperties(vki, physDevice).limits;
1845 	const deUint32					tfBufferDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
1846 	const deUint32					tfBufferDataStrideSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
1847 
1848 	if (m_transformFeedbackProperties.transformFeedbackDraw == DE_FALSE)
1849 		TCU_THROW(NotSupportedError, "transformFeedbackDraw feature is not supported");
1850 
1851 	if (limits.maxVertexInputBindingStride < m_parameters.vertexStride)
1852 		TCU_THROW(NotSupportedError, std::string("maxVertexInputBindingStride=" + de::toString(limits.maxVertexInputBindingStride) + ", while test requires " + de::toString(m_parameters.vertexStride)).c_str());
1853 
1854 	if (tfBufferDataSizeSupported < m_parameters.vertexStride)
1855 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) + ", while test requires " + de::toString(m_parameters.vertexStride)).c_str());
1856 
1857 	if (tfBufferDataStrideSupported < m_parameters.vertexStride)
1858 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) + ", while test requires " + de::toString(m_parameters.vertexStride)).c_str());
1859 }
1860 
1861 bool TransformFeedbackIndirectDrawTestInstance::verifyImage (const VkFormat imageFormat, const VkExtent2D& size, const void* resultData, uint32_t layerIdx)
1862 {
1863 	const tcu::Vec4				white			(tcu::RGBA::white().toVec());
1864 	const tcu::TextureFormat	textureFormat	(mapVkFormat(imageFormat));
1865 	const int					dataSize		(size.width * size.height * textureFormat.getPixelSize());
1866 	tcu::TextureLevel			referenceImage	(textureFormat, size.width, size.height);
1867 	tcu::PixelBufferAccess		referenceAccess	(referenceImage.getAccess());
1868 	const bool					isMultilayer	= (layerIdx != std::numeric_limits<uint32_t>::max());
1869 	const std::string			setName			= "Image comparison" + (isMultilayer ? " (layer " + std::to_string(layerIdx) + ")" : std::string());
1870 
1871 	// Generate reference image
1872 	for (int y = 0; y < referenceImage.getHeight(); ++y)
1873 		for (int x = 0; x < referenceImage.getWidth(); ++x)
1874 			referenceAccess.setPixel(white, x, y);
1875 
1876 	if (deMemCmp(resultData, referenceAccess.getDataPtr(), dataSize) != 0)
1877 	{
1878 		const tcu::ConstPixelBufferAccess	resultImage	(textureFormat, size.width, size.height, 1, resultData);
1879 		bool								ok;
1880 
1881 		ok = tcu::intThresholdCompare(m_context.getTestContext().getLog(), setName.c_str(), "", referenceAccess, resultImage, tcu::UVec4(1), tcu::COMPARE_LOG_RESULT);
1882 
1883 		return ok;
1884 	}
1885 
1886 	return true;
1887 }
1888 
1889 tcu::TestStatus TransformFeedbackIndirectDrawTestInstance::iterate (void)
1890 {
1891 	const DeviceInterface&				vk					= m_context.getDeviceInterface();
1892 	const VkDevice						device				= m_context.getDevice();
1893 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1894 	const VkQueue						queue				= m_context.getUniversalQueue();
1895 	Allocator&							allocator			= m_context.getDefaultAllocator();
1896 	const uint32_t						layerCount			= (m_multiview ? 2u : 1u);
1897 	const auto							colorViewType		= (layerCount > 1u ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
1898 
1899 	// Only used for multiview.
1900 	const std::vector<uint32_t>			subpassViewMasks	{ ((1u << layerCount) - 1u) };
1901 
1902 	const VkRenderPassMultiviewCreateInfo multiviewCreateInfo =
1903 	{
1904 		VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,	//	VkStructureType	sType;
1905 		nullptr,												//	const void*		pNext;
1906 		de::sizeU32(subpassViewMasks),							//	uint32_t		subpassCount;
1907 		de::dataOrNull(subpassViewMasks),						//	const uint32_t*	pViewMasks;
1908 		0u,														//	uint32_t		dependencyCount;
1909 		nullptr,												//	const int32_t*	pViewOffsets;
1910 		de::sizeU32(subpassViewMasks),							//	uint32_t		correlationMaskCount;
1911 		de::dataOrNull(subpassViewMasks),						//	const uint32_t*	pCorrelationMasks;
1912 	};
1913 
1914 	const Unique<VkRenderPass>			renderPass			(makeRenderPass			(vk,
1915 																					 device,
1916 																					 VK_FORMAT_R8G8B8A8_UNORM,
1917 																					 VK_FORMAT_UNDEFINED,
1918 																					 VK_ATTACHMENT_LOAD_OP_CLEAR,
1919 																					 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1920 																					 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1921 																					 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1922 																					 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1923 																					 nullptr,
1924 																					 (m_multiview ? &multiviewCreateInfo : nullptr)));
1925 
1926 	const Unique<VkShaderModule>		vertModule			(createShaderModule		(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
1927 	const Unique<VkShaderModule>		fragModule			(createShaderModule		(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
1928 
1929 	const VkFormat						colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
1930 	const VkImageUsageFlags				imageUsageFlags		= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1931 	const tcu::RGBA						clearColor			(tcu::RGBA::black());
1932 	const VkImageSubresourceRange		colorSubresRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, layerCount));
1933 	const VkDeviceSize					layerSize			(m_imageExtent2D.width * m_imageExtent2D.height * static_cast<uint32_t>(tcu::getPixelSize(mapVkFormat(colorFormat))));
1934 	const VkDeviceSize					colorBufferSize		(layerSize * layerCount);
1935 	const Unique<VkImage>				colorImage			(makeImage				(vk, device, makeImageCreateInfo(0u, VK_IMAGE_TYPE_2D, colorFormat, m_imageExtent2D, layerCount, imageUsageFlags)));
1936 	const UniquePtr<Allocation>			colorImageAlloc		(bindImage				(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1937 	const Unique<VkImageView>			colorAttachment		(makeImageView			(vk, device, *colorImage, colorViewType, colorFormat, colorSubresRange));
1938 	const Unique<VkBuffer>				colorBuffer			(makeBuffer				(vk, device, colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1939 	const UniquePtr<Allocation>			colorBufferAlloc	(bindBuffer				(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
1940 
1941 	const deUint32						vertexCount			= 6u;
1942 	const VkDeviceSize					vertexBufferSize	= vertexCount * m_parameters.vertexStride;
1943 	const VkBufferUsageFlags			vertexBufferUsage	= VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1944 	const Unique<VkBuffer>				vertexBuffer		(makeBuffer				(vk, device, vertexBufferSize, vertexBufferUsage));
1945 	const UniquePtr<Allocation>			vertexBufferAlloc	(bindBuffer				(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
1946 	const VkDeviceSize					vertexBufferOffset	(0u);
1947 	const float							vertexBufferVals[]	=
1948 																{
1949 																	-1.0f, -1.0f, 0.0f, 1.0f,
1950 																	-1.0f, +1.0f, 0.0f, 1.0f,
1951 																	+1.0f, -1.0f, 0.0f, 1.0f,
1952 																	-1.0f, +1.0f, 0.0f, 1.0f,
1953 																	+1.0f, -1.0f, 0.0f, 1.0f,
1954 																	+1.0f, +1.0f, 0.0f, 1.0f,
1955 																};
1956 
1957 	const deUint32						counterBufferValue	= m_parameters.vertexStride * vertexCount;
1958 	const VkDeviceSize					counterBufferSize	= sizeof(counterBufferValue);
1959 	const VkBufferUsageFlags			counterBufferUsage	= VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1960 	const Unique<VkBuffer>				counterBuffer		(makeBuffer								(vk, device, counterBufferSize, counterBufferUsage));
1961 	const UniquePtr<Allocation>			counterBufferAlloc	(bindBuffer								(vk, device, allocator, *counterBuffer, MemoryRequirement::HostVisible));
1962 
1963 	// Note: for multiview the framebuffer layer count is also 1.
1964 	const Unique<VkFramebuffer>			framebuffer			(makeFramebuffer						(vk, device, *renderPass, *colorAttachment, m_imageExtent2D.width, m_imageExtent2D.height));
1965 	const Unique<VkPipelineLayout>		pipelineLayout		(TransformFeedback::makePipelineLayout	(vk, device));
1966 	const Unique<VkPipeline>			pipeline			(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertModule, DE_NULL, DE_NULL, DE_NULL, *fragModule, m_imageExtent2D, 0u, DE_NULL, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, true));
1967 	const Unique<VkCommandPool>			cmdPool				(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1968 	const Unique<VkCommandBuffer>		cmdBuffer			(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
1969 
1970 	const VkImageMemoryBarrier			preCopyBarrier		= makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1971 																					 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1972 																					 *colorImage, colorSubresRange);
1973 	const VkBufferImageCopy				region				= makeBufferImageCopy(makeExtent3D(m_imageExtent2D.width, m_imageExtent2D.height, 1u),
1974 																				  makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, layerCount));
1975 	const VkBufferMemoryBarrier			postCopyBarrier		= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, VK_WHOLE_SIZE);
1976 
1977 	fillBuffer(vk, device, *counterBufferAlloc, counterBufferSize, &counterBufferValue, counterBufferSize);
1978 	fillBuffer(vk, device, *vertexBufferAlloc, vertexBufferSize, vertexBufferVals, sizeof(vertexBufferVals));
1979 
1980 	beginCommandBuffer(vk, *cmdBuffer);
1981 	{
1982 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D), clearColor.toVec());
1983 		{
1984 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &*vertexBuffer, &vertexBufferOffset);
1985 
1986 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
1987 
1988 			vk.cmdDrawIndirectByteCountEXT(*cmdBuffer, 1u, 0u, *counterBuffer, 0u, 0u, m_parameters.vertexStride);
1989 		}
1990 		endRenderPass(vk, *cmdBuffer);
1991 
1992 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, DE_NULL, 0u, DE_NULL, 1u, &preCopyBarrier);
1993 		vk.cmdCopyImageToBuffer(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &region);
1994 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &postCopyBarrier, DE_NULL, 0u);
1995 
1996 		invalidateAlloc(vk, device, *colorBufferAlloc);
1997 	}
1998 	endCommandBuffer(vk, *cmdBuffer);
1999 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2000 
2001 	bool fail = false;
2002 	for (uint32_t layerIdx = 0u; layerIdx < layerCount; ++layerIdx)
2003 	{
2004 		const auto dataPtr = reinterpret_cast<uint8_t*>(colorBufferAlloc->getHostPtr()) + layerIdx * layerSize;
2005 		if (!verifyImage(colorFormat, m_imageExtent2D, dataPtr))
2006 			fail = true;
2007 	}
2008 
2009 	if (fail)
2010 		return tcu::TestStatus::fail("Fail; check log for details");
2011 
2012 	return tcu::TestStatus::pass("Pass");
2013 }
2014 
2015 class TransformFeedbackBackwardDependencyTestInstance : public TransformFeedbackTestInstance
2016 {
2017 public:
2018 								TransformFeedbackBackwardDependencyTestInstance	(Context& context, const TestParameters& parameters);
2019 
2020 protected:
2021 	tcu::TestStatus				iterate											(void);
2022 	std::vector<VkDeviceSize>	generateSizesList								(const size_t bufBytes, const size_t chunkCount);
2023 };
2024 
2025 TransformFeedbackBackwardDependencyTestInstance::TransformFeedbackBackwardDependencyTestInstance (Context& context, const TestParameters& parameters)
2026 	: TransformFeedbackTestInstance	(context, parameters)
2027 {
2028 	if (m_transformFeedbackProperties.transformFeedbackDraw == DE_FALSE)
2029 		TCU_THROW(NotSupportedError, "transformFeedbackDraw feature is not supported");
2030 }
2031 
2032 std::vector<VkDeviceSize> TransformFeedbackBackwardDependencyTestInstance::generateSizesList (const size_t bufBytes, const size_t chunkCount)
2033 {
2034 	const VkDeviceSize			chunkSize	= bufBytes / chunkCount;
2035 	std::vector<VkDeviceSize>	result		(chunkCount, chunkSize);
2036 
2037 	DE_ASSERT(chunkSize * chunkCount == bufBytes);
2038 	DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
2039 	DE_ASSERT(bufBytes % sizeof(deUint32) == 0);
2040 	DE_ASSERT(chunkCount > 0);
2041 	DE_ASSERT(result.size() == chunkCount);
2042 
2043 	return result;
2044 }
2045 
2046 tcu::TestStatus TransformFeedbackBackwardDependencyTestInstance::iterate (void)
2047 {
2048 	const DeviceInterface&				vk					= m_context.getDeviceInterface();
2049 	const VkDevice						device				= m_context.getDevice();
2050 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
2051 	const VkQueue						queue				= m_context.getUniversalQueue();
2052 	Allocator&							allocator			= m_context.getDefaultAllocator();
2053 
2054 	const std::vector<VkDeviceSize>		chunkSizesList		= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
2055 	const std::vector<VkDeviceSize>		chunkOffsetsList	= generateOffsetsList(chunkSizesList);
2056 
2057 	const uint32_t						numPoints			= static_cast<uint32_t>(chunkSizesList[0] / sizeof(uint32_t));
2058 	const bool							indirectDraw		= (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT);
2059 
2060 	// Color buffer.
2061 	const tcu::IVec3					fbExtent			(static_cast<int>(numPoints), 1, 1);
2062 	const auto							vkExtent			= makeExtent3D(fbExtent);
2063 	const std::vector<VkViewport>		viewports			(1u, makeViewport(vkExtent));
2064 	const std::vector<VkRect2D>			scissors			(1u, makeRect2D(vkExtent));
2065 
2066 	const auto							colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
2067 	const auto							colorUsage			= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2068 	const tcu::Vec4						clearColor			(0.0f, 0.0f, 0.0f, 1.0f);
2069 	const tcu::Vec4						geomColor			(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
2070 	ImageWithBuffer						colorBuffer			(vk, device, allocator, vkExtent, colorFormat, colorUsage, VK_IMAGE_TYPE_2D);
2071 
2072 	// Must match vertex shader.
2073 	struct PushConstants
2074 	{
2075 		uint32_t	startValue;
2076 		float		width;
2077 		float		posY;
2078 	};
2079 
2080 	const auto							pcSize				= static_cast<uint32_t>(sizeof(PushConstants));
2081 	const Unique<VkShaderModule>		vertexModule		(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2082 	const Unique<VkShaderModule>		fragModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("frag"), 0u));
2083 	const Unique<VkRenderPass>			renderPass			(TransformFeedback::makeCustomRenderPass(vk, device, colorFormat));
2084 	const Unique<VkFramebuffer>			framebuffer			(makeFramebuffer						(vk, device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height));
2085 	const Unique<VkPipelineLayout>		pipelineLayout		(TransformFeedback::makePipelineLayout	(vk, device, pcSize));
2086 	const Unique<VkPipeline>			pipeline			(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, DE_NULL, *fragModule, makeExtent2D(vkExtent.width, vkExtent.height), 0u));
2087 	const Unique<VkCommandPool>			cmdPool				(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2088 	const Unique<VkCommandBuffer>		cmdBuffer			(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2089 
2090 	const VkBufferCreateInfo			tfBufCreateInfo		= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2091 	const Move<VkBuffer>				tfBuf				= createBuffer(vk, device, &tfBufCreateInfo);
2092 	const MovePtr<Allocation>			tfBufAllocation		= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2093 	const VkMemoryBarrier				tfMemoryBarrier		= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2094 	const VkDeviceSize					tfBufBindingSize	= m_parameters.bufferSize;
2095 	const VkDeviceSize					tfBufBindingOffset	= 0ull;
2096 
2097 	const size_t						tfcBufSize			= sizeof(deUint32);
2098 	const VkBufferCreateInfo			tfcBufCreateInfo	= makeBufferCreateInfo(tfcBufSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
2099 	const Move<VkBuffer>				tfcBuf				= createBuffer(vk, device, &tfcBufCreateInfo);
2100 	const MovePtr<Allocation>			tfcBufAllocation	= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfcBuf), MemoryRequirement::Any);
2101 	const VkDeviceSize					tfcBufBindingOffset	= 0ull;
2102 	const VkMemoryBarrier				tfcMemoryBarrier	= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT, VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT);
2103 
2104 	using BufferWithMemoryPtr = std::unique_ptr<BufferWithMemory>;
2105 	BufferWithMemoryPtr					indirectBuffer;
2106 	VkDeviceSize						indirectBufferSize;
2107 	VkBufferCreateInfo					indirectBufferInfo;
2108 	std::vector<VkDrawIndirectCommand>	indirectCommands;
2109 	const auto							indirectStructSize	= static_cast<uint32_t>(sizeof(decltype(indirectCommands)::value_type));
2110 	const auto							indirectStride		= indirectStructSize * 2u; // See below.
2111 
2112 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2113 	VK_CHECK(vk.bindBufferMemory(device, *tfcBuf, tfcBufAllocation->getMemory(), tfcBufAllocation->getOffset()));
2114 
2115 	DE_ASSERT(m_parameters.partCount == 2u);
2116 
2117 	if (indirectDraw)
2118 	{
2119 		// Prepare indirect commands. The first entry will be used as the count.
2120 		// Each subsequent indirect command will be padded with an unused structure.
2121 		indirectCommands.reserve(numPoints + 1u);
2122 		indirectCommands.push_back(VkDrawIndirectCommand{numPoints, 0u, 0u, 0u});
2123 
2124 		for (uint32_t drawIdx = 0u; drawIdx < numPoints; ++drawIdx)
2125 		{
2126 			indirectCommands.push_back(VkDrawIndirectCommand{1u, 1u, drawIdx, 0u});
2127 			indirectCommands.push_back(VkDrawIndirectCommand{0u, 0u, 0u, 0u});
2128 		}
2129 
2130 		indirectBufferSize = static_cast<VkDeviceSize>(de::dataSize(indirectCommands));
2131 		indirectBufferInfo = makeBufferCreateInfo(indirectBufferSize, VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT);
2132 
2133 		indirectBuffer.reset(new BufferWithMemory(vk, device, allocator, indirectBufferInfo, MemoryRequirement::HostVisible));
2134 		auto& indirectBufferAlloc	= indirectBuffer->getAllocation();
2135 		void* indirectBufferData	= indirectBufferAlloc.getHostPtr();
2136 
2137 		deMemcpy(indirectBufferData, de::dataOrNull(indirectCommands), de::dataSize(indirectCommands));
2138 		flushAlloc(vk, device, indirectBufferAlloc);
2139 	}
2140 
2141 	beginCommandBuffer(vk, *cmdBuffer);
2142 	{
2143 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
2144 		{
2145 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2146 
2147 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
2148 
2149 			{
2150 				const uint32_t		startValue = static_cast<uint32_t>(chunkOffsetsList[0] / sizeof(uint32_t));
2151 				const PushConstants	pcData
2152 				{
2153 					startValue,
2154 					static_cast<float>(vkExtent.width),
2155 					static_cast<float>(10.0f), // Push the points offscreen.
2156 				};
2157 
2158 				vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, pcSize, &pcData);
2159 
2160 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2161 				{
2162 					if (indirectDraw)
2163 						vk.cmdDrawIndirectCount(*cmdBuffer, indirectBuffer->get(), indirectStructSize, indirectBuffer->get(), 0u, numPoints, indirectStride);
2164 					else
2165 						vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
2166 				}
2167 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf, m_parameters.noOffsetArray ? DE_NULL : &tfcBufBindingOffset);
2168 			}
2169 
2170 			if (indirectDraw)
2171 			{
2172 				// This should be a no-op but allows us to reset the indirect draw counter in case it could influence the follow-up indirect draw.
2173 				vk.cmdDrawIndirectCount(*cmdBuffer, indirectBuffer->get(), indirectStructSize, indirectBuffer->get(), 0u, 0u/*no draws*/, indirectStride);
2174 			}
2175 
2176 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0u, 1u, &tfcMemoryBarrier, 0u, DE_NULL, DE_NULL, 0u);
2177 
2178 			{
2179 				const uint32_t		startValue = static_cast<deUint32>(chunkOffsetsList[1] / sizeof(deUint32));
2180 				const PushConstants	pcData
2181 				{
2182 					startValue,
2183 					static_cast<float>(vkExtent.width),
2184 					static_cast<float>(0.0f), // Points onscreen in this second draw.
2185 				};
2186 
2187 				vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, pcSize, &pcData);
2188 
2189 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 1, &*tfcBuf, m_parameters.noOffsetArray ? DE_NULL : &tfcBufBindingOffset);
2190 				{
2191 					vk.cmdDrawIndirectByteCountEXT(*cmdBuffer, 1u, 0u, *tfcBuf, 0u, 0u, 4u);
2192 				}
2193 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2194 			}
2195 
2196 		}
2197 		endRenderPass(vk, *cmdBuffer);
2198 
2199 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2200 	}
2201 	copyImageToBuffer(vk, *cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1));
2202 	endCommandBuffer(vk, *cmdBuffer);
2203 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2204 
2205 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
2206 
2207 	// Verify color buffer, to check vkCmdDrawIndirectByteCountEXT worked.
2208 	const auto					tcuFormat	= mapVkFormat(colorFormat);
2209 	tcu::TextureLevel			refLevel	(tcuFormat, fbExtent.x(), fbExtent.y());
2210 	const auto					refAccess	= refLevel.getAccess();
2211 	const auto					resAlloc	= colorBuffer.getBufferAllocation();
2212 	tcu::ConstPixelBufferAccess	resAccess	(tcuFormat, fbExtent, resAlloc.getHostPtr());
2213 	auto&						log			= m_context.getTestContext().getLog();
2214 	const tcu::Vec4				threshold	(0.0f, 0.0f, 0.0f, 0.0f);
2215 
2216 	tcu::clear(refAccess, geomColor);
2217 	invalidateAlloc(vk, device, resAlloc);
2218 
2219 	if (!tcu::floatThresholdCompare(log, "Result", "", refAccess, resAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
2220 		return tcu::TestStatus::fail("Color buffer contains unexpected results; check log for details");
2221 
2222 	return tcu::TestStatus::pass("Pass");
2223 }
2224 
2225 
2226 class TransformFeedbackQueryTestInstance : public TransformFeedbackTestInstance
2227 {
2228 public:
2229 						TransformFeedbackQueryTestInstance	(Context& context, const TestParameters& parameters);
2230 
2231 protected:
2232 	tcu::TestStatus		iterate								(void);
2233 };
2234 
2235 TransformFeedbackQueryTestInstance::TransformFeedbackQueryTestInstance (Context& context, const TestParameters& parameters)
2236 	: TransformFeedbackTestInstance	(context, parameters)
2237 {
2238 	const InstanceInterface&								vki							= m_context.getInstanceInterface();
2239 	const VkPhysicalDevice									physDevice					= m_context.getPhysicalDevice();
2240 	const VkPhysicalDeviceFeatures							features					= getPhysicalDeviceFeatures(vki, physDevice);
2241 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&		transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
2242 	const deUint32											streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
2243 	const deUint32											streamsRequired				= m_parameters.streamId + 1;
2244 
2245 	if (!features.geometryShader)
2246 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2247 
2248 	if (streamsRequired > 1 && transformFeedbackFeatures.geometryStreams == DE_FALSE)
2249 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2250 
2251 	if (streamsSupported < streamsRequired)
2252 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
2253 
2254 	if (m_transformFeedbackProperties.transformFeedbackQueries == DE_FALSE)
2255 		TCU_THROW(NotSupportedError, "transformFeedbackQueries feature is not supported");
2256 
2257 	if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
2258 	{
2259 		// Check VK_EXT_host_query_reset is supported
2260 		m_context.requireDeviceFunctionality("VK_EXT_host_query_reset");
2261 		if(m_context.getHostQueryResetFeatures().hostQueryReset == VK_FALSE)
2262 			throw tcu::NotSupportedError(std::string("Implementation doesn't support resetting queries from the host").c_str());
2263 	}
2264 }
2265 
2266 tcu::TestStatus TransformFeedbackQueryTestInstance::iterate (void)
2267 {
2268 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
2269 	const VkDevice						device					= m_context.getDevice();
2270 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
2271 	const VkQueue						queue					= m_context.getUniversalQueue();
2272 	Allocator&							allocator				= m_context.getDefaultAllocator();
2273 
2274 	const deUint64						overflowVertices		= 3u;
2275 	const deUint32						bytesPerVertex			= static_cast<deUint32>(4 * sizeof(float));
2276 	const deUint64						numVerticesInBuffer		= m_parameters.bufferSize / bytesPerVertex;
2277 	const deUint64						numVerticesToWrite		= numVerticesInBuffer + overflowVertices;
2278 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
2279 
2280 	const Unique<VkShaderModule>		vertModule				(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2281 	const Unique<VkShaderModule>		geomModule				(createShaderModule						(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
2282 
2283 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2284 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
2285 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertModule, DE_NULL, DE_NULL, *geomModule, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId, m_parameters.primTopology));
2286 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2287 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2288 
2289 	const deUint32						tfBufferSize			= (deUint32)topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesInBuffer) * (deUint32)topologyData.at(m_parameters.primTopology).primSize * bytesPerVertex;
2290 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(tfBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2291 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
2292 	const MovePtr<Allocation>			tfBufAllocation			= bindBuffer(vk, device, allocator, *tfBuf, MemoryRequirement::HostVisible);
2293 	const VkDeviceSize					tfBufBindingSize		= tfBufferSize;
2294 	const VkDeviceSize					tfBufBindingOffset		= 0ull;
2295 
2296 	const size_t						queryResultWidth		= (m_parameters.query64bits ? sizeof(deUint64) : sizeof(deUint32));
2297 	const vk::VkQueryControlFlags		queryExtraFlags			= (m_parameters.query64bits ? vk::VK_QUERY_RESULT_64_BIT : 0);
2298 	const deUint32						queryCountersNumber		= 1u;
2299 	const deUint32						queryIndex				= 0u;
2300 	constexpr deUint32					queryResultElements		= 2u;
2301 	const deUint32						queryDataSize			= static_cast<deUint32>(queryResultElements * queryResultWidth) + (m_parameters.queryResultWithAvailability ? (deUint32)queryResultWidth : 0u);
2302 	const VkQueryPoolCreateInfo			queryPoolCreateInfo		= makeQueryPoolCreateInfo(queryCountersNumber);
2303 	const Unique<VkQueryPool>			queryPool				(createQueryPool(vk, device, &queryPoolCreateInfo));
2304 
2305 	const VkQueryResultFlagBits			queryWait				= m_parameters.queryResultWithAvailability ? VK_QUERY_RESULT_WITH_AVAILABILITY_BIT : VK_QUERY_RESULT_WAIT_BIT;
2306 
2307 	Move<VkBuffer>						queryPoolResultsBuffer;
2308 	de::MovePtr<Allocation>				queryPoolResultsBufferAlloc;
2309 
2310 	tcu::TestLog&						log						= m_context.getTestContext().getLog();
2311 
2312 	DE_ASSERT(numVerticesInBuffer * bytesPerVertex == m_parameters.bufferSize);
2313 
2314 	if (m_parameters.testType == TEST_TYPE_QUERY_COPY || m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2315 	{
2316 		const VkBufferCreateInfo bufferParams =
2317 		{
2318 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,       // VkStructureType      sType;
2319 			DE_NULL,                                    // const void*          pNext;
2320 			0u,                                         // VkBufferCreateFlags  flags;
2321 			queryDataSize,                              // VkDeviceSize         size;
2322 			VK_BUFFER_USAGE_TRANSFER_DST_BIT,           // VkBufferUsageFlags   usage;
2323 			VK_SHARING_MODE_EXCLUSIVE,                  // VkSharingMode        sharingMode;
2324 			1u,                                         // deUint32             queueFamilyCount;
2325 			&queueFamilyIndex                           // const deUint32*      pQueueFamilyIndices;
2326 		};
2327 
2328 		queryPoolResultsBuffer = createBuffer(vk, device, &bufferParams);
2329 		queryPoolResultsBufferAlloc = allocator.allocate(getBufferMemoryRequirements(vk, device, *queryPoolResultsBuffer), MemoryRequirement::HostVisible);
2330 
2331 		VK_CHECK(vk.bindBufferMemory(device, *queryPoolResultsBuffer, queryPoolResultsBufferAlloc->getMemory(), queryPoolResultsBufferAlloc->getOffset()));
2332 	}
2333 
2334 	beginCommandBuffer(vk, *cmdBuffer);
2335 	{
2336 		if (m_parameters.testType != TEST_TYPE_QUERY_RESET)
2337 			vk.cmdResetQueryPool(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber);
2338 
2339 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2340 		{
2341 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2342 
2343 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, 1u, &*tfBuf, &tfBufBindingOffset, &tfBufBindingSize);
2344 
2345 			if (m_parameters.streamId == 0 && m_parameters.streamId0Mode != STREAM_ID_0_BEGIN_QUERY_INDEXED)
2346 				vk.cmdBeginQuery(*cmdBuffer, *queryPool, queryIndex, 0u);
2347 			else
2348 				vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex, 0u, m_parameters.streamId);
2349 			{
2350 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2351 				{
2352 					vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(numVerticesToWrite), 1u, 0u, 0u);
2353 				}
2354 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2355 			}
2356 			if (m_parameters.streamId == 0 && m_parameters.streamId0Mode != STREAM_ID_0_END_QUERY_INDEXED)
2357 				vk.cmdEndQuery(*cmdBuffer, *queryPool, queryIndex);
2358 			else
2359 				vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex, m_parameters.streamId);
2360 		}
2361 		endRenderPass(vk, *cmdBuffer);
2362 
2363 		if (m_parameters.testType == TEST_TYPE_QUERY_COPY || m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2364 		{
2365 			VkDeviceSize copyStride = queryDataSize;
2366 			if (queryCountersNumber == 1u && m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2367 				copyStride = 0;
2368 
2369 			vk.cmdCopyQueryPoolResults(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber, *queryPoolResultsBuffer, 0u, copyStride, (queryWait | queryExtraFlags));
2370 
2371 			const VkBufferMemoryBarrier bufferBarrier =
2372 			{
2373 				VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,	// VkStructureType	sType;
2374 				DE_NULL,									// const void*		pNext;
2375 				VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags	srcAccessMask;
2376 				VK_ACCESS_HOST_READ_BIT,					// VkAccessFlags	dstAccessMask;
2377 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			srcQueueFamilyIndex;
2378 				VK_QUEUE_FAMILY_IGNORED,					// deUint32			dstQueueFamilyIndex;
2379 				*queryPoolResultsBuffer,					// VkBuffer			buffer;
2380 				0ull,										// VkDeviceSize		offset;
2381 				VK_WHOLE_SIZE								// VkDeviceSize		size;
2382 			};
2383 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, DE_NULL, 1u, &bufferBarrier, 0u, DE_NULL);
2384 		}
2385 
2386 	}
2387 	endCommandBuffer(vk, *cmdBuffer);
2388 
2389 	if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
2390 		vk.resetQueryPool(device, *queryPool, queryIndex, queryCountersNumber);
2391 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2392 
2393 	{
2394 		union Results
2395 		{
2396 			deUint32	elements32[queryResultElements];
2397 			deUint64	elements64[queryResultElements];
2398 		};
2399 
2400 		std::vector<deUint8>	queryData		(queryDataSize, 0u);
2401 		const Results*			queryResults	= reinterpret_cast<Results*>(queryData.data());
2402 
2403 		if (m_parameters.testType != TEST_TYPE_QUERY_COPY && m_parameters.testType != TEST_TYPE_QUERY_COPY_STRIDE_ZERO)
2404 		{
2405 			vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber, queryDataSize, queryData.data(), queryDataSize, (queryWait | queryExtraFlags));
2406 		}
2407 		else
2408 		{
2409 			invalidateAlloc(vk, device, *queryPoolResultsBufferAlloc);
2410 			deMemcpy(queryData.data(), queryPoolResultsBufferAlloc->getHostPtr(), queryData.size());
2411 		}
2412 
2413 		// Query results not available
2414 		if (*reinterpret_cast<deUint32*>(&queryData[queryDataSize - queryResultWidth]) == 0)
2415 			return tcu::TestStatus::pass("Pass");
2416 
2417 		// The number of primitives successfully written to the corresponding transform feedback buffer.
2418 		const deUint64	numPrimitivesWritten	= (m_parameters.query64bits ? queryResults->elements64[0] : queryResults->elements32[0]);
2419 
2420 		// The number of primitives output to the vertex stream.
2421 		const deUint64	numPrimitivesNeeded		= (m_parameters.query64bits ? queryResults->elements64[1] : queryResults->elements32[1]);
2422 
2423 		// Count how many primitives we should get by using selected topology.
2424 		const auto		primitivesInBuffer		= topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesInBuffer);
2425 		const auto		primitivesToWrite		= topologyData.at(m_parameters.primTopology).getNumPrimitives(numVerticesToWrite);
2426 
2427 		log << tcu::TestLog::Message << "Primitives Written / Expected :  " << de::toString(numPrimitivesWritten) << " / " << de::toString(primitivesInBuffer) << tcu::TestLog::EndMessage;
2428 		log << tcu::TestLog::Message << "Primitives  Needed / Expected :  " << de::toString(numPrimitivesNeeded) << " / " << de::toString(primitivesToWrite) << tcu::TestLog::EndMessage;
2429 
2430 		if (numPrimitivesWritten != primitivesInBuffer)
2431 			return tcu::TestStatus::fail("numPrimitivesWritten=" + de::toString(numPrimitivesWritten) + " while expected " + de::toString(primitivesInBuffer));
2432 
2433 		if (numPrimitivesNeeded != primitivesToWrite)
2434 			return tcu::TestStatus::fail("numPrimitivesNeeded=" + de::toString(numPrimitivesNeeded) + " while expected " + de::toString(primitivesToWrite));
2435 	}
2436 
2437 	if (m_parameters.testType == TEST_TYPE_QUERY_RESET)
2438 	{
2439 		constexpr deUint32		queryResetElements		= queryResultElements + 1; // For the availability bit.
2440 
2441 		union Results
2442 		{
2443 			deUint32	elements32[queryResetElements];
2444 			deUint64	elements64[queryResetElements];
2445 		};
2446 
2447 		const deUint32			queryDataAvailSize		(static_cast<deUint32>(queryResetElements * queryResultWidth));
2448 		std::vector<deUint8>	queryData				(queryDataAvailSize, 0u);
2449 		Results*				queryResults			= reinterpret_cast<Results*>(queryData.data());
2450 
2451 		// Initialize values
2452 		if (m_parameters.query64bits)
2453 		{
2454 			queryResults->elements64[0] = 1u;	// numPrimitivesWritten
2455 			queryResults->elements64[1] = 1u;	// numPrimitivesNeeded
2456 			queryResults->elements64[2] = 1u;	// Availability bit
2457 		}
2458 		else
2459 		{
2460 			queryResults->elements32[0] = 1u;	// numPrimitivesWritten
2461 			queryResults->elements32[1] = 1u;	// numPrimitivesNeeded
2462 			queryResults->elements32[2] = 1u;	// Availability bit
2463 		}
2464 
2465 		vk.resetQueryPool(device, *queryPool, queryIndex, queryCountersNumber);
2466 
2467 		vk::VkResult	res						= vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber, queryDataAvailSize, queryData.data(), queryDataAvailSize, (vk::VK_QUERY_RESULT_WITH_AVAILABILITY_BIT | queryExtraFlags));
2468 		const deUint64	numPrimitivesWritten	= (m_parameters.query64bits ? queryResults->elements64[0] : queryResults->elements32[0]);
2469 		const deUint64	numPrimitivesNeeded		= (m_parameters.query64bits ? queryResults->elements64[1] : queryResults->elements32[1]);
2470 		const deUint64	availabilityState		= (m_parameters.query64bits ? queryResults->elements64[2] : queryResults->elements32[2]);
2471 
2472 		/* From the Vulkan spec:
2473 			*
2474 			* If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are both not set then no result values are written to pData
2475 			* for queries that are in the unavailable state at the time of the call, and vkGetQueryPoolResults returns VK_NOT_READY.
2476 			* However, availability state is still written to pData for those queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set.
2477 			*/
2478 		if (res != vk::VK_NOT_READY || availabilityState != 0u)
2479 			return tcu::TestStatus::fail("QueryPoolResults incorrect reset");
2480 	    if (numPrimitivesWritten != 1u || numPrimitivesNeeded != 1u)
2481 			return tcu::TestStatus::fail("QueryPoolResults data was modified");
2482 
2483 	}
2484 
2485 	return tcu::TestStatus::pass("Pass");
2486 }
2487 
2488 class TransformFeedbackMultiQueryTestInstance : public TransformFeedbackTestInstance
2489 {
2490 public:
2491 								TransformFeedbackMultiQueryTestInstance	(Context& context, const TestParameters& parameters);
2492 
2493 protected:
2494 	std::vector<VkDeviceSize>	generateSizesList							(const size_t bufBytes, const size_t chunkCount);
2495 	void						verifyTransformFeedbackBuffer				(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes, const deUint32 bufOffset, const float expected);
2496 	tcu::TestStatus				iterate										(void);
2497 };
2498 
TransformFeedbackMultiQueryTestInstance(Context& context, const TestParameters& parameters)2499 TransformFeedbackMultiQueryTestInstance::TransformFeedbackMultiQueryTestInstance (Context& context, const TestParameters& parameters)
2500 	: TransformFeedbackTestInstance	(context, parameters)
2501 {
2502 	const InstanceInterface&								vki							= m_context.getInstanceInterface();
2503 	const VkPhysicalDevice									physDevice					= m_context.getPhysicalDevice();
2504 	const VkPhysicalDeviceFeatures							features					= getPhysicalDeviceFeatures(vki, physDevice);
2505 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&		transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
2506 	const deUint32											streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
2507 	const deUint32											streamsRequired				= m_parameters.streamId + 1;
2508 	const deUint32											tfBuffersSupported			= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
2509 	const deUint32											tfBuffersRequired			= m_parameters.partCount;
2510 	const deUint32											bytesPerVertex				= m_parameters.bufferSize / m_parameters.partCount;
2511 	const deUint32											tfStreamDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackStreamDataSize;
2512 	const deUint32											tfBufferDataSizeSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataSize;
2513 	const deUint32											tfBufferDataStrideSupported	= m_transformFeedbackProperties.maxTransformFeedbackBufferDataStride;
2514 
2515 	DE_ASSERT(m_parameters.partCount == 2u);
2516 
2517 	if (!features.geometryShader)
2518 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2519 
2520 	if (transformFeedbackFeatures.geometryStreams == DE_FALSE)
2521 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2522 
2523 	if (streamsSupported < streamsRequired)
2524 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
2525 
2526 	if (tfBuffersSupported < tfBuffersRequired)
2527 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
2528 
2529 	if (tfStreamDataSizeSupported < bytesPerVertex)
2530 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreamDataSize=" + de::toString(tfStreamDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
2531 
2532 	if (tfBufferDataSizeSupported < bytesPerVertex)
2533 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataSize=" + de::toString(tfBufferDataSizeSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
2534 
2535 	if (tfBufferDataStrideSupported < bytesPerVertex)
2536 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBufferDataStride=" + de::toString(tfBufferDataStrideSupported) + ", while test requires " + de::toString(bytesPerVertex)).c_str());
2537 
2538 	if (m_transformFeedbackProperties.transformFeedbackQueries == DE_FALSE)
2539 		TCU_THROW(NotSupportedError, "transformFeedbackQueries feature is not supported");
2540 }
2541 
generateSizesList(const size_t bufBytes, const size_t chunkCount)2542 std::vector<VkDeviceSize> TransformFeedbackMultiQueryTestInstance::generateSizesList (const size_t bufBytes, const size_t chunkCount)
2543 {
2544 	const VkDeviceSize			chunkSize	= bufBytes / chunkCount;
2545 	std::vector<VkDeviceSize>	result		(chunkCount, chunkSize);
2546 
2547 	DE_ASSERT(chunkSize * chunkCount == bufBytes);
2548 	DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
2549 	DE_ASSERT(bufBytes % sizeof(deUint32) == 0);
2550 	DE_ASSERT(chunkCount > 0);
2551 	DE_ASSERT(result.size() == chunkCount);
2552 
2553 	return result;
2554 }
2555 
verifyTransformFeedbackBuffer(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes, const deUint32 bufOffset, const float expected)2556 void TransformFeedbackMultiQueryTestInstance::verifyTransformFeedbackBuffer (const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes, const deUint32 bufOffset, const float expected)
2557 {
2558 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
2559 	const VkDevice			device		= m_context.getDevice();
2560 	const deUint32			numPoints	= bufBytes / static_cast<deUint32>(sizeof(float));
2561 	const deUint8*			tfDataRaw	= getInvalidatedHostPtr<deUint8>(vk, device, *bufAlloc);
2562 	const float*			tfData		= reinterpret_cast<const float*>(&tfDataRaw[bufOffset]);
2563 
2564 	for (deUint32 i = 0; i < numPoints; ++i)
2565 		if (tfData[i] != expected)
2566 			TCU_FAIL(std::string("Failed at item ") + de::toString(i) + " received:" + de::toString(tfData[i]) + " expected:" + de::toString(expected));
2567 }
2568 
iterate(void)2569 tcu::TestStatus TransformFeedbackMultiQueryTestInstance::iterate (void)
2570 {
2571 	const DeviceInterface&						vk							= m_context.getDeviceInterface();
2572 	const VkDevice								device						= m_context.getDevice();
2573 	const deUint32								queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
2574 	const std::vector<deUint32>					queueFamilyIndices			= { queueFamilyIndex };
2575 	const VkQueue								queue						= m_context.getUniversalQueue();
2576 	Allocator&									allocator					= m_context.getDefaultAllocator();
2577 
2578 	const Unique<VkRenderPass>					renderPass					(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
2579 
2580 	const Unique<VkShaderModule>				vertModule					(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2581 	const Unique<VkShaderModule>				geomModule					(createShaderModule						(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
2582 
2583 	const Unique<VkFramebuffer>					framebuffer					(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2584 	const Unique<VkPipelineLayout>				pipelineLayout				(TransformFeedback::makePipelineLayout	(vk, device));
2585 	const Unique<VkPipeline>					pipeline					(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertModule, DE_NULL, DE_NULL, *geomModule, DE_NULL, m_imageExtent2D, 0u));
2586 	const Unique<VkCommandPool>					cmdPool						(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2587 	const Unique<VkCommandBuffer>				cmdBuffer					(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2588 
2589 	const VkBufferCreateInfo					tfBufCreateInfo				= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2590 	const Move<VkBuffer>						tfBuf						= createBuffer(vk, device, &tfBufCreateInfo);
2591 	const std::vector<VkBuffer>					tfBufArray					= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
2592 	const MovePtr<Allocation>					tfBufAllocation				= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2593 	const VkMemoryBarrier						tfMemoryBarrier				= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2594 	const std::vector<VkDeviceSize>				tfBufBindingSizes			= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
2595 	const std::vector<VkDeviceSize>				tfBufBindingOffsets			= generateOffsetsList(tfBufBindingSizes);
2596 	const std::vector<float>					tfBufExpectedValues			= { 0.5f, 0.5f + float(m_parameters.streamId) };
2597 	const deUint32								maxBufferSizeBytes			= static_cast<deUint32>(*std::max_element(tfBufBindingSizes.begin(), tfBufBindingSizes.end()));
2598 	const deUint32								bytesPerVertex				= static_cast<deUint32>(4 * sizeof(float));
2599 	const deUint32								numVerticesInBuffer			= maxBufferSizeBytes / bytesPerVertex;
2600 	const deUint32								numDrawVertices				= numVerticesInBuffer / 2;
2601 
2602 	const deUint32								queryIndex					= 0u;
2603 	const deUint32								queryCountersNumber			= 2u;
2604 	const deUint32								queryStride					= sizeof(TransformFeedbackQuery);
2605 	const deUint32								queryDataSize				= queryCountersNumber * queryStride;
2606 	const VkQueryPoolCreateInfo					queryPoolCreateInfo			= makeQueryPoolCreateInfo(queryCountersNumber);
2607 	const Unique<VkQueryPool>					queryPool					(createQueryPool(vk, device, &queryPoolCreateInfo));
2608 	const deUint32								queryInvalidCounterValue	= 999999u;
2609 	std::vector<TransformFeedbackQuery>			queryResultData				(queryCountersNumber, TransformFeedbackQuery{ queryInvalidCounterValue, queryInvalidCounterValue });
2610 	const std::vector<TransformFeedbackQuery>	queryExpectedData			({ TransformFeedbackQuery{ numVerticesInBuffer, 3 * numDrawVertices }, TransformFeedbackQuery{ numDrawVertices, numDrawVertices } });
2611 
2612 	const VkBufferCreateInfo					queryBufferCreateInfo		= makeBufferCreateInfo(queryDataSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT, queueFamilyIndices);
2613 	const Move<VkBuffer>						queryPoolResultsBuffer		= createBuffer(vk, device, &queryBufferCreateInfo);
2614 	const MovePtr<Allocation>					queryPoolResultsBufferAlloc	= allocator.allocate(getBufferMemoryRequirements(vk, device, *queryPoolResultsBuffer), MemoryRequirement::HostVisible);
2615 
2616 	DE_ASSERT(queryCountersNumber == queryExpectedData.size());
2617 
2618 	VK_CHECK(vk.bindBufferMemory(device, *queryPoolResultsBuffer, queryPoolResultsBufferAlloc->getMemory(), queryPoolResultsBufferAlloc->getOffset()));
2619 
2620 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2621 
2622 	beginCommandBuffer(vk, *cmdBuffer);
2623 	{
2624 		vk.cmdResetQueryPool(*cmdBuffer, *queryPool, queryIndex, queryCountersNumber);
2625 
2626 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2627 		{
2628 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2629 
2630 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
2631 
2632 			vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 0, 0u, 0u);
2633 			vk.cmdBeginQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 1, 0u, m_parameters.streamId);
2634 			{
2635 				vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2636 				{
2637 					vk.cmdDraw(*cmdBuffer, numDrawVertices, 1u, 0u, 0u);
2638 				}
2639 				vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2640 			}
2641 			vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 1, m_parameters.streamId);
2642 			vk.cmdEndQueryIndexedEXT(*cmdBuffer, *queryPool, queryIndex + 0, 0);
2643 		}
2644 		endRenderPass(vk, *cmdBuffer);
2645 
2646 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2647 	}
2648 	endCommandBuffer(vk, *cmdBuffer);
2649 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2650 
2651 	vk.getQueryPoolResults(device, *queryPool, queryIndex, queryCountersNumber, queryDataSize, queryResultData.data(), queryStride, (vk::VK_QUERY_RESULT_WAIT_BIT));
2652 
2653 	DE_ASSERT(queryResultData.size() == queryCountersNumber && queryExpectedData.size() == queryCountersNumber);
2654 	DE_ASSERT(queryCountersNumber > 0);
2655 
2656 	for (size_t counterNdx = 0; counterNdx < queryCountersNumber; ++counterNdx)
2657 	{
2658 		const TransformFeedbackQuery&	result		= queryResultData[counterNdx];
2659 		const TransformFeedbackQuery&	expected	= queryExpectedData[counterNdx];
2660 
2661 		DE_ASSERT(expected.written != queryInvalidCounterValue);
2662 		DE_ASSERT(expected.attempts != queryInvalidCounterValue);
2663 
2664 		if (result.written == queryInvalidCounterValue || result.attempts == queryInvalidCounterValue)
2665 			return tcu::TestStatus::fail("Query counters read failed");
2666 
2667 		if (result.written != expected.written)
2668 		{
2669 			const std::string	comment	= "At counter " + de::toString(counterNdx) + " vertices written " + de::toString(result.written) + ", while expected " + de::toString(expected.written);
2670 
2671 			return tcu::TestStatus::fail(comment.c_str());
2672 		}
2673 
2674 
2675 		if (result.attempts != expected.attempts)
2676 		{
2677 			const std::string	comment = "At counter " + de::toString(counterNdx) + " attempts committed " + de::toString(result.attempts) + ", while expected " + de::toString(expected.attempts);
2678 
2679 			return tcu::TestStatus::fail(comment.c_str());
2680 		}
2681 
2682 		if (counterNdx == 0 && !m_parameters.omitShaderWrite)
2683 			verifyTransformFeedbackBuffer(tfBufAllocation, bytesPerVertex * expected.written, static_cast<deUint32>(tfBufBindingOffsets[counterNdx]), tfBufExpectedValues[counterNdx]);
2684 	}
2685 
2686 	return tcu::TestStatus::pass("Pass");
2687 }
2688 
2689 
2690 class TransformFeedbackLinesOrTrianglesTestInstance : public TransformFeedbackTestInstance
2691 {
2692 public:
2693 								TransformFeedbackLinesOrTrianglesTestInstance	(Context& context, const TestParameters& parameters);
2694 
2695 protected:
2696 	std::vector<VkDeviceSize>	generateSizesList								(const size_t bufBytes, const size_t chunkCount);
2697 	void						verifyTransformFeedbackBufferLines				(const MovePtr<Allocation>&		bufAlloc,
2698 																				 const deUint32					bufBytes,
2699 																				 const std::vector<deUint32>&	primitives,
2700 																				 const deUint32					invocationCount,
2701 																				 const deUint32					partCount);
2702 	void						verifyTransformFeedbackBufferTriangles			(const MovePtr<Allocation>&		bufAlloc,
2703 																				 const deUint32					bufBytes,
2704 																				 const std::vector<deUint32>&	primitives,
2705 																				 const deUint32					invocationCount,
2706 																				 const deUint32					partCount);
2707 	tcu::TestStatus				iterate											(void);
2708 };
2709 
TransformFeedbackLinesOrTrianglesTestInstance(Context& context, const TestParameters& parameters)2710 TransformFeedbackLinesOrTrianglesTestInstance::TransformFeedbackLinesOrTrianglesTestInstance (Context& context, const TestParameters& parameters)
2711 	: TransformFeedbackTestInstance	(context, parameters)
2712 {
2713 	const InstanceInterface&							vki							= m_context.getInstanceInterface();
2714 	const VkPhysicalDevice								physDevice					= m_context.getPhysicalDevice();
2715 	const VkPhysicalDeviceFeatures						features					= getPhysicalDeviceFeatures(vki, physDevice);
2716 	const VkPhysicalDeviceTransformFeedbackFeaturesEXT&	transformFeedbackFeatures	= m_context.getTransformFeedbackFeaturesEXT();
2717 	const deUint32										streamsSupported			= m_transformFeedbackProperties.maxTransformFeedbackStreams;
2718 	const deUint32										streamsRequired				= m_parameters.streamId + 1;
2719 	const deUint32										tfBuffersSupported			= m_transformFeedbackProperties.maxTransformFeedbackBuffers;
2720 	const deUint32										tfBuffersRequired			= m_parameters.partCount;
2721 
2722 	DE_ASSERT(m_parameters.partCount == 2u);
2723 
2724 	if (m_transformFeedbackProperties.transformFeedbackStreamsLinesTriangles == DE_FALSE)
2725 		TCU_THROW(NotSupportedError, "transformFeedbackStreamsLinesTriangles required");
2726 
2727 	if (!features.geometryShader)
2728 		TCU_THROW(NotSupportedError, "Missing feature: geometryShader");
2729 
2730 	if (transformFeedbackFeatures.geometryStreams == DE_FALSE)
2731 		TCU_THROW(NotSupportedError, "geometryStreams feature is not supported");
2732 
2733 	if (streamsSupported < streamsRequired)
2734 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackStreams=" + de::toString(streamsSupported) + ", while test requires " + de::toString(streamsRequired)).c_str());
2735 
2736 	if (tfBuffersSupported < tfBuffersRequired)
2737 		TCU_THROW(NotSupportedError, std::string("maxTransformFeedbackBuffers=" + de::toString(tfBuffersSupported) + ", while test requires " + de::toString(tfBuffersRequired)).c_str());
2738 }
2739 
generateSizesList(const size_t bufBytes, const size_t chunkCount)2740 std::vector<VkDeviceSize> TransformFeedbackLinesOrTrianglesTestInstance::generateSizesList (const size_t bufBytes, const size_t chunkCount)
2741 {
2742 	const VkDeviceSize			chunkSize	= bufBytes / chunkCount;
2743 	std::vector<VkDeviceSize>	result		(chunkCount, chunkSize);
2744 
2745 	DE_ASSERT(chunkSize * chunkCount == bufBytes);
2746 	DE_ASSERT(bufBytes <= MINIMUM_TF_BUFFER_SIZE);
2747 	DE_ASSERT(bufBytes % sizeof(deUint32) == 0);
2748 	DE_ASSERT(chunkCount > 0);
2749 	DE_ASSERT(result.size() == chunkCount);
2750 
2751 	return result;
2752 }
2753 
verifyTransformFeedbackBufferLines(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes, const std::vector<deUint32>& primitives, const deUint32 invocationCount, const deUint32 partCount)2754 void TransformFeedbackLinesOrTrianglesTestInstance::verifyTransformFeedbackBufferLines (const MovePtr<Allocation>&		bufAlloc,
2755 																						const deUint32					bufBytes,
2756 																						const std::vector<deUint32>&	primitives,
2757 																						const deUint32					invocationCount,
2758 																						const deUint32					partCount)
2759 {
2760 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
2761 	const VkDevice			device		= m_context.getDevice();
2762 	const tcu::Vec4*		tfData		= getInvalidatedHostPtr<tcu::Vec4>(vk, device, *bufAlloc);
2763 	const deUint32			stripeCount	= static_cast<deUint32>(primitives.size());
2764 	const deUint32			vertexCount	= 2 * destripedLineCount(primitives) * invocationCount * partCount;
2765 	const deUint32			numPoints	= static_cast<deUint32>(bufBytes / sizeof(tcu::Vec4));
2766 	deUint32				n			= 0;
2767 	std::vector<tcu::Vec4>	reference;
2768 
2769 	reference.reserve(vertexCount);
2770 
2771 	for (deUint32 partNdx = 0; partNdx < partCount; ++partNdx)
2772 	{
2773 		for (deUint32 invocationNdx = 0; invocationNdx < invocationCount; ++invocationNdx)
2774 		{
2775 			for (deUint32 stripeNdx = 0; stripeNdx < stripeCount; ++stripeNdx)
2776 			{
2777 				const deUint32 stripeVertexCount = primitives[stripeNdx];
2778 
2779 				for (deUint32 vertexNdx = 0; vertexNdx < stripeVertexCount; ++vertexNdx)
2780 				{
2781 					const bool		firstOrLast	= vertexNdx == 0 || vertexNdx == stripeVertexCount - 1;
2782 					const tcu::Vec4 v			(float(n++), float(invocationNdx), float(stripeNdx), float(vertexNdx));
2783 
2784 					reference.push_back(v);
2785 
2786 					if (!firstOrLast)
2787 						reference.push_back(v);
2788 				}
2789 			}
2790 		}
2791 	}
2792 
2793 	DE_ASSERT(reference.size() == numPoints);
2794 
2795 	const tcu::Vec4 threshold (0.0001f, 0.0001f, 0.0001f, 0.0001f);
2796 	const auto errors = verifyVertexDataWithWinding(reference, tfData, numPoints, 2u, threshold);
2797 	checkErrorVec(m_context.getTestContext().getLog(), errors);
2798 }
2799 
verifyTransformFeedbackBufferTriangles(const MovePtr<Allocation>& bufAlloc, const deUint32 bufBytes, const std::vector<deUint32>& primitives, const deUint32 invocationCount, const deUint32 partCount)2800 void TransformFeedbackLinesOrTrianglesTestInstance::verifyTransformFeedbackBufferTriangles (const MovePtr<Allocation>&		bufAlloc,
2801 																							const deUint32					bufBytes,
2802 																							const std::vector<deUint32>&	primitives,
2803 																							const deUint32					invocationCount,
2804 																							const deUint32					partCount)
2805 {
2806 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
2807 	const VkDevice			device		= m_context.getDevice();
2808 	const tcu::Vec4*		tfData		= getInvalidatedHostPtr<tcu::Vec4>(vk, device, *bufAlloc);
2809 	const deUint32			stripeCount	= static_cast<deUint32>(primitives.size());
2810 	const deUint32			vertexCount	= 3 * destripedLineCount(primitives) * invocationCount * partCount;
2811 	const deUint32			numPoints	= static_cast<deUint32>(bufBytes / sizeof(tcu::Vec4));
2812 	deUint32				n			= 0;
2813 	std::vector<tcu::Vec4>	reference;
2814 
2815 	reference.reserve(vertexCount);
2816 
2817 	for (deUint32 partNdx = 0; partNdx < partCount; ++partNdx)
2818 	{
2819 		for (deUint32 invocationNdx = 0; invocationNdx < invocationCount; ++invocationNdx)
2820 		{
2821 			for (deUint32 stripeNdx = 0; stripeNdx < stripeCount; ++stripeNdx)
2822 			{
2823 				const deUint32			stripeVertexCount	= primitives[stripeNdx];
2824 				const deUint32			trianglesCount		= stripeVertexCount - 2;
2825 				std::vector<tcu::Vec4>	stripe				(stripeVertexCount);
2826 
2827 				for (deUint32 vertexNdx = 0; vertexNdx < stripeVertexCount; ++vertexNdx)
2828 					stripe[vertexNdx] = tcu::Vec4(float(n++), float(invocationNdx), float(stripeNdx), float(vertexNdx));
2829 
2830 				for (deUint32 triangleNdx = 0; triangleNdx < trianglesCount; ++triangleNdx)
2831 				{
2832 					if (triangleNdx % 2 == 0)
2833 					{
2834 						reference.push_back(stripe[triangleNdx + 0]);
2835 						reference.push_back(stripe[triangleNdx + 1]);
2836 						reference.push_back(stripe[triangleNdx + 2]);
2837 					}
2838 					else
2839 					{
2840 						reference.push_back(stripe[triangleNdx + 0]);
2841 						reference.push_back(stripe[triangleNdx + 2]);
2842 						reference.push_back(stripe[triangleNdx + 1]);
2843 					}
2844 				}
2845 			}
2846 		}
2847 	}
2848 
2849 	DE_ASSERT(reference.size() == numPoints);
2850 
2851 	const tcu::Vec4 threshold (0.0001f, 0.0001f, 0.0001f, 0.0001f);
2852 	const auto errors = verifyVertexDataWithWinding(reference, tfData, numPoints, 3u, threshold);
2853 	checkErrorVec(m_context.getTestContext().getLog(), errors);
2854 }
2855 
iterate(void)2856 tcu::TestStatus TransformFeedbackLinesOrTrianglesTestInstance::iterate (void)
2857 {
2858 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
2859 	const VkDevice						device					= m_context.getDevice();
2860 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
2861 	const VkQueue						queue					= m_context.getUniversalQueue();
2862 	Allocator&							allocator				= m_context.getDefaultAllocator();
2863 
2864 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
2865 
2866 	const Unique<VkShaderModule>		vertexModule			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2867 	const Unique<VkShaderModule>		geomModule				(createShaderModule						(vk, device, m_context.getBinaryCollection().get("geom"), 0u));
2868 
2869 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2870 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
2871 	const Unique<VkPipeline>			pipeline				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule, DE_NULL, DE_NULL, *geomModule, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
2872 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2873 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2874 
2875 	const deUint32						tfBufferSize			= m_parameters.bufferSize;
2876 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(tfBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2877 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
2878 	const std::vector<VkBuffer>			tfBufArray				= std::vector<VkBuffer>(m_parameters.partCount, *tfBuf);
2879 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2880 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2881 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= generateSizesList(tfBufferSize, m_parameters.partCount);
2882 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
2883 
2884 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2885 
2886 	beginCommandBuffer(vk, *cmdBuffer);
2887 	{
2888 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2889 		{
2890 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
2891 
2892 			vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0u, m_parameters.partCount, &tfBufArray[0], &tfBufBindingOffsets[0], &tfBufBindingSizes[0]);
2893 
2894 			vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2895 			{
2896 				vk.cmdDraw(*cmdBuffer, INVOCATION_COUNT, 1u, 0u, 0u);
2897 			}
2898 			vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2899 		}
2900 		endRenderPass(vk, *cmdBuffer);
2901 
2902 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2903 	}
2904 	endCommandBuffer(vk, *cmdBuffer);
2905 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2906 
2907 	switch (m_parameters.primTopology)
2908 	{
2909 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:		verifyTransformFeedbackBufferLines(tfBufAllocation, tfBufferSize, LINES_LIST, INVOCATION_COUNT, m_parameters.partCount);			break;
2910 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:	verifyTransformFeedbackBufferTriangles(tfBufAllocation, tfBufferSize, TRIANGLES_LIST, INVOCATION_COUNT, m_parameters.partCount);	break;
2911 		default:									TCU_THROW(InternalError, "Unknown topology");
2912 	}
2913 
2914 	return tcu::TestStatus::pass("Pass");
2915 }
2916 
2917 class TransformFeedbackDrawOutsideTestInstance : public TransformFeedbackTestInstance
2918 {
2919 public:
2920 						TransformFeedbackDrawOutsideTestInstance	(Context& context, const TestParameters& parameters);
2921 
2922 protected:
2923 	tcu::TestStatus		iterate										(void);
2924 };
2925 
TransformFeedbackDrawOutsideTestInstance(Context& context, const TestParameters& parameters)2926 TransformFeedbackDrawOutsideTestInstance::TransformFeedbackDrawOutsideTestInstance(Context& context, const TestParameters& parameters)
2927 	: TransformFeedbackTestInstance	(context, parameters)
2928 {
2929 }
2930 
iterate(void)2931 tcu::TestStatus TransformFeedbackDrawOutsideTestInstance::iterate (void)
2932 {
2933 	const DeviceInterface&				vk						= m_context.getDeviceInterface();
2934 	const VkDevice						device					= m_context.getDevice();
2935 	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
2936 	const VkQueue						queue					= m_context.getUniversalQueue();
2937 	Allocator&							allocator				= m_context.getDefaultAllocator();
2938 
2939 	const Unique<VkShaderModule>		vertexModule1			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert"), 0u));
2940 	const Unique<VkShaderModule>		vertexModule2			(createShaderModule						(vk, device, m_context.getBinaryCollection().get("vert2"), 0u));
2941 	const Unique<VkRenderPass>			renderPass				(makeRenderPass							(vk, device, VK_FORMAT_UNDEFINED));
2942 	const Unique<VkFramebuffer>			framebuffer				(makeFramebuffer						(vk, device, *renderPass, 0u, DE_NULL, m_imageExtent2D.width, m_imageExtent2D.height));
2943 	const Unique<VkPipelineLayout>		pipelineLayout			(TransformFeedback::makePipelineLayout	(vk, device));
2944 	const Unique<VkPipeline>			pipeline1				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule1, DE_NULL, DE_NULL, DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
2945 	const Unique<VkPipeline>			pipeline2				(makeGraphicsPipeline					(vk, device, *pipelineLayout, *renderPass, *vertexModule2, DE_NULL, DE_NULL, DE_NULL, DE_NULL, m_imageExtent2D, 0u, &m_parameters.streamId));
2946 	const Unique<VkCommandPool>			cmdPool					(createCommandPool						(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
2947 	const Unique<VkCommandBuffer>		cmdBuffer				(allocateCommandBuffer					(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
2948 
2949 	const VkBufferCreateInfo			tfBufCreateInfo			= makeBufferCreateInfo(m_parameters.bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
2950 	const Move<VkBuffer>				tfBuf					= createBuffer(vk, device, &tfBufCreateInfo);
2951 	const MovePtr<Allocation>			tfBufAllocation			= allocator.allocate(getBufferMemoryRequirements(vk, device, *tfBuf), MemoryRequirement::HostVisible);
2952 	const VkMemoryBarrier				tfMemoryBarrier			= makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
2953 	const std::vector<VkDeviceSize>		tfBufBindingSizes		= generateSizesList(m_parameters.bufferSize, m_parameters.partCount);
2954 	const std::vector<VkDeviceSize>		tfBufBindingOffsets		= generateOffsetsList(tfBufBindingSizes);
2955 
2956 	VK_CHECK(vk.bindBufferMemory(device, *tfBuf, tfBufAllocation->getMemory(), tfBufAllocation->getOffset()));
2957 
2958 	beginCommandBuffer(vk, *cmdBuffer);
2959 	{
2960 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, makeRect2D(m_imageExtent2D));
2961 		{
2962 			for (deUint32 i = 0; i < 2; ++i)
2963 			{
2964 				if (i == 0)
2965 					vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline1);
2966 				else
2967 					vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline2);
2968 
2969 				for (deUint32 drawNdx = 0; drawNdx < m_parameters.partCount; ++drawNdx)
2970 				{
2971 					const deUint32	startValue = static_cast<deUint32>(tfBufBindingOffsets[drawNdx] / sizeof(deUint32));
2972 					const deUint32	numPoints = static_cast<deUint32>(tfBufBindingSizes[drawNdx] / sizeof(deUint32));
2973 
2974 					vk.cmdBindTransformFeedbackBuffersEXT(*cmdBuffer, 0, 1, &*tfBuf, &tfBufBindingOffsets[drawNdx], &tfBufBindingSizes[drawNdx]);
2975 
2976 					vk.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0u, sizeof(startValue), &startValue);
2977 
2978 					if (i == 0)
2979 						vk.cmdBeginTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2980 					{
2981 						vk.cmdDraw(*cmdBuffer, numPoints, 1u, 0u, 0u);
2982 					}
2983 					if (i == 0)
2984 						vk.cmdEndTransformFeedbackEXT(*cmdBuffer, 0, 0, DE_NULL, DE_NULL);
2985 				}
2986 			}
2987 		}
2988 		endRenderPass(vk, *cmdBuffer);
2989 
2990 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &tfMemoryBarrier, 0u, DE_NULL, 0u, DE_NULL);
2991 	}
2992 	endCommandBuffer(vk, *cmdBuffer);
2993 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
2994 
2995 	verifyTransformFeedbackBuffer(tfBufAllocation, m_parameters.bufferSize);
2996 
2997 	return tcu::TestStatus::pass("Pass");
2998 }
2999 
3000 class TransformFeedbackHolesInstance : public vkt::TestInstance
3001 {
3002 public:
TransformFeedbackHolesInstance(Context& context, const bool extraDraw)3003 						TransformFeedbackHolesInstance	(Context& context, const bool extraDraw)
3004 							: vkt::TestInstance	(context)
3005 							, m_extraDraw		(extraDraw)
3006 							{}
~TransformFeedbackHolesInstance(void)3007 						~TransformFeedbackHolesInstance	(void) {}
3008 
3009 	tcu::TestStatus		iterate							(void) override;
3010 
3011 protected:
3012 	const bool m_extraDraw;
3013 };
3014 
iterate(void)3015 tcu::TestStatus TransformFeedbackHolesInstance::iterate (void)
3016 {
3017 	const auto&			ctx				= m_context.getContextCommonData();
3018 	const tcu::IVec3	fbExtent		(1, 1, 1);
3019 	const auto			vkExtent		= makeExtent3D(fbExtent);
3020 	const auto			fbFormat		= VK_FORMAT_R8G8B8A8_UNORM;
3021 	const auto			tcuFormat		= mapVkFormat(fbFormat);
3022 	const auto			fbUsage			= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
3023 	const tcu::Vec4		clearColor		(0.0f, 0.0f, 0.0f, 1.0f);
3024 	const tcu::Vec4		geomColor		(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader values.
3025 	const tcu::Vec4		threshold		(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
3026 	const auto			bindPoint		= VK_PIPELINE_BIND_POINT_GRAPHICS;
3027 	const auto&			binaries		= m_context.getBinaryCollection();
3028 	const bool			hasGeom			= binaries.contains("geom");
3029 	const auto			dataStages		= (hasGeom ? VK_SHADER_STAGE_GEOMETRY_BIT : VK_SHADER_STAGE_VERTEX_BIT);
3030 	const auto			xfbCompCount	= 3u; // Per vertex.
3031 	const auto			xfbChunkSize	= xfbCompCount * sizeof(float); // Per vertex, in bytes.
3032 	const auto			totalDraws		= (m_extraDraw ? 2u : 1u);
3033 
3034 	// Color buffer with verification buffer.
3035 	ImageWithBuffer colorBuffer (
3036 		ctx.vkd,
3037 		ctx.device,
3038 		ctx.allocator,
3039 		vkExtent,
3040 		fbFormat,
3041 		fbUsage,
3042 		VK_IMAGE_TYPE_2D);
3043 
3044 	// Vertices.
3045 	const std::vector<tcu::Vec4> vertices { tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f) };
3046 
3047 	// Vertex buffer.
3048 	const auto			vbSize			= static_cast<VkDeviceSize>(de::dataSize(vertices));
3049 	const auto			vbInfo			= makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
3050 	BufferWithMemory	vertexBuffer	(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
3051 	const auto			vbAlloc			= vertexBuffer.getAllocation();
3052 	void*				vbData			= vbAlloc.getHostPtr();
3053 	const auto			vbOffset		= static_cast<VkDeviceSize>(0);
3054 
3055 	deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
3056 	flushAlloc(ctx.vkd, ctx.device, vbAlloc);
3057 
3058 	// XFB buffer. When using an extra draw, leave space for a possible second draw (NB: but it should not be recorded, see below).
3059 	const auto			xfbSizeFactor	= static_cast<VkDeviceSize>(totalDraws);
3060 	const auto			xfbBufferSize	= static_cast<VkDeviceSize>(xfbChunkSize * vertices.size()) * xfbSizeFactor;
3061 	const auto			xfbBufferInfo	= makeBufferCreateInfo(xfbBufferSize, VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT);
3062 	BufferWithMemory	xfbBuffer		(ctx.vkd, ctx.device, ctx.allocator, xfbBufferInfo, MemoryRequirement::HostVisible);
3063 	const auto			xfbBufferAlloc	= xfbBuffer.getAllocation();
3064 	void*				xfbBufferData	= xfbBufferAlloc.getHostPtr();
3065 	const auto			xfbBufferOffset	= static_cast<VkDeviceSize>(0);
3066 
3067 	deMemset(xfbBufferData, 0, static_cast<size_t>(xfbBufferSize));
3068 	flushAlloc(ctx.vkd, ctx.device, xfbBufferAlloc);
3069 
3070 	// Push constants.
3071 	const tcu::Vec3				pcData	{ 10.0, 20.0, 30.0 }; // Must match the expected values in the frag shader.
3072 	const auto					pcSize	= static_cast<uint32_t>(sizeof(pcData));
3073 	const auto					pcRange	= makePushConstantRange(dataStages, 0u, pcSize);
3074 
3075 	const auto pipelineLayout	= makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
3076 	const auto renderPass		= makeRenderPass(ctx.vkd, ctx.device, fbFormat);
3077 	const auto framebuffer		= makeFramebuffer(ctx.vkd, ctx.device, *renderPass, colorBuffer.getImageView(), vkExtent.width, vkExtent.height);
3078 
3079 	// Modules.
3080 	const auto	vertModule		= createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
3081 	const auto	geomModule		= (hasGeom ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) : Move<VkShaderModule>());
3082 	const auto	fragModule		= createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
3083 
3084 	const std::vector<VkViewport>	viewports	(1u, makeViewport(vkExtent));
3085 	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(vkExtent));
3086 
3087 	const auto pipeline = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout,
3088 		*vertModule, VK_NULL_HANDLE, VK_NULL_HANDLE, *geomModule, *fragModule,
3089 		*renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
3090 
3091 	CommandPoolWithBuffer cmd (ctx.vkd, ctx.device, ctx.qfIndex);
3092 	const auto cmdBuffer = *cmd.cmdBuffer;
3093 
3094 	beginCommandBuffer(ctx.vkd, cmdBuffer);
3095 	beginRenderPass(ctx.vkd, cmdBuffer, *renderPass, *framebuffer, scissors.at(0u), clearColor);
3096 	ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
3097 	ctx.vkd.cmdBindPipeline(cmdBuffer, bindPoint, *pipeline);
3098 	ctx.vkd.cmdPushConstants(cmdBuffer, *pipelineLayout, dataStages, 0u, pcSize, &pcData);
3099 	ctx.vkd.cmdBindTransformFeedbackBuffersEXT(cmdBuffer, 0u, 1u, &xfbBuffer.get(), &xfbBufferOffset, &xfbBufferSize);
3100 	ctx.vkd.cmdBeginTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3101 	ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
3102 	ctx.vkd.cmdEndTransformFeedbackEXT(cmdBuffer, 0u, 0u, nullptr, nullptr);
3103 	if (m_extraDraw)
3104 	{
3105 		// When m_extraDraw is true, record a new draw outside the transform feedback section. The XFB buffer will have enough space
3106 		// to record this draw, but it should not be recorded, obviously, so the values in the buffer should stay zero. We are also
3107 		// avoiding any state changes between both draws.
3108 		ctx.vkd.cmdDraw(cmdBuffer, de::sizeU32(vertices), 1u, 0u, 0u);
3109 	}
3110 	endRenderPass(ctx.vkd, cmdBuffer);
3111 	const auto xfbBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT, VK_ACCESS_HOST_READ_BIT);
3112 	ctx.vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &xfbBarrier, 0u, nullptr, 0u, nullptr);
3113 	copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(),
3114 		fbExtent.swizzle(0, 1), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
3115 		VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
3116 	endCommandBuffer(ctx.vkd, cmdBuffer);
3117 	submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
3118 
3119 	// Verify color output.
3120 	invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
3121 	tcu::PixelBufferAccess resultAccess (tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
3122 
3123 	tcu::TextureLevel	referenceLevel	(tcuFormat, fbExtent.x(), fbExtent.y());
3124 	auto				referenceAccess	= referenceLevel.getAccess();
3125 	tcu::clear(referenceAccess, geomColor);
3126 
3127 	auto& log = m_context.getTestContext().getLog();
3128 	if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold, tcu::COMPARE_LOG_ON_ERROR))
3129 		return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
3130 
3131 	// Verify XFB buffer.
3132 	const tcu::Vec3	refRecordedValues	{ pcData.x(), 0.0f, pcData.z() };	// Per-vertex, must match vert/geom shader, note Y is not saved.
3133 	const tcu::Vec3	refEmptyValues		{ 0.0f, 0.0f, 0.0f };				// For empty areas of the XFB buffer.
3134 	const auto		dataPtr				= reinterpret_cast<const char*>(xfbBufferData);
3135 
3136 	for (uint32_t drawIdx = 0u; drawIdx < totalDraws; ++drawIdx)
3137 	{
3138 		const auto& refValues = ((drawIdx > 0u) ? refEmptyValues : refRecordedValues);
3139 		for (size_t vertIdx = 0u; vertIdx < vertices.size(); ++vertIdx)
3140 		{
3141 			const auto	vertexDataPtr	= dataPtr + (vertIdx * xfbChunkSize) + (drawIdx * vertices.size() * xfbChunkSize);
3142 			tcu::Vec3	vertValues		(0.0f, 0.0f, 0.0f);
3143 			deMemcpy(&vertValues, vertexDataPtr, sizeof(vertValues));
3144 
3145 			if (vertValues != refValues)
3146 			{
3147 				std::ostringstream msg;
3148 				msg << "Invalid data found for vertex " << vertIdx << ": expected " << refRecordedValues << " and found " << vertValues;
3149 				TCU_FAIL(msg.str());
3150 			}
3151 		}
3152 	}
3153 
3154 	return tcu::TestStatus::pass("Pass");
3155 }
3156 
3157 class TransformFeedbackTestCase : public vkt::TestCase
3158 {
3159 public:
3160 						TransformFeedbackTestCase	(tcu::TestContext &context, const char *name, const TestParameters& parameters);
3161 
3162 protected:
3163 	vkt::TestInstance*	createInstance				(vkt::Context& context) const;
3164 	void				initPrograms				(SourceCollections& programCollection) const;
3165 	virtual void		checkSupport				(Context& context) const;
3166 
3167 	TestParameters		m_parameters;
3168 };
3169 
TransformFeedbackTestCase(tcu::TestContext &context, const char *name, const TestParameters& parameters)3170 TransformFeedbackTestCase::TransformFeedbackTestCase (tcu::TestContext &context, const char *name, const TestParameters& parameters)
3171 	: TestCase		(context, name)
3172 	, m_parameters	(parameters)
3173 {
3174 }
3175 
vectorToString(const std::vector<deUint32>& v)3176 std::string vectorToString (const std::vector<deUint32>& v)
3177 {
3178 	std::ostringstream css;
3179 
3180 	DE_ASSERT(!v.empty());
3181 
3182 	for (auto x: v)
3183 		css << x << ",";
3184 
3185 	return css.str().substr(0, css.str().size() - 1);
3186 }
3187 
createInstance(vkt::Context& context) const3188 vkt::TestInstance*	TransformFeedbackTestCase::createInstance (vkt::Context& context) const
3189 {
3190 	if (m_parameters.testType == TEST_TYPE_BASIC)
3191 		return new TransformFeedbackBasicTestInstance(context, m_parameters);
3192 
3193 	if (m_parameters.testType == TEST_TYPE_RESUME)
3194 		return new TransformFeedbackResumeTestInstance(context, m_parameters);
3195 
3196 	if (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)
3197 		return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
3198 
3199 	if (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)
3200 		return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
3201 
3202 	if (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)
3203 		return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
3204 
3205 	if (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL)
3206 		return new TransformFeedbackBuiltinTestInstance(context, m_parameters);
3207 
3208 	if (m_parameters.testType == TEST_TYPE_WINDING)
3209 		return new TransformFeedbackWindingOrderTestInstance(context, m_parameters);
3210 
3211 	if (m_parameters.testType == TEST_TYPE_STREAMS)
3212 		return new TransformFeedbackStreamsTestInstance(context, m_parameters);
3213 
3214 	if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
3215 		return new TransformFeedbackStreamsTestInstance(context, m_parameters);
3216 
3217 	if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE)
3218 		return new TransformFeedbackStreamsTestInstance(context, m_parameters);
3219 
3220 	if (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
3221 		return new TransformFeedbackStreamsTestInstance(context, m_parameters);
3222 
3223 	if (m_parameters.testType == TEST_TYPE_MULTISTREAMS)
3224 		return new TransformFeedbackMultistreamTestInstance(context, m_parameters);
3225 
3226 	if (m_parameters.testType == TEST_TYPE_MULTISTREAMS_SAME_LOCATION)
3227 		return new TransformFeedbackMultistreamSameLocationTestInstance(context, m_parameters);
3228 
3229 	if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT)
3230 		return new TransformFeedbackIndirectDrawTestInstance(context, m_parameters, false);
3231 
3232 	if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
3233 		return new TransformFeedbackIndirectDrawTestInstance(context, m_parameters, true);
3234 
3235 	if (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY || m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT)
3236 		return new TransformFeedbackBackwardDependencyTestInstance(context, m_parameters);
3237 
3238 	if (m_parameters.testType == TEST_TYPE_QUERY_GET				||
3239 		m_parameters.testType == TEST_TYPE_QUERY_COPY				||
3240 		m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO	||
3241 		m_parameters.testType == TEST_TYPE_QUERY_RESET)
3242 		return new TransformFeedbackQueryTestInstance(context, m_parameters);
3243 
3244 	if (m_parameters.testType == TEST_TYPE_MULTIQUERY)
3245 		return new TransformFeedbackMultiQueryTestInstance(context, m_parameters);
3246 
3247 	if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX	||
3248 		m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY	||
3249 		m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
3250 		return new TransformFeedbackDepthClipControlTestInstance(context, m_parameters);
3251 
3252 	if (m_parameters.testType == TEST_TYPE_LINES_TRIANGLES)
3253 		return new TransformFeedbackLinesOrTrianglesTestInstance(context, m_parameters);
3254 
3255 	if (m_parameters.testType == TEST_TYPE_DRAW_OUTSIDE)
3256 		return new TransformFeedbackDrawOutsideTestInstance(context, m_parameters);
3257 
3258 	if (m_parameters.testType == TEST_TYPE_HOLES_VERTEX || m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
3259 	{
3260 		// We repurpose partCount to indicate somehow the number of draws.
3261 		const bool extraDraw = (m_parameters.partCount > 1u);
3262 		return new TransformFeedbackHolesInstance (context, extraDraw);
3263 	}
3264 
3265 	TCU_THROW(InternalError, "Specified test type not found");
3266 }
3267 
checkSupport(Context& context) const3268 void TransformFeedbackTestCase::checkSupport (Context& context) const
3269 {
3270 	context.requireDeviceFunctionality("VK_EXT_transform_feedback");
3271 
3272 	if (context.getTransformFeedbackFeaturesEXT().transformFeedback == VK_FALSE)
3273 		TCU_THROW(NotSupportedError, "transformFeedback feature is not supported");
3274 
3275 	if (m_parameters.useMaintenance5)
3276 		context.requireDeviceFunctionality("VK_KHR_maintenance5");
3277 
3278 	// transformFeedbackRasterizationStreamSelect is required when vertex streams other than zero are rasterized
3279 	if (m_parameters.requireRastStreamSelect && (context.getTransformFeedbackPropertiesEXT().transformFeedbackRasterizationStreamSelect == VK_FALSE) && (m_parameters.streamId > 0))
3280 		TCU_THROW(NotSupportedError, "transformFeedbackRasterizationStreamSelect property is not supported");
3281 
3282 	if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
3283 	{
3284 		const auto& features = context.getMultiviewFeatures();
3285 		if (!features.multiview)
3286 			TCU_THROW(NotSupportedError, "multiview not supported");
3287 	}
3288 
3289 	if (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT)
3290 		context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
3291 
3292 	if (m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
3293 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
3294 }
3295 
initPrograms(SourceCollections& programCollection) const3296 void TransformFeedbackTestCase::initPrograms (SourceCollections& programCollection) const
3297 {
3298 	const bool backwardDependency	= (m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY
3299 									|| m_parameters.testType == TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT);
3300 	const bool vertexShaderOnly		=  m_parameters.testType == TEST_TYPE_BASIC
3301 									|| m_parameters.testType == TEST_TYPE_RESUME
3302 									|| (m_parameters.testType == TEST_TYPE_WINDING && m_parameters.primTopology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
3303 	const bool requiresFullPipeline	=  m_parameters.testType == TEST_TYPE_STREAMS
3304 									|| m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE
3305 									|| m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE
3306 									|| m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE
3307 									|| (m_parameters.testType == TEST_TYPE_WINDING && m_parameters.primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST);
3308 	const bool xfbBuiltinPipeline	=  m_parameters.testType == TEST_TYPE_XFB_POINTSIZE
3309 									|| m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE
3310 									|| m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE
3311 									|| m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL;
3312 
3313 	if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX)
3314 	{
3315 		// Vertex shader
3316 		{
3317 			std::ostringstream src;
3318 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3319 				<< "\n"
3320 				<< "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
3321 				<< "{\n"
3322 				<< "    vec4 gl_Position;\n"
3323 				<< "};\n"
3324 				<< "\n"
3325 				<< "void main(void)\n"
3326 				<< "{\n"
3327 				<< "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
3328 				<< "}\n";
3329 
3330 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3331 		}
3332 
3333 		return;
3334 	}
3335 
3336 	if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY)
3337 	{
3338 		// Vertex shader
3339 		{
3340 			std::ostringstream src;
3341 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3342 				<< "\n"
3343 				<< "void main(void)\n"
3344 				<< "{\n"
3345 				<< "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
3346 				<< "}\n";
3347 
3348 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3349 		}
3350 
3351 		// Geometry shader
3352 		{
3353 			std::ostringstream src;
3354 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3355 				<< "\n"
3356 				<< "layout(points) in;\n"
3357 				<< "layout(points, max_vertices = 1) out;\n"
3358 				<< "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
3359 				<< "{\n"
3360 				<< "    vec4 gl_Position;\n"
3361 				<< "};\n"
3362 				<< "\n"
3363 				<< "void main(void)\n"
3364 				<< "{\n"
3365 				<< "    gl_Position = gl_in[0].gl_Position;\n"
3366 				<< "    EmitVertex();\n"
3367 				<< "    EndPrimitive();\n"
3368 				<< "}\n";
3369 
3370 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
3371 		}
3372 
3373 		return;
3374 	}
3375 
3376 	if (m_parameters.testType == TEST_TYPE_DEPTH_CLIP_CONTROL_TESE)
3377 	{
3378 		// Vertex shader
3379 		{
3380 			std::ostringstream src;
3381 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3382 				<< "\n"
3383 				<< "void main(void)\n"
3384 				<< "{\n"
3385 				<< "    gl_Position = vec4(1.0, 1.0, float(gl_VertexIndex) / 3.0 - 1.0, 1.0);\n"
3386 				<< "}\n";
3387 
3388 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3389 		}
3390 
3391 		// Tesselation control shader
3392 		{
3393 			std::ostringstream src;
3394 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3395 				<< "layout(vertices = 3) out;\n"
3396 				<< "void main (void)\n"
3397 				<< "{\n"
3398 				<< "    gl_TessLevelInner[0] = 0.0;\n"
3399 				<< "    gl_TessLevelOuter[0] = 1.0;\n"
3400 				<< "    gl_TessLevelOuter[1] = 1.0;\n"
3401 				<< "    gl_TessLevelOuter[2] = 1.0;\n"
3402 				<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3403 				<< "}\n";
3404 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
3405 		}
3406 
3407 		// Tessellation evaluation shader
3408 		{
3409 			std::ostringstream src;
3410 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3411 				<< "layout(triangles, ccw) in;\n"
3412 				<< "layout(xfb_buffer = 0, xfb_offset = 0) out gl_PerVertex\n"
3413 				<< "{\n"
3414 				<< "    vec4 gl_Position;\n"
3415 				<< "};\n"
3416 				<< "\n"
3417 				<< "void main (void)\n"
3418 				<< "{\n"
3419 				<< "    vec4 p0 = gl_TessCoord.x * gl_in[0].gl_Position;\n"
3420 				<< "    vec4 p1 = gl_TessCoord.y * gl_in[1].gl_Position;\n"
3421 				<< "    vec4 p2 = gl_TessCoord.z * gl_in[2].gl_Position;\n"
3422 				<< "    gl_Position = p0 + p1 + p2;\n"
3423 				<< "}\n";
3424 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
3425 		}
3426 
3427 		return;
3428 	}
3429 
3430 	if (vertexShaderOnly)
3431 	{
3432 		// Vertex shader
3433 		{
3434 			std::ostringstream src;
3435 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3436 				<< "\n"
3437 				<< "layout(push_constant) uniform pushConstants\n"
3438 				<< "{\n"
3439 				<< "    uint start;\n"
3440 				<< "} uInput;\n"
3441 				<< "\n"
3442 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
3443 				<< "\n"
3444 				<< "void main(void)\n"
3445 				<< "{\n"
3446 				<< "    idx_out = uInput.start + gl_VertexIndex;\n"
3447 				<< "}\n";
3448 
3449 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3450 		}
3451 
3452 		return;
3453 	}
3454 
3455 	if (backwardDependency)
3456 	{
3457 		// Vertex shader.
3458 		{
3459 			std::ostringstream src;
3460 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3461 				<< "\n"
3462 				<< "layout(push_constant, std430) uniform PushConstantBlock\n"
3463 				<< "{\n"
3464 				<< "    uint  start;\n"
3465 				<< "    float width;\n"
3466 				<< "    float posY;\n"
3467 				<< "} pc;\n"
3468 				<< "\n"
3469 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
3470 				<< "\n"
3471 				<< "void main(void)\n"
3472 				<< "{\n"
3473 				<< "    idx_out           = pc.start + gl_VertexIndex;\n"
3474 				<< "    const float posX  = ((float(gl_VertexIndex) + 0.5) / pc.width) * 2.0 - 1.0;\n"
3475 				<< "    gl_Position       = vec4(posX, pc.posY, 0.0, 1.0);\n"
3476 				<< "    gl_PointSize      = 1.0;\n"
3477 				<< "}\n";
3478 
3479 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3480 		}
3481 
3482 		// Fragment shader.
3483 		{
3484 			std::ostringstream frag;
3485 			frag
3486 				<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3487 				<< "layout (location=0) out vec4 outColor;\n"
3488 				<< "void main (void) { outColor = vec4(0.0, 0.0, 1.0, 1.0); }\n"
3489 				;
3490 			programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
3491 		}
3492 
3493 		return;
3494 	}
3495 
3496 	if (m_parameters.primTopology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
3497 	{
3498 		// Vertex shader
3499 		{
3500 			std::ostringstream src;
3501 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3502 				<< "layout(push_constant) uniform pushConstants\n"
3503 				<< "{\n"
3504 				<< "    uint start;\n"
3505 				<< "} uInput;\n"
3506 				<< "void main(void)\n"
3507 				<< "{\n"
3508 				<< "}\n";
3509 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3510 		}
3511 
3512 		// Tesselation control shader
3513 		{
3514 			std::ostringstream src;
3515 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3516 				<< "layout(vertices = 3) out;\n"
3517 				<< "void main (void)\n"
3518 				<< "{\n"
3519 				<< "    gl_TessLevelInner[0] = 2.0;\n" // generate three triangles out of each patch
3520 				<< "    gl_TessLevelOuter[0] = 1.0;\n"
3521 				<< "    gl_TessLevelOuter[1] = 1.0;\n"
3522 				<< "    gl_TessLevelOuter[2] = 1.0;\n"
3523 				<< "}\n";
3524 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
3525 		}
3526 
3527 		// Tessellation evaluation shader
3528 		{
3529 			std::ostringstream src;
3530 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3531 				<< "layout(triangles, ccw) in;\n"
3532 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
3533 				<< "\n"
3534 				<< "void main (void)\n"
3535 				<< "{\n"
3536 				<< "    idx_out = gl_PrimitiveID;\n" // all vertex generated from patch will have its id
3537 				<< "}\n";
3538 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
3539 		}
3540 
3541 		return;
3542 	}
3543 
3544 	if (xfbBuiltinPipeline)
3545 	{
3546 		const std::string	outputBuiltIn		= (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)     ? "float gl_PointSize;\n"
3547 												: (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)  ? "float gl_ClipDistance[8];\n"
3548 												: (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)  ? "float gl_CullDistance[8];\n"
3549 												: (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ? "float gl_CullDistance[5];\nfloat gl_ClipDistance[1];\n"
3550 												: "";
3551 		const std::string	operationBuiltIn	= (m_parameters.testType == TEST_TYPE_XFB_POINTSIZE)     ? "gl_PointSize = float(gl_VertexIndex) / 32768.0f;"
3552 												: (m_parameters.testType == TEST_TYPE_XFB_CLIPDISTANCE)  ? "for (int i=0; i<8; i++) gl_ClipDistance[i] = float(8 * gl_VertexIndex + i) / 32768.0f;"
3553 												: (m_parameters.testType == TEST_TYPE_XFB_CULLDISTANCE)  ? "for (int i=0; i<8; i++) gl_CullDistance[i] = float(8 * gl_VertexIndex + i) / 32768.0f;"
3554 												: (m_parameters.testType == TEST_TYPE_XFB_CLIP_AND_CULL) ? "for (int i=0; i<5; i++) gl_CullDistance[i] = float(6 * gl_VertexIndex + i) / 32768.0f;\n"
3555 																										   "gl_ClipDistance[0] = float(6 * gl_VertexIndex + 5) / 32768.0f;\n"
3556 												: "";
3557 
3558 		// Vertex shader
3559 		{
3560 			std::ostringstream src;
3561 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3562 				<< "\n"
3563 				<< "layout(xfb_buffer = " << m_parameters.partCount - 1 << ", xfb_offset = 0) out gl_PerVertex\n"
3564 				<< "{\n"
3565 				<< outputBuiltIn
3566 				<< "};\n"
3567 				<< "\n"
3568 				<< "void main(void)\n"
3569 				<< "{\n"
3570 				<< operationBuiltIn
3571 				<< "}\n";
3572 
3573 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3574 		}
3575 
3576 		return;
3577 	}
3578 
3579 	if (m_parameters.testType == TEST_TYPE_MULTISTREAMS)
3580 	{
3581 		// vertex shader
3582 		{
3583 			std::ostringstream src;
3584 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3585 				<< "\n"
3586 				<< "void main(void)\n"
3587 				<< "{\n"
3588 				<< "}\n";
3589 
3590 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3591 		}
3592 
3593 		// geometry shader
3594 		{
3595 			const deUint32		s	= m_parameters.streamId;
3596 			std::ostringstream	src;
3597 
3598 			DE_ASSERT(s != 0);
3599 
3600 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3601 				<< "\n"
3602 				<< "layout(points) in;\n"
3603 				<< "\n"
3604 				<< "layout(points, max_vertices = 32) out;\n"
3605 				<< "layout(stream = " << 0 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
3606 				<< "layout(stream = " << s << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
3607 				<< "\n"
3608 				<< "const int counts[] = int[](1, 1, 2, 4, 8);\n"
3609 				<< "\n"
3610 				<< "void main(void)\n"
3611 				<< "{\n"
3612 				<< "    int c0 = 0;\n"
3613 				<< "    int c1 = 0;\n"
3614 				<< "\n"
3615 				<< "    // Start 1st buffer from point where 0th buffer ended\n"
3616 				<< "    for (int i = 0; i < counts.length(); i++)\n"
3617 				<< "        c1 = c1 + 4 * counts[i];\n"
3618 				<< "\n"
3619 				<< "    for (int i = 0; i < counts.length(); i++)\n"
3620 				<< "    {\n"
3621 				<< "        const int n0 = counts[i];\n"
3622 				<< "        const int n1 = counts[counts.length() - 1 - i];\n"
3623 				<< "\n"
3624 				<< "        for (int j = 0; j < n0; j++)\n"
3625 				<< "        {\n"
3626 				<< "            out0 = vec4(ivec4(c0, c0 + 1, c0 + 2, c0 + 3));\n"
3627 				<< "            c0 = c0 + 4;\n"
3628 				<< "            EmitStreamVertex(0);\n"
3629 				<< "            EndStreamPrimitive(0);\n"
3630 				<< "        }\n"
3631 				<< "\n"
3632 				<< "        for (int j = 0; j < n1; j++)\n"
3633 				<< "        {\n"
3634 				<< "            out1 = vec4(ivec4(c1, c1 + 1, c1 + 2, c1 + 3));\n"
3635 				<< "            c1 = c1 + 4;\n"
3636 				<< "            EmitStreamVertex(" << s << ");\n"
3637 				<< "            EndStreamPrimitive(" << s << ");\n"
3638 				<< "        }\n"
3639 				<< "    }\n"
3640 				<< "}\n";
3641 
3642 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
3643 		}
3644 
3645 		return;
3646 	}
3647 
3648 	if (m_parameters.testType == TEST_TYPE_MULTISTREAMS_SAME_LOCATION)
3649 	{
3650 		// vertex shader
3651 		{
3652 			std::ostringstream src;
3653 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3654 				<< "\n"
3655                 << "layout(location=0) out uint id;"
3656 				<< "void main(void)\n"
3657 				<< "{\n"
3658                 << "  id = gl_VertexIndex;"
3659 				<< "}\n";
3660 
3661 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3662 		}
3663 
3664 		// geometry shader
3665 		{
3666 			const deUint32		s	= m_parameters.streamId;
3667 			std::ostringstream	src;
3668 
3669 			DE_ASSERT(s != 0);
3670 
3671 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3672 				<< "\n"
3673 				<< "layout(points) in;\n"
3674 				<< "\n"
3675 				<< "layout(points, max_vertices = 2) out;\n"
3676                 << "\n"
3677                 << "layout(location=0) in uint id[1];"
3678 				<< "layout(stream = " << 0 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0, component = 0) out uint out0;\n"
3679 				<< "layout(stream = " << s << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 4, location = 0, component = 1) out uint out1;\n"
3680 				<< "\n"
3681 				<< "void main(void)\n"
3682 				<< "{\n"
3683 				<< "	out0 = id[0] * 2 + 0;\n"
3684 				<< "	EmitStreamVertex(0);\n"
3685 				<< "	EndStreamPrimitive(0);\n"
3686 				<< "\n"
3687 				<< "	out1 = id[0] * 2 + 1;\n"
3688 				<< "	EmitStreamVertex(" << s << ");\n"
3689 				<< "	EndStreamPrimitive(" << s << ");\n"
3690 				<< "}\n";
3691 
3692 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
3693 		}
3694 
3695 		return;
3696 	}
3697 
3698 	if (requiresFullPipeline)
3699 	{
3700 		// vertex shader
3701 		{
3702 			std::ostringstream src;
3703 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3704 				<< "\n"
3705 				<< "void main(void)\n"
3706 				<< "{\n"
3707 				<< "}\n";
3708 
3709 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3710 		}
3711 
3712 		// geometry shader
3713 		{
3714 			const deUint32		s					= m_parameters.streamId;
3715 			const bool			requirePoints		= m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE;
3716 			const std::string	outputPrimitiveType	= requirePoints ? "points" : "triangle_strip";
3717 			const std::string	outputBuiltIn		= (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)    ? "    float gl_PointSize;\n"
3718 													: (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE) ? "    float gl_ClipDistance[];\n"
3719 													: (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE) ? "    float gl_CullDistance[];\n"
3720 													: "";
3721 			std::ostringstream	src;
3722 
3723 			DE_ASSERT(s != 0);
3724 
3725 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3726 				<< "\n"
3727 				<< "layout(points) in;\n"
3728 				<< "layout(" << outputPrimitiveType << ", max_vertices = 16) out;\n"
3729 				<< "layout(stream = " << s << ") out;\n"
3730 				<< "layout(location = 0) out vec4 color;\n"
3731 				<< "\n"
3732 				<< "layout(stream = " << s << ") out gl_PerVertex\n"
3733 				<< "{\n"
3734 				<< "    vec4 gl_Position;\n"
3735 				<< outputBuiltIn
3736 				<< "};\n"
3737 				<< "\n"
3738 				<< "void main(void)\n"
3739 				<< "{\n"
3740 				<< "    // Color constants\n"
3741 				<< "    vec4 g = vec4(0.0, 1.0, 0.0, 1.0);\n"
3742 				<< "    vec4 m = vec4(1.0, 0.0, 1.0, 1.0);\n"
3743 				<< "    // Coordinate constants: leftmost column\n"
3744 				<< "    vec4 a = vec4(-1.0,-1.0, 0.0, 1.0);\n"
3745 				<< "    vec4 b = vec4(-1.0, 0.0, 0.0, 1.0);\n"
3746 				<< "    vec4 c = vec4(-1.0, 1.0, 0.0, 1.0);\n"
3747 				<< "    // Coordinate constants: middle column\n"
3748 				<< "    vec4 i = vec4( 0.0,-1.0, 0.0, 1.0);\n"
3749 				<< "    vec4 j = vec4( 0.0, 0.0, 0.0, 1.0);\n"
3750 				<< "    vec4 k = vec4( 0.0, 1.0, 0.0, 1.0);\n"
3751 				<< "    // Coordinate constants: rightmost column\n"
3752 				<< "    vec4 x = vec4( 1.0,-1.0, 0.0, 1.0);\n"
3753 				<< "    vec4 y = vec4( 1.0, 0.0, 0.0, 1.0);\n"
3754 				<< "    vec4 z = vec4( 1.0, 1.0, 0.0, 1.0);\n"
3755 				<< "\n";
3756 
3757 			if (m_parameters.testType == TEST_TYPE_STREAMS)
3758 			{
3759 				src << "    if (gl_PrimitiveIDIn == 0)\n"
3760 					<< "    {\n"
3761 					<< "        color = m; gl_Position = b; EmitStreamVertex(" << s << ");\n"
3762 					<< "        color = m; gl_Position = y; EmitStreamVertex(" << s << ");\n"
3763 					<< "        color = m; gl_Position = c; EmitStreamVertex(" << s << ");\n"
3764 					<< "        EndStreamPrimitive(" << s << ");\n"
3765 					<< "    }\n"
3766 					<< "    else\n"
3767 					<< "    {\n"
3768 					<< "        color = m; gl_Position = y; EmitStreamVertex(" << s << ");\n"
3769 					<< "        color = m; gl_Position = c; EmitStreamVertex(" << s << ");\n"
3770 					<< "        color = m; gl_Position = z; EmitStreamVertex(" << s << ");\n"
3771 					<< "        EndStreamPrimitive(" << s << ");\n"
3772 					<< "    }\n";
3773 			}
3774 
3775 			if (m_parameters.testType == TEST_TYPE_STREAMS_POINTSIZE)
3776 			{
3777 				const std::string	pointSize	= "gl_PointSize = " + de::toString(m_parameters.pointSize) + ".0f";
3778 
3779 				src << "    if (gl_PrimitiveIDIn == 0)\n"
3780 					<< "    {\n"
3781 					<< "        color = g; gl_Position = (a + j) / 2.0f; gl_PointSize = 1.0f; EmitStreamVertex(0);\n"
3782 					<< "        EndStreamPrimitive(0);\n"
3783 					<< "        color = m; gl_Position = (b + k) / 2.0f; gl_PointSize = 1.0f; EmitStreamVertex(" << s << ");\n"
3784 					<< "        EndStreamPrimitive(" << s << ");\n"
3785 					<< "    }\n"
3786 					<< "    else\n"
3787 					<< "    {\n"
3788 					<< "        color = g; gl_Position = (j + x) / 2.0f; " << pointSize << "; EmitStreamVertex(0);\n"
3789 					<< "        EndStreamPrimitive(0);\n"
3790 					<< "        color = m; gl_Position = (k + y) / 2.0f; " << pointSize << "; EmitStreamVertex(" << s << ");\n"
3791 					<< "        EndStreamPrimitive(" << s << ");\n"
3792 					<< "    }\n";
3793 			}
3794 
3795 			if (m_parameters.testType == TEST_TYPE_STREAMS_CLIPDISTANCE)
3796 			{
3797 				src << "    if (gl_PrimitiveIDIn == 0)\n"
3798 					<< "    {\n"
3799 					<< "        color = m; gl_Position = b; gl_ClipDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3800 					<< "        color = m; gl_Position = c; gl_ClipDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3801 					<< "        color = m; gl_Position = y; gl_ClipDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3802 					<< "        EndStreamPrimitive(" << s << ");\n"
3803 					<< "    }\n"
3804 					<< "    else\n"
3805 					<< "    {\n"
3806 					<< "        color = m; gl_Position = y; gl_ClipDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3807 					<< "        color = m; gl_Position = c; gl_ClipDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3808 					<< "        color = m; gl_Position = z; gl_ClipDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3809 					<< "        EndStreamPrimitive(" << s << ");\n"
3810 					<< "    }\n";
3811 			}
3812 
3813 			if (m_parameters.testType == TEST_TYPE_STREAMS_CULLDISTANCE)
3814 			{
3815 				src << "    if (gl_PrimitiveIDIn == 0)\n"
3816 					<< "    {\n"
3817 					<< "        color = m; gl_Position = b; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3818 					<< "        color = m; gl_Position = c; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3819 					<< "        color = m; gl_Position = j; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3820 					<< "        EndStreamPrimitive(" << s << ");\n"
3821 					<< "        color = m; gl_Position = j; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3822 					<< "        color = m; gl_Position = c; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3823 					<< "        color = m; gl_Position = k; gl_CullDistance[0] = -1.0; EmitStreamVertex(" << s << ");\n"
3824 					<< "        EndStreamPrimitive(" << s << ");\n"
3825 					<< "    }\n"
3826 					<< "    else\n"
3827 					<< "    {\n"
3828 					<< "        color = m; gl_Position = j; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3829 					<< "        color = m; gl_Position = k; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3830 					<< "        color = m; gl_Position = y; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3831 					<< "        EndStreamPrimitive(" << s << ");\n"
3832 					<< "        color = m; gl_Position = y; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3833 					<< "        color = m; gl_Position = k; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3834 					<< "        color = m; gl_Position = z; gl_CullDistance[0] =  1.0; EmitStreamVertex(" << s << ");\n"
3835 					<< "        EndStreamPrimitive(" << s << ");\n"
3836 					<< "    }\n";
3837 			}
3838 
3839 			src << "}\n";
3840 
3841 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
3842 		}
3843 
3844 		// Fragment shader
3845 		{
3846 			std::ostringstream src;
3847 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3848 				<< "\n"
3849 				<< "layout(location = 0) in  vec4 i_color;\n"
3850 				<< "layout(location = 0) out vec4 o_color;\n"
3851 				<< "\n"
3852 				<< "void main(void)\n"
3853 				<< "{\n"
3854 				<< "    o_color = i_color;\n"
3855 				<< "}\n";
3856 
3857 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
3858 		}
3859 
3860 		return;
3861 	}
3862 
3863 	if (m_parameters.testType == TEST_TYPE_DRAW_INDIRECT || m_parameters.testType == TEST_TYPE_DRAW_INDIRECT_MULTIVIEW)
3864 	{
3865 		// vertex shader
3866 		{
3867 			std::ostringstream src;
3868 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3869 				<< "\n"
3870 				<< "layout(location = 0) in vec4 in_position;\n"
3871 				<< "\n"
3872 				<< "void main(void)\n"
3873 				<< "{\n"
3874 				<< "    gl_Position = in_position;\n"
3875 				<< "}\n";
3876 
3877 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3878 		}
3879 
3880 		// Fragment shader
3881 		{
3882 			std::ostringstream src;
3883 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3884 				<< "\n"
3885 				<< "layout(location = 0) out vec4 o_color;\n"
3886 				<< "\n"
3887 				<< "void main(void)\n"
3888 				<< "{\n"
3889 				<< "    o_color = vec4(1.0, 1.0, 1.0, 1.0);\n"
3890 				<< "}\n";
3891 
3892 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
3893 		}
3894 
3895 		return;
3896 	}
3897 
3898 	if (m_parameters.testType == TEST_TYPE_QUERY_GET				||
3899 		m_parameters.testType == TEST_TYPE_QUERY_COPY				||
3900 		m_parameters.testType == TEST_TYPE_QUERY_COPY_STRIDE_ZERO	||
3901 		m_parameters.testType == TEST_TYPE_QUERY_RESET)
3902 	{
3903 		struct TopologyShaderInfo
3904 		{
3905 			std::string glslIn;
3906 			std::string glslOut;
3907 			std::string spirvIn;
3908 			std::string spirvOut;
3909 		};
3910 
3911 		const std::map<VkPrimitiveTopology, TopologyShaderInfo>	primitiveNames	=
3912 		{
3913 			{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST						, { "points"				, "points"			, "InputPoints"				, "OutputPoints"		} },
3914 			{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST						, { "lines"					, "line_strip"		, "InputLines"				, "OutputLineStrip"		} },
3915 			{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP						, { "lines"					, "line_strip"		, "InputLines"				, "OutputLineStrip"		} },
3916 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST					, { "triangles"				, "triangle_strip"	, "Triangles"				, "OutputTriangleStrip"	} },
3917 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP					, { "triangles"				, "triangle_strip"	, "Triangles"				, "OutputTriangleStrip"	} },
3918 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN					, { "triangles"				, "triangle_strip"	, "Triangles"				, "OutputTriangleStrip"	} },
3919 			{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY		, { "lines_adjacency"		, "line_strip"		, "InputLinesAdjacency"		, "OutputLineStrip"		} },
3920 			{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY		, { "lines_adjacency"		, "line_strip"		, "InputLinesAdjacency"		, "OutputLineStrip"		} },
3921 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY	, { "triangles_adjacency"	, "triangle_strip"	, "InputTrianglesAdjacency"	, "OutputTriangleStrip"	} },
3922 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY	, { "triangles_adjacency"	, "triangle_strip"	, "InputTrianglesAdjacency"	, "OutputTriangleStrip"	} }
3923 		};
3924 
3925 		// Vertex shader
3926 		{
3927 			std::ostringstream src;
3928 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3929 				<< "\n"
3930 				<< "layout(location = 0) out vec4 out0;\n"
3931 				<< "\n"
3932 				<< "void main(void)\n"
3933 				<< "{\n"
3934 				<< "    float n = 4.0 * float(gl_VertexIndex);\n"
3935 				<< "    out0 = vec4(n + 0.0, n + 1.0, n + 2.0, n + 3.0);\n"
3936 				<< "}\n";
3937 
3938 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
3939 		}
3940 
3941 		// geometry shader
3942 		if (m_parameters.streamId == 0)
3943 		{
3944 			std::ostringstream	src;
3945 
3946 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
3947 				<< "\n"
3948 				<< "layout(" << primitiveNames.at(m_parameters.primTopology).glslIn << ") in;\n"
3949 				<< "layout(location = 0) in vec4 in0[];\n"
3950 				<< "\n"
3951 				<< "layout(" << primitiveNames.at(m_parameters.primTopology).glslOut << ", max_vertices = " << topologyData.at(m_parameters.primTopology).primSize<< ") out;\n"
3952 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
3953 				<< "\n"
3954 				<< "void main(void)\n"
3955 				<< "{\n";
3956 
3957 			for (deUint32 i = 0; i < topologyData.at(m_parameters.primTopology).primSize; i++)
3958 			{
3959 				if (!m_parameters.omitShaderWrite)
3960 					src << "    out0 = in0[" << i << "];\n";
3961 				src << "    EmitVertex();\n";
3962 			}
3963 
3964 			src << "    EndPrimitive();\n"
3965 				<< "}\n";
3966 
3967 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
3968 		}
3969 		else
3970 		{
3971 			const deUint32		s	= m_parameters.streamId;
3972 			std::ostringstream	src;
3973 
3974 			if (m_parameters.testType == TEST_TYPE_QUERY_GET)
3975 			{
3976 				// The SPIR-V program below is roughly equivalent to the following GLSL code:
3977 				//
3978 				// #version 450
3979 				// #extension GL_ARB_enhanced_layouts : require
3980 				//
3981 				// layout(points) in;
3982 				// layout(location = 0) in vec4 in0[];
3983 				//
3984 				// layout(points, max_vertices = 1) out;
3985 				// layout(location=0, stream=1, xfb_buffer=0, xfb_stride=16) out OutBlock {
3986 				//     layout(xfb_offset=0, location=0) vec4 out0;
3987 				// } outBlock;
3988 				//
3989 				// void main(void)
3990 				// {
3991 				//     outBlock.out0 = in0[0];
3992 				//     EmitStreamVertex(1);
3993 				//     EndStreamPrimitive(1);
3994 				// }
3995 				//
3996 				// However, the stream number has been parametrized and the code generated by glslang has been tuned to move the
3997 				// Stream, XfbBuffer and XfbStride decorations to the structure member instead of the block. This allows us to test
3998 				// transform feedback decorations on structure members as part of these basic tests.
3999 				src	<< "; SPIR-V\n"
4000 					<< "; Version: 1.0\n"
4001 					<< "; Generator: Khronos Glslang Reference Front End; 10\n"
4002 					<< "; Bound: 64\n"
4003 					<< "; Schema: 0\n"
4004 					<< "               OpCapability Geometry\n"
4005 					<< "               OpCapability TransformFeedback\n"
4006 					<< "               OpCapability GeometryStreams\n"
4007 					<< "          %1 = OpExtInstImport \"GLSL.std.450\"\n"
4008 					<< "               OpMemoryModel Logical GLSL450\n"
4009 					<< "               OpEntryPoint Geometry %main \"main\" %outBlock %in0\n"
4010 					<< "               OpExecutionMode %main Xfb\n"
4011 					<< "               OpExecutionMode %main " << primitiveNames.at(m_parameters.primTopology).spirvIn << "\n"
4012 					<< "               OpExecutionMode %main Invocations 1\n"
4013 					<< "               OpExecutionMode %main  " << primitiveNames.at(m_parameters.primTopology).spirvOut << "\n"
4014 					<< "               OpExecutionMode %main OutputVertices " << topologyData.at(m_parameters.primTopology).primSize << "\n"
4015 					<< "               OpSource GLSL 450\n"
4016 					<< "               OpSourceExtension \"GL_ARB_enhanced_layouts\"\n"
4017 					<< "               OpName %main \"main\"\n"
4018 					<< "               OpName %OutBlock \"OutBlock\"\n"
4019 					<< "               OpMemberName %OutBlock 0 \"out0\"\n"
4020 					<< "               OpName %outBlock \"outBlock\"\n"
4021 					<< "               OpName %in0 \"in0\"\n"
4022 					<< "               OpMemberDecorate %OutBlock 0 Location 0\n"
4023 					<< "               OpMemberDecorate %OutBlock 0 Offset 0\n"
4024 					// These Stream, XfbBuffer and XfbStride decorations have been moved to the struct member.
4025 					<< "               OpMemberDecorate %OutBlock 0 Stream " << s << "\n"
4026 					<< "               OpMemberDecorate %OutBlock 0 XfbBuffer 0\n"
4027 					<< "               OpMemberDecorate %OutBlock 0 XfbStride 16\n"
4028 					<< "               OpDecorate %OutBlock Block\n"
4029 					// The decorations mentioned above were using OpDecorate and assigned to %outBlock itself here.
4030 					<< "               OpDecorate %in0 Location 0\n"
4031 					<< "       %void = OpTypeVoid\n"
4032 					<< "          %3 = OpTypeFunction %void\n"
4033 					<< "      %float = OpTypeFloat 32\n"
4034 					<< "    %v4float = OpTypeVector %float 4\n"
4035 					<< "   %OutBlock = OpTypeStruct %v4float\n"
4036 					<< "%_ptr_Output_OutBlock = OpTypePointer Output %OutBlock\n"
4037 					<< "   %outBlock = OpVariable %_ptr_Output_OutBlock Output\n"
4038 					<< "        %int = OpTypeInt 32 1\n"
4039 					<< "      %int_0 = OpConstant %int 0\n";
4040 
4041 				for (deUint32 i = 1; i < topologyData.at(m_parameters.primTopology).primSize + 1; i++)
4042 				{
4043 					src << "%int_" << i << " = OpConstant %int " << i << "\n";
4044 				}
4045 
4046 				src << "       %uint = OpTypeInt 32 0\n"
4047 					<< "     %uint_0 = OpConstant %uint " << topologyData.at(m_parameters.primTopology).primSize << "\n"
4048 					<< "%_arr_v4float_uint_0 = OpTypeArray %v4float %uint_0\n"
4049 					<< "%_ptr_Input__arr_v4float_uint_0 = OpTypePointer Input %_arr_v4float_uint_0\n"
4050 					<< "        %in0 = OpVariable %_ptr_Input__arr_v4float_uint_0 Input\n"
4051 					<< "%_ptr_Input_v4float = OpTypePointer Input %v4float\n"
4052 					<< "%_ptr_Output_v4float = OpTypePointer Output %v4float\n"
4053 					<< "  %streamNum = OpConstant %int " << s << "\n"
4054 					<< "       %main = OpFunction %void None %3\n"
4055 					<< "          %5 = OpLabel\n";
4056 
4057 				for (deUint32 i = 1; i < topologyData.at(m_parameters.primTopology).primSize + 1; i++)
4058 				{
4059 					src << "%" << i << "1 = OpAccessChain %_ptr_Input_v4float %in0 %int_" << i << "\n"
4060 						<< "          %" << i << "2 = OpLoad %v4float %" << i << "1\n"
4061 						<< "          %" << i << "3 = OpAccessChain %_ptr_Output_v4float %outBlock %int_0\n"
4062 						<< "               OpStore %" << i << "3 %" << i << "2\n"
4063 						<< "               OpEmitStreamVertex %streamNum\n";
4064 				}
4065 
4066 				src << "               OpEndStreamPrimitive %streamNum\n"
4067 					<< "               OpReturn\n"
4068 					<< "               OpFunctionEnd\n"
4069 					;
4070 
4071 				programCollection.spirvAsmSources.add("geom") << src.str();
4072 			}
4073 			else
4074 			{
4075 				src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4076 					<< "\n"
4077 					<< "layout(" << primitiveNames.at(m_parameters.primTopology).glslIn << ") in;\n"
4078 					<< "layout(location = 0) in vec4 in0[];\n"
4079 					<< "\n"
4080 					<< "layout(" << primitiveNames.at(m_parameters.primTopology).glslOut << ", max_vertices = " << topologyData.at(m_parameters.primTopology).primSize << ") out;\n"
4081 					<< "layout(stream = " << s << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
4082 					<< "\n"
4083 					<< "void main(void)\n"
4084 					<< "{\n";
4085 
4086 				for (deUint32 i = 0; i < topologyData.at(m_parameters.primTopology).primSize; i++)
4087 				{
4088 					src << "    out0 = in0[" << i << "];\n"
4089 						<< "    EmitStreamVertex(" << s << ");\n";
4090 				}
4091 
4092 				src << "    EndStreamPrimitive(" << s << ");\n"
4093 					<< "}\n";
4094 
4095 				programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4096 			}
4097 		}
4098 
4099 		return;
4100 	}
4101 
4102 	if (m_parameters.testType == TEST_TYPE_MULTIQUERY)
4103 	{
4104 		// vertex shader
4105 		{
4106 			std::ostringstream src;
4107 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4108 				<< "\n"
4109 				<< "layout(location = 0) out ivec4 out0;\n"
4110 				<< "\n"
4111 				<< "void main(void)\n"
4112 				<< "{\n"
4113 				<< "    out0 = ivec4(gl_VertexIndex);\n"
4114 				<< "}\n";
4115 
4116 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4117 		}
4118 
4119 		// geometry shader
4120 		{
4121 			const deUint32		s	= m_parameters.streamId;
4122 			std::ostringstream	src;
4123 
4124 			DE_ASSERT(s != 0);
4125 
4126 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4127 				<< "\n"
4128 				<< "layout(points) in;\n"
4129 				<< "\n"
4130 				<< "layout(points, max_vertices = 4) out;\n"
4131 				<< "\n"
4132 				<< "layout(stream = " << 0 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
4133 				<< "layout(stream = " << s << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
4134 				<< "\n"
4135 				<< "void main(void)\n"
4136 				<< "{\n"
4137 				<< "    const int   n0 = 3;\n"
4138 				<< "    const int   n1 = 1;\n"
4139 				<< "    const float c0 = 0.5f;\n"
4140 				<< "    const float c1 = 0.5f + float(" << s << ");\n"
4141 				<< "\n"
4142 				<< "    for (int j = 0; j < n0; j++)\n"
4143 				<< "    {\n";
4144 
4145 			if (!m_parameters.omitShaderWrite)
4146 				src << "        out0 = vec4(c0);\n";
4147 
4148 			src	<< "        EmitStreamVertex(0);\n"
4149 				<< "        EndStreamPrimitive(0);\n"
4150 				<< "    }\n"
4151 				<< "\n"
4152 				<< "    for (int j = 0; j < n1; j++)\n"
4153 				<< "    {\n"
4154 				<< "        out1 = vec4(c1);\n"
4155 				<< "        EmitStreamVertex(" << s << ");\n"
4156 				<< "        EndStreamPrimitive(" << s << ");\n"
4157 				<< "    }\n"
4158 				<< "}\n";
4159 
4160 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4161 		}
4162 
4163 		return;
4164 	}
4165 
4166 	if (m_parameters.testType == TEST_TYPE_LINES_TRIANGLES)
4167 	{
4168 		// vertex shader
4169 		{
4170 			std::ostringstream src;
4171 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4172 				<< "\n"
4173 				<< "void main(void)\n"
4174 				<< "{\n"
4175 				<< "}\n";
4176 
4177 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4178 		}
4179 
4180 		// geometry shader
4181 		{
4182 			const deUint32		s			= m_parameters.streamId;
4183 			const bool			line		= isPrimitiveTopologyLine(m_parameters.primTopology);
4184 			const bool			tri			= isPrimitiveTopologyTriangle(m_parameters.primTopology);
4185 			const std::string	p			= line ? std::string("line_strip")
4186 											: tri ? std::string("triangle_strip")
4187 											: std::string("");
4188 			const std::string	vertexCount	= line ? vectorToString(LINES_LIST)
4189 											: tri ? vectorToString(TRIANGLES_LIST)
4190 											: std::string("");
4191 			std::ostringstream	src;
4192 
4193 			DE_ASSERT(s != 0);
4194 
4195 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4196 				<< "\n"
4197 				<< "layout(points) in;\n"
4198 				<< "\n"
4199 				<< "layout(" << p << ", max_vertices = 256) out;\n"
4200 				<< "layout(stream = " << 0 << ", xfb_buffer = 0, xfb_offset = 0, xfb_stride = 16, location = 0) out vec4 out0;\n"
4201 				<< "layout(stream = " << s << ", xfb_buffer = 1, xfb_offset = 0, xfb_stride = 16, location = 1) out vec4 out1;\n"
4202 				<< "\n"
4203 				<< "const int vertices_in_primitive[] = int[](" << vertexCount  << ");\n"
4204 				<< "\n"
4205 				<< "int num_vertices_in_primitives()\n"
4206 				<< "{\n"
4207 				<< "    int c = 0;\n"
4208 				<< "\n"
4209 				<< "    for (int i = 0; i < vertices_in_primitive.length(); i++)\n"
4210 				<< "        c = c + vertices_in_primitive[i];\n"
4211 				<< "\n"
4212 				<< "    return c;\n"
4213 				<< "}\n"
4214 				<< "\n"
4215 				<< "void main(void)\n"
4216 				<< "{\n"
4217 				<< "    int vc = num_vertices_in_primitives();\n"
4218 				<< "    int c0 = vc * gl_PrimitiveIDIn;\n"
4219 				<< "    int c1 = vc * (" << INVOCATION_COUNT << " + gl_PrimitiveIDIn);\n"
4220 				<< "\n"
4221 				<< "    for (int i = 0; i < vertices_in_primitive.length(); i++)\n"
4222 				<< "    {\n"
4223 				<< "        const int n = vertices_in_primitive[i];\n"
4224 				<< "\n"
4225 				<< "        for (int j = 0; j < n; j++)\n"
4226 				<< "        {\n"
4227 				<< "            out0 = vec4(ivec4(c0, gl_PrimitiveIDIn, i, j));\n"
4228 				<< "            c0 = c0 + 1;\n"
4229 				<< "            EmitStreamVertex(0);\n"
4230 				<< "\n"
4231 				<< "            out1 = vec4(ivec4(c1, gl_PrimitiveIDIn, i, j));\n"
4232 				<< "            c1 = c1 + 1;\n"
4233 				<< "            EmitStreamVertex(" << s << ");\n"
4234 				<< "        }\n"
4235 				<< "\n"
4236 				<< "        EndStreamPrimitive(0);\n"
4237 				<< "        EndStreamPrimitive(" << s << ");\n"
4238 				<< "    }\n"
4239 				<< "}\n";
4240 
4241 			programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
4242 		}
4243 
4244 		return;
4245 	}
4246 
4247 	if (m_parameters.testType == TEST_TYPE_DRAW_OUTSIDE)
4248 	{
4249 		// Vertex shader
4250 		{
4251 			std::ostringstream src;
4252 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4253 				<< "\n"
4254 				<< "layout(push_constant) uniform pushConstants\n"
4255 				<< "{\n"
4256 				<< "    uint start;\n"
4257 				<< "} uInput;\n"
4258 				<< "\n"
4259 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
4260 				<< "\n"
4261 				<< "void main(void)\n"
4262 				<< "{\n"
4263 				<< "    idx_out = uInput.start + gl_VertexIndex;\n"
4264 				<< "    gl_PointSize = 1.0f;\n"
4265 				<< "}\n";
4266 
4267 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
4268 		}
4269 
4270 		{
4271 			std::ostringstream src;
4272 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
4273 				<< "\n"
4274 				<< "layout(push_constant) uniform pushConstants\n"
4275 				<< "{\n"
4276 				<< "    uint start;\n"
4277 				<< "} uInput;\n"
4278 				<< "\n"
4279 				<< "layout(xfb_buffer = 0, xfb_offset = 0, xfb_stride = 4, location = 0) out uint idx_out;\n"
4280 				<< "\n"
4281 				<< "void main(void)\n"
4282 				<< "{\n"
4283 				<< "    idx_out = uInput.start + gl_VertexIndex * 2u;\n"
4284 				<< "    gl_PointSize = 1.0f;\n"
4285 				<< "}\n";
4286 
4287 			programCollection.glslSources.add("vert2") << glu::VertexSource(src.str());
4288 		}
4289 
4290 		return;
4291 	}
4292 
4293 	if (m_parameters.testType == TEST_TYPE_HOLES_VERTEX || m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
4294 	{
4295 		// The fragment shader is the same in both variants.
4296 		{
4297 			std::ostringstream frag;
4298 			frag
4299 				<< "#version 460\n"
4300 				<< "layout (location=0) out vec4 outColor;\n"
4301 				<< "\n"
4302 				<< "layout (location = 0) in float goku;\n"
4303 				<< "layout (location = 0, component = 1) in float trunks;\n"
4304 				<< "layout (location = 0, component = 2) in float vegeta;\n"
4305 				<< "\n"
4306 				<< "void main ()\n"
4307 				<< "{\n"
4308 				<< "    outColor = ((goku == 10.0 && trunks == 20.0 && vegeta == 30.0)\n"
4309 				<< "             ? vec4(0.0, 0.0, 1.0, 1.0)\n"
4310 				<< "             : vec4(0.0, 0.0, 0.0, 1.0));\n"
4311 				<< "}\n"
4312 				;
4313 			programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
4314 		}
4315 
4316 		const std::string pcDecl =
4317 			"layout (push_constant, std430) uniform PushConstantBlock {\n"
4318 			"    vec3 values;\n"
4319 			"} pc;\n"
4320 			;
4321 
4322 		const std::string dbChars =
4323 			"layout (location = 0, xfb_buffer = 0, xfb_stride = 12, xfb_offset = 0) flat out float goku;\n"
4324 			"layout (location = 0, component = 1) flat out float trunks;\n"
4325 			"layout (location = 0, xfb_buffer = 0, xfb_stride = 12, xfb_offset = 8, component = 2) flat out float vegeta;\n"
4326 			;
4327 
4328 		const std::string assignments =
4329 			"    goku   = pc.values.x;\n"
4330 			"    trunks = pc.values.y;\n"
4331 			"    vegeta = pc.values.z;\n"
4332 			;
4333 
4334 		if (m_parameters.testType == TEST_TYPE_HOLES_GEOMETRY)
4335 		{
4336 			std::ostringstream geom;
4337 			geom
4338 				<< "#version 460\n"
4339 				<< "layout (points) in;\n"
4340 				<< "layout (max_vertices=1, points) out;\n"
4341 				<< "\n"
4342 				<< dbChars
4343 				<< "\n"
4344 				<< pcDecl
4345 				<< "\n"
4346 				<< "void main ()\n"
4347 				<< "{\n"
4348 				<< "    gl_Position  = gl_in[0].gl_Position;\n"
4349 				<< "    gl_PointSize = gl_in[0].gl_PointSize;\n"
4350 				<< "\n"
4351 				<< assignments
4352 				<< "\n"
4353 				<< "    EmitVertex();\n"
4354 				<< "}\n"
4355 				;
4356 			programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
4357 		}
4358 
4359 		const bool vertOnly = (m_parameters.testType == TEST_TYPE_HOLES_VERTEX);
4360 		std::ostringstream vert;
4361 		vert
4362 			<< "#version 460\n"
4363 			<< "layout (location = 0) in vec4 inPos;\n"
4364 			<< "\n"
4365 			<< (vertOnly ? dbChars : "")
4366 			<< "\n"
4367 			<< (vertOnly ? pcDecl : "")
4368 			<< "\n"
4369 			<< "void main ()\n"
4370 			<< "{\n"
4371 			<< "    gl_Position  = inPos;\n"
4372 			<< "    gl_PointSize = 1.0;\n"
4373 			<< "\n"
4374 			<< (vertOnly ? assignments : "")
4375 			<< "}\n"
4376 			;
4377 		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
4378 
4379 		return;
4380 	}
4381 
4382 	DE_ASSERT(0 && "Unknown test");
4383 }
4384 
createTransformFeedbackSimpleTests(tcu::TestCaseGroup* group)4385 void createTransformFeedbackSimpleTests(tcu::TestCaseGroup* group)
4386 {
4387 	{
4388 		const deUint32		bufferCounts[]	= { 1u, 2u, 4u, 8u };
4389 		const deUint32		bufferSizes[]	= { 256u, 512u, 128u * 1024u };
4390 		const TestType		testTypes[]		= { TEST_TYPE_BASIC, TEST_TYPE_RESUME, TEST_TYPE_XFB_POINTSIZE, TEST_TYPE_XFB_CLIPDISTANCE, TEST_TYPE_XFB_CULLDISTANCE, TEST_TYPE_XFB_CLIP_AND_CULL, TEST_TYPE_DRAW_OUTSIDE };
4391 		const std::string	testTypeNames[]	= { "basic", "resume", "xfb_pointsize", "xfb_clipdistance", "xfb_culldistance", "xfb_clip_and_cull", "draw_outside" };
4392 
4393 		for (deUint32 testTypesNdx = 0; testTypesNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypesNdx)
4394 		{
4395 			const TestType		testType	= testTypes[testTypesNdx];
4396 			const std::string	testName	= testTypeNames[testTypesNdx];
4397 
4398 			for (deUint32 bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(bufferCounts); ++bufferCountsNdx)
4399 			{
4400 				const deUint32	partCount	= bufferCounts[bufferCountsNdx];
4401 
4402 				for (deUint32 bufferSizesNdx = 0; bufferSizesNdx < DE_LENGTH_OF_ARRAY(bufferSizes); ++bufferSizesNdx)
4403 				{
4404 					const deUint32	bufferSize	= bufferSizes[bufferSizesNdx];
4405 					TestParameters	parameters	= { testType, bufferSize, partCount, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, true, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4406 
4407 					// Simple Transform Feedback test
4408 					group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(partCount) + "_" + de::toString(bufferSize)).c_str(), parameters));
4409 					parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
4410 					group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_beginqueryindexed_streamid_0_" + de::toString(partCount) + "_" + de::toString(bufferSize)).c_str(), parameters));
4411 					parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
4412 					group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_endqueryindexed_streamid_0_" + de::toString(partCount) + "_" + de::toString(bufferSize)).c_str(), parameters));
4413 				}
4414 			}
4415 		}
4416 	}
4417 
4418 	{
4419 		const deUint32		bufferCounts[]	= { 6u, 8u, 10u, 12u };
4420 		const TestType		testType		= TEST_TYPE_WINDING;
4421 		const std::string	testName		= "winding";
4422 
4423 		for (const auto& topology : topologyData)
4424 		{
4425 			// Note: no need to test POINT_LIST as is tested in many tests.
4426 			if (topology.first == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
4427 				continue;
4428 
4429 			for (deUint32 bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(bufferCounts); ++bufferCountsNdx)
4430 			{
4431 				const deUint32	vertexCount	= bufferCounts[bufferCountsNdx];
4432 
4433 				TestParameters	parameters	= { testType, 0u, vertexCount, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, topology.first, false };
4434 
4435 				// Topology winding test
4436 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + topology.second.topologyName + de::toString(vertexCount)).c_str(), parameters));
4437 			}
4438 		}
4439 	}
4440 
4441 	{
4442 		for (int i = 0; i < 2; ++i)
4443 		{
4444 			const bool			multiview		= (i > 0);
4445 			const deUint32		vertexStrides[]	= { 4u, 61u, 127u, 251u, 509u };
4446 			const TestType		testType		= (multiview ? TEST_TYPE_DRAW_INDIRECT_MULTIVIEW : TEST_TYPE_DRAW_INDIRECT);
4447 			const std::string	testName		= std::string("draw_indirect") + (multiview ? "_multiview" : "");
4448 
4449 			for (deUint32 vertexStridesNdx = 0; vertexStridesNdx < DE_LENGTH_OF_ARRAY(vertexStrides); ++vertexStridesNdx)
4450 			{
4451 				const deUint32	vertexStrideBytes	= static_cast<deUint32>(sizeof(deUint32) * vertexStrides[vertexStridesNdx]);
4452 				TestParameters	parameters			= { testType, 0u, 0u, 0u, 0u, vertexStrideBytes, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4453 
4454 				// Rendering tests with various strides
4455 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(vertexStrideBytes)).c_str(), parameters));
4456 				parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
4457 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_beginqueryindexed_streamid_0_" + de::toString(vertexStrideBytes)).c_str(), parameters));
4458 				parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
4459 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_endqueryindexed_streamid_0_" + de::toString(vertexStrideBytes)).c_str(), parameters));
4460 			}
4461 		}
4462 	}
4463 
4464 	{
4465 		const struct
4466 		{
4467 			TestType		testType;
4468 			const char*		testName;
4469 		} testCases[] =
4470 		{
4471 			{ TEST_TYPE_BACKWARD_DEPENDENCY,			"backward_dependency"			},
4472 			{ TEST_TYPE_BACKWARD_DEPENDENCY_INDIRECT,	"backward_dependency_indirect"	},
4473 		};
4474 
4475 		for (const auto& testCase : testCases)
4476 		{
4477 			const auto&			testType	= testCase.testType;
4478 			const std::string	testName	= testCase.testName;
4479 			TestParameters		parameters	= { testType, 512u, 2u, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4480 
4481 			// Rendering test checks backward pipeline dependency
4482 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), testName.c_str(), parameters));
4483 			parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
4484 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_beginqueryindexed_streamid_0").c_str(), parameters));
4485 			parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
4486 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_endqueryindexed_streamid_0").c_str(), parameters));
4487 
4488 			// Rendering test checks backward pipeline dependency (using NULL for offset array)
4489 			parameters.noOffsetArray = true;
4490 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_no_offset_array").c_str(), parameters));
4491 		}
4492 	}
4493 
4494 	{
4495 		const deUint32		usedStreamId[]			= { 0u, 1u, 3u, 6u, 14u };
4496 		const deUint32		vertexCounts[]			= { 6u, 61u, 127u, 251u, 509u }; // Lowest value has to be at least 6. Otherwise the triangles with adjacency can't be generated.
4497 		const TestType		testType				= TEST_TYPE_QUERY_GET;
4498 		const std::string	testName				= "query";
4499 		const TestType		testTypeCopy[]			= { TEST_TYPE_QUERY_COPY, TEST_TYPE_QUERY_COPY_STRIDE_ZERO };
4500 		const std::string	testNameCopy[]			= { "query_copy", "query_copy_stride_zero" };
4501 		const TestType		testTypeHostQueryReset	= TEST_TYPE_QUERY_RESET;
4502 		const std::string	testNameHostQueryReset	= "host_query_reset";
4503 
4504 		for (const auto& topology : topologyData)
4505 		{
4506 			// Currently, we don't test tessellation here.
4507 			if (topology.first == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST)
4508 				continue;
4509 
4510 			for (const auto& streamCounts : usedStreamId)
4511 			{
4512 				const deUint32	streamId	= streamCounts;
4513 
4514 				for (const auto& numVertices : vertexCounts)
4515 				{
4516 					for (deUint32 i = 0; i < 2; ++i)
4517 					{
4518 						const bool				query64Bits		= (i == 1);
4519 						const std::string		widthStr		= (query64Bits ? "_64bits" : "_32bits");
4520 
4521 						deUint32				vertCount		= numVertices;
4522 
4523 						// The number of vertices in original test was 4.
4524 						if (topology.first == VK_PRIMITIVE_TOPOLOGY_POINT_LIST && vertCount == 6) vertCount -= 2;
4525 
4526 						// Round the number of vertices to match the used primitive topology - if necessary.
4527 						const deUint32			primitiveCount	= (deUint32)topology.second.getNumPrimitives(vertCount);
4528 						const deUint32			vertexCount		= (deUint32)topology.second.getNumVertices(primitiveCount);
4529 
4530 						DE_ASSERT(vertexCount > 0);
4531 
4532 						const deUint32			bytesPerVertex	= static_cast<deUint32>(4 * sizeof(float));
4533 						const deUint32			bufferSize		= bytesPerVertex * vertexCount;
4534 						TestParameters			parameters		= { testType, bufferSize, 0u, streamId, 0u, 0u, STREAM_ID_0_NORMAL, query64Bits, false, true, false, false, topology.first, false };
4535 						const std::string		fullTestName	= testName + "_" + topology.second.topologyName + de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr;
4536 
4537 						// Written primitives query test
4538 						group->addChild(new TransformFeedbackTestCase(group->getTestContext(), fullTestName.c_str(), parameters));
4539 
4540 						TestParameters			omitParameters	= { testType, bufferSize, 0u, streamId, 0u, 0u, STREAM_ID_0_NORMAL, query64Bits, false, true, true, false, topology.first, false };
4541 						const std::string		omitTestName	= testName + "_omit_write_" + topology.second.topologyName + de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr;
4542 						group->addChild(new TransformFeedbackTestCase(group->getTestContext(), omitTestName.c_str(), omitParameters));
4543 
4544 						for (deUint32 testTypeCopyNdx = 0; testTypeCopyNdx < DE_LENGTH_OF_ARRAY(testTypeCopy); testTypeCopyNdx++)
4545 						{
4546 							TestParameters	parametersCopy		= { testTypeCopy[testTypeCopyNdx], bufferSize, 0u, streamId, 0u, 0u, STREAM_ID_0_NORMAL, query64Bits, false, true, false, false, topology.first, false };
4547 							const std::string		fullTestNameCopy	= testNameCopy[testTypeCopyNdx] + "_" + topology.second.topologyName + de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr;
4548 							group->addChild(new TransformFeedbackTestCase(group->getTestContext(), fullTestNameCopy.c_str(), parametersCopy));
4549 
4550 							parametersCopy.queryResultWithAvailability = true;
4551 							const std::string		fullTestNameQueryWithAvailability = testNameCopy[testTypeCopyNdx] + "_" + topology.second.topologyName + de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr + "_query_with_availability";
4552 							group->addChild(new TransformFeedbackTestCase(group->getTestContext(), fullTestNameQueryWithAvailability.c_str(), parametersCopy));
4553 						}
4554 
4555 						const TestParameters	parametersHostQueryReset	= { testTypeHostQueryReset, bufferSize, 0u, streamId, 0u, 0u, STREAM_ID_0_NORMAL, query64Bits, false, true, false, false, topology.first, false };
4556 						const std::string		fullTestNameHostQueryReset	= testNameHostQueryReset + "_" + topology.second.topologyName + de::toString(streamId) + "_" + de::toString(vertexCount) + widthStr;
4557 						group->addChild(new TransformFeedbackTestCase(group->getTestContext(), fullTestNameHostQueryReset.c_str(), parametersHostQueryReset));
4558 
4559 						if (streamId == 0)
4560 						{
4561 							std::string	testNameStream0 = fullTestName;
4562 							testNameStream0 += "_beginqueryindexed_streamid_0";
4563 							parameters.streamId0Mode = STREAM_ID_0_BEGIN_QUERY_INDEXED;
4564 							group->addChild(new TransformFeedbackTestCase(group->getTestContext(), testNameStream0.c_str(), parameters));
4565 							testNameStream0 = fullTestName;
4566 							testNameStream0 += "_endqueryindexed_streamid_0";
4567 							parameters.streamId0Mode = STREAM_ID_0_END_QUERY_INDEXED;
4568 							group->addChild(new TransformFeedbackTestCase(group->getTestContext(), testNameStream0.c_str(), parameters));
4569 						}
4570 					}
4571 				}
4572 			}
4573 		}
4574 	}
4575 
4576 	// Depth clip control tests.
4577 	{
4578 		TestParameters	parameters	= { TEST_TYPE_DEPTH_CLIP_CONTROL_VERTEX, 96, 1u, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, true, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4579 
4580 		group->addChild(new TransformFeedbackTestCase(group->getTestContext(), "depth_clip_control_vertex", parameters));
4581 	}
4582 	{
4583 		TestParameters	parameters	= { TEST_TYPE_DEPTH_CLIP_CONTROL_GEOMETRY, 96, 1u, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, true, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4584 
4585 		group->addChild(new TransformFeedbackTestCase(group->getTestContext(), "depth_clip_control_geometry", parameters));
4586 	}
4587 	{
4588 		TestParameters	parameters	= { TEST_TYPE_DEPTH_CLIP_CONTROL_TESE, 96, 1u, 0u, 0u, 0u, STREAM_ID_0_NORMAL, false, false, true, false, false, VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, false };
4589 
4590 		group->addChild(new TransformFeedbackTestCase(group->getTestContext(), "depth_clip_control_tese", parameters));
4591 	}
4592 
4593 	{
4594 		const deUint32		usedStreamId[]	= { 1u, 3u, 6u, 14u };
4595 		const TestType		testType		= TEST_TYPE_LINES_TRIANGLES;
4596 		const std::string	testName		= "lines_or_triangles";
4597 
4598 		for (const auto& topology : topologyData)
4599 		{
4600 			const deUint32	outputVertexCount	= (topology.first == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP)     ? 2 * destripedLineCount(LINES_LIST)
4601 												: (topology.first == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) ? 3 * destripedTriangleCount(TRIANGLES_LIST)
4602 												: 0;
4603 
4604 			if (outputVertexCount == 0)
4605 				continue;
4606 
4607 			for (const auto& streamId : usedStreamId)
4608 			{
4609 				const deUint32			partCount		= 2u;
4610 				const deUint32			bytesPerVertex	= static_cast<deUint32>(sizeof(tcu::Vec4));
4611 				const deUint32			bufferSize		= partCount * INVOCATION_COUNT * outputVertexCount * bytesPerVertex;
4612 				const std::string		fullTestName	= testName + "_" + topology.second.topologyName + de::toString(streamId);
4613 				const TestParameters	parameters		=
4614 				{
4615 					testType,			//  TestType			testType;
4616 					bufferSize,			//  deUint32			bufferSize;
4617 					partCount,			//  deUint32			partCount;
4618 					streamId,			//  deUint32			streamId;
4619 					0u,					//  deUint32			pointSize;
4620 					0u,					//  deUint32			vertexStride;
4621 					STREAM_ID_0_NORMAL,	//  StreamId0Mode		streamId0Mode;
4622 					false,				//  bool				query64bits;
4623 					false,				//  bool				noOffsetArray;
4624 					true,				//  bool				requireRastStreamSelect;
4625 					false,				//  bool				omitShaderWrite;
4626 					false,				//  bool				useMaintenance5;
4627 					topology.first,		//  VkPrimitiveTopology	primTopology;
4628 					false				//  bool				queryResultWithAvailability;
4629 				};
4630 
4631 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), fullTestName.c_str(), parameters));
4632 			}
4633 		}
4634 	}
4635 
4636 #ifndef CTS_USES_VULKANSC
4637 	{
4638 		const TestParameters parameters
4639 		{
4640 			TEST_TYPE_RESUME,						//  TestType			testType;
4641 			96u,									//  deUint32			bufferSize;
4642 			2u,										//  deUint32			partCount;
4643 			1u,										//  deUint32			streamId;
4644 			0u,										//  deUint32			pointSize;
4645 			0u,										//  deUint32			vertexStride;
4646 			STREAM_ID_0_NORMAL,						//  StreamId0Mode		streamId0Mode;
4647 			false,									//  bool				query64bits;
4648 			false,									//  bool				noOffsetArray;
4649 			true,									//  bool				requireRastStreamSelect;
4650 			false,									//  bool				omitShaderWrite;
4651 			true,									//  bool				useMaintenance5;
4652 			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	//  VkPrimitiveTopology	primTopology;
4653 			false									//  bool				queryResultWithAvailability
4654 		};
4655 		group->addChild(new TransformFeedbackTestCase(group->getTestContext(), "maintenance5", parameters));
4656 	}
4657 #endif // CTS_USES_VULKANSC
4658 }
4659 
createTransformFeedbackStreamsSimpleTests(tcu::TestCaseGroup* group)4660 void createTransformFeedbackStreamsSimpleTests (tcu::TestCaseGroup* group)
4661 {
4662 	const deUint32		usedStreamId[]		= { 1u, 3u, 6u, 14u };
4663 	const TestType		testTypes[]			= { TEST_TYPE_STREAMS, TEST_TYPE_STREAMS_POINTSIZE, TEST_TYPE_STREAMS_CLIPDISTANCE, TEST_TYPE_STREAMS_CULLDISTANCE };
4664 	const std::string	testTypeNames[]		= { "streams", "streams_pointsize", "streams_clipdistance", "streams_culldistance" };
4665 
4666 	for (deUint32 testTypesNdx = 0; testTypesNdx < DE_LENGTH_OF_ARRAY(testTypes); ++testTypesNdx)
4667 	{
4668 		const TestType		testType	= testTypes[testTypesNdx];
4669 		const std::string	testName	= testTypeNames[testTypesNdx];
4670 		const deUint32		pointSize	= (testType == TEST_TYPE_STREAMS_POINTSIZE) ? 2u : 0u;
4671 
4672 		for (deUint32 streamCountsNdx = 0; streamCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++streamCountsNdx)
4673 		{
4674 			const deUint32	streamId	= usedStreamId[streamCountsNdx];
4675 			TestParameters	parameters	= { testType, 0u, 0u, streamId, pointSize, 0u, STREAM_ID_0_NORMAL, false, false, true, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4676 
4677 			// Streams usage test
4678 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(streamId)).c_str(), parameters));
4679 		}
4680 	}
4681 
4682 	{
4683 		const TestType		testType	= TEST_TYPE_MULTISTREAMS;
4684 		const std::string	testName	= "multistreams";
4685 
4686 		for (deUint32 bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++bufferCountsNdx)
4687 		{
4688 			const deUint32			streamId			= usedStreamId[bufferCountsNdx];
4689 			const deUint32			streamsUsed			= 2u;
4690 			const deUint32			maxBytesPerVertex	= 256u;
4691 			const TestParameters	parameters			= { testType, maxBytesPerVertex * streamsUsed, streamsUsed, streamId, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4692 
4693 			// Simultaneous multiple streams usage test
4694 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(streamId)).c_str(), parameters));
4695 		}
4696 	}
4697 
4698 	{
4699 		const TestType		testType	= TEST_TYPE_MULTISTREAMS_SAME_LOCATION;
4700 		const std::string	testName	= "multistreams_same_location";
4701 		for (const auto streamId : usedStreamId)
4702 		{
4703 			const deUint32			streamsUsed			= 2u;
4704 			const TestParameters	parameters			= { testType, 32 * 4, streamsUsed, streamId, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4705 
4706 			// Simultaneous multiple streams to the same location usage test
4707 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(streamId)).c_str(), parameters));
4708 		}
4709 	}
4710 
4711 	{
4712 		const TestType		testType	= TEST_TYPE_MULTIQUERY;
4713 		const std::string	testName	= "multiquery";
4714 
4715 		for (deUint32 bufferCountsNdx = 0; bufferCountsNdx < DE_LENGTH_OF_ARRAY(usedStreamId); ++bufferCountsNdx)
4716 		{
4717 			const deUint32			streamId			= usedStreamId[bufferCountsNdx];
4718 			const deUint32			streamsUsed			= 2u;
4719 			const deUint32			maxBytesPerVertex	= 256u;
4720 			const TestParameters	parameters			= { testType, maxBytesPerVertex * streamsUsed, streamsUsed, streamId, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4721 			const TestParameters	writeOmitParameters	= { testType, maxBytesPerVertex * streamsUsed, streamsUsed, streamId, 0u, 0u, STREAM_ID_0_NORMAL, false, false, false, true, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };
4722 
4723 			// Simultaneous multiple queries usage test
4724 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_" + de::toString(streamId)).c_str(), parameters));
4725 			group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + "_omit_write_" + de::toString(streamId)).c_str(), writeOmitParameters));
4726 		}
4727 	}
4728 
4729 	{
4730 		struct
4731 		{
4732 			TestType		testType;
4733 			const char*		suffix;
4734 		} holeCases[] =
4735 		{
4736 			{ TEST_TYPE_HOLES_VERTEX,	"_vert" },
4737 			{ TEST_TYPE_HOLES_GEOMETRY,	"_geom" },
4738 		};
4739 		const std::string testNameBase = "holes";
4740 
4741 		for (const auto& holeCase : holeCases)
4742 			for (const auto& extraDraw : { false, true})
4743 			{
4744 				const auto				partCount	= (extraDraw ? 2u : 1u);
4745 				const auto				testName	= testNameBase + (extraDraw ? "_extra_draw" : "");
4746 				const TestParameters	parameters	{ holeCase.testType, 0u, partCount, 0u, 1u, 0u, STREAM_ID_0_NORMAL, false, false, false, false, false, VK_PRIMITIVE_TOPOLOGY_POINT_LIST, false };;
4747 
4748 				// Test skipping components in the XFB buffer
4749 				group->addChild(new TransformFeedbackTestCase(group->getTestContext(), (testName + holeCase.suffix).c_str(), parameters));
4750 			}
4751 	}
4752 }
4753 
createTransformFeedbackAndStreamsSimpleTests(tcu::TestCaseGroup* group)4754 void createTransformFeedbackAndStreamsSimpleTests (tcu::TestCaseGroup* group)
4755 {
4756 	createTransformFeedbackSimpleTests(group);
4757 	createTransformFeedbackStreamsSimpleTests(group);
4758 }
4759 } // anonymous
4760 
createTransformFeedbackSimpleTests(tcu::TestContext& testCtx)4761 tcu::TestCaseGroup* createTransformFeedbackSimpleTests (tcu::TestContext& testCtx)
4762 {
4763 	return createTestGroup(testCtx, "simple", createTransformFeedbackAndStreamsSimpleTests);
4764 }
4765 
4766 } // TransformFeedback
4767 } // vkt
4768