• 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 "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 
42 namespace vkt
43 {
44 namespace robustness
45 {
46 
47 using namespace vk;
48 
49 typedef std::vector<VkVertexInputBindingDescription>	BindingList;
50 typedef std::vector<VkVertexInputAttributeDescription>	AttributeList;
51 
52 class VertexAccessTest : public vkt::TestCase
53 {
54 public:
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 
~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 											 VkFormat				inputFormat,
84 											 deUint32				numVertexValues,
85 											 deUint32				numInstanceValues,
86 											 deUint32				numVertices,
87 											 deUint32				numInstances);
88 
~DrawAccessTest(void)89 	virtual				~DrawAccessTest		(void) {}
90 	TestInstance*		createInstance		(Context& context) const;
91 
92 protected:
93 };
94 
95 class DrawIndexedAccessTest : public VertexAccessTest
96 {
97 public:
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 
~DrawIndexedAccessTest(void)114 	virtual				~DrawIndexedAccessTest		(void) {}
115 	TestInstance*		createInstance				(Context& context) const;
116 
117 protected:
118 	const IndexConfig	m_indexConfig;
119 };
120 
121 class VertexAccessInstance : public vkt::TestInstance
122 {
123 public:
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 
142 private:
143 	bool								isValueWithinVertexBufferOrZero			(void* vertexBuffer, VkDeviceSize vertexBufferSize, const void* value, deUint32 valueIndexa);
144 
145 protected:
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 
200 class DrawAccessInstance : public VertexAccessInstance
201 {
202 public:
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 
~DrawAccessInstance(void)216 	virtual				~DrawAccessInstance	(void) {}
217 
218 protected:
219 	virtual void		initVertexIds		(deUint32 *indicesPtr, size_t indexCount);
220 	virtual deUint32	getIndex			(deUint32 vertexNum) const;
221 };
222 
223 class DrawIndexedAccessInstance : public VertexAccessInstance
224 {
225 public:
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 
~DrawIndexedAccessInstance(void)240 	virtual								~DrawIndexedAccessInstance	(void) {}
241 
242 protected:
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 
VertexAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,deUint32 numVertexValues,deUint32 numInstanceValues,deUint32 numVertices,deUint32 numInstances)251 VertexAccessTest::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 
checkSupport(Context & context) const269 void 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 
initPrograms(SourceCollections & programCollection) const275 void 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 
DrawAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,deUint32 numVertexValues,deUint32 numInstanceValues,deUint32 numVertices,deUint32 numInstances)382 DrawAccessTest::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 
createInstance(Context & context) const394 TestInstance* 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 
415 const deUint32 lastIndexOutOfBounds[] =
416 {
417 	0, 1, 2, 3, 4, 100,		// Indices of 100 and above are out of bounds
418 };
419 const deUint32 indicesOutOfBounds[] =
420 {
421 	0, 100, 2, 101, 3, 102,	// Indices of 100 and above are out of bounds
422 };
423 const deUint32 triangleOutOfBounds[] =
424 {
425 	100, 101, 102, 3, 4, 5,	// Indices of 100 and above are out of bounds
426 };
427 
428 const 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 
DrawIndexedAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,IndexConfig indexConfig)435 DrawIndexedAccessTest::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 
createInstance(Context & context) const451 TestInstance* 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 
VertexAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,deUint32 numVertexValues,deUint32 numInstanceValues,deUint32 numVertices,deUint32 numInstances,const std::vector<deUint32> & indices)473 VertexAccessInstance::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 
~VertexAccessInstance(void)772 VertexAccessInstance::~VertexAccessInstance(void)
773 {
774 }
775 
iterate(void)776 tcu::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 
verifyResult(void)831 bool 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 
isValueWithinVertexBufferOrZero(void * vertexBuffer,VkDeviceSize vertexBufferSize,const void * value,deUint32 valueIndex)972 bool 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 
isExpectedValueFromVertexBuffer(const void * vertexBuffer,deUint32 vertexIndex,VkFormat vertexFormat,const void * value)1011 bool 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 
getBufferSizeInBytes(deUint32 numScalars,VkFormat format)1064 VkDeviceSize 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 
DrawAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,deUint32 numVertexValues,deUint32 numInstanceValues,deUint32 numVertices,deUint32 numInstances)1082 DrawAccessInstance::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 
initVertexIds(deUint32 * indicesPtr,size_t indexCount)1106 void DrawAccessInstance::initVertexIds (deUint32 *indicesPtr, size_t indexCount)
1107 {
1108 	for (deUint32 i = 0; i < indexCount; i++)
1109 		indicesPtr[i] = i;
1110 }
1111 
getIndex(deUint32 vertexNum) const1112 deUint32 DrawAccessInstance::getIndex (deUint32 vertexNum) const
1113 {
1114 	return vertexNum;
1115 }
1116 
1117 // DrawIndexedAccessInstance
1118 
DrawIndexedAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,deUint32 numVertexValues,deUint32 numInstanceValues,deUint32 numVertices,deUint32 numInstances,const std::vector<deUint32> & indices)1119 DrawIndexedAccessInstance::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 
initVertexIds(deUint32 * indicesPtr,size_t indexCount)1145 void 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 
getIndex(deUint32 vertexNum) const1157 deUint32 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 
createDrawTests(tcu::TestContext & testCtx,VkFormat format)1166 static 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 
createDrawIndexedTests(tcu::TestContext & testCtx,VkFormat format)1205 static 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 
addVertexFormatTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup)1237 static 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 
createVertexAccessTests(tcu::TestContext & testCtx)1271 tcu::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