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