1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2016 Imagination Technologies Ltd.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*!
21 * \file
22 * \brief Robust Vertex Buffer Access Tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktRobustnessVertexAccessTests.hpp"
26#include "vktRobustnessUtil.hpp"
27#include "vktTestCaseUtil.hpp"
28#include "vkBuilderUtil.hpp"
29#include "vkImageUtil.hpp"
30#include "vkMemUtil.hpp"
31#include "vkPrograms.hpp"
32#include "vkQueryUtil.hpp"
33#include "vkDeviceUtil.hpp"
34#include "vkRef.hpp"
35#include "vkRefUtil.hpp"
36#include "vkTypeUtil.hpp"
37#include "tcuTestLog.hpp"
38#include "deMath.h"
39#include "deUniquePtr.hpp"
40#include <vector>
41
42namespace vkt
43{
44namespace robustness
45{
46
47using namespace vk;
48
49typedef std::vector<VkVertexInputBindingDescription>	BindingList;
50typedef std::vector<VkVertexInputAttributeDescription>	AttributeList;
51
52class VertexAccessTest : public vkt::TestCase
53{
54public:
55						VertexAccessTest	(tcu::TestContext&		testContext,
56											 const std::string&		name,
57											 VkFormat				inputFormat,
58											 deUint32				numVertexValues,
59											 deUint32				numInstanceValues,
60											 deUint32				numVertices,
61											 deUint32				numInstances);
62
63	virtual				~VertexAccessTest	(void) {}
64
65	void				initPrograms		(SourceCollections& programCollection) const;
66	void				checkSupport		(Context& context) const;
67	TestInstance*		createInstance		(Context& context) const = 0;
68
69protected:
70	const VkFormat		m_inputFormat;
71	const deUint32		m_numVertexValues;
72	const deUint32		m_numInstanceValues;
73	const deUint32		m_numVertices;
74	const deUint32		m_numInstances;
75
76};
77
78class DrawAccessTest : public VertexAccessTest
79{
80public:
81						DrawAccessTest		(tcu::TestContext&		testContext,
82											 const std::string&		name,
83											 VkFormat				inputFormat,
84											 deUint32				numVertexValues,
85											 deUint32				numInstanceValues,
86											 deUint32				numVertices,
87											 deUint32				numInstances);
88
89	virtual				~DrawAccessTest		(void) {}
90	TestInstance*		createInstance		(Context& context) const;
91
92protected:
93};
94
95class DrawIndexedAccessTest : public VertexAccessTest
96{
97public:
98	enum IndexConfig
99	{
100		INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS,
101		INDEX_CONFIG_INDICES_OUT_OF_BOUNDS,
102		INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS,
103
104		INDEX_CONFIG_COUNT
105	};
106
107	const static std::vector<deUint32> s_indexConfigs[INDEX_CONFIG_COUNT];
108
109						DrawIndexedAccessTest		(tcu::TestContext&		testContext,
110													 const std::string&		name,
111													 VkFormat				inputFormat,
112													 IndexConfig			indexConfig);
113
114	virtual				~DrawIndexedAccessTest		(void) {}
115	TestInstance*		createInstance				(Context& context) const;
116
117protected:
118	const IndexConfig	m_indexConfig;
119};
120
121class VertexAccessInstance : public vkt::TestInstance
122{
123public:
124										VertexAccessInstance					(Context&						context,
125																				 Move<VkDevice>					device,
126#ifndef CTS_USES_VULKANSC
127																				 de::MovePtr<vk::DeviceDriver>	deviceDriver,
128#else
129																				 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
130#endif // CTS_USES_VULKANSC
131																				 VkFormat						inputFormat,
132																				 deUint32						numVertexValues,
133																				 deUint32						numInstanceValues,
134																				 deUint32						numVertices,
135																				 deUint32						numInstances,
136																				 const std::vector<deUint32>&	indices);
137
138	virtual								~VertexAccessInstance					(void);
139	virtual tcu::TestStatus				iterate									(void);
140	virtual bool						verifyResult							(void);
141
142private:
143	bool								isValueWithinVertexBufferOrZero			(void* vertexBuffer, VkDeviceSize vertexBufferSize, const void* value, deUint32 valueIndexa);
144
145protected:
146	static bool							isExpectedValueFromVertexBuffer			(const void* vertexBuffer, deUint32 vertexIndex, VkFormat vertexFormat, const void* value);
147	static VkDeviceSize					getBufferSizeInBytes					(deUint32 numScalars, VkFormat format);
148
149	virtual void						initVertexIds							(deUint32 *indicesPtr, size_t indexCount) = 0;
150	virtual deUint32					getIndex								(deUint32 vertexNum) const = 0;
151
152	Move<VkDevice>						m_device;
153#ifndef CTS_USES_VULKANSC
154	de::MovePtr<vk::DeviceDriver>		m_deviceDriver;
155#else
156	de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	m_deviceDriver;
157#endif // CTS_USES_VULKANSC
158
159	const VkFormat						m_inputFormat;
160	const deUint32						m_numVertexValues;
161	const deUint32						m_numInstanceValues;
162	const deUint32						m_numVertices;
163	const deUint32						m_numInstances;
164	AttributeList						m_vertexInputAttributes;
165	BindingList							m_vertexInputBindings;
166
167	Move<VkBuffer>						m_vertexRateBuffer;
168	VkDeviceSize						m_vertexRateBufferSize;
169	de::MovePtr<Allocation>				m_vertexRateBufferAlloc;
170	VkDeviceSize						m_vertexRateBufferAllocSize;
171
172	Move<VkBuffer>						m_instanceRateBuffer;
173	VkDeviceSize						m_instanceRateBufferSize;
174	de::MovePtr<Allocation>				m_instanceRateBufferAlloc;
175	VkDeviceSize						m_instanceRateBufferAllocSize;
176
177	Move<VkBuffer>						m_vertexNumBuffer;
178	VkDeviceSize						m_vertexNumBufferSize;
179	de::MovePtr<Allocation>				m_vertexNumBufferAlloc;
180
181	Move<VkBuffer>						m_indexBuffer;
182	VkDeviceSize						m_indexBufferSize;
183	de::MovePtr<Allocation>				m_indexBufferAlloc;
184
185	Move<VkBuffer>						m_outBuffer; // SSBO
186	VkDeviceSize						m_outBufferSize;
187	de::MovePtr<Allocation>				m_outBufferAlloc;
188	VkDeviceSize						m_outBufferAllocSize;
189
190	Move<VkDescriptorPool>				m_descriptorPool;
191	Move<VkDescriptorSetLayout>			m_descriptorSetLayout;
192	Move<VkDescriptorSet>				m_descriptorSet;
193
194	Move<VkFence>						m_fence;
195	VkQueue								m_queue;
196
197	de::MovePtr<GraphicsEnvironment>	m_graphicsTestEnvironment;
198};
199
200class DrawAccessInstance : public VertexAccessInstance
201{
202public:
203						DrawAccessInstance	(Context&				context,
204											 Move<VkDevice>			device,
205#ifndef CTS_USES_VULKANSC
206											de::MovePtr<vk::DeviceDriver>	deviceDriver,
207#else
208											de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
209#endif // CTS_USES_VULKANSC
210											 VkFormat				inputFormat,
211											 deUint32				numVertexValues,
212											 deUint32				numInstanceValues,
213											 deUint32				numVertices,
214											 deUint32				numInstances);
215
216	virtual				~DrawAccessInstance	(void) {}
217
218protected:
219	virtual void		initVertexIds		(deUint32 *indicesPtr, size_t indexCount);
220	virtual deUint32	getIndex			(deUint32 vertexNum) const;
221};
222
223class DrawIndexedAccessInstance : public VertexAccessInstance
224{
225public:
226										DrawIndexedAccessInstance	(Context&						context,
227																	 Move<VkDevice>					device,
228#ifndef CTS_USES_VULKANSC
229																	 de::MovePtr<vk::DeviceDriver>		deviceDriver,
230#else
231																	 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
232#endif // CTS_USES_VULKANSC
233																	 VkFormat						inputFormat,
234																	 deUint32						numVertexValues,
235																	 deUint32						numInstanceValues,
236																	 deUint32						numVertices,
237																	 deUint32						numInstances,
238																	 const std::vector<deUint32>&	indices);
239
240	virtual								~DrawIndexedAccessInstance	(void) {}
241
242protected:
243	virtual void						initVertexIds				(deUint32 *indicesPtr, size_t indexCount);
244	virtual deUint32					getIndex					(deUint32 vertexNum) const;
245
246	const std::vector<deUint32>			m_indices;
247};
248
249// VertexAccessTest
250
251VertexAccessTest::VertexAccessTest (tcu::TestContext&		testContext,
252									const std::string&		name,
253									VkFormat				inputFormat,
254									deUint32				numVertexValues,
255									deUint32				numInstanceValues,
256									deUint32				numVertices,
257									deUint32				numInstances)
258
259	: vkt::TestCase				(testContext, name)
260	, m_inputFormat				(inputFormat)
261	, m_numVertexValues			(numVertexValues)
262	, m_numInstanceValues		(numInstanceValues)
263	, m_numVertices				(numVertices)
264	, m_numInstances			(numInstances)
265{
266}
267
268
269void VertexAccessTest::checkSupport(Context& context) const
270{
271	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getDeviceFeatures().robustBufferAccess)
272		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
273}
274
275void VertexAccessTest::initPrograms (SourceCollections& programCollection) const
276{
277	std::ostringstream		attributeDeclaration;
278	std::ostringstream		attributeUse;
279
280	std::ostringstream		vertexShaderSource;
281	std::ostringstream		fragmentShaderSource;
282
283	std::ostringstream		attributeTypeStr;
284	const int				numChannels				= getNumUsedChannels(mapVkFormat(m_inputFormat).order);
285	const deUint32			numScalarsPerVertex		= numChannels * 3; // Use 3 identical attributes
286	deUint32				numValues				= 0;
287
288	const bool				isR64					= (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT);
289
290	if (numChannels == 1)
291	{
292		if (isUintFormat(m_inputFormat))
293			attributeTypeStr << "uint";
294		else if (isIntFormat(m_inputFormat))
295			attributeTypeStr << "int";
296		else
297			attributeTypeStr << "float";
298
299		attributeTypeStr << (isR64 ? "64_t" : " ");
300	}
301	else
302	{
303		if (isUintFormat(m_inputFormat))
304			attributeTypeStr << "uvec";
305		else if (isIntFormat(m_inputFormat))
306			attributeTypeStr << "ivec";
307		else
308			attributeTypeStr << "vec";
309
310		attributeTypeStr << numChannels;
311	}
312
313	for (int attrNdx = 0; attrNdx < 3; attrNdx++)
314	{
315		attributeDeclaration << "layout(location = " << attrNdx << ") in " << attributeTypeStr.str() << " attr" << attrNdx << ";\n";
316
317		for (int chanNdx = 0; chanNdx < numChannels; chanNdx++)
318		{
319			attributeUse << "\toutData[(gl_InstanceIndex * " << numScalarsPerVertex * m_numVertices
320						 << ") + (vertexNum * " << numScalarsPerVertex << " + " << numValues++ << ")] = attr" << attrNdx;
321
322			if (numChannels == 1)
323				attributeUse << ";\n";
324			else
325				attributeUse << "[" << chanNdx << "];\n";
326		}
327	}
328
329	attributeDeclaration << "layout(location = 3) in int vertexNum;\n";
330
331	attributeUse << "\n";
332
333	std::string outType = "";
334	if (isUintFormat(m_inputFormat))
335		outType = "uint";
336	else if (isIntFormat(m_inputFormat))
337		outType = "int";
338	else
339		outType = "float";
340
341	outType += isR64 ? "64_t" : "";
342
343	std::string extensions	= "";
344	std::string version		= "#version 310 es\n";
345	if (isR64)
346	{
347		extensions	= "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
348		version		= "#version 440\n";
349	}
350
351	vertexShaderSource <<
352		version <<
353		"precision highp float;\n"
354		<< extensions
355		<< attributeDeclaration.str() <<
356		"layout(set = 0, binding = 0, std430) buffer outBuffer\n"
357		"{\n"
358		"\t" << outType << " outData[" << (m_numVertices * numValues) * m_numInstances << "];\n"
359		"};\n\n"
360		"void main (void)\n"
361		"{\n"
362		<< attributeUse.str() <<
363		"\tgl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
364		"}\n";
365
366	programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
367
368	fragmentShaderSource <<
369		"#version 310 es\n"
370		"precision highp float;\n"
371		"layout(location = 0) out vec4 fragColor;\n"
372		"void main (void)\n"
373		"{\n"
374		"\tfragColor = vec4(1.0);\n"
375		"}\n";
376
377	programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
378}
379
380// DrawAccessTest
381
382DrawAccessTest::DrawAccessTest (tcu::TestContext&		testContext,
383								const std::string&		name,
384								VkFormat				inputFormat,
385								deUint32				numVertexValues,
386								deUint32				numInstanceValues,
387								deUint32				numVertices,
388								deUint32				numInstances)
389
390	: VertexAccessTest		(testContext, name, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances)
391{
392}
393
394TestInstance* DrawAccessTest::createInstance (Context& context) const
395{
396	Move<VkDevice>	device = createRobustBufferAccessDevice(context);
397#ifndef CTS_USES_VULKANSC
398	de::MovePtr<vk::DeviceDriver>	deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion()));
399#else
400	de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()), vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
401#endif // CTS_USES_VULKANSC
402
403	return new DrawAccessInstance(context,
404								  device,
405								  deviceDriver,
406								  m_inputFormat,
407								  m_numVertexValues,
408								  m_numInstanceValues,
409								  m_numVertices,
410								  m_numInstances);
411}
412
413// DrawIndexedAccessTest
414
415const deUint32 lastIndexOutOfBounds[] =
416{
417	0, 1, 2, 3, 4, 100,		// Indices of 100 and above are out of bounds
418};
419const deUint32 indicesOutOfBounds[] =
420{
421	0, 100, 2, 101, 3, 102,	// Indices of 100 and above are out of bounds
422};
423const deUint32 triangleOutOfBounds[] =
424{
425	100, 101, 102, 3, 4, 5,	// Indices of 100 and above are out of bounds
426};
427
428const std::vector<deUint32> DrawIndexedAccessTest::s_indexConfigs[INDEX_CONFIG_COUNT] =
429{
430	std::vector<deUint32>(lastIndexOutOfBounds, lastIndexOutOfBounds + DE_LENGTH_OF_ARRAY(lastIndexOutOfBounds)),
431	std::vector<deUint32>(indicesOutOfBounds, indicesOutOfBounds + DE_LENGTH_OF_ARRAY(indicesOutOfBounds)),
432	std::vector<deUint32>(triangleOutOfBounds, triangleOutOfBounds + DE_LENGTH_OF_ARRAY(triangleOutOfBounds)),
433};
434
435DrawIndexedAccessTest::DrawIndexedAccessTest (tcu::TestContext&		testContext,
436											  const std::string&	name,
437											  VkFormat				inputFormat,
438											  IndexConfig			indexConfig)
439
440	: VertexAccessTest	(testContext,
441						 name,
442						 inputFormat,
443						 getNumUsedChannels(mapVkFormat(inputFormat).order) * (deUint32)s_indexConfigs[indexConfig].size() * 2,	// numVertexValues
444						 getNumUsedChannels(mapVkFormat(inputFormat).order),													// numInstanceValues
445						 (deUint32)s_indexConfigs[indexConfig].size(),															// numVertices
446						 1)																										// numInstances
447	, m_indexConfig		(indexConfig)
448{
449}
450
451TestInstance* DrawIndexedAccessTest::createInstance (Context& context) const
452{
453	Move<VkDevice>	device = createRobustBufferAccessDevice(context);
454#ifndef CTS_USES_VULKANSC
455	de::MovePtr<vk::DeviceDriver>	deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion()));
456#else
457	de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver = de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(), context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()), vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
458#endif // CTS_USES_VULKANSC
459
460	return new DrawIndexedAccessInstance(context,
461										 device,
462										 deviceDriver,
463										 m_inputFormat,
464										 m_numVertexValues,
465										 m_numInstanceValues,
466										 m_numVertices,
467										 m_numInstances,
468										 s_indexConfigs[m_indexConfig]);
469}
470
471// VertexAccessInstance
472
473VertexAccessInstance::VertexAccessInstance (Context&						context,
474											Move<VkDevice>					device,
475#ifndef CTS_USES_VULKANSC
476											de::MovePtr<vk::DeviceDriver>	deviceDriver,
477#else
478											de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
479#endif // CTS_USES_VULKANSC
480											VkFormat						inputFormat,
481											deUint32						numVertexValues,
482											deUint32						numInstanceValues,
483											deUint32						numVertices,
484											deUint32						numInstances,
485											const std::vector<deUint32>&	indices)
486
487	: vkt::TestInstance			(context)
488	, m_device					(device)
489	, m_deviceDriver			(deviceDriver)
490	, m_inputFormat				(inputFormat)
491	, m_numVertexValues			(numVertexValues)
492	, m_numInstanceValues		(numInstanceValues)
493	, m_numVertices				(numVertices)
494	, m_numInstances			(numInstances)
495{
496	const DeviceInterface&		vk						= *m_deviceDriver;
497	const deUint32				queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
498	const auto&					vki						= context.getInstanceInterface();
499	const VkPhysicalDevice		physicalDevice			= chooseDevice(vki, context.getInstance(), context.getTestContext().getCommandLine());
500	SimpleAllocator				memAlloc				(vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
501	const deUint32				formatSizeInBytes		= tcu::getPixelSize(mapVkFormat(m_inputFormat));
502
503	// Check storage support
504	if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
505	{
506		TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
507	}
508
509	if (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT)
510	{
511		const VkFormatProperties	formatProperties	= getPhysicalDeviceFormatProperties(vki, physicalDevice, m_inputFormat);
512		context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
513
514		if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
515			TCU_THROW(NotSupportedError, "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT not supported");
516	}
517
518
519	const VkVertexInputAttributeDescription attributes[] =
520	{
521		// input rate: vertex
522		{
523			0u,								// deUint32 location;
524			0u,								// deUint32 binding;
525			m_inputFormat,					// VkFormat format;
526			0u,								// deUint32 offset;
527		},
528		{
529			1u,								// deUint32 location;
530			0u,								// deUint32 binding;
531			m_inputFormat,					// VkFormat format;
532			formatSizeInBytes,				// deUint32 offset;
533		},
534
535		// input rate: instance
536		{
537			2u,								// deUint32 location;
538			1u,								// deUint32 binding;
539			m_inputFormat,					// VkFormat format;
540			0u,								// deUint32 offset;
541		},
542
543		// Attribute for vertex number
544		{
545			3u,								// deUint32 location;
546			2u,								// deUint32 binding;
547			VK_FORMAT_R32_SINT,				// VkFormat format;
548			0,								// deUint32 offset;
549		},
550	};
551
552	const VkVertexInputBindingDescription bindings[] =
553	{
554		{
555			0u,								// deUint32				binding;
556			formatSizeInBytes * 2,			// deUint32				stride;
557			VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputRate	inputRate;
558		},
559		{
560			1u,								// deUint32				binding;
561			formatSizeInBytes,				// deUint32				stride;
562			VK_VERTEX_INPUT_RATE_INSTANCE	// VkVertexInputRate	inputRate;
563		},
564		{
565			2u,								// deUint32				binding;
566			sizeof(deInt32),				// deUint32				stride;
567			VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputRate	inputRate;
568		},
569	};
570
571	m_vertexInputBindings	= std::vector<VkVertexInputBindingDescription>(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings));
572	m_vertexInputAttributes	= std::vector<VkVertexInputAttributeDescription>(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes));
573
574	// Create vertex buffer for vertex input rate
575	{
576		VkMemoryRequirements bufferMemoryReqs;
577
578		m_vertexRateBufferSize = getBufferSizeInBytes(m_numVertexValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
579
580		const VkBufferCreateInfo	vertexRateBufferParams	=
581		{
582			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
583			DE_NULL,									// const void*			pNext;
584			0u,											// VkBufferCreateFlags	flags;
585			m_vertexRateBufferSize,						// VkDeviceSize			size;
586			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
587			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
588			1u,											// deUint32				queueFamilyIndexCount;
589			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
590		};
591
592		m_vertexRateBuffer			= createBuffer(vk, *m_device, &vertexRateBufferParams);
593		bufferMemoryReqs			= getBufferMemoryRequirements(vk, *m_device, *m_vertexRateBuffer);
594		m_vertexRateBufferAllocSize	= bufferMemoryReqs.size;
595		m_vertexRateBufferAlloc		= memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
596
597		VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexRateBuffer, m_vertexRateBufferAlloc->getMemory(), m_vertexRateBufferAlloc->getOffset()));
598		populateBufferWithTestValues(m_vertexRateBufferAlloc->getHostPtr(), (deUint32)m_vertexRateBufferAllocSize, m_inputFormat);
599		flushMappedMemoryRange(vk, *m_device, m_vertexRateBufferAlloc->getMemory(), m_vertexRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
600	}
601
602	// Create vertex buffer for instance input rate
603	{
604		VkMemoryRequirements bufferMemoryReqs;
605
606		m_instanceRateBufferSize = getBufferSizeInBytes(m_numInstanceValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
607
608		const VkBufferCreateInfo	instanceRateBufferParams	=
609		{
610			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
611			DE_NULL,									// const void*			pNext;
612			0u,											// VkBufferCreateFlags	flags;
613			m_instanceRateBufferSize,					// VkDeviceSize			size;
614			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
615			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
616			1u,											// deUint32				queueFamilyIndexCount;
617			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
618		};
619
620		m_instanceRateBuffer			= createBuffer(vk, *m_device, &instanceRateBufferParams);
621		bufferMemoryReqs				= getBufferMemoryRequirements(vk, *m_device, *m_instanceRateBuffer);
622		m_instanceRateBufferAllocSize	= bufferMemoryReqs.size;
623		m_instanceRateBufferAlloc		= memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
624
625		VK_CHECK(vk.bindBufferMemory(*m_device, *m_instanceRateBuffer, m_instanceRateBufferAlloc->getMemory(), m_instanceRateBufferAlloc->getOffset()));
626		populateBufferWithTestValues(m_instanceRateBufferAlloc->getHostPtr(), (deUint32)m_instanceRateBufferAllocSize, m_inputFormat);
627		flushMappedMemoryRange(vk, *m_device, m_instanceRateBufferAlloc->getMemory(), m_instanceRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
628	}
629
630	// Create vertex buffer that stores the vertex number (from 0 to m_numVertices - 1)
631	{
632		m_vertexNumBufferSize = 128 * sizeof(deInt32); // Allocate enough device memory for all indices (0 to 127).
633
634		const VkBufferCreateInfo	vertexNumBufferParams	=
635		{
636			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
637			DE_NULL,									// const void*			pNext;
638			0u,											// VkBufferCreateFlags	flags;
639			m_vertexNumBufferSize,						// VkDeviceSize			size;
640			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
641			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
642			1u,											// deUint32				queueFamilyIndexCount;
643			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
644		};
645
646		m_vertexNumBuffer		= createBuffer(vk, *m_device, &vertexNumBufferParams);
647		m_vertexNumBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexNumBuffer), MemoryRequirement::HostVisible);
648
649		VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexNumBuffer, m_vertexNumBufferAlloc->getMemory(), m_vertexNumBufferAlloc->getOffset()));
650	}
651
652	// Create index buffer if required
653	if (!indices.empty())
654	{
655		m_indexBufferSize = sizeof(deUint32) * indices.size();
656
657		const VkBufferCreateInfo	indexBufferParams	=
658		{
659			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
660			DE_NULL,									// const void*			pNext;
661			0u,											// VkBufferCreateFlags	flags;
662			m_indexBufferSize,							// VkDeviceSize			size;
663			VK_BUFFER_USAGE_INDEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
664			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
665			1u,											// deUint32				queueFamilyIndexCount;
666			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
667		};
668
669		m_indexBuffer		= createBuffer(vk, *m_device, &indexBufferParams);
670		m_indexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indexBuffer), MemoryRequirement::HostVisible);
671
672		VK_CHECK(vk.bindBufferMemory(*m_device, *m_indexBuffer, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset()));
673		deMemcpy(m_indexBufferAlloc->getHostPtr(), indices.data(), (size_t)m_indexBufferSize);
674		flushMappedMemoryRange(vk, *m_device, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
675	}
676
677	// Create result ssbo
678	{
679		const int	numChannels	= getNumUsedChannels(mapVkFormat(m_inputFormat).order);
680
681		m_outBufferSize = getBufferSizeInBytes(m_numVertices * m_numInstances * numChannels * 3, VK_FORMAT_R32_UINT);
682
683		const VkBufferCreateInfo	outBufferParams		=
684		{
685			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
686			DE_NULL,									// const void*			pNext;
687			0u,											// VkBufferCreateFlags	flags;
688			m_outBufferSize,							// VkDeviceSize			size;
689			VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,			// VkBufferUsageFlags	usage;
690			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
691			1u,											// deUint32				queueFamilyIndexCount;
692			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
693		};
694
695		m_outBuffer								= createBuffer(vk, *m_device, &outBufferParams);
696		const VkMemoryRequirements requirements = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
697		m_outBufferAlloc						= memAlloc.allocate(requirements, MemoryRequirement::HostVisible);
698		m_outBufferAllocSize					= requirements.size;
699
700		VK_CHECK(vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
701		deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferSize);
702		flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(), VK_WHOLE_SIZE);
703	}
704
705	// Create descriptor set data
706	{
707		DescriptorPoolBuilder descriptorPoolBuilder;
708		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
709		m_descriptorPool = descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
710
711		DescriptorSetLayoutBuilder setLayoutBuilder;
712		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
713		m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
714
715		const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
716		{
717			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
718			DE_NULL,											// const void*					pNext;
719			*m_descriptorPool,									// VkDescriptorPool				desciptorPool;
720			1u,													// deUint32						setLayoutCount;
721			&m_descriptorSetLayout.get()						// const VkDescriptorSetLayout*	pSetLayouts;
722		};
723
724		m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
725
726		const VkDescriptorBufferInfo outBufferDescriptorInfo	= makeDescriptorBufferInfo(*m_outBuffer, 0ull, VK_WHOLE_SIZE);
727
728		DescriptorSetUpdateBuilder setUpdateBuilder;
729		setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outBufferDescriptorInfo);
730		setUpdateBuilder.update(vk, *m_device);
731	}
732
733	// Create fence
734	{
735		const VkFenceCreateInfo fenceParams =
736		{
737			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
738			DE_NULL,								// const void*			pNext;
739			0u										// VkFenceCreateFlags	flags;
740		};
741
742		m_fence = createFence(vk, *m_device, &fenceParams);
743	}
744
745	// Get queue
746	vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
747
748	// Setup graphics test environment
749	{
750		GraphicsEnvironment::DrawConfig drawConfig;
751
752		drawConfig.vertexBuffers.push_back(*m_vertexRateBuffer);
753		drawConfig.vertexBuffers.push_back(*m_instanceRateBuffer);
754		drawConfig.vertexBuffers.push_back(*m_vertexNumBuffer);
755
756		drawConfig.vertexCount		= m_numVertices;
757		drawConfig.instanceCount	= m_numInstances;
758		drawConfig.indexBuffer		= *m_indexBuffer;
759		drawConfig.indexCount		= (deUint32)(m_indexBufferSize / sizeof(deUint32));
760
761		m_graphicsTestEnvironment	= de::MovePtr<GraphicsEnvironment>(new GraphicsEnvironment(m_context,
762																							   *m_deviceDriver,
763																							   *m_device,
764																							   *m_descriptorSetLayout,
765																							   *m_descriptorSet,
766																							   GraphicsEnvironment::VertexBindings(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings)),
767																							   GraphicsEnvironment::VertexAttributes(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes)),
768																							   drawConfig));
769	}
770}
771
772VertexAccessInstance::~VertexAccessInstance(void)
773{
774}
775
776tcu::TestStatus VertexAccessInstance::iterate (void)
777{
778	const DeviceInterface&		vk			= *m_deviceDriver;
779	const vk::VkCommandBuffer	cmdBuffer	= m_graphicsTestEnvironment->getCommandBuffer();
780
781	// Initialize vertex ids
782	{
783		deUint32 *bufferPtr = reinterpret_cast<deUint32*>(m_vertexNumBufferAlloc->getHostPtr());
784		deMemset(bufferPtr, 0, (size_t)m_vertexNumBufferSize);
785
786		initVertexIds(bufferPtr, (size_t)(m_vertexNumBufferSize / sizeof(deUint32)));
787
788		flushMappedMemoryRange(vk, *m_device, m_vertexNumBufferAlloc->getMemory(), m_vertexNumBufferAlloc->getOffset(), VK_WHOLE_SIZE);
789	}
790
791	// Submit command buffer
792	{
793		const VkSubmitInfo	submitInfo	=
794		{
795			VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
796			DE_NULL,						// const void*					pNext;
797			0u,								// deUint32						waitSemaphoreCount;
798			DE_NULL,						// const VkSemaphore*			pWaitSemaphores;
799			DE_NULL,						// const VkPIpelineStageFlags*	pWaitDstStageMask;
800			1u,								// deUint32						commandBufferCount;
801			&cmdBuffer,						// const VkCommandBuffer*		pCommandBuffers;
802			0u,								// deUint32						signalSemaphoreCount;
803			DE_NULL							// const VkSemaphore*			pSignalSemaphores;
804		};
805
806		VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
807		VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
808		VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
809	}
810
811	// Prepare result buffer for read
812	{
813		const VkMappedMemoryRange	outBufferRange	=
814		{
815			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//  VkStructureType	sType;
816			DE_NULL,								//  const void*		pNext;
817			m_outBufferAlloc->getMemory(),			//  VkDeviceMemory	mem;
818			0ull,									//  VkDeviceSize	offset;
819			m_outBufferAllocSize,					//  VkDeviceSize	size;
820		};
821
822		VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
823	}
824
825	if (verifyResult())
826		return tcu::TestStatus::pass("All values OK");
827	else
828		return tcu::TestStatus::fail("Invalid value(s) found");
829}
830
831bool VertexAccessInstance::verifyResult (void)
832{
833	std::ostringstream			logMsg;
834	const DeviceInterface&		vk						= *m_deviceDriver;
835	tcu::TestLog&				log						= m_context.getTestContext().getLog();
836	const deUint32				numChannels				= getNumUsedChannels(mapVkFormat(m_inputFormat).order);
837	const deUint32				numScalarsPerVertex		= numChannels * 3; // Use 3 identical attributes
838	void*						outDataPtr				= m_outBufferAlloc->getHostPtr();
839	const deUint32				outValueSize			= static_cast<deUint32>((m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT)
840										? sizeof(deUint64) : sizeof(deUint32));
841	bool						allOk					= true;
842
843	const VkMappedMemoryRange	outBufferRange			=
844	{
845		VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	// VkStructureType	sType;
846		DE_NULL,								// const void*		pNext;
847		m_outBufferAlloc->getMemory(),			// VkDeviceMemory	mem;
848		m_outBufferAlloc->getOffset(),			// VkDeviceSize		offset;
849		m_outBufferAllocSize,					// VkDeviceSize		size;
850	};
851
852	VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
853
854	for (deUint32 valueNdx = 0; valueNdx < m_outBufferSize / outValueSize; valueNdx++)
855	{
856		deUint32			numInBufferValues;
857		void*				inBufferPtr;
858		VkDeviceSize		inBufferAllocSize;
859		deUint32			inBufferValueIndex;
860		bool				isOutOfBoundsAccess		= false;
861		const deUint32		attributeIndex			= (valueNdx / numChannels) % 3;
862		deUint32*			ptr32					= (deUint32*)outDataPtr;
863		deUint64*			ptr64					= (deUint64*)outDataPtr;
864		const void*			outValuePtr				= ((m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT) ?
865														(void*)(ptr64 + valueNdx) :
866														(void*)(ptr32 + valueNdx));
867
868		if (attributeIndex == 2)
869		{
870			// Instance rate
871			const deUint32	elementIndex	= valueNdx / (numScalarsPerVertex * m_numVertices); // instance id
872
873			numInBufferValues	= m_numInstanceValues;
874			inBufferPtr			= m_instanceRateBufferAlloc->getHostPtr();
875			inBufferAllocSize	= m_instanceRateBufferAllocSize;
876			inBufferValueIndex	= (elementIndex * numChannels) + (valueNdx % numScalarsPerVertex) - (2 * numChannels);
877		}
878		else
879		{
880			// Vertex rate
881			const deUint32	vertexNdx		= valueNdx / numScalarsPerVertex;
882			const deUint32	instanceNdx		= vertexNdx / m_numVertices;
883			const deUint32	elementIndex	= valueNdx / numScalarsPerVertex; // vertex id
884
885			numInBufferValues	= m_numVertexValues;
886			inBufferPtr			= m_vertexRateBufferAlloc->getHostPtr();
887			inBufferAllocSize	= m_vertexRateBufferAllocSize;
888			inBufferValueIndex	= (getIndex(elementIndex) * (numChannels * 2)) + (valueNdx % numScalarsPerVertex) - instanceNdx * (m_numVertices * numChannels * 2);
889
890			// Binding 0 contains two attributes, so bounds checking for attribute 0 must also consider attribute 1 to determine if the binding is out of bounds.
891			if ((attributeIndex == 0) && (numInBufferValues >= numChannels))
892				numInBufferValues -= numChannels;
893		}
894
895		isOutOfBoundsAccess	= (inBufferValueIndex >= numInBufferValues);
896
897		const deInt32		distanceToOutOfBounds	= (deInt32)outValueSize * ((deInt32)numInBufferValues - (deInt32)inBufferValueIndex);
898
899		if (!isOutOfBoundsAccess && (distanceToOutOfBounds < 16))
900			isOutOfBoundsAccess = (((inBufferValueIndex / numChannels) + 1) * numChannels > numInBufferValues);
901
902		// Log value information
903		{
904			// Vertex separator
905			if (valueNdx && valueNdx % numScalarsPerVertex == 0)
906				logMsg << "\n";
907
908			logMsg << "\n" << valueNdx << ": Value ";
909
910			// Result index and value
911			if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
912				logValue(logMsg, outValuePtr, VK_FORMAT_R32_SFLOAT, 4);
913			else
914				logValue(logMsg, outValuePtr, m_inputFormat, 4);
915
916			// Attribute name
917			logMsg << "\tfrom attr" << attributeIndex;
918			if (numChannels > 1)
919				logMsg << "[" << valueNdx % numChannels << "]";
920
921			// Input rate
922			if (attributeIndex == 2)
923				logMsg << "\tinstance rate";
924			else
925				logMsg << "\tvertex rate";
926		}
927
928		if (isOutOfBoundsAccess)
929		{
930			const bool isValidValue = isValueWithinVertexBufferOrZero(inBufferPtr, inBufferAllocSize, outValuePtr, inBufferValueIndex);
931
932			logMsg << "\t(out of bounds)";
933
934			if (!isValidValue)
935			{
936				// Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
937				// or the maximum representable positive integer value (if the format is integer-based).
938
939				const bool	canMatchVec4Pattern	= ((valueNdx % numChannels == 3) || m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32);
940				bool		matchesVec4Pattern	= false;
941
942				if (canMatchVec4Pattern)
943				{
944					if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
945						matchesVec4Pattern	=  verifyOutOfBoundsVec4(outValuePtr, m_inputFormat);
946					else
947						matchesVec4Pattern	=  verifyOutOfBoundsVec4(((deUint32*)outValuePtr) - 3, m_inputFormat);
948				}
949
950				if (!canMatchVec4Pattern || !matchesVec4Pattern)
951				{
952					logMsg << ", Failed: expected a value within the buffer range or 0";
953
954					if (canMatchVec4Pattern)
955						logMsg << ", or the [0, 0, 0, x] pattern";
956
957					allOk = false;
958				}
959			}
960		}
961		else if (!isExpectedValueFromVertexBuffer(inBufferPtr, inBufferValueIndex, m_inputFormat, outValuePtr))
962		{
963			logMsg << ", Failed: unexpected value";
964			allOk = false;
965		}
966	}
967	log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
968
969	return allOk;
970}
971
972bool VertexAccessInstance::isValueWithinVertexBufferOrZero(void* vertexBuffer, VkDeviceSize vertexBufferSize, const void* value, deUint32 valueIndex)
973{
974	if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
975	{
976		const float		normValue		= *reinterpret_cast<const float*>(value);
977		const deUint32	scalarIndex		= valueIndex % 4;
978		const bool		isAlpha			= (scalarIndex == 3);
979		deUint32		encodedValue;
980
981		if (isAlpha)
982			encodedValue = deMin32(deUint32(deFloatRound(normValue * 0x3u)), 0x3u);
983		else
984			encodedValue = deMin32(deUint32(deFloatRound(normValue * 0x3FFu)), 0x3FFu);
985
986		if (encodedValue == 0)
987			return true;
988
989		for (deUint32 i = 0; i < vertexBufferSize / 4; i++)
990		{
991			const deUint32	packedValue		= reinterpret_cast<deUint32*>(vertexBuffer)[i];
992			deUint32		unpackedValue;
993
994			if (scalarIndex < 3)
995				unpackedValue = (packedValue >> (10 * scalarIndex)) & 0x3FFu;
996			else
997				unpackedValue = (packedValue >> 30) & 0x3u;
998
999			if (unpackedValue == encodedValue)
1000				return true;
1001		}
1002
1003		return false;
1004	}
1005	else
1006	{
1007		return isValueWithinBufferOrZero(vertexBuffer, vertexBufferSize, value, sizeof(deUint32));
1008	}
1009}
1010
1011bool VertexAccessInstance::isExpectedValueFromVertexBuffer (const void* vertexBuffer, deUint32 vertexIndex, VkFormat vertexFormat, const void* value)
1012{
1013	if (isUintFormat(vertexFormat))
1014	{
1015		if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1016		{
1017			const deUint64* bufferPtr = reinterpret_cast<const deUint64*>(vertexBuffer);
1018			return bufferPtr[vertexIndex] == *reinterpret_cast<const deUint64 *>(value);
1019		}
1020		else
1021		{
1022			const deUint32* bufferPtr = reinterpret_cast<const deUint32*>(vertexBuffer);
1023			return bufferPtr[vertexIndex] == *reinterpret_cast<const deUint32 *>(value);
1024		}
1025	}
1026	else if (isIntFormat(vertexFormat))
1027	{
1028		if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1029		{
1030			const deInt64* bufferPtr = reinterpret_cast<const deInt64*>(vertexBuffer);
1031			return bufferPtr[vertexIndex] == *reinterpret_cast<const deInt64 *>(value);
1032		}
1033		else
1034		{
1035			const deInt32* bufferPtr = reinterpret_cast<const deInt32*>(vertexBuffer);
1036			return bufferPtr[vertexIndex] == *reinterpret_cast<const deInt32 *>(value);
1037		}
1038	}
1039	else if (isFloatFormat(vertexFormat))
1040	{
1041		const float* bufferPtr = reinterpret_cast<const float*>(vertexBuffer);
1042
1043		return areEqual(bufferPtr[vertexIndex], *reinterpret_cast<const float *>(value));
1044	}
1045	else if (vertexFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1046	{
1047		const deUint32*	bufferPtr		= reinterpret_cast<const deUint32*>(vertexBuffer);
1048		const deUint32	packedValue		= bufferPtr[vertexIndex / 4];
1049		const deUint32	scalarIndex		= vertexIndex % 4;
1050		float			normValue;
1051
1052		if (scalarIndex < 3)
1053			normValue = float((packedValue >> (10 * scalarIndex)) & 0x3FFu) / 0x3FFu;
1054		else
1055			normValue = float(packedValue >> 30) / 0x3u;
1056
1057		return areEqual(normValue, *reinterpret_cast<const float *>(value));
1058	}
1059
1060	DE_ASSERT(false);
1061	return false;
1062}
1063
1064VkDeviceSize VertexAccessInstance::getBufferSizeInBytes (deUint32 numScalars, VkFormat format)
1065{
1066	if (isUintFormat(format) || isIntFormat(format) || isFloatFormat(format))
1067	{
1068		return numScalars * ((format == VK_FORMAT_R64_UINT || format == VK_FORMAT_R64_SINT) ? 8 : 4);
1069	}
1070	else if (format == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1071	{
1072		DE_ASSERT(numScalars % 4 == 0);
1073		return numScalars;
1074	}
1075
1076	DE_ASSERT(false);
1077	return 0;
1078}
1079
1080// DrawAccessInstance
1081
1082DrawAccessInstance::DrawAccessInstance (Context&				context,
1083										Move<VkDevice>			device,
1084#ifndef CTS_USES_VULKANSC
1085										de::MovePtr<vk::DeviceDriver>	deviceDriver,
1086#else
1087										de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
1088#endif // CTS_USES_VULKANSC
1089										VkFormat				inputFormat,
1090										deUint32				numVertexValues,
1091										deUint32				numInstanceValues,
1092										deUint32				numVertices,
1093										deUint32				numInstances)
1094	: VertexAccessInstance (context,
1095							device,
1096							deviceDriver,
1097							inputFormat,
1098							numVertexValues,
1099							numInstanceValues,
1100							numVertices,
1101							numInstances,
1102							std::vector<deUint32>()) // No index buffer
1103{
1104}
1105
1106void DrawAccessInstance::initVertexIds (deUint32 *indicesPtr, size_t indexCount)
1107{
1108	for (deUint32 i = 0; i < indexCount; i++)
1109		indicesPtr[i] = i;
1110}
1111
1112deUint32 DrawAccessInstance::getIndex (deUint32 vertexNum) const
1113{
1114	return vertexNum;
1115}
1116
1117// DrawIndexedAccessInstance
1118
1119DrawIndexedAccessInstance::DrawIndexedAccessInstance (Context&						context,
1120													  Move<VkDevice>				device,
1121#ifndef CTS_USES_VULKANSC
1122													  de::MovePtr<vk::DeviceDriver>		deviceDriver,
1123#else
1124													  de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
1125#endif // CTS_USES_VULKANSC
1126													  VkFormat						inputFormat,
1127													  deUint32						numVertexValues,
1128													  deUint32						numInstanceValues,
1129													  deUint32						numVertices,
1130													  deUint32						numInstances,
1131													  const std::vector<deUint32>&	indices)
1132	: VertexAccessInstance	(context,
1133							 device,
1134							 deviceDriver,
1135							 inputFormat,
1136							 numVertexValues,
1137							 numInstanceValues,
1138							 numVertices,
1139							 numInstances,
1140							 indices)
1141	, m_indices				(indices)
1142{
1143}
1144
1145void DrawIndexedAccessInstance::initVertexIds (deUint32 *indicesPtr, size_t indexCount)
1146{
1147	DE_UNREF(indexCount);
1148
1149	for (deUint32 i = 0; i < m_indices.size(); i++)
1150	{
1151		DE_ASSERT(m_indices[i] < indexCount);
1152
1153		indicesPtr[m_indices[i]] = i;
1154	}
1155}
1156
1157deUint32 DrawIndexedAccessInstance::getIndex (deUint32 vertexNum) const
1158{
1159	DE_ASSERT(vertexNum < (deUint32)m_indices.size());
1160
1161	return m_indices[vertexNum];
1162}
1163
1164// Test node creation functions
1165
1166static tcu::TestCaseGroup* createDrawTests (tcu::TestContext& testCtx, VkFormat format)
1167{
1168	struct TestConfig
1169	{
1170		std::string		name;
1171		VkFormat		inputFormat;
1172		deUint32		numVertexValues;
1173		deUint32		numInstanceValues;
1174		deUint32		numVertices;
1175		deUint32		numInstances;
1176	};
1177
1178	const deUint32 numChannels = getNumUsedChannels(mapVkFormat(format).order);
1179
1180	const TestConfig testConfigs[] =
1181	{
1182		// name											format	numVertexValues			numInstanceValues	numVertices		numInstances
1183		// Create data for 6 vertices, draw 9 vertices
1184		{ "vertex_out_of_bounds",	format,	numChannels * 2 * 6,	numChannels,		9,				1	 },
1185		// Create data for half a vertex, draw 3 vertices
1186		{ "vertex_incomplete",	format,	numChannels,			numChannels,		3,				1	 },
1187		// Create data for 1 instance, draw 3 instances
1188		{ "instance_out_of_bounds",		format,	numChannels * 2 * 9,	numChannels,		3,				3	 },
1189	};
1190
1191	de::MovePtr<tcu::TestCaseGroup>	drawTests (new tcu::TestCaseGroup(testCtx, "draw"));
1192
1193	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1194	{
1195		const TestConfig &config = testConfigs[i];
1196
1197		drawTests->addChild(new DrawAccessTest(testCtx, config.name, config.inputFormat,
1198											   config.numVertexValues, config.numInstanceValues,
1199											   config.numVertices, config.numInstances));
1200	}
1201
1202	return drawTests.release();
1203}
1204
1205static tcu::TestCaseGroup* createDrawIndexedTests (tcu::TestContext& testCtx, VkFormat format)
1206{
1207	struct TestConfig
1208	{
1209		std::string							name;
1210		VkFormat							inputFormat;
1211		DrawIndexedAccessTest::IndexConfig	indexConfig;
1212	};
1213
1214	const TestConfig testConfigs[] =
1215	{
1216		// name								format		indexConfig
1217		// Only last index is out of bounds
1218		{ "last_index_out_of_bounds",		format,		DrawIndexedAccessTest::INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS },
1219		// Random indices out of bounds
1220		{ "indices_out_of_bounds",		format,		DrawIndexedAccessTest::INDEX_CONFIG_INDICES_OUT_OF_BOUNDS },
1221		// First triangle is out of bounds
1222		{ "triangle_out_of_bounds",		format,		DrawIndexedAccessTest::INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS },
1223	};
1224
1225	de::MovePtr<tcu::TestCaseGroup>	drawTests (new tcu::TestCaseGroup(testCtx, "draw_indexed"));
1226
1227	for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1228	{
1229		const TestConfig &config = testConfigs[i];
1230
1231		drawTests->addChild(new DrawIndexedAccessTest(testCtx, config.name, config.inputFormat, config.indexConfig));
1232	}
1233
1234	return drawTests.release();
1235}
1236
1237static void addVertexFormatTests (tcu::TestContext& testCtx, tcu::TestCaseGroup* parentGroup)
1238{
1239	const VkFormat vertexFormats[] =
1240	{
1241		VK_FORMAT_R32_UINT,
1242		VK_FORMAT_R32_SINT,
1243		VK_FORMAT_R32_SFLOAT,
1244		VK_FORMAT_R32G32_UINT,
1245		VK_FORMAT_R32G32_SINT,
1246		VK_FORMAT_R32G32_SFLOAT,
1247		VK_FORMAT_R32G32B32_UINT,
1248		VK_FORMAT_R32G32B32_SINT,
1249		VK_FORMAT_R32G32B32_SFLOAT,
1250		VK_FORMAT_R32G32B32A32_UINT,
1251		VK_FORMAT_R32G32B32A32_SINT,
1252		VK_FORMAT_R32G32B32A32_SFLOAT,
1253		VK_FORMAT_R64_UINT,
1254		VK_FORMAT_R64_SINT,
1255
1256		VK_FORMAT_A2B10G10R10_UNORM_PACK32
1257	};
1258
1259	for (int i = 0; i < DE_LENGTH_OF_ARRAY(vertexFormats); i++)
1260	{
1261		const std::string				formatName	= getFormatName(vertexFormats[i]);
1262		de::MovePtr<tcu::TestCaseGroup>	formatGroup	(new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str()));
1263
1264		formatGroup->addChild(createDrawTests(testCtx, vertexFormats[i]));
1265		formatGroup->addChild(createDrawIndexedTests(testCtx, vertexFormats[i]));
1266
1267		parentGroup->addChild(formatGroup.release());
1268	}
1269}
1270
1271tcu::TestCaseGroup* createVertexAccessTests (tcu::TestContext& testCtx)
1272{
1273	de::MovePtr<tcu::TestCaseGroup> vertexAccessTests	(new tcu::TestCaseGroup(testCtx, "vertex_access"));
1274
1275	addVertexFormatTests(testCtx, vertexAccessTests.get());
1276
1277	return vertexAccessTests.release();
1278}
1279
1280} // robustness
1281} // vkt
1282