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