• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2023 The Khronos Group Inc.
6 * Copyright (c) 2023 LunarG, Inc.
7 * Copyright (c) 2023 Google LLC
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 *
21 *//*
22  * \file
23  * \brief Extended dynamic state tests
24 *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineBindVertexBuffers2Tests.hpp"
27 #include "deUniquePtr.hpp"
28 #include "tcuTestCase.hpp"
29 #include "vktTestCase.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkRefUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkCmdUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vktPipelineClearUtil.hpp"
38 #include "vkBufferWithMemory.hpp"
39 #include "vkSafetyCriticalUtil.hpp"
40 #include "vktCustomInstancesDevices.hpp"
41 #include "vkDeviceUtil.hpp"
42 #include "tcuCommandLine.hpp"
43 #include "deRandom.hpp"
44 
45 namespace vkt
46 {
47 namespace pipeline
48 {
49 
50 struct TestParams
51 {
52 	deUint32	colorStride;
53 	deUint32	vertexStride;
54 	deUint32	colorOffset;
55 	deUint32	vertexOffset;
56 };
57 
makeImageCreateInfo(const vk::VkExtent2D extent,const vk::VkFormat format,const vk::VkImageUsageFlags usage)58 vk::VkImageCreateInfo makeImageCreateInfo (const vk::VkExtent2D extent, const vk::VkFormat format, const vk::VkImageUsageFlags usage)
59 {
60 	const vk::VkImageCreateInfo	imageParams	=
61 	{
62 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
63 		DE_NULL,											// const void*				pNext;
64 		(vk::VkImageCreateFlags)0u,							// VkImageCreateFlags		flags;
65 		vk::VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
66 		format,												// VkFormat					format;
67 		vk::makeExtent3D(extent.width, extent.height, 1),	// VkExtent3D				extent;
68 		1u,													// deUint32					mipLevels;
69 		1u,													// deUint32					arrayLayers;
70 		vk::VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
71 		vk::VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
72 		usage,												// VkImageUsageFlags		usage;
73 		vk::VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
74 		0u,													// deUint32					queueFamilyIndexCount;
75 		DE_NULL,											// const deUint32*			pQueueFamilyIndices;
76 		vk::VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
77 	};
78 	return imageParams;
79 }
80 
81 //make a buffer to read an image back after rendering
makeBufferForImage(const vk::DeviceInterface & vkd,const vk::VkDevice device,vk::Allocator & allocator,tcu::TextureFormat tcuFormat,vk::VkExtent2D imageExtent)82 std::unique_ptr<vk::BufferWithMemory> makeBufferForImage (const vk::DeviceInterface& vkd, const vk::VkDevice device, vk::Allocator& allocator, tcu::TextureFormat tcuFormat, vk::VkExtent2D imageExtent)
83 {
84 	const auto	outBufferSize		= static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * imageExtent.width * imageExtent.height);
85 	const auto	outBufferUsage		= vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT;
86 	const auto	outBufferInfo		= makeBufferCreateInfo(outBufferSize, outBufferUsage);
87 	auto outBuffer = std::unique_ptr<vk::BufferWithMemory>(new vk::BufferWithMemory(vkd, device, allocator, outBufferInfo, vk::MemoryRequirement::HostVisible));
88 
89 	return outBuffer;
90 }
91 
makeBindingDescription(uint32_t binding,uint32_t stride,vk::VkVertexInputRate inputRate)92 vk::VkVertexInputBindingDescription makeBindingDescription(uint32_t binding, uint32_t stride, vk::VkVertexInputRate inputRate)
93 {
94 	vk::VkVertexInputBindingDescription bindingDescription;
95 
96 	bindingDescription.binding = binding;
97 	bindingDescription.stride = stride;
98 	bindingDescription.inputRate = inputRate;
99 
100 	return bindingDescription;
101 }
102 
makeAttributeDescription(uint32_t location,uint32_t binding,vk::VkFormat format,uint32_t offset)103 vk::VkVertexInputAttributeDescription makeAttributeDescription (uint32_t location, uint32_t binding, vk::VkFormat format, uint32_t offset)
104 {
105 	vk::VkVertexInputAttributeDescription attributeDescription;
106 
107 	attributeDescription.location = location;
108 	attributeDescription.binding = binding;
109 	attributeDescription.format = format;
110 	attributeDescription.offset = offset;
111 
112 	return attributeDescription;
113 }
114 
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)115 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
116 {
117 	auto&	alloc	= buffer.getAllocation();
118 	auto	dst		= reinterpret_cast<char*>(alloc.getHostPtr());
119 
120 	deMemcpy(dst + offset, src, size);
121 	vk::flushAlloc(vkd, device, alloc);
122 }
123 
124 #ifndef CTS_USES_VULKANSC
125 typedef de::MovePtr<vk::DeviceDriver> DeviceDriverPtr;
126 #else
127 typedef de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> DeviceDriverPtr;
128 #endif // CTS_USES_VULKANSC
129 
130 typedef vk::Move<vk::VkDevice> DevicePtr;
131 
createRobustBufferAccessDevice(Context & context,const vk::VkPhysicalDeviceFeatures2 * enabledFeatures2)132 vk::Move<vk::VkDevice> createRobustBufferAccessDevice (Context& context, const vk::VkPhysicalDeviceFeatures2* enabledFeatures2)
133 {
134 	const float queuePriority = 1.0f;
135 
136 	// Create a universal queue that supports graphics and compute
137 	const vk::VkDeviceQueueCreateInfo	queueParams =
138 	{
139 		vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,	// VkStructureType				sType;
140 		DE_NULL,										// const void*					pNext;
141 		0u,												// VkDeviceQueueCreateFlags		flags;
142 		context.getUniversalQueueFamilyIndex(),			// deUint32						queueFamilyIndex;
143 		1u,												// deUint32						queueCount;
144 		&queuePriority									// const float*					pQueuePriorities;
145 	};
146 
147 	vk::VkPhysicalDeviceFeatures enabledFeatures1 = context.getDeviceFeatures();
148 	enabledFeatures1.robustBufferAccess = true;
149 
150 	// \note Extensions in core are not explicitly enabled even though
151 	//		 they are in the extension list advertised to tests.
152 	const auto& extensionPtrs = context.getDeviceCreationExtensions();
153 
154 	void* pNext = (void*)enabledFeatures2;
155 #ifdef CTS_USES_VULKANSC
156 	VkDeviceObjectReservationCreateInfo memReservationInfo = context.getTestContext().getCommandLine().isSubProcess() ? context.getResourceInterface()->getStatMax() : resetDeviceObjectReservationCreateInfo();
157 	memReservationInfo.pNext = pNext;
158 	pNext = &memReservationInfo;
159 
160 	VkPhysicalDeviceVulkanSC10Features sc10Features =
161 		createDefaultSC10Features();
162 	sc10Features.pNext = pNext;
163 	pNext = &sc10Features;
164 
165 	VkPipelineCacheCreateInfo			pcCI;
166 	std::vector<VkPipelinePoolSize>		poolSizes;
167 	if (context.getTestContext().getCommandLine().isSubProcess())
168 	{
169 		if (context.getResourceInterface()->getCacheDataSize() > 0)
170 		{
171 			pcCI =
172 			{
173 				VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,		// VkStructureType				sType;
174 				DE_NULL,											// const void*					pNext;
175 				VK_PIPELINE_CACHE_CREATE_READ_ONLY_BIT |
176 					VK_PIPELINE_CACHE_CREATE_USE_APPLICATION_STORAGE_BIT,	// VkPipelineCacheCreateFlags	flags;
177 				context.getResourceInterface()->getCacheDataSize(),	// deUintptr					initialDataSize;
178 				context.getResourceInterface()->getCacheData()		// const void*					pInitialData;
179 			};
180 			memReservationInfo.pipelineCacheCreateInfoCount = 1;
181 			memReservationInfo.pPipelineCacheCreateInfos = &pcCI;
182 		}
183 
184 		poolSizes = context.getResourceInterface()->getPipelinePoolSizes();
185 		if (!poolSizes.empty())
186 		{
187 			memReservationInfo.pipelinePoolSizeCount = deUint32(poolSizes.size());
188 			memReservationInfo.pPipelinePoolSizes = poolSizes.data();
189 		}
190 	}
191 #endif
192 
193 	const vk::VkDeviceCreateInfo		deviceParams =
194 	{
195 		vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,	// VkStructureType					sType;
196 		pNext,										// const void*						pNext;
197 		0u,											// VkDeviceCreateFlags				flags;
198 		1u,											// deUint32							queueCreateInfoCount;
199 		&queueParams,								// const VkDeviceQueueCreateInfo*	pQueueCreateInfos;
200 		0u,											// deUint32							enabledLayerCount;
201 		nullptr,									// const char* const*				ppEnabledLayerNames;
202 		de::sizeU32(extensionPtrs),					// deUint32							enabledExtensionCount;
203 		de::dataOrNull(extensionPtrs),				// const char* const*				ppEnabledExtensionNames;
204 		enabledFeatures2 ? nullptr : &enabledFeatures1	// const VkPhysicalDeviceFeatures*	pEnabledFeatures;
205 	};
206 
207 	// We are creating a custom device with a potentially large amount of extensions and features enabled, using the default device
208 	// as a reference. Some implementations may only enable certain device extensions if some instance extensions are enabled, so in
209 	// this case it's important to reuse the context instance when creating the device.
210 	const auto& vki = context.getInstanceInterface();
211 	const auto	instance = context.getInstance();
212 	const auto	physicalDevice = chooseDevice(vki, instance, context.getTestContext().getCommandLine());
213 
214 	return createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), context.getPlatformInterface(),
215 		instance, vki, physicalDevice, &deviceParams);
216 }
217 
218 enum BeyondType
219 {
220 	BUFFER,
221 	SIZE
222 };
223 
224 struct TestParamsMaint5
225 {
226 	vk::VkPrimitiveTopology	topology;
227 	deUint32				width;
228 	deUint32				height;
229 	deUint32				bufferCount;
230 	deUint32				rndSeed;
231 	bool					wholeSize;
232 	BeyondType				beyondType;
233 };
234 
235 class BindBuffers2Instance : public vkt::TestInstance
236 {
237 public:
BindBuffers2Instance(Context & context,const vk::PipelineConstructionType pipelineConstructionType,const TestParams params,const bool singleBind,const deUint32 count)238 						BindBuffers2Instance		(Context& context, const vk::PipelineConstructionType	pipelineConstructionType, const TestParams params, const bool singleBind, const deUint32 count)
239 							: vkt::TestInstance				(context)
240 							, m_pipelineConstructionType	(pipelineConstructionType)
241 							, m_params						(params)
242 							, m_singleBind					(singleBind)
243 							, m_count						(count)
244 							{}
~BindBuffers2Instance(void)245 	virtual				~BindBuffers2Instance		(void) {}
246 
247 	tcu::TestStatus		iterate						(void) override;
248 
249 private:
250 	const vk::PipelineConstructionType	m_pipelineConstructionType;
251 	const TestParams					m_params;
252 	const bool							m_singleBind;
253 	const deUint32						m_count;
254 };
255 
iterate(void)256 tcu::TestStatus BindBuffers2Instance::iterate (void)
257 {
258 	const vk::VkInstance			instance			= m_context.getInstance();
259 	const vk::InstanceDriver		instanceDriver		(m_context.getPlatformInterface(), instance);
260 	const vk::InstanceInterface&	vki					= m_context.getInstanceInterface();
261 	const vk::DeviceInterface&		vk					= m_context.getDeviceInterface();
262 	const vk::VkPhysicalDevice		physicalDevice		= m_context.getPhysicalDevice();
263 	const vk::VkDevice				device				= m_context.getDevice();
264 	const vk::VkQueue				queue				= m_context.getUniversalQueue();
265 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
266 	vk::Allocator&					allocator			= m_context.getDefaultAllocator();
267 	const auto&						deviceExtensions	= m_context.getDeviceExtensions();
268 	tcu::TestLog&					log					= m_context.getTestContext().getLog();
269 
270 	vk::VkExtent2D					extent				= {	32u, 32u };
271 
272 	const std::vector<vk::VkViewport>	viewports	{ vk::makeViewport(extent) };
273 	const std::vector<vk::VkRect2D>		scissors	{ vk::makeRect2D(extent) };
274 
275 	const vk::VkPipelineLayoutCreateInfo		pipelineLayoutInfo		=
276 	{
277 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// VkStructureType				sType;
278 		DE_NULL,											// const void*					pNext;
279 		0u,													// VkPipelineLayoutCreateFlags	flags;
280 		0u,													// deUint32						descriptorSetCount;
281 		DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
282 		0u,													// deUint32						pushConstantRangeCount;
283 		DE_NULL												// const VkPushDescriptorRange*	pPushDescriptorRanges;
284 	};
285 
286 	const vk::VkImageSubresourceRange				colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
287 	const vk::Move<vk::VkImage>						colorImage			(makeImage(vk, device, makeImageCreateInfo(extent, vk::VK_FORMAT_R32G32B32A32_SFLOAT, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT)));
288 	const de::MovePtr<vk::Allocation>				colorImageAlloc		(bindImage(vk, device, allocator, *colorImage, vk::MemoryRequirement::Any));
289 	const vk::Move<vk::VkImageView>					colorImageView		(makeImageView(vk, device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D, vk::VK_FORMAT_R32G32B32A32_SFLOAT, colorSubresourceRange));
290 
291 	const vk::PipelineLayoutWrapper					pipelineLayout		(m_pipelineConstructionType, vk, device, &pipelineLayoutInfo);
292 	vk::RenderPassWrapper							renderPass			(m_pipelineConstructionType, vk, device, vk::VK_FORMAT_R32G32B32A32_SFLOAT);
293 	renderPass.createFramebuffer(vk, device, *colorImage, *colorImageView, extent.width, extent.height);
294 	const vk::ShaderWrapper							vertShaderModule	= vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"));
295 	const vk::ShaderWrapper							fragShaderModule	= vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"));
296 
297 	//buffer to read the output image
298 	auto											outBuffer			= makeBufferForImage(vk, device, allocator, mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT), extent);
299 	auto&											outBufferAlloc		= outBuffer->getAllocation();
300 
301 	std::vector<vk::VkVertexInputAttributeDescription>		attributes;
302 	if (m_count == 2)
303 	{
304 		attributes = {
305 			makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32_SFLOAT, 0),
306 			makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0),
307 			makeAttributeDescription(2, 2, vk::VK_FORMAT_R32G32_SFLOAT, 0),
308 			makeAttributeDescription(3, 3, vk::VK_FORMAT_R32G32_SFLOAT, 0),
309 		};
310 	}
311 	else if (m_count == 3)
312 	{
313 		attributes = {
314 			makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32_SFLOAT, 0),
315 			makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0),
316 			makeAttributeDescription(2, 2, vk::VK_FORMAT_R32_SFLOAT, 0),
317 			makeAttributeDescription(3, 3, vk::VK_FORMAT_R32_SFLOAT, 0),
318 			makeAttributeDescription(4, 4, vk::VK_FORMAT_R32_SFLOAT, 0),
319 			makeAttributeDescription(5, 5, vk::VK_FORMAT_R32_SFLOAT, 0),
320 		};
321 	}
322 	else if (m_count == 4)
323 	{
324 		attributes = {
325 			makeAttributeDescription(0, 0, vk::VK_FORMAT_R32_SFLOAT, 0),
326 			makeAttributeDescription(1, 1, vk::VK_FORMAT_R32_SFLOAT, 0),
327 			makeAttributeDescription(2, 2, vk::VK_FORMAT_R32_SFLOAT, 0),
328 			makeAttributeDescription(3, 3, vk::VK_FORMAT_R32_SFLOAT, 0),
329 			makeAttributeDescription(4, 4, vk::VK_FORMAT_R32_SFLOAT, 0),
330 			makeAttributeDescription(5, 5, vk::VK_FORMAT_R32_SFLOAT, 0),
331 			makeAttributeDescription(6, 6, vk::VK_FORMAT_R32_SFLOAT, 0),
332 			makeAttributeDescription(7, 7, vk::VK_FORMAT_R32_SFLOAT, 0),
333 		};
334 	}
335 	else
336 	{
337 		attributes = {
338 			makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0),
339 			makeAttributeDescription(1, 1, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0),
340 		};
341 	}
342 
343 	log << tcu::TestLog::Message << "VkVertexInputAttributeDescription:" << tcu::TestLog::EndMessage;
344 	for (const auto& attrib : attributes) {
345 		log << tcu::TestLog::Message << "location " << attrib.location << ", binding " << attrib.binding << ", format " << attrib.format << tcu::TestLog::EndMessage;
346 	}
347 
348 	std::vector<vk::VkVertexInputBindingDescription>		bindings;
349 	for (deUint32 i = 0; i < m_count; ++i)
350 	{
351 		bindings.push_back(makeBindingDescription(i * 2, 99 /*ignored*/, vk::VK_VERTEX_INPUT_RATE_INSTANCE));
352 		bindings.push_back(makeBindingDescription(i * 2 + 1, 99 /*ignored*/, vk::VK_VERTEX_INPUT_RATE_VERTEX));
353 	};
354 	log << tcu::TestLog::Message << "VkVertexInputBindingDescription:\n" << tcu::TestLog::EndMessage;
355 	for (const auto& binding : bindings) {
356 		log << tcu::TestLog::Message << "binding " << binding.binding << ", stride " << binding.stride << ", inputRate " << binding.inputRate << tcu::TestLog::EndMessage;
357 	}
358 
359 	vk::VkPipelineVertexInputStateCreateInfo		vertexInputState	= vk::initVulkanStructure();
360 	vertexInputState.vertexBindingDescriptionCount = (deUint32)bindings.size();
361 	vertexInputState.pVertexBindingDescriptions = bindings.data();
362 	vertexInputState.vertexAttributeDescriptionCount = (deUint32)attributes.size();
363 	vertexInputState.pVertexAttributeDescriptions = attributes.data();
364 
365 	vk::VkPipelineInputAssemblyStateCreateInfo		inputAssemblyState	= vk::initVulkanStructure();
366 	inputAssemblyState.topology = vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
367 
368 	const vk::VkDynamicState						dynamicState		= vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
369 
370 	const vk::VkPipelineDynamicStateCreateInfo		dynamicStateInfo	=
371 	{
372 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
373 		nullptr,													//	const void*							pNext;
374 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
375 		1u,															//	uint32_t							dynamicStateCount;
376 		&dynamicState,												//	const VkDynamicState*				pDynamicStates;
377 	};
378 
379 	vk::GraphicsPipelineWrapper	graphicsPipelineWrapper	{ vki, vk, physicalDevice, device, deviceExtensions, m_pipelineConstructionType };
380 	graphicsPipelineWrapper.setDefaultDepthStencilState()
381 		.setDefaultColorBlendState()
382 		.setDefaultRasterizationState()
383 		.setDefaultMultisampleState()
384 		.setDynamicState(&dynamicStateInfo)
385 		.setupVertexInputState(&vertexInputState, &inputAssemblyState)
386 		.setupPreRasterizationShaderState(viewports,
387 			scissors,
388 			pipelineLayout,
389 			renderPass.get(),
390 			0u,
391 			vertShaderModule)
392 		.setupFragmentShaderState(pipelineLayout,
393 			renderPass.get(),
394 			0u,
395 			fragShaderModule)
396 		.setupFragmentOutputState(renderPass.get())
397 		.setMonolithicPipelineLayout(pipelineLayout)
398 		.buildPipeline();
399 
400 	const vk::Move<vk::VkCommandPool>				cmdPool			(createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
401 	const vk::Move<vk::VkCommandBuffer>				cmdBuffer		(allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
402 
403 	deUint32										instanceCount	= 4u;
404 	vk::VkDeviceSize								colorStride		= m_params.colorStride * sizeof(float);
405 	vk::VkDeviceSize								colorOffset		= m_params.colorOffset * sizeof(float);
406 	vk::VkDeviceSize								vertexStride	= m_params.vertexStride * sizeof(float);
407 	vk::VkDeviceSize								vertexOffset	= m_params.vertexOffset * sizeof(float);
408 
409 	tcu::Vec4										colors[]		=
410 	{
411 		tcu::Vec4(0.21f, 0.41f, 0.61f, 0.81f),
412 		tcu::Vec4(0.22f, 0.42f, 0.62f, 0.82f),
413 		tcu::Vec4(0.23f, 0.43f, 0.63f, 0.83f),
414 		tcu::Vec4(0.24f, 0.44f, 0.64f, 0.84f),
415 	};
416 
417 	tcu::Vec4										vertices[] =
418 	{
419 		tcu::Vec4(0.0f, 0.0f, 0.0f, 0.0f),
420 		tcu::Vec4(0.0f, 1.0f, 0.0f, 0.0f),
421 		tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
422 		tcu::Vec4(1.0f, 1.0f, 0.0f, 0.0f),
423 	};
424 
425 	std::vector<float>								colorData;
426 	for (deUint32 i = 0; i < colorOffset / sizeof(float); ++i)
427 		colorData.push_back(0);
428 
429 	for (deUint32 i = 0; i < 4; ++i)
430 	{
431 		colorData.push_back(colors[i].x());
432 		colorData.push_back(colors[i].y());
433 		colorData.push_back(colors[i].z());
434 		colorData.push_back(colors[i].w());
435 		for (deUint32 j = 4; j < colorStride / sizeof(float); ++j)
436 			colorData.push_back(0.0f);
437 	}
438 
439 	std::vector<float>								vertexData;
440 	for (deUint32 i = 0; i < vertexOffset / sizeof(float); ++i)
441 		vertexData.push_back(0);
442 
443 	for (deUint32 i = 0; i < 4; ++i)
444 	{
445 		vertexData.push_back(vertices[i].x());
446 		vertexData.push_back(vertices[i].y());
447 		vertexData.push_back(vertices[i].z());
448 		vertexData.push_back(vertices[i].w());
449 		for (deUint32 j = 4; j < vertexStride / sizeof(float); ++j)
450 			vertexData.push_back(0.0f);
451 	}
452 
453 	vk::VkClearValue								clearColorValue		= defaultClearValue(vk::VK_FORMAT_R32G32B32A32_SFLOAT);
454 	vk::VkDeviceSize								colorBufferSize		= colorData.size() * sizeof(float);
455 	vk::VkDeviceSize								vertexBufferSize	= vertexData.size() * sizeof(float);
456 
457 	const auto										colorCreateInfo		= vk::makeBufferCreateInfo(colorBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
458 	const auto										vertexCreateInfo	= vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
459 	de::MovePtr<vk::BufferWithMemory>				colorBuffer			= de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vk, device, allocator, colorCreateInfo, vk::MemoryRequirement::HostVisible));
460 	de::MovePtr<vk::BufferWithMemory>				vertexBuffer		= de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vk, device, allocator, vertexCreateInfo, vk::MemoryRequirement::HostVisible));
461 	copyAndFlush(vk, device, *colorBuffer, 0, colorData.data(), colorData.size() * sizeof(float));
462 	copyAndFlush(vk, device, *vertexBuffer, 0, vertexData.data(), vertexData.size() * sizeof(float));
463 
464 	beginCommandBuffer(vk, *cmdBuffer);
465 	renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, extent.width, extent.height), clearColorValue);
466 	graphicsPipelineWrapper.bind(*cmdBuffer);
467 
468 	vk::VkBuffer		buffers[]	= { **colorBuffer, **vertexBuffer, **colorBuffer, **vertexBuffer, **colorBuffer, **vertexBuffer, **colorBuffer, **vertexBuffer };
469 	std::vector<vk::VkDeviceSize>	offsets	= { colorOffset, vertexOffset };
470 	if (m_count == 2)
471 	{
472 		offsets.push_back(colorOffset + sizeof(float) * 2);
473 		offsets.push_back(vertexOffset + sizeof(float) * 2);
474 	}
475 	else if (m_count == 3)
476 	{
477 		offsets.push_back(colorOffset + sizeof(float) * 2);
478 		offsets.push_back(vertexOffset + sizeof(float) * 2);
479 		offsets.push_back(colorOffset + sizeof(float) * 3);
480 		offsets.push_back(vertexOffset + sizeof(float) * 3);
481 	}
482 	else if (m_count == 4)
483 	{
484 		offsets.push_back(colorOffset + sizeof(float));
485 		offsets.push_back(vertexOffset + sizeof(float));
486 		offsets.push_back(colorOffset + sizeof(float) * 2);
487 		offsets.push_back(vertexOffset + sizeof(float) * 2);
488 		offsets.push_back(colorOffset + sizeof(float) * 3);
489 		offsets.push_back(vertexOffset + sizeof(float) * 3);
490 	}
491 	std::vector<vk::VkDeviceSize>	sizes;
492 	for (deUint32 i = 0; i < m_count; ++i)
493 	{
494 		sizes.push_back(colorBufferSize - offsets[i * 2]);
495 		sizes.push_back(vertexBufferSize - offsets[i * 2 + 1]);
496 	}
497 	vk::VkDeviceSize	strides[]	= { colorStride, vertexStride, colorStride, vertexStride, colorStride, vertexStride, colorStride, vertexStride };
498 	if (m_singleBind)
499 	{
500 #ifndef CTS_USES_VULKANSC
501 		vk.cmdBindVertexBuffers2(*cmdBuffer, 0, 2 * m_count, buffers, offsets.data(), sizes.data(), strides);
502 #else
503 		vk.cmdBindVertexBuffers2EXT(*cmdBuffer, 0, 2 * m_count, buffers, offsets.data(), sizes.data(), strides);
504 #endif
505 	}
506 	else
507 	{
508 		for (deUint32 i = 0; i < m_count * 2; ++i)
509 		{
510 #ifndef CTS_USES_VULKANSC
511 			vk.cmdBindVertexBuffers2(*cmdBuffer, i, 1, &buffers[i], &offsets[i], &sizes[i], &strides[i]);
512 #else
513 			vk.cmdBindVertexBuffers2EXT(*cmdBuffer, i, 1, &buffers[i], &offsets[i], &sizes[i], &strides[i]);
514 #endif
515 		}
516 	}
517 	log << tcu::TestLog::Message << "vkCmdBindVertexBuffers2" << tcu::TestLog::EndMessage;
518 	for (deUint32 i = 0; i < m_count * 2; ++i)
519 	{
520 		log << tcu::TestLog::Message << "binding " << i << ", buffer " << buffers[i] << ", offset " << offsets[i] << ", size " << sizes[i] << ", stride " << strides[i] << tcu::TestLog::EndMessage;
521 	}
522 
523 	vk.cmdDraw(*cmdBuffer, 4, instanceCount, 0, 0);
524 	renderPass.end(vk, *cmdBuffer);
525 
526 	vk::copyImageToBuffer(vk, *cmdBuffer, *colorImage, (*outBuffer).get(), tcu::IVec2(extent.width, extent.height));
527 	endCommandBuffer(vk, *cmdBuffer);
528 
529 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
530 
531 	invalidateAlloc(vk, device, outBufferAlloc);
532 	const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT), tcu::IVec3(extent.width, extent.height, 1), (const char*)outBufferAlloc.getHostPtr());
533 
534 	const deUint32 h = result.getHeight();
535 	const deUint32 w = result.getWidth();
536 	for (deUint32 y = 0; y < h; y++)
537 	{
538 		for (deUint32 x = 0; x < w; x++)
539 		{
540 			tcu::Vec4	pix = result.getPixel(x, y);
541 
542 			if (x >= w / 2 && y >= h / 2 && pix != colors[0])
543 			{
544 				log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix << ", but expected color was " << colors[0] << tcu::TestLog::EndMessage;
545 				return tcu::TestStatus::fail("Fail");
546 			}
547 			if (x < w / 2 && y >= h / 2 && pix != colors[colorStride == 0 ? 0 : 1])
548 			{
549 				log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix << ", but expected color was " << colors[colorStride == 0 ? 0 : 1] << tcu::TestLog::EndMessage;
550 				return tcu::TestStatus::fail("Fail");
551 			}
552 			if (x >= w / 2 && y < h / 2 && pix != colors[colorStride == 0 ? 0 : 2])
553 			{
554 				log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix << ", but expected color was " << colors[colorStride == 0 ? 0 : 2] << tcu::TestLog::EndMessage;
555 				return tcu::TestStatus::fail("Fail");
556 			}
557 			if (x < w / 2 && y < h / 2 && pix != colors[colorStride == 0 ? 0 : 3])
558 			{
559 				log << tcu::TestLog::Message << "Color at (" << x << ", " << y << ") was " << pix << ", but expected color was " << colors[colorStride == 0 ? 0 : 3] << tcu::TestLog::EndMessage;
560 				return tcu::TestStatus::fail("Fail");
561 			}
562 		}
563 	}
564 
565 	return tcu::TestStatus::pass("Pass");
566 }
567 
568 class BindVertexBuffers2Instance : public vkt::TestInstance
569 {
570 public:
BindVertexBuffers2Instance(Context & context,DeviceDriverPtr driver,DevicePtr device,vk::PipelineConstructionType pipelineConstructionType,const TestParamsMaint5 & params,bool robustness2)571 						BindVertexBuffers2Instance	(Context&						context,
572 													 DeviceDriverPtr				driver,
573 													 DevicePtr						device,
574 													 vk::PipelineConstructionType	pipelineConstructionType,
575 													 const TestParamsMaint5&		params,
576 													 bool							robustness2)
577 							: vkt::TestInstance(context)
578 							, m_pipelineConstructionType(pipelineConstructionType)
579 							, m_params(params)
580 							, m_robustness2(robustness2)
581 							, m_deviceDriver(driver)
582 							, m_device(device)
583 							, m_physicalDevice(chooseDevice(context.getInstanceInterface(), context.getInstance(), context.getTestContext().getCommandLine()))
584 							, m_allocator(getDeviceInterface(), getDevice(), getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), m_physicalDevice))
585 							, m_pipelineWrapper(context.getInstanceInterface(), context.getDeviceInterface(), m_physicalDevice, getDevice(), m_context.getDeviceExtensions(), m_pipelineConstructionType, 0u)
586 							, m_vertShaderModule(context.getDeviceInterface(), getDevice(), m_context.getBinaryCollection().get("vert"))
587 							, m_fragShaderModule(context.getDeviceInterface(), getDevice(), m_context.getBinaryCollection().get("frag")) { }
588 	virtual				~BindVertexBuffers2Instance	(void) = default;
589 
590 	tcu::TestStatus		iterate(void) override;
591 
592 protected:
593 	typedef std::vector<vk::VkDeviceSize> Sizes;
594 	typedef std::vector<de::SharedPtr<vk::BufferWithMemory>> Buffers;
595 	const vk::DeviceInterface&	getDeviceInterface	() const;
596 	vk::VkDevice				getDevice			() const;
597 	vk::VkQueue					getQueue			() const;
598 	vk::Allocator&				getAllocator();
599 	void						createPipeline		(const vk::PipelineLayoutWrapper&	layout,
600 													 vk::VkRenderPass		renderPass);
601 	Buffers						createBuffers		(Sizes&					offsets,
602 													 Sizes&					strides,
603 													 Sizes&					sizes);
604 
605 private:
606 	const vk::PipelineConstructionType	m_pipelineConstructionType;
607 	const TestParamsMaint5				m_params;
608 	const bool							m_robustness2;
609 	DeviceDriverPtr						m_deviceDriver;
610 	DevicePtr							m_device;
611 	const vk::VkPhysicalDevice			m_physicalDevice;
612 	vk::SimpleAllocator					m_allocator;
613 	vk::GraphicsPipelineWrapper			m_pipelineWrapper;
614 	const vk::ShaderWrapper				m_vertShaderModule;
615 	const vk::ShaderWrapper				m_fragShaderModule;
616 };
617 
getDeviceInterface() const618 const vk::DeviceInterface& BindVertexBuffers2Instance::getDeviceInterface () const
619 {
620 	return m_robustness2 ? *m_deviceDriver : m_context.getDeviceInterface();
621 }
622 
getDevice() const623 vk::VkDevice BindVertexBuffers2Instance::getDevice () const
624 {
625 	return m_robustness2 ? *m_device : m_context.getDevice();
626 }
627 
getQueue() const628 vk::VkQueue BindVertexBuffers2Instance::getQueue () const
629 {
630 	vk::VkQueue queue = DE_NULL;
631 	if (m_robustness2)
632 	{
633 		const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
634 		m_deviceDriver->getDeviceQueue(getDevice(), queueFamilyIndex, 0, &queue);
635 	}
636 	else
637 	{
638 		queue = m_context.getUniversalQueue();
639 	}
640 	return queue;
641 }
642 
getAllocator()643 vk::Allocator& BindVertexBuffers2Instance::getAllocator ()
644 {
645 	return m_allocator;
646 }
647 
createPipeline(const vk::PipelineLayoutWrapper & layout,vk::VkRenderPass renderPass)648 void BindVertexBuffers2Instance::createPipeline (const vk::PipelineLayoutWrapper& layout, vk::VkRenderPass renderPass)
649 {
650 	vk::VkPhysicalDeviceProperties	dp{};
651 	m_context.getInstanceInterface().getPhysicalDeviceProperties(m_physicalDevice, &dp);
652 
653 	const std::vector<vk::VkViewport>	viewports	{ vk::makeViewport(m_params.width, m_params.height) };
654 	const std::vector<vk::VkRect2D>		scissors	{ vk::makeRect2D(m_params.width, m_params.height) };
655 
656 	std::vector<vk::VkVertexInputBindingDescription>		bindings
657 	{
658 		// color buffer binding
659 		makeBindingDescription(0, dp.limits.maxVertexInputBindingStride /* ignored */, vk::VK_VERTEX_INPUT_RATE_VERTEX)
660 	};
661 	for (deUint32 b = 1; b < m_params.bufferCount; ++b)
662 	{
663 		// vertex buffer binding
664 		bindings.push_back(makeBindingDescription(b, dp.limits.maxVertexInputBindingStride /* ignored */, vk::VK_VERTEX_INPUT_RATE_VERTEX));
665 	}
666 
667 	std::vector<vk::VkVertexInputAttributeDescription>		attributes
668 	{
669 		// color attribute layout information
670 		makeAttributeDescription(0, 0, vk::VK_FORMAT_R32G32B32_SFLOAT, 0)
671 	};
672 	for (deUint32 lb = 1; lb < m_params.bufferCount; ++lb)
673 	{
674 		attributes.push_back(makeAttributeDescription(lb, 1, vk::VK_FORMAT_R32G32_SFLOAT, 0));
675 	}
676 
677 	vk::VkPipelineVertexInputStateCreateInfo				vertexInputState = vk::initVulkanStructure();
678 	vertexInputState.vertexBindingDescriptionCount		= (deUint32)bindings.size();
679 	vertexInputState.pVertexBindingDescriptions			= bindings.data();
680 	vertexInputState.vertexAttributeDescriptionCount	= (deUint32)attributes.size();
681 	vertexInputState.pVertexAttributeDescriptions		= attributes.data();
682 
683 	vk::VkPipelineInputAssemblyStateCreateInfo				inputAssemblyState = vk::initVulkanStructure();
684 	inputAssemblyState.topology	= m_params.topology;
685 
686 	const vk::VkDynamicState								dynamicState = vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT;
687 
688 	const vk::VkPipelineDynamicStateCreateInfo				dynamicStateInfo
689 	{
690 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
691 		nullptr,													//	const void*							pNext;
692 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
693 		1u,															//	uint32_t							dynamicStateCount;
694 		&dynamicState,												//	const VkDynamicState*				pDynamicStates;
695 	};
696 
697 	const vk::VkPipelineRasterizationStateCreateInfo		rasterizationCreateInfo
698 	{
699 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	// VkStructureType								sType
700 		DE_NULL,														// const void*									pNext
701 		0u,																// VkPipelineRasterizationStateCreateFlags		flags
702 		VK_FALSE,														// VkBool32										depthClampEnable
703 		VK_FALSE,														// VkBool32										rasterizerDiscardEnable
704 		vk::VK_POLYGON_MODE_FILL,										// VkPolygonMode								polygonMode
705 		vk::VK_CULL_MODE_NONE,											// VkCullModeFlags								cullMode
706 		vk::VK_FRONT_FACE_CLOCKWISE,									// VkFrontFace									frontFace
707 		VK_FALSE,														// VkBool32										depthBiasEnable
708 		0.0f,															// float										depthBiasConstantFactor
709 		0.0f,															// float										depthBiasClamp
710 		0.0f,															// float										depthBiasSlopeFactor
711 		1.0f															// float										lineWidth
712 	};
713 
714 	m_pipelineWrapper.setDefaultDepthStencilState()
715 		.setDefaultColorBlendState()
716 		//.setDefaultRasterizationState()
717 		.setDefaultMultisampleState()
718 		.setDynamicState(&dynamicStateInfo)
719 		.setupVertexInputState(&vertexInputState, &inputAssemblyState)
720 		.setupPreRasterizationShaderState(
721 			viewports,
722 			scissors,
723 			layout,
724 			renderPass,
725 			0u,
726 			m_vertShaderModule,
727 			&rasterizationCreateInfo)
728 		.setupFragmentShaderState(
729 			layout,
730 			renderPass,
731 			0u,
732 			m_fragShaderModule)
733 		.setupFragmentOutputState(renderPass)
734 		.setMonolithicPipelineLayout(layout)
735 	.buildPipeline();
736 }
737 
createBuffers(Sizes & offsets,Sizes & strides,Sizes & sizes)738 BindVertexBuffers2Instance::Buffers BindVertexBuffers2Instance::createBuffers (Sizes& offsets, Sizes& strides, Sizes& sizes)
739 {
740 	Buffers						buffers;
741 	vk::Allocator&				allocator	= getAllocator();
742 	const vk::DeviceInterface&	vk			= getDeviceInterface();
743 	const vk::VkDevice			device		= getDevice();
744 	de::Random					rnd			(m_params.rndSeed);
745 	const float					p			= 1.0f / float(m_params.bufferCount - 1); DE_ASSERT(m_params.bufferCount >= 2);
746 	const deUint32				compCount	= deUint32(sizeof(tcu::Vec2) / sizeof(float));
747 
748 	std::vector<float>			pointTemplate;
749 	deUint32					returnSize	= 0;
750 	deUint32					sourceSize	= 0;
751 	deUint32					allocSize	= 0;
752 
753 	if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
754 	{
755 		//-1 / -1 / 0 / -1 / -1 / 0
756 		pointTemplate.push_back	(-p);
757 		pointTemplate.push_back	(-p);
758 		pointTemplate.push_back		(0.0f);
759 		pointTemplate.push_back		(-p);
760 		pointTemplate.push_back			(-p);
761 		pointTemplate.push_back			(0.0f);
762 		if (!m_robustness2)
763 		{
764 			pointTemplate.push_back(0.0f);
765 			pointTemplate.push_back(0.0f);
766 			// Beyonds do not matter
767 			sourceSize	= 4;
768 			allocSize	= 4;
769 			returnSize	= 4; // or WHOLE_SIZE
770 		}
771 		else
772 		{
773 			pointTemplate.push_back(+p); // those should be read as (0,0)
774 			pointTemplate.push_back(+p);
775 
776 			switch (m_params.beyondType)
777 			{
778 			case BeyondType::BUFFER:
779 				sourceSize	= 3;
780 				allocSize	= 3;
781 				returnSize	= 3;
782 				break;
783 			case BeyondType::SIZE:
784 				DE_ASSERT(m_params.wholeSize == false);
785 				sourceSize	= 4;
786 				allocSize	= 4;
787 				returnSize	= 3;
788 				break;
789 			}
790 		}
791 	}
792 	else if (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
793 	{
794 		// -1/0/ -1/-1 /0/-1 /-1/0 /0/-1
795 		pointTemplate.push_back	(-p);
796 		pointTemplate.push_back	(0.0f);
797 		pointTemplate.push_back		(-p);
798 		pointTemplate.push_back		(-p);
799 		pointTemplate.push_back			(0.0);
800 		pointTemplate.push_back			(-p);
801 		pointTemplate.push_back	(-p);
802 		pointTemplate.push_back	(0.0f);
803 		pointTemplate.push_back		(0.0f);
804 		pointTemplate.push_back		(-p);
805 		if (!m_robustness2)
806 		{
807 			pointTemplate.push_back(0.0f);
808 			pointTemplate.push_back(0.0f);
809 			// Beyonds do not matter
810 			sourceSize	= 6;
811 			allocSize	= 6;
812 			returnSize	= 6; // or WHOLE_SIZE
813 		}
814 		else
815 		{
816 			// those should be read as (0,0)
817 			pointTemplate.push_back(+p);
818 			pointTemplate.push_back(+p);
819 
820 			switch (m_params.beyondType)
821 			{
822 			case BeyondType::BUFFER:
823 				sourceSize	= 5;
824 				allocSize	= 5;
825 				returnSize	= 5;
826 				break;
827 			case BeyondType::SIZE:
828 				sourceSize	= 6;
829 				allocSize	= 6;
830 				returnSize	= 5;
831 				break;
832 			}
833 		}
834 	}
835 	else
836 	{
837 		DE_ASSERT(0);
838 	}
839 	DE_ASSERT((allocSize != 0) && (allocSize >= sourceSize));
840 
841 	const std::vector<float>&	source		= pointTemplate;
842 
843 	std::vector<tcu::Vec3> colorTemplate(7);
844 	for (int i = 1; i <= 7; ++i)
845 	{
846 		colorTemplate[i - 1] = {
847 			i & 0x1 ? 1.0f : 0.6f,
848 			i & 0x2 ? 1.0f : 0.6f,
849 			i & 0x4 ? 1.0f : 0.6f
850 		};
851 	}
852 	std::vector<float> colors(sourceSize * 3);
853 	for (deUint32 i = 0; i < sourceSize; ++i)
854 	{
855 		const tcu::Vec3& c = colorTemplate[i % colorTemplate.size()];
856 		colors[3 * i + 0] = c.x();
857 		colors[3 * i + 1] = c.y();
858 		colors[3 * i + 2] = c.z();
859 	}
860 	vk::VkDeviceSize clrSize = allocSize * 3 * sizeof(float);
861 	const vk::VkBufferCreateInfo clrCreateInfo = vk::makeBufferCreateInfo(clrSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
862 	de::SharedPtr<vk::BufferWithMemory> clrBuffer(new vk::BufferWithMemory(vk, device, allocator, clrCreateInfo, vk::MemoryRequirement::HostVisible));
863 	copyAndFlush(vk, device, *clrBuffer, 0, colors.data(), deUint32(colors.size() * sizeof(float)));
864 	buffers.push_back(clrBuffer);
865 
866 	sizes.resize(m_params.bufferCount);
867 	sizes[0] = m_params.wholeSize ? VK_WHOLE_SIZE : (returnSize * 3 * sizeof(float));
868 
869 	offsets.resize(m_params.bufferCount);
870 	strides.resize(m_params.bufferCount);
871 
872 	// random offsets multiplyied later by 4, special value 0 for no-offset
873 	offsets[0] = 0;
874 	for (deUint32 i = 1; i < m_params.bufferCount; ++i)
875 	{
876 		auto nextOffset = [&]() {
877 			vk::VkDeviceSize offset = rnd.getUint64() % 30;
878 			while (offset == 0)
879 				offset = rnd.getUint64() % 30;
880 			return offset;
881 		};
882 		offsets[i] = (m_params.rndSeed == 0) ? vk::VkDeviceSize(0) : nextOffset();
883 	}
884 
885 	// random strides multiplyied later by 4, special value for atributes stride
886 	strides[0] = { sizeof(tcu::Vec3) };
887 	for (deUint32 i = 1; i < m_params.bufferCount; ++i)
888 	{
889 		auto nextStride = [&]() {
890 			vk::VkDeviceSize stride = rnd.getUint64() % 30;
891 			while (stride == 0)
892 				stride = rnd.getUint64() % 30;
893 			return stride;
894 		};
895 		strides[i] = (m_params.rndSeed == 0) ? vk::VkDeviceSize(0) : nextStride();
896 	}
897 
898 	for (deUint32 i = 1; i < m_params.bufferCount; ++i)
899 	{
900 		const deUint32		stride	= deUint32(strides[i]);
901 		const deUint32		offset	= deUint32(offsets[i]);
902 		std::vector<float>	points	(offset + sourceSize * (compCount + stride));
903 
904 		for (deUint32 j = 0; j < offset; ++j)
905 		{
906 			points[j] = float(i * 13) + 0.234f;
907 		}
908 		for (uint32_t j = 0; j < sourceSize; ++j)
909 		{
910 			auto k = offset + j * (compCount + stride);
911 			points[k + 0] = source[j * compCount + 0];
912 			points[k + 1] = source[j * compCount + 1];
913 			for (uint32_t s = 0; s < stride; ++s)
914 			{
915 				points[k + compCount + s] = float(i * 19) + 0.543f;
916 			}
917 		}
918 
919 		vk::VkDeviceSize size = (offset + allocSize * (compCount + stride)) * sizeof(float);
920 		const vk::VkBufferCreateInfo createInfo = vk::makeBufferCreateInfo(size, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
921 		de::SharedPtr<vk::BufferWithMemory> buffer(new vk::BufferWithMemory(vk, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
922 		copyAndFlush(vk, device, *buffer, 0, points.data(), deUint32(points.size() * sizeof(float)));
923 
924 		sizes[i]	= m_params.wholeSize ? VK_WHOLE_SIZE : ((compCount + stride) * returnSize * sizeof(float));
925 		strides[i]	= (compCount + stride) * sizeof(float);
926 		offsets[i]	= offset * sizeof(float);
927 		buffers.push_back(buffer);
928 	}
929 
930 	return buffers;
931 }
932 
933 template<class X> struct collection_element { };
934 template<template<class, class...> class coll__, class X, class... Y>
935 	struct collection_element<coll__<X, Y...>> { typedef X type; };
936 template<class coll__> using collection_element_t = typename collection_element<coll__>::type;
937 
iterate(void)938 tcu::TestStatus BindVertexBuffers2Instance::iterate (void)
939 {
940 	const vk::DeviceInterface&				vk					= getDeviceInterface();
941 	const vk::VkDevice						device				= getDevice();
942 	const deUint32							queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
943 	const vk::VkQueue						queue				= getQueue();
944 	vk::Allocator&							allocator			= getAllocator();
945 	tcu::TestLog&							log					= m_context.getTestContext().getLog();
946 
947 	const vk::VkExtent2D					extent				{ m_params.width, m_params.height };
948 	const vk::VkImageSubresourceRange		colorSubresRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
949 	const vk::VkFormat						colorFormat			= vk::VK_FORMAT_R32G32B32A32_SFLOAT;
950 	const vk::Move<vk::VkImage>				colorImage			= makeImage(vk, device, makeImageCreateInfo(extent, colorFormat, vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
951 	const de::MovePtr<vk::Allocation>		colorImageAlloc		= bindImage(vk, device, allocator, *colorImage, vk::MemoryRequirement::Any);
952 	const vk::Move<vk::VkImageView>			colorImageView		= makeImageView(vk, device, *colorImage, vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresRange);
953 	vk::RenderPassWrapper					renderPass			(m_pipelineConstructionType, vk, device, colorFormat);
954 	renderPass.createFramebuffer(vk, device, colorImage.get(), colorImageView.get(), extent.width, extent.height);
955 	const vk::VkPipelineLayoutCreateInfo	pipelineLayoutInfo	= vk::initVulkanStructure();
956 	const vk::PipelineLayoutWrapper			pipelineLayout(m_pipelineConstructionType, vk, device, &pipelineLayoutInfo, nullptr);
957 
958 	const vk::VkClearValue					clearColorValue		= vk::makeClearValueColor(tcu::Vec4(0.5f));
959 	const vk::Move<vk::VkCommandPool>		cmdPool				= createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
960 	const vk::Move<vk::VkCommandBuffer>		cmdBuffer			= allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
961 
962 	Sizes									offsets;
963 	Sizes									strides;
964 	Sizes									sizes;
965 	Buffers									buffers				= createBuffers(offsets, strides, sizes);
966 	std::vector<vk::VkBuffer>				vkBuffers			(buffers.size());
967 	std::transform(buffers.begin(), buffers.end(), vkBuffers.begin(), [](collection_element_t<decltype(buffers)> buffer) { return **buffer; });
968 
969 	deUint32								vertexCount			= 0;
970 	switch (m_params.topology)
971 	{
972 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
973 			vertexCount = 4;
974 			break;
975 		case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
976 			vertexCount = 6;
977 			break;
978 		default:	DE_ASSERT(0);
979 			break;
980 	};
981 
982 	std::unique_ptr<vk::BufferWithMemory>	outBuffer			= makeBufferForImage(vk, device, allocator, mapVkFormat(colorFormat), extent);
983 	vk::Allocation&							outBufferAlloc		= outBuffer->getAllocation();
984 
985 	createPipeline(pipelineLayout, *renderPass);
986 
987 	beginCommandBuffer(vk, *cmdBuffer);
988 		renderPass.begin(vk, *cmdBuffer, vk::makeRect2D(0, 0, extent.width, extent.height), 1u, &clearColorValue);
989 		m_pipelineWrapper.bind(*cmdBuffer);
990 #ifndef CTS_USES_VULKANSC
991 		vk.cmdBindVertexBuffers2(*cmdBuffer, 0, m_params.bufferCount, vkBuffers.data(), offsets.data(), sizes.data(), strides.data());
992 #else
993 		vk.cmdBindVertexBuffers2EXT(*cmdBuffer, 0, m_params.bufferCount, vkBuffers.data(), offsets.data(), sizes.data(), strides.data());
994 #endif
995 		vk.cmdDraw(*cmdBuffer, vertexCount, 1, 0, 0);
996 		renderPass.end(vk, *cmdBuffer);
997 		vk::copyImageToBuffer(vk, *cmdBuffer, *colorImage, **outBuffer, tcu::IVec2(extent.width, extent.height));
998 	endCommandBuffer(vk, *cmdBuffer);
999 
1000 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1001 
1002 	invalidateAlloc(vk, device, outBufferAlloc);
1003 	const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(colorFormat), extent.width, extent.height, 1, outBufferAlloc.getHostPtr());
1004 
1005 	bool		testPasses		= false;
1006 	deUint32	equalClearCount = 0;
1007 	deUint32	halfWidth		= m_params.width / 2;
1008 	deUint32	halfHeight		= m_params.height / 2;
1009 
1010 	for (deUint32 Y = 0; (Y < halfHeight); ++Y)
1011 	for (deUint32 X = 0; (X < halfWidth); ++X)
1012 	{
1013 		const tcu::Vec4 px = result.getPixel(X, Y);
1014 		if (	px.x() == clearColorValue.color.float32[0]
1015 			&&	px.y() == clearColorValue.color.float32[1]
1016 			&&	px.z() == clearColorValue.color.float32[2])
1017 		{
1018 			equalClearCount = equalClearCount + 1;
1019 		}
1020 	}
1021 	const double mismatch = double(equalClearCount) / double(halfWidth * halfHeight);
1022 	const std::string mismatchText = "Mismatch: " + std::to_string(deUint32(mismatch * 100.9)) + '%';
1023 
1024 	const float			eps				= 0.2f;
1025 	const tcu::Vec3		threshold		(eps, eps, eps);
1026 	const tcu::UVec2	middle			(halfWidth - 1u, halfHeight - 1u);
1027 	const tcu::Vec4		rgba			= result.getPixel(middle.x(), middle.y());
1028 	const tcu::Vec3		rgb				= rgba.swizzle(0, 1, 2);
1029 	const bool			belowThreshold	= tcu::boolAll(tcu::lessThan(rgb, threshold));
1030 
1031 	if (!m_robustness2)
1032 	{
1033 		const auto expectedMismatch = 0.0;
1034 		testPasses = (belowThreshold == false) && (mismatch == expectedMismatch);
1035 		if (!testPasses)
1036 		{
1037 			std::ostringstream msg;
1038 			msg << "FAILURE: no robustness; pixel at " << middle << " is " << rgb << " (should be >= "
1039 			    << threshold << "); mismatch in upper left quarter " << mismatch << " (should be " << expectedMismatch << ")";
1040 			log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1041 		}
1042 	}
1043 	else
1044 	{
1045 		const auto mismatchLimit = 0.25;
1046 		testPasses = (belowThreshold == true) && (mismatch < mismatchLimit);
1047 		if (!testPasses)
1048 		{
1049 			std::ostringstream msg;
1050 			msg << "FAILURE: robustness2; pixel at " << middle << " is " << rgb
1051 			    << " (should be < " << threshold << "); mismatch in upper left quarter " << mismatch
1052 				<< " (should be below " << mismatchLimit << ")";
1053 			log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
1054 		}
1055 	}
1056 
1057 	auto logOffsets = (log << tcu::TestLog::Message << "Offsets: ");
1058 	for (deUint32 k = 0; k < m_params.bufferCount; ++k) {
1059 		if (k) logOffsets << ", ";
1060 		logOffsets << offsets[k];
1061 	} logOffsets << tcu::TestLog::EndMessage;
1062 
1063 	auto logSizes = (log << tcu::TestLog::Message << "Sizes: ");
1064 	for (deUint32 k = 0; k < m_params.bufferCount; ++k) {
1065 		if (k) logSizes << ", ";
1066 		logSizes << ((sizes[k] == VK_WHOLE_SIZE) ? "WHOLE_SIZE" : std::to_string(sizes[k]).c_str());
1067 	} logSizes << tcu::TestLog::EndMessage;
1068 
1069 	auto logStrides = (log << tcu::TestLog::Message << "Strides: ");
1070 	for (deUint32 k = 0; k < m_params.bufferCount; ++k) {
1071 		if (k) logStrides << ", ";
1072 		logStrides << strides[k];
1073 	} logStrides << tcu::TestLog::EndMessage;
1074 
1075 	if (!testPasses)
1076 	{
1077 		std::ostringstream os;
1078 		os << (m_params.topology == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ? "list" : "strip");
1079 		os << ".buffs" << m_params.bufferCount;
1080 		os << (m_params.wholeSize ? ".whole_size" : ".true_size");
1081 		if (m_robustness2)
1082 		{
1083 			os << ".robust";
1084 			os << (m_params.beyondType == BeyondType::BUFFER ? ".over_buff" : ".over_size");
1085 		}
1086 		os.flush();
1087 
1088 		log << tcu::TestLog::ImageSet("Result", "")
1089 			<< tcu::TestLog::Image(os.str(), "", result)
1090 			<< tcu::TestLog::EndImageSet;
1091 	}
1092 
1093 	if (!testPasses)
1094 		return tcu::TestStatus::fail(mismatchText + "; check log for details");
1095 	return tcu::TestStatus::pass(mismatchText);
1096 }
1097 
1098 class BindBuffers2Case : public vkt::TestCase
1099 {
1100 public:
BindBuffers2Case(tcu::TestContext & testCtx,const std::string & name,const vk::PipelineConstructionType pipelineConstructionType,const TestParams params,const bool singleBind,const deUint32 count)1101 					BindBuffers2Case	(tcu::TestContext& testCtx, const std::string& name, const vk::PipelineConstructionType	pipelineConstructionType, const TestParams params, const bool singleBind, const deUint32 count)
1102 						: vkt::TestCase					(testCtx, name)
1103 						, m_pipelineConstructionType	(pipelineConstructionType)
1104 						, m_params						(params)
1105 						, m_singleBind					(singleBind)
1106 						, m_count						(count)
1107 						{}
~BindBuffers2Case(void)1108 	virtual			~BindBuffers2Case	(void) {}
1109 
1110 	void			checkSupport			(vkt::Context& context) const override;
1111 	virtual void	initPrograms			(vk::SourceCollections& programCollection) const override;
createInstance(Context & context) const1112 	TestInstance*	createInstance			(Context& context) const override { return new BindBuffers2Instance(context, m_pipelineConstructionType, m_params, m_singleBind, m_count); }
1113 
1114 private:
1115 	const vk::PipelineConstructionType	m_pipelineConstructionType;
1116 	const TestParams					m_params;
1117 	const bool							m_singleBind;
1118 	const deUint32						m_count;
1119 };
1120 
checkSupport(Context & context) const1121 void BindBuffers2Case::checkSupport(Context& context) const
1122 {
1123 	context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
1124 
1125 	vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
1126 }
1127 
initPrograms(vk::SourceCollections & programCollection) const1128 void BindBuffers2Case::initPrograms(vk::SourceCollections& programCollection) const
1129 {
1130 	std::stringstream vert;
1131 	std::stringstream frag;
1132 
1133 	std::string inputs;
1134 	std::string combined;
1135 	if (m_count == 2)
1136 	{
1137 		inputs =
1138 			"layout (location=0) in vec2 rg;\n"
1139 			"layout (location=1) in vec2 xy;\n"
1140 			"layout (location=2) in vec2 ba;\n"
1141 			"layout (location=3) in vec2 zw;\n";
1142 		combined =
1143 			"    vec4 vertex = vec4(xy, zw);\n"
1144 			"    vec4 color = vec4(rg, ba);\n";
1145 	}
1146 	else if (m_count == 3)
1147 	{
1148 		inputs =
1149 			"layout (location=0) in vec2 rg;\n"
1150 			"layout (location=1) in vec2 xy;\n"
1151 			"layout (location=2) in float b;\n"
1152 			"layout (location=3) in float z;\n"
1153 			"layout (location=4) in float a;\n"
1154 			"layout (location=5) in float w;\n";
1155 		combined =
1156 			"    vec4 vertex = vec4(xy, z, w);\n"
1157 			"    vec4 color = vec4(rg, b, a);\n";
1158 	}
1159 	else if (m_count == 4)
1160 	{
1161 		inputs =
1162 			"layout (location=0) in float r;\n"
1163 			"layout (location=1) in float x;\n"
1164 			"layout (location=2) in float g;\n"
1165 			"layout (location=3) in float y;\n"
1166 			"layout (location=4) in float b;\n"
1167 			"layout (location=5) in float z;\n"
1168 			"layout (location=6) in float a;\n"
1169 			"layout (location=7) in float w;\n";
1170 		combined =
1171 			"    vec4 vertex = vec4(x, y, z, w);\n"
1172 			"    vec4 color = vec4(r, g, b, a);\n";
1173 	}
1174 	else
1175 	{
1176 		inputs =
1177 			"layout (location=0) in vec4 rgba;\n"
1178 			"layout (location=1) in vec4 xyzw;\n";
1179 		combined =
1180 			"    vec4 vertex = vec4(xyzw);\n"
1181 			"    vec4 color = vec4(rgba);\n";
1182 	}
1183 
1184 	vert
1185 		<< "#version 450\n"
1186 		<< inputs
1187 		<< "layout (location=0) out vec4 outColor;\n"
1188 		<< "void main() {\n"
1189 		<< "    vec2 pos = vec2(-float(gl_InstanceIndex & 1), -float((gl_InstanceIndex >> 1) & 1));\n"
1190 		<< combined
1191 		<< "    gl_Position = vertex + vec4(pos, 0.0f, 1.0f);\n"
1192 		<< "    outColor = color;\n"
1193 		<< "}\n";
1194 
1195 	frag
1196 		<< "#version 450\n"
1197 		<< "layout (location=0) in vec4 inColor;\n"
1198 		<< "layout (location=0) out vec4 outColor;\n"
1199 		<< "void main() {\n"
1200 		<< "    outColor = inColor;\n"
1201 		<< "}\n";
1202 
1203 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1204 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
1205 }
1206 
1207 class BindVertexBuffers2Case : public vkt::TestCase
1208 {
1209 public:
BindVertexBuffers2Case(tcu::TestContext & testCtx,const std::string & name,vk::PipelineConstructionType pipelineConstructionType,const TestParamsMaint5 & params,bool robustness2)1210 					BindVertexBuffers2Case	(tcu::TestContext&				testCtx,
1211 											 const std::string&				name,
1212 											 vk::PipelineConstructionType	pipelineConstructionType,
1213 											 const TestParamsMaint5&		params,
1214 											 bool							robustness2)
1215 						: vkt::TestCase(testCtx, name)
1216 						, m_pipelineConstructionType(pipelineConstructionType)
1217 						, m_params(params)
1218 						, m_robustness2(robustness2) { }
1219 	virtual			~BindVertexBuffers2Case	(void) = default;
1220 
1221 	void			checkSupport			(vkt::Context&					context) const override;
1222 	virtual void	initPrograms			(vk::SourceCollections&			programCollection) const override;
1223 	TestInstance*	createInstance			(Context&						context) const override;
1224 
1225 private:
1226 	const vk::PipelineConstructionType	m_pipelineConstructionType;
1227 	const TestParamsMaint5				m_params;
1228 	const bool							m_robustness2;
1229 };
1230 
checkSupport(Context & context) const1231 void BindVertexBuffers2Case::checkSupport (Context& context) const
1232 {
1233 	context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
1234 
1235 #ifndef CTS_USES_VULKANSC
1236 	context.requireDeviceFunctionality(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
1237 #endif // CTS_USES_VULKANSC
1238 
1239 	if (m_robustness2)
1240 	{
1241 		vk::VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = vk::initVulkanStructure();
1242 		vk::VkPhysicalDeviceFeatures2 features2 = vk::initVulkanStructure(&robustness2Features);
1243 
1244 		context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
1245 		if (!features2.features.robustBufferAccess)
1246 			TCU_THROW(NotSupportedError, "robustBufferAccess not supported by this implementation");
1247 
1248 		context.requireDeviceFunctionality("VK_EXT_robustness2");
1249 		if (!robustness2Features.robustBufferAccess2)
1250 			TCU_THROW(NotSupportedError, "robustBufferAccess2 not supported by this implementation");
1251 	}
1252 
1253 	vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
1254 }
1255 
initPrograms(vk::SourceCollections & programCollection) const1256 void BindVertexBuffers2Case::initPrograms (vk::SourceCollections& programCollection) const
1257 {
1258 	std::ostringstream	vert;
1259 	vert << "#version 450\n";
1260 	vert << "layout(location = 0) in vec3 in_color;\n";
1261 	for (deUint32 i = 1; i < m_params.bufferCount; ++i)
1262 		vert << "layout(location = " << i << ") in vec2 pos" << i << ";\n";
1263 	vert << "layout(location = 0) out vec3 out_color;\n";
1264 	vert << "void main() {\n";
1265 	vert << "  gl_Position = vec4(";
1266 	for (deUint32 i = 1; i < m_params.bufferCount; ++i)
1267 	{
1268 		if (i > 1) vert << '+';
1269 		vert << "pos" << i;
1270 	}
1271 	vert << ", 0.0, 1.0);\n";
1272 	vert << "  out_color = in_color;\n";
1273 	vert << "}\n";
1274 	vert.flush();
1275 
1276 	const std::string frag(
1277 		"#version 450\n"
1278 		"layout (location = 0) in  vec3 in_color;\n"
1279 		"layout (location = 0) out vec4 out_color;\n"
1280 		"void main() {\n"
1281 		"    out_color = vec4(in_color, 1.0);\n"
1282 		"}\n"
1283 	);
1284 
1285 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
1286 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag);
1287 }
1288 
createInstance(Context & context) const1289 TestInstance* BindVertexBuffers2Case::createInstance (Context& context) const
1290 {
1291 	DevicePtr		device;
1292 	DeviceDriverPtr	driver;
1293 
1294 	if (m_robustness2)
1295 	{
1296 		vk::VkPhysicalDeviceFeatures2							features2				= vk::initVulkanStructure();
1297 		vk::VkPhysicalDeviceRobustness2FeaturesEXT				robustness2Features		= vk::initVulkanStructure();
1298 #ifndef CTS_USES_VULKANSC
1299 		vk::VkPhysicalDeviceMaintenance5FeaturesKHR				maintenance5Features	= vk::initVulkanStructure();
1300 		vk::VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT	gplFeatures				= vk::initVulkanStructure();
1301 		vk::VkPhysicalDeviceShaderObjectFeaturesEXT				shaderObjectFeatures	= vk::initVulkanStructure();
1302 #endif // CTS_USES_VULKANSC
1303 
1304 		features2.features.robustBufferAccess		= VK_TRUE;
1305 		robustness2Features.robustBufferAccess2		= VK_TRUE;
1306 #ifndef CTS_USES_VULKANSC
1307 		maintenance5Features.maintenance5			= VK_TRUE;
1308 		gplFeatures.graphicsPipelineLibrary			= VK_TRUE;
1309 		shaderObjectFeatures.shaderObject			= VK_TRUE;
1310 #endif // CTS_USES_VULKANSC
1311 
1312 		const auto addFeatures = vk::makeStructChainAdder(&features2);
1313 		addFeatures(&robustness2Features);
1314 
1315 #ifndef CTS_USES_VULKANSC
1316 		addFeatures(&maintenance5Features);
1317 		if (vk::isConstructionTypeLibrary(m_pipelineConstructionType))
1318 			addFeatures(&gplFeatures);
1319 		else if (vk::isConstructionTypeShaderObject(m_pipelineConstructionType))
1320 			addFeatures(&shaderObjectFeatures);
1321 #else
1322 		TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_graphics_pipeline_library");
1323 #endif // CTS_USES_VULKANSC
1324 
1325 		device = createRobustBufferAccessDevice(context, &features2);
1326 		driver =
1327 #ifndef CTS_USES_VULKANSC
1328 			DeviceDriverPtr(new vk::DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion()));
1329 #else
1330 			DeviceDriverPtr(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(),
1331 				context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()),
1332 				vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
1333 #endif // CTS_USES_VULKANSC
1334 	}
1335 
1336 	return (new BindVertexBuffers2Instance(context, driver, device, m_pipelineConstructionType, m_params, m_robustness2));
1337 }
1338 
1339 tcu::TestCaseGroup* createCmdBindVertexBuffers2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType);
createCmdBindBuffers2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1340 tcu::TestCaseGroup* createCmdBindBuffers2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
1341 {
1342 	de::MovePtr<tcu::TestCaseGroup> cmdBindBuffers2Group(new tcu::TestCaseGroup(testCtx, "bind_buffers_2"));
1343 
1344 	const struct
1345 	{
1346 		TestParams	params;
1347 		const char* name;
1348 	} strideTests[] =
1349 	{
1350 		// Values are multiplied by sizeof(float) in the test
1351 		{ {0u,		4u,		0u,		0u,		},	"stride_0_4_offset_0_0"		},
1352 		{ {0u,		4u,		1u,		0u,		},	"stride_0_4_offset_1_0"		},
1353 		{ {4u,		4u,		0u,		0u,		},	"stride_4_4_offset_0_0"		},
1354 		{ {5u,		5u,		0u,		7u,		},	"stride_5_5_offset_0_7"		},
1355 		{ {5u,		8u,		15u,	22u,	},	"stride_5_8_offset_15_22"	},
1356 		{ {7u,		22u,	100u,	0u,		},	"stride_7_22_offset_100_0"	},
1357 		{ {40u,		28u,	0u,		0u,		},	"stride_40_28_offset_0_0"	},
1358 	};
1359 
1360 	const struct
1361 	{
1362 		bool		singleBind;
1363 		const char* name;
1364 	} bindTests[] =
1365 	{
1366 		// Values are multiplied by sizeof(float) in the test
1367 		{ true,		"single"		},
1368 		{ false,	"separate"		},
1369 	};
1370 
1371 	const struct
1372 	{
1373 		deUint32	count;
1374 		const char* name;
1375 	} countTests[] =
1376 	{
1377 		{ 1,		"count_1"		},
1378 		{ 2,		"count_2"		},
1379 		{ 3,		"count_3"		},
1380 		{ 4,		"count_4"		},
1381 	};
1382 
1383 	for (const auto bindTest : bindTests)
1384 	{
1385 		de::MovePtr<tcu::TestCaseGroup> bindGroup(new tcu::TestCaseGroup(testCtx, bindTest.name));
1386 		for (const auto& strideTest : strideTests)
1387 		{
1388 			de::MovePtr<tcu::TestCaseGroup> typeGroup(new tcu::TestCaseGroup(testCtx, strideTest.name));
1389 			for (const auto& countTest : countTests)
1390 			{
1391 				typeGroup->addChild(new BindBuffers2Case(testCtx, countTest.name, pipelineConstructionType, strideTest.params, bindTest.singleBind, countTest.count));
1392 			}
1393 			bindGroup->addChild(typeGroup.release());
1394 		}
1395 		cmdBindBuffers2Group->addChild(bindGroup.release());
1396 	}
1397 
1398 #ifndef CTS_USES_VULKANSC
1399 	cmdBindBuffers2Group->addChild(createCmdBindVertexBuffers2Tests(testCtx, pipelineConstructionType));
1400 #endif // CTS_USES_VULKANSC
1401 
1402 	return cmdBindBuffers2Group.release();
1403 }
1404 
createCmdBindVertexBuffers2Tests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)1405 tcu::TestCaseGroup* createCmdBindVertexBuffers2Tests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
1406 {
1407 	const deUint32	counts[]		{ 5, 9 };
1408 	const deUint32	randoms[]		{ 321, 432 };
1409 	const deUint32	robustRandoms[]	{ 543, 654 };
1410 	const std::pair<bool, const char*> sizes[] {
1411 		{ true,   "whole_size"	},
1412 		{ false,  "true_size"	}
1413 	};
1414 	const std::pair<BeyondType, const char*> beyondTypes[] {
1415 		{ BeyondType::BUFFER,	"beyond_buffer"	},
1416 		{ BeyondType::SIZE,		"beyond_size"	}
1417 	};
1418 	const std::pair<vk::VkPrimitiveTopology, const char*> topos[] {
1419 		{ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	"triangle_list"		},
1420 		{ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	"triangle_strip"	},
1421 	};
1422 
1423 	std::string name;
1424 	const deUint32 defaultWidth = 32;
1425 	const deUint32 defaultHeight = 32;
1426 
1427 	de::MovePtr<tcu::TestCaseGroup> rootGroup(new tcu::TestCaseGroup(testCtx, "maintenance5", ""));
1428 
1429 	for (const auto& topo : topos)
1430 	{
1431 		de::MovePtr<tcu::TestCaseGroup> topoGroup(new tcu::TestCaseGroup(testCtx, topo.second, ""));
1432 
1433 		for (deUint32 count : counts)
1434 		{
1435 			name = "buffers" + std::to_string(count);
1436 			de::MovePtr<tcu::TestCaseGroup> countGroup(new tcu::TestCaseGroup(testCtx, name.c_str(), ""));
1437 
1438 			for (deUint32 random : randoms)
1439 			{
1440 				name = "stride_offset_rnd" + std::to_string(random);
1441 				de::MovePtr<tcu::TestCaseGroup> randomGroup(new tcu::TestCaseGroup(testCtx, name.c_str(), ""));
1442 
1443 				for (const auto& size : sizes)
1444 				{
1445 					TestParamsMaint5 p;
1446 					p.width			= defaultWidth;
1447 					p.height		= defaultHeight;
1448 					p.topology		= topo.first;
1449 					p.wholeSize		= size.first;
1450 					p.rndSeed		= random;
1451 					p.bufferCount	= count;
1452 					p.beyondType	= BeyondType::BUFFER;
1453 
1454 					randomGroup->addChild(new BindVertexBuffers2Case(testCtx, size.second, pipelineConstructionType, p, false));
1455 				}
1456 				countGroup->addChild(randomGroup.release());
1457 			}
1458 			topoGroup->addChild(countGroup.release());
1459 		}
1460 		rootGroup->addChild(topoGroup.release());
1461 	}
1462 
1463 	de::MovePtr<tcu::TestCaseGroup> robustGroup(new tcu::TestCaseGroup(testCtx, "robustness2", ""));
1464 	for (const auto& topo : topos)
1465 	{
1466 		de::MovePtr<tcu::TestCaseGroup> topoGroup(new tcu::TestCaseGroup(testCtx, topo.second, ""));
1467 
1468 		for (deUint32 count : counts)
1469 		{
1470 			name = "buffers" + std::to_string(count);
1471 			de::MovePtr<tcu::TestCaseGroup> countGroup(new tcu::TestCaseGroup(testCtx, name.c_str(), ""));
1472 
1473 			for (deUint32 random : robustRandoms)
1474 			{
1475 				name = "stride_offset_rnd" + std::to_string(random);
1476 				de::MovePtr<tcu::TestCaseGroup> randomGroup(new tcu::TestCaseGroup(testCtx, name.c_str(), ""));
1477 
1478 				for (const auto& size : sizes)
1479 				{
1480 					de::MovePtr<tcu::TestCaseGroup> sizeGroup(new tcu::TestCaseGroup(testCtx, size.second, ""));
1481 
1482 					TestParamsMaint5 p;
1483 					p.width			= defaultWidth;
1484 					p.height		= defaultHeight;
1485 					p.topology		= topo.first;
1486 					p.wholeSize		= size.first;
1487 					p.rndSeed		= random;
1488 					p.bufferCount	= count;
1489 
1490 					if (p.wholeSize)
1491 					{
1492 						p.beyondType = BeyondType::BUFFER;
1493 						auto beyondType = std::find_if(std::begin(beyondTypes), std::end(beyondTypes),
1494 							[&](const std::pair<BeyondType, const char*>& b) { return b.first == p.beyondType; });
1495 						sizeGroup->addChild(new BindVertexBuffers2Case(testCtx, beyondType->second, pipelineConstructionType, p, true));
1496 					}
1497 					else
1498 					{
1499 						for (const auto& beyondType : beyondTypes)
1500 						{
1501 							p.beyondType = beyondType.first;
1502 							sizeGroup->addChild(new BindVertexBuffers2Case(testCtx, beyondType.second, pipelineConstructionType, p, true));
1503 						}
1504 					}
1505 					randomGroup->addChild(sizeGroup.release());
1506 				}
1507 				countGroup->addChild(randomGroup.release());
1508 			}
1509 			topoGroup->addChild(countGroup.release());
1510 		}
1511 		robustGroup->addChild(topoGroup.release());
1512 	}
1513 	rootGroup->addChild(robustGroup.release());
1514 
1515 	return rootGroup.release();
1516 }
1517 
1518 } // pipeline
1519 } // vkt
1520