• 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 buffer access tests for uniform/storage buffers and
23  *        uniform/storage texel buffers.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktRobustnessBufferAccessTests.hpp"
27 #include "vktRobustnessUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkImageUtil.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 
39 #include <limits>
40 #include <sstream>
41 
42 namespace vkt
43 {
44 namespace robustness
45 {
46 
47 using namespace vk;
48 
49 enum ShaderType
50 {
51 	SHADER_TYPE_MATRIX_COPY,
52 	SHADER_TYPE_VECTOR_COPY,
53 	SHADER_TYPE_SCALAR_COPY,
54 	SHADER_TYPE_TEXEL_COPY,
55 
56 	SHADER_TYPE_COUNT
57 };
58 
59 enum BufferAccessType
60 {
61 	BUFFER_ACCESS_TYPE_READ,
62 	BUFFER_ACCESS_TYPE_READ_FROM_STORAGE,
63 	BUFFER_ACCESS_TYPE_WRITE,
64 };
65 
min(VkDeviceSize a,VkDeviceSize b)66 static VkDeviceSize min (VkDeviceSize a, VkDeviceSize b)
67 {
68 	return (a < b) ? a : b;
69 }
70 
71 class RobustBufferAccessTest : public vkt::TestCase
72 {
73 public:
74 	static const deUint32		s_testArraySize;
75 	static const deUint32		s_numberOfBytesAccessed;
76 
77 								RobustBufferAccessTest		(tcu::TestContext&		testContext,
78 															 const std::string&		name,
79 															 const std::string&		description,
80 															 VkShaderStageFlags		shaderStage,
81 															 ShaderType				shaderType,
82 															 VkFormat				bufferFormat,
83 															 bool					testPipelineRobustness);
84 
~RobustBufferAccessTest(void)85 	virtual						~RobustBufferAccessTest		(void) {}
86 
87 	virtual void				checkSupport				(Context& context) const;
88 
89 private:
90 	static void					genBufferShaderAccess		(ShaderType				shaderType,
91 															 VkFormat				bufferFormat,
92 															 bool					readFromStorage,
93 															 std::ostringstream&	bufferDefinition,
94 															 std::ostringstream&	bufferUse);
95 
96 	static void					genTexelBufferShaderAccess	(VkFormat				bufferFormat,
97 															 std::ostringstream&	bufferDefinition,
98 															 std::ostringstream&	bufferUse,
99 															 bool					readFromStorage);
100 
101 protected:
102 	bool						is64BitsTest				(void) const;
103 	bool						isVertexTest				(void) const;
104 	bool						isFragmentTest				(void) const;
105 
106 	static void					initBufferAccessPrograms	(SourceCollections&		programCollection,
107 															 VkShaderStageFlags		shaderStage,
108 															 ShaderType				shaderType,
109 															 VkFormat				bufferFormat,
110 															 bool					readFromStorage);
111 
112 	const VkShaderStageFlags	m_shaderStage;
113 	const ShaderType			m_shaderType;
114 	const VkFormat				m_bufferFormat;
115 	const bool m_testPipelineRobustness;
116 };
117 
118 class RobustBufferReadTest : public RobustBufferAccessTest
119 {
120 public:
121 								RobustBufferReadTest		(tcu::TestContext&		testContext,
122 															 const std::string&		name,
123 															 const std::string&		description,
124 															 VkShaderStageFlags		shaderStage,
125 															 ShaderType				shaderType,
126 															 VkFormat				bufferFormat,
127 															 bool					testPipelineRobustness,
128 															 VkDeviceSize			readAccessRange,
129 															 bool					readFromStorage,
130 															 bool					accessOutOfBackingMemory);
131 
~RobustBufferReadTest(void)132 	virtual						~RobustBufferReadTest		(void) {}
133 
134 	virtual void				initPrograms				(SourceCollections& programCollection) const;
135 	virtual TestInstance*		createInstance				(Context& context) const;
136 
137 private:
138 	const bool					m_readFromStorage;
139 	const VkDeviceSize			m_readAccessRange;
140 	const bool					m_accessOutOfBackingMemory;
141 };
142 
143 class RobustBufferWriteTest : public RobustBufferAccessTest
144 {
145 public:
146 								RobustBufferWriteTest		(tcu::TestContext&		testContext,
147 															 const std::string&		name,
148 															 const std::string&		description,
149 															 VkShaderStageFlags		shaderStage,
150 															 ShaderType				shaderType,
151 															 VkFormat				bufferFormat,
152 															 bool					testPipelineRobustness,
153 															 VkDeviceSize			writeAccessRange,
154 															 bool					accessOutOfBackingMemory);
155 
~RobustBufferWriteTest(void)156 	virtual						~RobustBufferWriteTest		(void) {}
157 
158 	virtual void				initPrograms				(SourceCollections& programCollection) const;
159 	virtual TestInstance*		createInstance				(Context& context) const;
160 
161 private:
162 	const VkDeviceSize			m_writeAccessRange;
163 	const bool					m_accessOutOfBackingMemory;
164 };
165 
166 class BufferAccessInstance : public vkt::TestInstance
167 {
168 public:
169 									BufferAccessInstance			(Context&			context,
170 																	 Move<VkDevice>		device,
171 #ifndef CTS_USES_VULKANSC
172 																	 de::MovePtr<vk::DeviceDriver>	deviceDriver,
173 #else
174 																	 de::MovePtr<vk::DeviceDriverSC,vk::DeinitDeviceDeleter>	deviceDriver,
175 #endif // CTS_USES_VULKANSC
176 																	 ShaderType			shaderType,
177 																	 VkShaderStageFlags	shaderStage,
178 																	 VkFormat			bufferFormat,
179 																	 BufferAccessType	bufferAccessType,
180 																	 VkDeviceSize		inBufferAccessRange,
181 																	 VkDeviceSize		outBufferAccessRange,
182 																	 bool				accessOutOfBackingMemory,
183 																	 bool				testPipelineRobustness);
184 
185 	virtual							~BufferAccessInstance			(void);
186 
187 	virtual tcu::TestStatus			iterate							(void);
188 
189 	virtual bool					verifyResult					(void);
190 
191 private:
192 	bool							isExpectedValueFromInBuffer		(VkDeviceSize offsetInBytes, const void* valuePtr, VkDeviceSize valueSize);
193 	bool							isOutBufferValueUnchanged		(VkDeviceSize offsetInBytes, VkDeviceSize valueSize);
194 
195 protected:
196 	Move<VkDevice>					m_device;
197 #ifndef CTS_USES_VULKANSC
198 	de::MovePtr<vk::DeviceDriver>	m_deviceDriver;
199 #else
200 	de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	m_deviceDriver;
201 #endif // CTS_USES_VULKANSC
202 	de::MovePtr<TestEnvironment>	m_testEnvironment;
203 
204 	const ShaderType				m_shaderType;
205 	const VkShaderStageFlags		m_shaderStage;
206 
207 	const VkFormat					m_bufferFormat;
208 	const BufferAccessType			m_bufferAccessType;
209 
210 	const VkDeviceSize				m_inBufferAccessRange;
211 	Move<VkBuffer>					m_inBuffer;
212 	de::MovePtr<Allocation>			m_inBufferAlloc;
213 	VkDeviceSize					m_inBufferAllocSize;
214 	VkDeviceSize					m_inBufferMaxAccessRange;
215 
216 	const VkDeviceSize				m_outBufferAccessRange;
217 	Move<VkBuffer>					m_outBuffer;
218 	de::MovePtr<Allocation>			m_outBufferAlloc;
219 	VkDeviceSize					m_outBufferAllocSize;
220 	VkDeviceSize					m_outBufferMaxAccessRange;
221 
222 	Move<VkBuffer>					m_indicesBuffer;
223 	de::MovePtr<Allocation>			m_indicesBufferAlloc;
224 
225 	Move<VkDescriptorPool>			m_descriptorPool;
226 	Move<VkDescriptorSetLayout>		m_descriptorSetLayout;
227 	Move<VkDescriptorSet>			m_descriptorSet;
228 
229 	Move<VkFence>					m_fence;
230 	VkQueue							m_queue;
231 
232 	// Used when m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT
233 	Move<VkBuffer>					m_vertexBuffer;
234 	de::MovePtr<Allocation>			m_vertexBufferAlloc;
235 
236 	// Used when m_shaderType == SHADER_TYPE_TEXEL_COPY
237 	Move<VkBufferView>				m_inTexelBufferView;
238 	Move<VkBufferView>				m_outTexelBufferView;
239 
240 	const bool						m_accessOutOfBackingMemory;
241 	const bool						m_testPipelineRobustness;
242 };
243 
244 class BufferReadInstance: public BufferAccessInstance
245 {
246 public:
247 									BufferReadInstance			(Context&				context,
248 																 Move<VkDevice>			device,
249 #ifndef CTS_USES_VULKANSC
250 																 de::MovePtr<vk::DeviceDriver>		deviceDriver,
251 #else
252 																 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
253 #endif // CTS_USES_VULKANSC
254 																 ShaderType				shaderType,
255 																 VkShaderStageFlags		shaderStage,
256 																 VkFormat				bufferFormat,
257 																 bool					readFromStorage,
258 																 VkDeviceSize			inBufferAccessRange,
259 																 bool					accessOutOfBackingMemory,
260 																 bool					testPipelineRobustness);
261 
~BufferReadInstance(void)262 	virtual							~BufferReadInstance			(void) {}
263 
264 private:
265 };
266 
267 class BufferWriteInstance: public BufferAccessInstance
268 {
269 public:
270 									BufferWriteInstance			(Context&				context,
271 																 Move<VkDevice>			device,
272 #ifndef CTS_USES_VULKANSC
273 																 de::MovePtr<vk::DeviceDriver>		deviceDriver,
274 #else
275 																 de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
276 #endif // CTS_USES_VULKANSC
277 																 ShaderType				shaderType,
278 																 VkShaderStageFlags		shaderStage,
279 																 VkFormat				bufferFormat,
280 																 VkDeviceSize			writeBufferAccessRange,
281 																 bool					accessOutOfBackingMemory,
282 																 bool					testPipelineRobustness);
283 
~BufferWriteInstance(void)284 	virtual							~BufferWriteInstance		(void) {}
285 };
286 
287 // RobustBufferAccessTest
288 
289 const deUint32 RobustBufferAccessTest::s_testArraySize = 128; // Fit within minimum required maxUniformBufferRange
290 const deUint32 RobustBufferAccessTest::s_numberOfBytesAccessed	= (deUint32)(16 * sizeof(float)); // size of mat4
291 
RobustBufferAccessTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness)292 RobustBufferAccessTest::RobustBufferAccessTest (tcu::TestContext&		testContext,
293 												const std::string&		name,
294 												const std::string&		description,
295 												VkShaderStageFlags		shaderStage,
296 												ShaderType				shaderType,
297 												VkFormat				bufferFormat,
298 												bool					testPipelineRobustness)
299 	: vkt::TestCase		(testContext, name, description)
300 	, m_shaderStage		(shaderStage)
301 	, m_shaderType		(shaderType)
302 	, m_bufferFormat	(bufferFormat)
303 	, m_testPipelineRobustness (testPipelineRobustness)
304 {
305 	DE_ASSERT(m_shaderStage == VK_SHADER_STAGE_VERTEX_BIT || m_shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT || m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT);
306 }
307 
checkSupport(Context & context) const308 void RobustBufferAccessTest::checkSupport(Context& context) const
309 {
310 	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getDeviceFeatures().robustBufferAccess)
311 		TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
312 
313 	if (is64BitsTest())
314 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_SHADER_INT64);
315 
316 	if (isVertexTest())
317 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_VERTEX_PIPELINE_STORES_AND_ATOMICS);
318 
319 	if (isFragmentTest())
320 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
321 }
322 
genBufferShaderAccess(ShaderType shaderType,VkFormat bufferFormat,bool readFromStorage,std::ostringstream & bufferDefinition,std::ostringstream & bufferUse)323 void RobustBufferAccessTest::genBufferShaderAccess (ShaderType			shaderType,
324 												    VkFormat			bufferFormat,
325 												    bool				readFromStorage,
326 												    std::ostringstream&	bufferDefinition,
327 												    std::ostringstream&	bufferUse)
328 {
329 	if (isFloatFormat(bufferFormat))
330 	{
331 		bufferDefinition <<
332 			"layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") " << (readFromStorage ? "buffer" : "uniform") << " InBuffer\n"
333 			"{\n"
334 			"	mat4 inMatrix[" << s_testArraySize << "];\n"
335 			"};\n\n";
336 
337 		bufferDefinition <<
338 			"layout(binding = 1, std430) buffer OutBuffer\n"
339 			"{\n"
340 			"	mat4 outMatrix[" << s_testArraySize << "];\n"
341 			"};\n\n";
342 
343 		bufferDefinition <<
344 			"layout(binding = 2, std140) uniform Indices\n"
345 			"{\n"
346 			"	int inIndex;\n"
347 			"	int outIndex;\n"
348 			"};\n\n";
349 
350 		switch (shaderType)
351 		{
352 			case SHADER_TYPE_MATRIX_COPY:
353 				bufferUse <<
354 					"	mat4 tmp = inMatrix[inIndex];\n"
355 					"	outMatrix[outIndex] = tmp;\n";
356 				break;
357 
358 			case SHADER_TYPE_VECTOR_COPY:
359 				bufferUse <<
360 					"	outMatrix[outIndex][0] = inMatrix[inIndex][0];\n"
361 					"	outMatrix[outIndex][1] = inMatrix[inIndex][1];\n"
362 					"	outMatrix[outIndex][2] = inMatrix[inIndex][2];\n"
363 					"	outMatrix[outIndex][3] = inMatrix[inIndex][3];\n";
364 				break;
365 
366 			case SHADER_TYPE_SCALAR_COPY:
367 				bufferUse <<
368 					"	outMatrix[outIndex][0][0] = inMatrix[inIndex][0][0];\n"
369 					"	outMatrix[outIndex][0][1] = inMatrix[inIndex][0][1];\n"
370 					"	outMatrix[outIndex][0][2] = inMatrix[inIndex][0][2];\n"
371 					"	outMatrix[outIndex][0][3] = inMatrix[inIndex][0][3];\n"
372 
373 					"	outMatrix[outIndex][1][0] = inMatrix[inIndex][1][0];\n"
374 					"	outMatrix[outIndex][1][1] = inMatrix[inIndex][1][1];\n"
375 					"	outMatrix[outIndex][1][2] = inMatrix[inIndex][1][2];\n"
376 					"	outMatrix[outIndex][1][3] = inMatrix[inIndex][1][3];\n"
377 
378 					"	outMatrix[outIndex][2][0] = inMatrix[inIndex][2][0];\n"
379 					"	outMatrix[outIndex][2][1] = inMatrix[inIndex][2][1];\n"
380 					"	outMatrix[outIndex][2][2] = inMatrix[inIndex][2][2];\n"
381 					"	outMatrix[outIndex][2][3] = inMatrix[inIndex][2][3];\n"
382 
383 					"	outMatrix[outIndex][3][0] = inMatrix[inIndex][3][0];\n"
384 					"	outMatrix[outIndex][3][1] = inMatrix[inIndex][3][1];\n"
385 					"	outMatrix[outIndex][3][2] = inMatrix[inIndex][3][2];\n"
386 					"	outMatrix[outIndex][3][3] = inMatrix[inIndex][3][3];\n";
387 				break;
388 
389 			default:
390 				DE_ASSERT(false);
391 		}
392 	}
393 	else
394 	{
395 		std::string typePrefixStr;
396 
397 		if (isUintFormat(bufferFormat))
398 		{
399 			typePrefixStr = "u";
400 		}
401 		else if (isIntFormat(bufferFormat))
402 		{
403 			typePrefixStr =  "i";
404 		}
405 		else
406 		{
407 			DE_ASSERT(false);
408 		}
409 
410 		typePrefixStr += (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT) ?
411 						 "64" : "";
412 
413 		bufferDefinition <<
414 			"layout(binding = 0, " << (readFromStorage ? "std430" : "std140") << ") " << (readFromStorage ? "buffer readonly" : "uniform") << " InBuffer\n"
415 			"{\n"
416 			"	" << typePrefixStr << "vec4 inVecs[" << s_testArraySize << "][4];\n"
417 			"};\n\n";
418 
419 		bufferDefinition <<
420 			"layout(binding = 1, std430) buffer OutBuffer\n"
421 			"{\n"
422 			"	" << typePrefixStr << "vec4 outVecs[" << s_testArraySize << "][4];\n"
423 			"};\n\n";
424 
425 		bufferDefinition <<
426 			"layout(binding = 2, std140) uniform Indices\n"
427 			"{\n"
428 			"	int inIndex;\n"
429 			"	int outIndex;\n"
430 			"};\n\n";
431 
432 		switch (shaderType)
433 		{
434 			case SHADER_TYPE_MATRIX_COPY:
435 				// Shader type not supported for integer types.
436 				DE_ASSERT(false);
437 				break;
438 
439 			case SHADER_TYPE_VECTOR_COPY:
440 				bufferUse <<
441 					"	outVecs[outIndex][0] = inVecs[inIndex][0];\n"
442 					"	outVecs[outIndex][1] = inVecs[inIndex][1];\n"
443 					"	outVecs[outIndex][2] = inVecs[inIndex][2];\n"
444 					"	outVecs[outIndex][3] = inVecs[inIndex][3];\n";
445 				break;
446 
447 			case SHADER_TYPE_SCALAR_COPY:
448 				bufferUse <<
449 					"	outVecs[outIndex][0][0] = inVecs[inIndex][0][0];\n"
450 					"	outVecs[outIndex][0][1] = inVecs[inIndex][0][1];\n"
451 					"	outVecs[outIndex][0][2] = inVecs[inIndex][0][2];\n"
452 					"	outVecs[outIndex][0][3] = inVecs[inIndex][0][3];\n"
453 
454 					"	outVecs[outIndex][1][0] = inVecs[inIndex][1][0];\n"
455 					"	outVecs[outIndex][1][1] = inVecs[inIndex][1][1];\n"
456 					"	outVecs[outIndex][1][2] = inVecs[inIndex][1][2];\n"
457 					"	outVecs[outIndex][1][3] = inVecs[inIndex][1][3];\n"
458 
459 					"	outVecs[outIndex][2][0] = inVecs[inIndex][2][0];\n"
460 					"	outVecs[outIndex][2][1] = inVecs[inIndex][2][1];\n"
461 					"	outVecs[outIndex][2][2] = inVecs[inIndex][2][2];\n"
462 					"	outVecs[outIndex][2][3] = inVecs[inIndex][2][3];\n"
463 
464 					"	outVecs[outIndex][3][0] = inVecs[inIndex][3][0];\n"
465 					"	outVecs[outIndex][3][1] = inVecs[inIndex][3][1];\n"
466 					"	outVecs[outIndex][3][2] = inVecs[inIndex][3][2];\n"
467 					"	outVecs[outIndex][3][3] = inVecs[inIndex][3][3];\n";
468 				break;
469 
470 			default:
471 				DE_ASSERT(false);
472 		}
473 	}
474 }
475 
genTexelBufferShaderAccess(VkFormat bufferFormat,std::ostringstream & bufferDefinition,std::ostringstream & bufferUse,bool readFromStorage)476 void RobustBufferAccessTest::genTexelBufferShaderAccess (VkFormat				bufferFormat,
477 														 std::ostringstream&	bufferDefinition,
478 														 std::ostringstream&	bufferUse,
479 														 bool					readFromStorage)
480 {
481 	const char*		layoutTypeStr;
482 	const char*		inTexelBufferTypeStr;
483 	const char*		outTexelBufferTypeStr;
484 	const deUint32	texelSize				= mapVkFormat(bufferFormat).getPixelSize();
485 
486 	if (isFloatFormat(bufferFormat))
487 	{
488 		layoutTypeStr			= "rgba32f";
489 		inTexelBufferTypeStr	= readFromStorage ? "imageBuffer" : "textureBuffer";
490 		outTexelBufferTypeStr	= "imageBuffer";
491 	}
492 	else if (isUintFormat(bufferFormat))
493 	{
494 		layoutTypeStr			= "rgba32ui";
495 		inTexelBufferTypeStr	= readFromStorage ? "uimageBuffer" : "utextureBuffer";
496 		outTexelBufferTypeStr	= "uimageBuffer";
497 	}
498 	else if (isIntFormat(bufferFormat))
499 	{
500 		layoutTypeStr			= "rgba32i";
501 		inTexelBufferTypeStr	= readFromStorage ? "iimageBuffer" : "itextureBuffer";
502 		outTexelBufferTypeStr	= "iimageBuffer";
503 	}
504 	else if (bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
505 	{
506 		layoutTypeStr			= "rgb10_a2";
507 		inTexelBufferTypeStr	= readFromStorage ? "imageBuffer" : "textureBuffer"; outTexelBufferTypeStr	= "imageBuffer";
508 	}
509 	else
510 	{
511 		TCU_THROW(NotSupportedError, (std::string("Unsupported format: ") + getFormatName(bufferFormat)).c_str());
512 	}
513 
514 	bufferDefinition << "layout(set = 0, binding = 0" << ((readFromStorage) ? (std::string(", ") + layoutTypeStr) : "") << ") uniform highp "
515 					 << ((readFromStorage) ? "readonly " : "") << inTexelBufferTypeStr << " inImage;\n";
516 
517 	bufferDefinition << "layout(set = 0, binding = 1, " << layoutTypeStr << ") uniform highp writeonly " << outTexelBufferTypeStr << " outImage;\n";
518 
519 	bufferDefinition <<
520 		"layout(binding = 2, std140) uniform Offsets\n"
521 		"{\n"
522 		"	int inOffset;\n"
523 		"	int outOffset;\n"
524 		"};\n\n";
525 
526 	bufferUse << "	for (int i = 0; i < " << (s_numberOfBytesAccessed / texelSize) << "; i++)\n"
527 			  << "	{\n"
528 			  << "		imageStore(outImage, outOffset + i, " << (readFromStorage ? "imageLoad" : "texelFetch") << "(inImage, inOffset + i));\n"
529 			  << "	}\n";
530 }
531 
is64BitsTest(void) const532 bool RobustBufferAccessTest::is64BitsTest (void) const
533 {
534 	return (m_bufferFormat == VK_FORMAT_R64_SINT || m_bufferFormat == VK_FORMAT_R64_UINT);
535 }
536 
isVertexTest(void) const537 bool RobustBufferAccessTest::isVertexTest (void) const
538 {
539 	return ((m_shaderStage & VK_SHADER_STAGE_VERTEX_BIT) != 0u);
540 }
541 
isFragmentTest(void) const542 bool RobustBufferAccessTest::isFragmentTest (void) const
543 {
544 	return ((m_shaderStage & VK_SHADER_STAGE_FRAGMENT_BIT) != 0u);
545 }
546 
initBufferAccessPrograms(SourceCollections & programCollection,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool readFromStorage)547 void RobustBufferAccessTest::initBufferAccessPrograms (SourceCollections&	programCollection,
548 													   VkShaderStageFlags	shaderStage,
549 													   ShaderType			shaderType,
550 													   VkFormat				bufferFormat,
551 													   bool					readFromStorage)
552 {
553 	std::ostringstream	bufferDefinition;
554 	std::ostringstream	bufferUse;
555 	std::string			extensions;
556 
557 	if (bufferFormat == vk::VK_FORMAT_R64_UINT || bufferFormat == vk::VK_FORMAT_R64_SINT)
558 	{
559 		extensions = "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
560 	}
561 
562 	if (shaderType != SHADER_TYPE_TEXEL_COPY)
563 	{
564 		genBufferShaderAccess(shaderType, bufferFormat, readFromStorage, bufferDefinition, bufferUse);
565 	}
566 
567 	if (shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
568 	{
569 		std::ostringstream computeShaderSource;
570 
571 		if (shaderType == SHADER_TYPE_TEXEL_COPY)
572 			genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
573 
574 		computeShaderSource <<
575 			"#version 440\n"
576 			"#extension GL_EXT_texture_buffer : require\n"
577 			<< extensions <<
578 			"precision highp float;\n"
579 			"layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;\n"
580 			<< bufferDefinition.str() <<
581 			"void main (void)\n"
582 			"{\n"
583 			<< bufferUse.str() <<
584 			"}\n";
585 
586 		programCollection.glslSources.add("compute") << glu::ComputeSource(computeShaderSource.str());
587 	}
588 	else
589 	{
590 		std::ostringstream vertexShaderSource;
591 		std::ostringstream fragmentShaderSource;
592 
593 		if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
594 		{
595 			if (shaderType == SHADER_TYPE_TEXEL_COPY)
596 				genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
597 
598 			vertexShaderSource <<
599 				"#version 440\n"
600 				"#extension GL_EXT_texture_buffer : require\n"
601 				<< extensions <<
602 				"precision highp float;\n"
603 				"layout(location = 0) in vec4 position;\n\n"
604 				<< bufferDefinition.str() << "\n"
605 				"out gl_PerVertex {\n"
606 				"	vec4 gl_Position;\n"
607 				"};\n\n"
608 				"void main (void)\n"
609 				"{\n"
610 				<< bufferUse.str() <<
611 				"	gl_Position = position;\n"
612 				"}\n";
613 		}
614 		else
615 		{
616 			vertexShaderSource <<
617 				"#version 440\n"
618 				"precision highp float;\n"
619 				"layout(location = 0) in vec4 position;\n\n"
620 				"out gl_PerVertex {\n"
621 				"	vec4 gl_Position;\n"
622 				"};\n\n"
623 				"void main (void)\n"
624 				"{\n"
625 				"	gl_Position = position;\n"
626 				"}\n";
627 		}
628 
629 		programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
630 
631 		if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
632 		{
633 			if (shaderType == SHADER_TYPE_TEXEL_COPY)
634 				genTexelBufferShaderAccess(bufferFormat, bufferDefinition, bufferUse, readFromStorage);
635 
636 			fragmentShaderSource <<
637 				"#version 440\n"
638 				"#extension GL_EXT_texture_buffer : require\n"
639 				<< extensions <<
640 				"precision highp float;\n"
641 				"layout(location = 0) out vec4 fragColor;\n"
642 				<< bufferDefinition.str() <<
643 				"void main (void)\n"
644 				"{\n"
645 				<< bufferUse.str() <<
646 				"	fragColor = vec4(1.0);\n"
647 				"}\n";
648 		}
649 		else
650 		{
651 			fragmentShaderSource <<
652 				"#version 440\n"
653 				"precision highp float;\n"
654 				"layout(location = 0) out vec4 fragColor;\n\n"
655 				"void main (void)\n"
656 				"{\n"
657 				"	fragColor = vec4(1.0);\n"
658 				"}\n";
659 		}
660 
661 		programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
662 	}
663 }
664 
665 // RobustBufferReadTest
666 
RobustBufferReadTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness,VkDeviceSize readAccessRange,bool readFromStorage,bool accessOutOfBackingMemory)667 RobustBufferReadTest::RobustBufferReadTest (tcu::TestContext&	testContext,
668 											const std::string&	name,
669 											const std::string&	description,
670 											VkShaderStageFlags	shaderStage,
671 											ShaderType			shaderType,
672 											VkFormat			bufferFormat,
673 											bool				testPipelineRobustness,
674 											VkDeviceSize		readAccessRange,
675 											bool				readFromStorage,
676 											bool				accessOutOfBackingMemory)
677 	: RobustBufferAccessTest		(testContext, name, description, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
678 	, m_readFromStorage				(readFromStorage)
679 	, m_readAccessRange				(readAccessRange)
680 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
681 {
682 }
683 
initPrograms(SourceCollections & programCollection) const684 void RobustBufferReadTest::initPrograms (SourceCollections& programCollection) const
685 {
686 	initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat, m_readFromStorage);
687 }
688 
createInstance(Context & context) const689 TestInstance* RobustBufferReadTest::createInstance (Context& context) const
690 {
691 	const bool is64BitsTest_	= is64BitsTest();
692 	const bool isVertexTest_	= isVertexTest();
693 	const bool isFragmentTest_	= isFragmentTest();
694 
695 	VkPhysicalDeviceFeatures2							features2					= initVulkanStructure();
696 
697 	if (!m_testPipelineRobustness)
698 		features2.features.robustBufferAccess = VK_TRUE;
699 
700 	if (is64BitsTest_)
701 		features2.features.shaderInt64 = VK_TRUE;
702 
703 	if (isVertexTest_)
704 		features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
705 
706 	if (isFragmentTest_)
707 		features2.features.fragmentStoresAndAtomics = VK_TRUE;
708 
709 #ifndef CTS_USES_VULKANSC
710 	VkPhysicalDevicePipelineRobustnessFeaturesEXT		pipelineRobustnessFeatures	= initVulkanStructure();
711 	if (m_testPipelineRobustness)
712 	{
713 		context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
714 
715 		pipelineRobustnessFeatures.pipelineRobustness = VK_TRUE;
716 
717 		pipelineRobustnessFeatures.pNext = features2.pNext;
718 		features2.pNext = &pipelineRobustnessFeatures;
719 	}
720 #endif
721 
722 	const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
723 
724 	Move<VkDevice>	device			= createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
725 #ifndef CTS_USES_VULKANSC
726 	de::MovePtr<vk::DeviceDriver>	deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device));
727 #else
728 	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 ));
729 #endif // CTS_USES_VULKANSC
730 
731 	return new BufferReadInstance(context, device, deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_readFromStorage, m_readAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
732 }
733 
734 // RobustBufferWriteTest
735 
RobustBufferWriteTest(tcu::TestContext & testContext,const std::string & name,const std::string & description,VkShaderStageFlags shaderStage,ShaderType shaderType,VkFormat bufferFormat,bool testPipelineRobustness,VkDeviceSize writeAccessRange,bool accessOutOfBackingMemory)736 RobustBufferWriteTest::RobustBufferWriteTest (tcu::TestContext&		testContext,
737 											  const std::string&	name,
738 											  const std::string&	description,
739 											  VkShaderStageFlags	shaderStage,
740 											  ShaderType			shaderType,
741 											  VkFormat				bufferFormat,
742 											  bool					testPipelineRobustness,
743 											  VkDeviceSize			writeAccessRange,
744 											  bool					accessOutOfBackingMemory)
745 
746 	: RobustBufferAccessTest		(testContext, name, description, shaderStage, shaderType, bufferFormat, testPipelineRobustness)
747 	, m_writeAccessRange			(writeAccessRange)
748 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
749 {
750 }
751 
initPrograms(SourceCollections & programCollection) const752 void RobustBufferWriteTest::initPrograms (SourceCollections& programCollection) const
753 {
754 	initBufferAccessPrograms(programCollection, m_shaderStage, m_shaderType, m_bufferFormat, false /* readFromStorage */);
755 }
756 
createInstance(Context & context) const757 TestInstance* RobustBufferWriteTest::createInstance (Context& context) const
758 {
759 	const bool is64BitsTest_	= is64BitsTest();
760 	const bool isVertexTest_	= isVertexTest();
761 	const bool isFragmentTest_	= isFragmentTest();
762 
763 	VkPhysicalDeviceFeatures2							features2					= initVulkanStructure();
764 
765 	if (!m_testPipelineRobustness)
766 		features2.features.robustBufferAccess = VK_TRUE;
767 
768 	if (is64BitsTest_)
769 		features2.features.shaderInt64 = VK_TRUE;
770 
771 	if (isVertexTest_)
772 		features2.features.vertexPipelineStoresAndAtomics = VK_TRUE;
773 
774 	if (isFragmentTest_)
775 		features2.features.fragmentStoresAndAtomics = VK_TRUE;
776 
777 #ifndef CTS_USES_VULKANSC
778 	VkPhysicalDevicePipelineRobustnessFeaturesEXT		pipelineRobustnessFeatures	= initVulkanStructure();
779 	if (m_testPipelineRobustness)
780 	{
781 		context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
782 
783 		const auto&	vki				= context.getInstanceInterface();
784 		const auto	physicalDevice	= context.getPhysicalDevice();
785 
786 		pipelineRobustnessFeatures.pNext = features2.pNext;
787 		features2.pNext = &pipelineRobustnessFeatures;
788 
789 		vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
790 	}
791 #endif
792 
793 	const bool useFeatures2 = (m_testPipelineRobustness || is64BitsTest_ || isVertexTest_ || isFragmentTest_);
794 
795 	Move<VkDevice>	device = createRobustBufferAccessDevice(context, (useFeatures2 ? &features2 : nullptr));
796 #ifndef CTS_USES_VULKANSC
797 	de::MovePtr<vk::DeviceDriver>	deviceDriver = de::MovePtr<DeviceDriver>(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device));
798 #else
799 	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()), DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
800 #endif // CTS_USES_VULKANSC
801 
802 	return new BufferWriteInstance(context, device, deviceDriver, m_shaderType, m_shaderStage, m_bufferFormat, m_writeAccessRange, m_accessOutOfBackingMemory, m_testPipelineRobustness);
803 }
804 
805 // BufferAccessInstance
806 
BufferAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,BufferAccessType bufferAccessType,VkDeviceSize inBufferAccessRange,VkDeviceSize outBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)807 BufferAccessInstance::BufferAccessInstance (Context&			context,
808 											Move<VkDevice>		device,
809 #ifndef CTS_USES_VULKANSC
810 											de::MovePtr<vk::DeviceDriver>	deviceDriver,
811 #else
812 											de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
813 #endif // CTS_USES_VULKANSC
814 											ShaderType			shaderType,
815 											VkShaderStageFlags	shaderStage,
816 											VkFormat			bufferFormat,
817 											BufferAccessType	bufferAccessType,
818 											VkDeviceSize		inBufferAccessRange,
819 											VkDeviceSize		outBufferAccessRange,
820 											bool				accessOutOfBackingMemory,
821 											bool				testPipelineRobustness)
822 	: vkt::TestInstance				(context)
823 	, m_device						(device)
824 	, m_deviceDriver				(deviceDriver)
825 	, m_shaderType					(shaderType)
826 	, m_shaderStage					(shaderStage)
827 	, m_bufferFormat				(bufferFormat)
828 	, m_bufferAccessType			(bufferAccessType)
829 	, m_inBufferAccessRange			(inBufferAccessRange)
830 	, m_outBufferAccessRange		(outBufferAccessRange)
831 	, m_accessOutOfBackingMemory	(accessOutOfBackingMemory)
832 	, m_testPipelineRobustness		(testPipelineRobustness)
833 {
834 	const DeviceInterface&		vk						= *m_deviceDriver;
835 	const auto&					vki						= context.getInstanceInterface();
836 	const auto					instance				= context.getInstance();
837 	const deUint32				queueFamilyIndex		= context.getUniversalQueueFamilyIndex();
838 	const bool					isTexelAccess			= !!(m_shaderType == SHADER_TYPE_TEXEL_COPY);
839 	const bool					readFromStorage			= !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
840 	const VkPhysicalDevice		physicalDevice			= chooseDevice(vki, instance, context.getTestContext().getCommandLine());
841 	SimpleAllocator				memAlloc				(vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
842 	tcu::TestLog&				log						= m_context.getTestContext().getLog();
843 
844 	DE_ASSERT(RobustBufferAccessTest::s_numberOfBytesAccessed % sizeof(deUint32) == 0);
845 	DE_ASSERT(inBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
846 	DE_ASSERT(outBufferAccessRange <= RobustBufferAccessTest::s_numberOfBytesAccessed);
847 
848 	if (m_bufferFormat == VK_FORMAT_R64_UINT || m_bufferFormat == VK_FORMAT_R64_SINT)
849 	{
850 		context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
851 	}
852 
853 	// Check storage support
854 	if (shaderStage == VK_SHADER_STAGE_VERTEX_BIT)
855 	{
856 		if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
857 		{
858 			TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
859 		}
860 	}
861 	else if (shaderStage == VK_SHADER_STAGE_FRAGMENT_BIT)
862 	{
863 		if (!context.getDeviceFeatures().fragmentStoresAndAtomics)
864 		{
865 			TCU_THROW(NotSupportedError, "Stores not supported in fragment stage");
866 		}
867 	}
868 
869 	// Check format support
870 	{
871 		VkFormatFeatureFlags		requiredFormatFeatures	= 0;
872 		const VkFormatProperties	formatProperties		= getPhysicalDeviceFormatProperties(vki, physicalDevice, m_bufferFormat);
873 
874 		if (isTexelAccess)
875 		{
876 			requiredFormatFeatures	= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT | VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT;
877 		}
878 
879 		if ((formatProperties.bufferFeatures & requiredFormatFeatures) != requiredFormatFeatures)
880 		{
881 			TCU_THROW(NotSupportedError, (std::string("Format cannot be used in uniform and storage") + (isTexelAccess ? " texel" : "") + " buffers: "
882 										  + getFormatName(m_bufferFormat)).c_str());
883 		}
884 	}
885 
886 	// Create buffer to read data from
887 	{
888 		VkBufferUsageFlags		inBufferUsageFlags;
889 		VkMemoryRequirements	inBufferMemoryReqs;
890 
891 		if (isTexelAccess)
892 		{
893 			inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
894 		}
895 		else
896 		{
897 			inBufferUsageFlags = readFromStorage ? VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
898 		}
899 
900 		const VkBufferCreateInfo	inBufferParams =
901 		{
902 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
903 			DE_NULL,									// const void*			pNext;
904 			0u,											// VkBufferCreateFlags	flags;
905 			m_inBufferAccessRange,						// VkDeviceSize			size;
906 			inBufferUsageFlags,							// VkBufferUsageFlags	usage;
907 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
908 			VK_QUEUE_FAMILY_IGNORED,					// deUint32				queueFamilyIndexCount;
909 			DE_NULL										// const deUint32*		pQueueFamilyIndices;
910 		};
911 
912 		m_inBuffer				= createBuffer(vk, *m_device, &inBufferParams);
913 
914 		inBufferMemoryReqs		= getBufferMemoryRequirements(vk, *m_device, *m_inBuffer);
915 		m_inBufferAllocSize		= inBufferMemoryReqs.size;
916 		m_inBufferAlloc			= memAlloc.allocate(inBufferMemoryReqs, MemoryRequirement::HostVisible);
917 
918 		// Size of the most restrictive bound
919 		m_inBufferMaxAccessRange = min(m_inBufferAllocSize, min(inBufferParams.size, m_inBufferAccessRange));
920 
921 		VK_CHECK(vk.bindBufferMemory(*m_device, *m_inBuffer, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset()));
922 		populateBufferWithTestValues(m_inBufferAlloc->getHostPtr(), m_inBufferAllocSize, m_bufferFormat);
923 		flushMappedMemoryRange(vk, *m_device, m_inBufferAlloc->getMemory(), m_inBufferAlloc->getOffset(), VK_WHOLE_SIZE);
924 
925 		log << tcu::TestLog::Message << "inBufferAllocSize = " << m_inBufferAllocSize << tcu::TestLog::EndMessage;
926 		log << tcu::TestLog::Message << "inBufferMaxAccessRange = " << m_inBufferMaxAccessRange << tcu::TestLog::EndMessage;
927 	}
928 
929 	// Create buffer to write data into
930 	{
931 		VkMemoryRequirements		outBufferMemoryReqs;
932 		const VkBufferUsageFlags	outBufferUsageFlags	= (m_shaderType == SHADER_TYPE_TEXEL_COPY) ? VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT
933 																								   : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
934 
935 		const VkBufferCreateInfo	outBufferParams		=
936 		{
937 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
938 			DE_NULL,									// const void*			pNext;
939 			0u,											// VkBufferCreateFlags	flags;
940 			m_outBufferAccessRange,						// VkDeviceSize			size;
941 			outBufferUsageFlags,						// VkBufferUsageFlags	usage;
942 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
943 			VK_QUEUE_FAMILY_IGNORED,					// deUint32				queueFamilyIndexCount;
944 			DE_NULL										// const deUint32*		pQueueFamilyIndices;
945 		};
946 
947 		m_outBuffer					= createBuffer(vk, *m_device, &outBufferParams);
948 
949 		outBufferMemoryReqs			= getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
950 		m_outBufferAllocSize		= outBufferMemoryReqs.size;
951 		m_outBufferAlloc			= memAlloc.allocate(outBufferMemoryReqs, MemoryRequirement::HostVisible);
952 
953 #ifdef CTS_USES_VULKANSC
954 		if (m_context.getTestContext().getCommandLine().isSubProcess())
955 #endif // CTS_USES_VULKANSC
956 		{
957 			// If we are requesting access out of the memory that backs the buffer, make sure the test is able to do so.
958 			if (m_accessOutOfBackingMemory)
959 			{
960 				if (m_outBufferAllocSize >= ((RobustBufferAccessTest::s_testArraySize + 1) * RobustBufferAccessTest::s_numberOfBytesAccessed))
961 				{
962 					TCU_THROW(NotSupportedError, "Cannot access beyond the end of the memory that backs the buffer");
963 				}
964 			}
965 		}
966 
967 		// Size of the most restrictive bound
968 		m_outBufferMaxAccessRange = min(m_outBufferAllocSize, min(outBufferParams.size, m_outBufferAccessRange));
969 
970 		VK_CHECK(vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
971 		deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferAllocSize);
972 		flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(), VK_WHOLE_SIZE);
973 
974 		log << tcu::TestLog::Message << "outBufferAllocSize = " << m_outBufferAllocSize << tcu::TestLog::EndMessage;
975 		log << tcu::TestLog::Message << "outBufferMaxAccessRange = " << m_outBufferMaxAccessRange << tcu::TestLog::EndMessage;
976 	}
977 
978 	// Create buffer for indices/offsets
979 	{
980 		struct IndicesBuffer
981 		{
982 			deInt32 inIndex;
983 			deInt32 outIndex;
984 		};
985 
986 		IndicesBuffer indices = { 0, 0 };
987 
988 		const VkBufferCreateInfo	indicesBufferParams			=
989 		{
990 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
991 			DE_NULL,									// const void*			pNext;
992 			0u,											// VkBufferCreateFlags	flags;
993 			sizeof(IndicesBuffer),						// VkDeviceSize			size;
994 			VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,			// VkBufferUsageFlags	usage;
995 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
996 			VK_QUEUE_FAMILY_IGNORED,					// deUint32				queueFamilyIndexCount;
997 			DE_NULL,									// const deUint32*		pQueueFamilyIndices;
998 		};
999 
1000 		m_indicesBuffer				= createBuffer(vk, *m_device, &indicesBufferParams);
1001 		m_indicesBufferAlloc		= memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indicesBuffer), MemoryRequirement::HostVisible);
1002 
1003 		VK_CHECK(vk.bindBufferMemory(*m_device, *m_indicesBuffer, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset()));
1004 
1005 		if (m_accessOutOfBackingMemory)
1006 		{
1007 			if (m_bufferAccessType == BUFFER_ACCESS_TYPE_WRITE)
1008 			{
1009 				indices.outIndex = RobustBufferAccessTest::s_testArraySize - 1;
1010 			}
1011 			else
1012 			{
1013 				indices.inIndex = RobustBufferAccessTest::s_testArraySize - 1;
1014 			}
1015 		}
1016 
1017 		deMemcpy(m_indicesBufferAlloc->getHostPtr(), &indices, sizeof(IndicesBuffer));
1018 
1019 		flushMappedMemoryRange(vk, *m_device, m_indicesBufferAlloc->getMemory(), m_indicesBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1020 
1021 		log << tcu::TestLog::Message << "inIndex = " << indices.inIndex << tcu::TestLog::EndMessage;
1022 		log << tcu::TestLog::Message << "outIndex = " << indices.outIndex << tcu::TestLog::EndMessage;
1023 	}
1024 
1025 	// Create descriptor data
1026 	{
1027 		VkDescriptorType	inBufferDescriptorType;
1028 		VkDescriptorType	outBufferDescriptorType;
1029 
1030 		if (isTexelAccess)
1031 		{
1032 			inBufferDescriptorType	= readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
1033 			outBufferDescriptorType	= VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
1034 		}
1035 		else
1036 		{
1037 			inBufferDescriptorType	= readFromStorage ? VK_DESCRIPTOR_TYPE_STORAGE_BUFFER : VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1038 			outBufferDescriptorType	= VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1039 		}
1040 
1041 		DescriptorPoolBuilder descriptorPoolBuilder;
1042 		descriptorPoolBuilder.addType(inBufferDescriptorType, 1u);
1043 		descriptorPoolBuilder.addType(outBufferDescriptorType, 1u);
1044 		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1u);
1045 		m_descriptorPool = descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1046 
1047 		DescriptorSetLayoutBuilder setLayoutBuilder;
1048 		setLayoutBuilder.addSingleBinding(inBufferDescriptorType, VK_SHADER_STAGE_ALL);
1049 		setLayoutBuilder.addSingleBinding(outBufferDescriptorType, VK_SHADER_STAGE_ALL);
1050 		setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
1051 		m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
1052 
1053 		const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo =
1054 		{
1055 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,		// VkStructureType				sType;
1056 			DE_NULL,											// const void*					pNext;
1057 			*m_descriptorPool,									// VkDescriptorPool				descriptorPool;
1058 			1u,													// deUint32						setLayoutCount;
1059 			&m_descriptorSetLayout.get()						// const VkDescriptorSetLayout*	pSetLayouts;
1060 		};
1061 
1062 		m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
1063 
1064 		DescriptorSetUpdateBuilder setUpdateBuilder;
1065 
1066 		if (isTexelAccess)
1067 		{
1068 			const VkBufferViewCreateInfo inBufferViewCreateInfo =
1069 			{
1070 				VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,		// VkStructureType			sType;
1071 				DE_NULL,										// const void*				pNext;
1072 				0u,												// VkBufferViewCreateFlags	flags;
1073 				*m_inBuffer,									// VkBuffer					buffer;
1074 				m_bufferFormat,									// VkFormat					format;
1075 				0ull,											// VkDeviceSize				offset;
1076 				m_inBufferAccessRange							// VkDeviceSize				range;
1077 			};
1078 			m_inTexelBufferView	= createBufferView(vk, *m_device, &inBufferViewCreateInfo, DE_NULL);
1079 
1080 			const VkBufferViewCreateInfo outBufferViewCreateInfo =
1081 			{
1082 				VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,		// VkStructureType			sType;
1083 				DE_NULL,										// const void*				pNext;
1084 				0u,												// VkBufferViewCreateFlags	flags;
1085 				*m_outBuffer,									// VkBuffer					buffer;
1086 				m_bufferFormat,									// VkFormat					format;
1087 				0ull,											// VkDeviceSize				offset;
1088 				m_outBufferAccessRange,							// VkDeviceSize				range;
1089 			};
1090 			m_outTexelBufferView	= createBufferView(vk, *m_device, &outBufferViewCreateInfo, DE_NULL);
1091 
1092 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &m_inTexelBufferView.get());
1093 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &m_outTexelBufferView.get());
1094 		}
1095 		else
1096 		{
1097 			const VkDescriptorBufferInfo inBufferDescriptorInfo		= makeDescriptorBufferInfo(*m_inBuffer, 0ull, m_inBufferAccessRange);
1098 			const VkDescriptorBufferInfo outBufferDescriptorInfo	= makeDescriptorBufferInfo(*m_outBuffer, 0ull, m_outBufferAccessRange);
1099 
1100 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0), inBufferDescriptorType, &inBufferDescriptorInfo);
1101 			setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(1), outBufferDescriptorType, &outBufferDescriptorInfo);
1102 		}
1103 
1104 		const VkDescriptorBufferInfo indicesBufferDescriptorInfo	= makeDescriptorBufferInfo(*m_indicesBuffer, 0ull, 8ull);
1105 		setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(2), VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, &indicesBufferDescriptorInfo);
1106 
1107 		setUpdateBuilder.update(vk, *m_device);
1108 	}
1109 
1110 	// Create fence
1111 	{
1112 		const VkFenceCreateInfo fenceParams =
1113 		{
1114 			VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,	// VkStructureType		sType;
1115 			DE_NULL,								// const void*			pNext;
1116 			0u										// VkFenceCreateFlags	flags;
1117 		};
1118 
1119 		m_fence = createFence(vk, *m_device, &fenceParams);
1120 	}
1121 
1122 	// Get queue
1123 	vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
1124 
1125 	if (m_shaderStage == VK_SHADER_STAGE_COMPUTE_BIT)
1126 	{
1127 		m_testEnvironment = de::MovePtr<TestEnvironment>(new ComputeEnvironment(m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet, m_testPipelineRobustness));
1128 	}
1129 	else
1130 	{
1131 		using tcu::Vec4;
1132 
1133 		const VkVertexInputBindingDescription vertexInputBindingDescription =
1134 		{
1135 			0u,								// deUint32					binding;
1136 			sizeof(tcu::Vec4),				// deUint32					strideInBytes;
1137 			VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputStepRate	inputRate;
1138 		};
1139 
1140 		const VkVertexInputAttributeDescription vertexInputAttributeDescription =
1141 		{
1142 			0u,								// deUint32	location;
1143 			0u,								// deUint32	binding;
1144 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat	format;
1145 			0u								// deUint32	offset;
1146 		};
1147 
1148 		const Vec4 vertices[] =
1149 		{
1150 			Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
1151 			Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
1152 			Vec4(1.0f, -1.0f, 0.0f, 1.0f),
1153 		};
1154 
1155 		// Create vertex buffer
1156 		{
1157 			const VkDeviceSize			vertexBufferSize	= (VkDeviceSize)(4u * sizeof(tcu::Vec4));
1158 			const VkBufferCreateInfo	vertexBufferParams	=
1159 			{
1160 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
1161 				DE_NULL,									// const void*			pNext;
1162 				0u,											// VkBufferCreateFlags	flags;
1163 				vertexBufferSize,							// VkDeviceSize			size;
1164 				VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
1165 				VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
1166 				VK_QUEUE_FAMILY_IGNORED,					// deUint32				queueFamilyIndexCount;
1167 				DE_NULL										// const deUint32*		pQueueFamilyIndices;
1168 			};
1169 
1170 			DE_ASSERT(vertexBufferSize > 0);
1171 
1172 			m_vertexBuffer		= createBuffer(vk, *m_device, &vertexBufferParams);
1173 			m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexBuffer), MemoryRequirement::HostVisible);
1174 
1175 			VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
1176 
1177 			// Load vertices into vertex buffer
1178 			deMemcpy(m_vertexBufferAlloc->getHostPtr(), vertices, sizeof(tcu::Vec4) * DE_LENGTH_OF_ARRAY(vertices));
1179 			flushMappedMemoryRange(vk, *m_device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), VK_WHOLE_SIZE);
1180 		}
1181 
1182 		const GraphicsEnvironment::DrawConfig drawWithOneVertexBuffer =
1183 		{
1184 			std::vector<VkBuffer>(1, *m_vertexBuffer),	// std::vector<VkBuffer>	vertexBuffers;
1185 			DE_LENGTH_OF_ARRAY(vertices),				// deUint32					vertexCount;
1186 			1,											// deUint32					instanceCount;
1187 			DE_NULL,									// VkBuffer					indexBuffer;
1188 			0u,											// deUint32					indexCount;
1189 		};
1190 
1191 		m_testEnvironment = de::MovePtr<TestEnvironment>(new GraphicsEnvironment(m_context,
1192 																				 *m_deviceDriver,
1193 																				 *m_device,
1194 																				 *m_descriptorSetLayout,
1195 																				 *m_descriptorSet,
1196 																				 GraphicsEnvironment::VertexBindings(1, vertexInputBindingDescription),
1197 																				 GraphicsEnvironment::VertexAttributes(1, vertexInputAttributeDescription),
1198 																				 drawWithOneVertexBuffer,
1199 																				 m_testPipelineRobustness));
1200 	}
1201 }
1202 
~BufferAccessInstance(void)1203 BufferAccessInstance::~BufferAccessInstance(void)
1204 {
1205 }
1206 
1207 // Verifies if the buffer has the value initialized by BufferAccessInstance::populateReadBuffer at a given offset.
isExpectedValueFromInBuffer(VkDeviceSize offsetInBytes,const void * valuePtr,VkDeviceSize valueSize)1208 bool BufferAccessInstance::isExpectedValueFromInBuffer (VkDeviceSize offsetInBytes, const void* valuePtr, VkDeviceSize valueSize)
1209 {
1210 	DE_ASSERT(offsetInBytes % 4 == 0);
1211 	DE_ASSERT(offsetInBytes < m_inBufferAllocSize);
1212 
1213 	const deUint32 valueIndex = deUint32(offsetInBytes / 4) + 2;
1214 
1215 	if (isUintFormat(m_bufferFormat))
1216 	{
1217 		return !deMemCmp(valuePtr, &valueIndex, (size_t)valueSize);
1218 	}
1219 	else if (isIntFormat(m_bufferFormat))
1220 	{
1221 		const deInt32 value = -deInt32(valueIndex);
1222 		return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1223 	}
1224 	else if (isFloatFormat(m_bufferFormat))
1225 	{
1226 		const float value = float(valueIndex);
1227 		return !deMemCmp(valuePtr, &value, (size_t)valueSize);
1228 	}
1229 	else if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1230 	{
1231 		const deUint32	r		= ((valueIndex + 0) & ((2u << 10) - 1u));
1232 		const deUint32	g		= ((valueIndex + 1) & ((2u << 10) - 1u));
1233 		const deUint32	b		= ((valueIndex + 2) & ((2u << 10) - 1u));
1234 		const deUint32	a		= ((valueIndex + 0) & ((2u << 2) - 1u));
1235 		const deUint32	abgr	= (a << 30) | (b << 20) | (g << 10) | r;
1236 
1237 		return !deMemCmp(valuePtr, &abgr, (size_t)valueSize);
1238 	}
1239 	else
1240 	{
1241 		DE_ASSERT(false);
1242 		return false;
1243 	}
1244 }
1245 
isOutBufferValueUnchanged(VkDeviceSize offsetInBytes,VkDeviceSize valueSize)1246 bool BufferAccessInstance::isOutBufferValueUnchanged (VkDeviceSize offsetInBytes, VkDeviceSize valueSize)
1247 {
1248 	const deUint8 *const	outValuePtr		= (deUint8*)m_outBufferAlloc->getHostPtr() + offsetInBytes;
1249 	const deUint32			defaultValue	= 0xFFFFFFFFu;
1250 
1251 	return !deMemCmp(outValuePtr, &defaultValue, (size_t)valueSize);
1252 }
1253 
iterate(void)1254 tcu::TestStatus BufferAccessInstance::iterate (void)
1255 {
1256 	const DeviceInterface&		vk			= *m_deviceDriver;
1257 	const vk::VkCommandBuffer	cmdBuffer	= m_testEnvironment->getCommandBuffer();
1258 
1259 	// Submit command buffer
1260 	{
1261 		const VkSubmitInfo	submitInfo	=
1262 		{
1263 			VK_STRUCTURE_TYPE_SUBMIT_INFO,	// VkStructureType				sType;
1264 			DE_NULL,						// const void*					pNext;
1265 			0u,								// deUint32						waitSemaphoreCount;
1266 			DE_NULL,						// const VkSemaphore*			pWaitSemaphores;
1267 			DE_NULL,						// const VkPIpelineStageFlags*	pWaitDstStageMask;
1268 			1u,								// deUint32						commandBufferCount;
1269 			&cmdBuffer,						// const VkCommandBuffer*		pCommandBuffers;
1270 			0u,								// deUint32						signalSemaphoreCount;
1271 			DE_NULL							// const VkSemaphore*			pSignalSemaphores;
1272 		};
1273 
1274 		VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
1275 		VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
1276 		VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
1277 	}
1278 
1279 	// Prepare result buffer for read
1280 	{
1281 		const VkMappedMemoryRange	outBufferRange	=
1282 		{
1283 			VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,	//  VkStructureType	sType;
1284 			DE_NULL,								//  const void*		pNext;
1285 			m_outBufferAlloc->getMemory(),			//  VkDeviceMemory	mem;
1286 			0ull,									//  VkDeviceSize	offset;
1287 			m_outBufferAllocSize,					//  VkDeviceSize	size;
1288 		};
1289 
1290 		VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
1291 	}
1292 
1293 	if (verifyResult())
1294 		return tcu::TestStatus::pass("All values OK");
1295 	else
1296 		return tcu::TestStatus::fail("Invalid value(s) found");
1297 }
1298 
verifyResult(void)1299 bool BufferAccessInstance::verifyResult (void)
1300 {
1301 	std::ostringstream	logMsg;
1302 	tcu::TestLog&		log					= m_context.getTestContext().getLog();
1303 	const bool			isReadAccess		= !!(m_bufferAccessType == BUFFER_ACCESS_TYPE_READ || m_bufferAccessType == BUFFER_ACCESS_TYPE_READ_FROM_STORAGE);
1304 	const void*			inDataPtr			= m_inBufferAlloc->getHostPtr();
1305 	const void*			outDataPtr			= m_outBufferAlloc->getHostPtr();
1306 	bool				allOk				= true;
1307 	deUint32			valueNdx			= 0;
1308 	const VkDeviceSize	maxAccessRange		= isReadAccess ? m_inBufferMaxAccessRange : m_outBufferMaxAccessRange;
1309 
1310 	for (VkDeviceSize offsetInBytes = 0; offsetInBytes < m_outBufferAllocSize; offsetInBytes += 4)
1311 	{
1312 		deUint8*			outValuePtr		= (deUint8*)outDataPtr + offsetInBytes;
1313 		const size_t		outValueSize	= (size_t)min(4, (m_outBufferAllocSize - offsetInBytes));
1314 
1315 		if (offsetInBytes >= RobustBufferAccessTest::s_numberOfBytesAccessed)
1316 		{
1317 			// The shader will only write 16 values into the result buffer. The rest of the values
1318 			// should remain unchanged or may be modified if we are writing out of bounds.
1319 			if (!isOutBufferValueUnchanged(offsetInBytes, outValueSize)
1320 				&& (isReadAccess || !isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, 4)))
1321 			{
1322 				logMsg << "\nValue " << valueNdx++ << " has been modified with an unknown value: " << *((deUint32 *)outValuePtr);
1323 				allOk = false;
1324 			}
1325 		}
1326 		else
1327 		{
1328 			const deInt32	distanceToOutOfBounds	= (deInt32)maxAccessRange - (deInt32)offsetInBytes;
1329 			bool			isOutOfBoundsAccess		= false;
1330 
1331 			logMsg << "\n" << valueNdx++ << ": ";
1332 
1333 			logValue(logMsg, outValuePtr, m_bufferFormat, outValueSize);
1334 
1335 			if (m_accessOutOfBackingMemory)
1336 			{
1337 				isOutOfBoundsAccess = true;
1338 			}
1339 			else
1340 			{
1341 				// Check if the shader operation accessed an operand located less than 16 bytes away
1342 				// from the out of bounds address.
1343 
1344 				deUint32 operandSize = 0;
1345 
1346 				switch (m_shaderType)
1347 				{
1348 					case SHADER_TYPE_SCALAR_COPY:
1349 						operandSize		= 4; // Size of scalar
1350 						break;
1351 
1352 					case SHADER_TYPE_VECTOR_COPY:
1353 						operandSize		= 4 * ((m_bufferFormat == vk::VK_FORMAT_R64_UINT || m_bufferFormat == vk::VK_FORMAT_R64_SINT) ? 8 : 4);// Size of vec4
1354 						break;
1355 
1356 					case SHADER_TYPE_MATRIX_COPY:
1357 						operandSize		= 4 * 16; // Size of mat4
1358 						break;
1359 
1360 					case SHADER_TYPE_TEXEL_COPY:
1361 						operandSize		= mapVkFormat(m_bufferFormat).getPixelSize();
1362 						break;
1363 
1364 					default:
1365 						DE_ASSERT(false);
1366 				}
1367 
1368 				isOutOfBoundsAccess = (maxAccessRange < 16)
1369 									|| (((offsetInBytes / operandSize + 1) * operandSize) > (maxAccessRange - 16));
1370 			}
1371 
1372 			if (isOutOfBoundsAccess)
1373 			{
1374 				logMsg << " (out of bounds " << (isReadAccess ? "read": "write") << ")";
1375 
1376 				const bool	isValuePartiallyOutOfBounds = ((distanceToOutOfBounds > 0) && ((deUint32)distanceToOutOfBounds < 4));
1377 				bool		isValidValue				= false;
1378 
1379 				if (isValuePartiallyOutOfBounds && !m_accessOutOfBackingMemory)
1380 				{
1381 					// The value is partially out of bounds
1382 
1383 					bool	isOutOfBoundsPartOk = true;
1384 					bool	isWithinBoundsPartOk = true;
1385 
1386 					if (isReadAccess)
1387 					{
1388 						isWithinBoundsPartOk	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds);
1389 						isOutOfBoundsPartOk		= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds , outValueSize - distanceToOutOfBounds);
1390 					}
1391 					else
1392 					{
1393 						isWithinBoundsPartOk	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, distanceToOutOfBounds)
1394 												  || isOutBufferValueUnchanged(offsetInBytes, distanceToOutOfBounds);
1395 
1396 						isOutOfBoundsPartOk		= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, (deUint8*)outValuePtr + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds)
1397 												  || isOutBufferValueUnchanged(offsetInBytes + distanceToOutOfBounds, outValueSize - distanceToOutOfBounds);
1398 					}
1399 
1400 					logMsg << ", first " << distanceToOutOfBounds << " byte(s) " << (isWithinBoundsPartOk ? "OK": "wrong");
1401 					logMsg << ", last " << outValueSize - distanceToOutOfBounds << " byte(s) " << (isOutOfBoundsPartOk ? "OK": "wrong");
1402 
1403 					isValidValue	= isWithinBoundsPartOk && isOutOfBoundsPartOk;
1404 				}
1405 				else
1406 				{
1407 					if (isReadAccess)
1408 					{
1409 						isValidValue	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1410 					}
1411 					else
1412 					{
1413 						isValidValue	= isOutBufferValueUnchanged(offsetInBytes, outValueSize);
1414 
1415 						if (!isValidValue)
1416 						{
1417 							// Out of bounds writes may modify values withing the memory ranges bound to the buffer
1418 							isValidValue	= isValueWithinBufferOrZero(inDataPtr, m_inBufferAllocSize, outValuePtr, outValueSize);
1419 
1420 							if (isValidValue)
1421 								logMsg << ", OK, written within the memory range bound to the buffer";
1422 						}
1423 					}
1424 				}
1425 
1426 				if (!isValidValue)
1427 				{
1428 					// Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
1429 					// or the maximum representable positive integer value (if the format is integer-based).
1430 
1431 					const bool	canMatchVec4Pattern	= (isReadAccess
1432 													&& !isValuePartiallyOutOfBounds
1433 													&& (m_shaderType == SHADER_TYPE_VECTOR_COPY || m_shaderType == SHADER_TYPE_TEXEL_COPY)
1434 													&& ((offsetInBytes / 4 + 1) % 4 == 0 || m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32));
1435 					bool		matchesVec4Pattern	= false;
1436 
1437 					if (canMatchVec4Pattern)
1438 					{
1439 						if (m_bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1440 							matchesVec4Pattern	= verifyOutOfBoundsVec4(outValuePtr, m_bufferFormat);
1441 						else
1442 							matchesVec4Pattern	= verifyOutOfBoundsVec4(reinterpret_cast<deUint32*>(outValuePtr) - 3, m_bufferFormat);
1443 					}
1444 
1445 					if (!canMatchVec4Pattern || !matchesVec4Pattern)
1446 					{
1447 						logMsg << ". Failed: ";
1448 
1449 						if (isReadAccess)
1450 						{
1451 							logMsg << "expected value within the buffer range or 0";
1452 
1453 							if (canMatchVec4Pattern)
1454 								logMsg << ", or the [0, 0, 0, x] pattern";
1455 						}
1456 						else
1457 						{
1458 							logMsg << "written out of the range";
1459 						}
1460 
1461 						allOk = false;
1462 					}
1463 				}
1464 			}
1465 			else // We are within bounds
1466 			{
1467 				if (isReadAccess)
1468 				{
1469 					if (!isExpectedValueFromInBuffer(offsetInBytes, outValuePtr, 4))
1470 					{
1471 						logMsg << ", Failed: unexpected value";
1472 						allOk = false;
1473 					}
1474 				}
1475 				else
1476 				{
1477 					// Out of bounds writes may change values within the bounds.
1478 					if (!isValueWithinBufferOrZero(inDataPtr, m_inBufferAccessRange, outValuePtr, 4))
1479 					{
1480 						logMsg << ", Failed: unexpected value";
1481 						allOk = false;
1482 					}
1483 				}
1484 			}
1485 		}
1486 	}
1487 
1488 	log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
1489 
1490 	return allOk;
1491 }
1492 
1493 // BufferReadInstance
1494 
BufferReadInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,bool readFromStorage,VkDeviceSize inBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)1495 BufferReadInstance::BufferReadInstance (Context&			context,
1496 										Move<VkDevice>		device,
1497 #ifndef CTS_USES_VULKANSC
1498 										de::MovePtr<vk::DeviceDriver>	deviceDriver,
1499 #else
1500 										de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
1501 #endif // CTS_USES_VULKANSC
1502 										ShaderType			shaderType,
1503 										VkShaderStageFlags	shaderStage,
1504 										VkFormat			bufferFormat,
1505 										bool				readFromStorage,
1506 										VkDeviceSize		inBufferAccessRange,
1507 										bool				accessOutOfBackingMemory,
1508 										bool				testPipelineRobustness)
1509 
1510 	: BufferAccessInstance	(context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1511 							 readFromStorage ? BUFFER_ACCESS_TYPE_READ_FROM_STORAGE : BUFFER_ACCESS_TYPE_READ,
1512 							 inBufferAccessRange,
1513 							 RobustBufferAccessTest::s_numberOfBytesAccessed,	// outBufferAccessRange
1514 							 accessOutOfBackingMemory,
1515 							 testPipelineRobustness)
1516 {
1517 }
1518 
1519 // BufferWriteInstance
1520 
BufferWriteInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,ShaderType shaderType,VkShaderStageFlags shaderStage,VkFormat bufferFormat,VkDeviceSize writeBufferAccessRange,bool accessOutOfBackingMemory,bool testPipelineRobustness)1521 BufferWriteInstance::BufferWriteInstance (Context&				context,
1522 										  Move<VkDevice>		device,
1523 #ifndef CTS_USES_VULKANSC
1524 										  de::MovePtr<vk::DeviceDriver>		deviceDriver,
1525 #else
1526 										  de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>	deviceDriver,
1527 #endif // CTS_USES_VULKANSC
1528 										  ShaderType			shaderType,
1529 										  VkShaderStageFlags	shaderStage,
1530 										  VkFormat				bufferFormat,
1531 										  VkDeviceSize			writeBufferAccessRange,
1532 										  bool					accessOutOfBackingMemory,
1533 										  bool					testPipelineRobustness)
1534 
1535 	: BufferAccessInstance	(context, device, deviceDriver, shaderType, shaderStage, bufferFormat,
1536 							 BUFFER_ACCESS_TYPE_WRITE,
1537 							 RobustBufferAccessTest::s_numberOfBytesAccessed,	// inBufferAccessRange
1538 							 writeBufferAccessRange,
1539 							 accessOutOfBackingMemory,
1540 							 testPipelineRobustness)
1541 {
1542 }
1543 
1544 // Test node creation functions
1545 
getShaderStageName(VkShaderStageFlagBits shaderStage)1546 static const char* getShaderStageName (VkShaderStageFlagBits shaderStage)
1547 {
1548 	switch (shaderStage)
1549 	{
1550 		case VK_SHADER_STAGE_VERTEX_BIT:					return "vertex";
1551 		case VK_SHADER_STAGE_FRAGMENT_BIT:					return "fragment";
1552 		case VK_SHADER_STAGE_COMPUTE_BIT:					return "compute";
1553 		case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:		return "tess_control";
1554 		case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:	return "tess_eval";
1555 		case VK_SHADER_STAGE_GEOMETRY_BIT:					return "geometry";
1556 
1557 		default:
1558 			DE_ASSERT(false);
1559 	}
1560 
1561 	return DE_NULL;
1562 }
1563 
addBufferAccessTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentNode,bool testPipelineRobustness)1564 static void addBufferAccessTests (tcu::TestContext& testCtx, tcu::TestCaseGroup* parentNode, bool testPipelineRobustness)
1565 {
1566 	struct BufferRangeConfig
1567 	{
1568 		const char*		name;
1569 		VkDeviceSize	range;
1570 	};
1571 
1572 	const VkShaderStageFlagBits bufferAccessStages[] =
1573 	{
1574 		VK_SHADER_STAGE_VERTEX_BIT,
1575 		VK_SHADER_STAGE_FRAGMENT_BIT,
1576 		VK_SHADER_STAGE_COMPUTE_BIT,
1577 	};
1578 
1579 	const VkFormat bufferFormats[] =
1580 	{
1581 		VK_FORMAT_R32_SINT,
1582 		VK_FORMAT_R32_UINT,
1583 		VK_FORMAT_R64_SINT,
1584 		VK_FORMAT_R64_UINT,
1585 		VK_FORMAT_R32_SFLOAT
1586 	};
1587 
1588 	const VkFormat texelBufferFormats[] =
1589 	{
1590 		VK_FORMAT_R32G32B32A32_SINT,
1591 		VK_FORMAT_R32G32B32A32_UINT,
1592 		VK_FORMAT_R32G32B32A32_SFLOAT,
1593 
1594 		VK_FORMAT_A2B10G10R10_UNORM_PACK32
1595 	};
1596 
1597 	const BufferRangeConfig bufferRangeConfigs[] =
1598 	{
1599 		{ "range_1_byte",		1ull },
1600 		{ "range_3_bytes",		3ull },
1601 		{ "range_4_bytes",		4ull },		// size of float
1602 		{ "range_32_bytes",		32ull },	// size of half mat4
1603 	};
1604 
1605 	const BufferRangeConfig texelBufferRangeConfigs[] =
1606 	{
1607 		{ "range_1_texel",		1u },
1608 		{ "range_3_texels",		3u },
1609 	};
1610 
1611 	const char* shaderTypeNames[SHADER_TYPE_COUNT] =
1612 	{
1613 		"mat4_copy",
1614 		"vec4_copy",
1615 		"scalar_copy",
1616 		"texel_copy",
1617 	};
1618 
1619 	for (int stageNdx = 0; stageNdx < DE_LENGTH_OF_ARRAY(bufferAccessStages); stageNdx++)
1620 	{
1621 		const VkShaderStageFlagBits			stage			= bufferAccessStages[stageNdx];
1622 		de::MovePtr<tcu::TestCaseGroup>		stageTests		(new tcu::TestCaseGroup(testCtx, getShaderStageName(stage), ""));
1623 
1624 		for (int shaderTypeNdx = 0; shaderTypeNdx < SHADER_TYPE_COUNT; shaderTypeNdx++)
1625 		{
1626 			const VkFormat*					formats;
1627 			size_t							formatsLength;
1628 			const BufferRangeConfig*		ranges;
1629 			size_t							rangesLength;
1630 			deUint32						rangeMultiplier;
1631 			de::MovePtr<tcu::TestCaseGroup> shaderTypeTests	(new tcu::TestCaseGroup(testCtx, shaderTypeNames[shaderTypeNdx], ""));
1632 
1633 			if ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY)
1634 			{
1635 				formats			= texelBufferFormats;
1636 				formatsLength	= DE_LENGTH_OF_ARRAY(texelBufferFormats);
1637 
1638 				ranges			= texelBufferRangeConfigs;
1639 				rangesLength	= DE_LENGTH_OF_ARRAY(texelBufferRangeConfigs);
1640 			}
1641 			else
1642 			{
1643 				formats			= bufferFormats;
1644 				formatsLength	= DE_LENGTH_OF_ARRAY(bufferFormats);
1645 
1646 				ranges			= bufferRangeConfigs;
1647 				rangesLength	= DE_LENGTH_OF_ARRAY(bufferRangeConfigs);
1648 			}
1649 
1650 			for (size_t formatNdx = 0; formatNdx < formatsLength; formatNdx++)
1651 			{
1652 				const VkFormat	bufferFormat	= formats[formatNdx];
1653 
1654 				rangeMultiplier = ((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY) ? mapVkFormat(bufferFormat).getPixelSize() : 1;
1655 
1656 				if (!isFloatFormat(bufferFormat) && ((ShaderType)shaderTypeNdx) == SHADER_TYPE_MATRIX_COPY)
1657 				{
1658 					// Use SHADER_TYPE_MATRIX_COPY with floating-point formats only
1659 					break;
1660 				}
1661 
1662 				// Avoid too much duplication by excluding certain test cases
1663 				if (testPipelineRobustness &&
1664 					!(bufferFormat == VK_FORMAT_R32_UINT || bufferFormat == VK_FORMAT_R64_SINT || bufferFormat == VK_FORMAT_R32_SFLOAT || bufferFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32))
1665 				{
1666 					continue;
1667 				}
1668 
1669 				const std::string				formatName		= getFormatName(bufferFormat);
1670 				de::MovePtr<tcu::TestCaseGroup>	formatTests		(new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str(), ""));
1671 
1672 				de::MovePtr<tcu::TestCaseGroup> uboReadTests		(new tcu::TestCaseGroup(testCtx, "oob_uniform_read", ""));
1673 				de::MovePtr<tcu::TestCaseGroup> ssboReadTests		(new tcu::TestCaseGroup(testCtx, "oob_storage_read", ""));
1674 				de::MovePtr<tcu::TestCaseGroup> ssboWriteTests		(new tcu::TestCaseGroup(testCtx, "oob_storage_write", ""));
1675 
1676 				for (size_t rangeNdx = 0; rangeNdx < rangesLength; rangeNdx++)
1677 				{
1678 					const BufferRangeConfig&	rangeConfig			= ranges[rangeNdx];
1679 					const VkDeviceSize			rangeInBytes		= rangeConfig.range * rangeMultiplier;
1680 
1681 					uboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false, false));
1682 
1683 					// Avoid too much duplication by excluding certain test cases
1684 					if (!testPipelineRobustness)
1685 						ssboReadTests->addChild(new RobustBufferReadTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, true, false));
1686 
1687 					ssboWriteTests->addChild(new RobustBufferWriteTest(testCtx, rangeConfig.name, "", stage, (ShaderType)shaderTypeNdx, bufferFormat, testPipelineRobustness, rangeInBytes, false));
1688 
1689 				}
1690 
1691 				formatTests->addChild(uboReadTests.release());
1692 				formatTests->addChild(ssboReadTests.release());
1693 				formatTests->addChild(ssboWriteTests.release());
1694 
1695 				shaderTypeTests->addChild(formatTests.release());
1696 			}
1697 
1698 			// Read/write out of the memory that backs the buffer
1699 			{
1700 				de::MovePtr<tcu::TestCaseGroup>	outOfAllocTests		(new tcu::TestCaseGroup(testCtx, "out_of_alloc", ""));
1701 
1702 				const VkFormat format = (((ShaderType)shaderTypeNdx == SHADER_TYPE_TEXEL_COPY ) ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R32_SFLOAT);
1703 
1704 				outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_uniform_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, false, true));
1705 
1706 				// Avoid too much duplication by excluding certain test cases
1707 				if (!testPipelineRobustness)
1708 					outOfAllocTests->addChild(new RobustBufferReadTest(testCtx, "oob_storage_read", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true, true));
1709 
1710 				outOfAllocTests->addChild(new RobustBufferWriteTest(testCtx, "oob_storage_write", "", stage, (ShaderType)shaderTypeNdx, format, testPipelineRobustness, 16, true));
1711 
1712 				shaderTypeTests->addChild(outOfAllocTests.release());
1713 			}
1714 
1715 			stageTests->addChild(shaderTypeTests.release());
1716 		}
1717 		parentNode->addChild(stageTests.release());
1718 	}
1719 }
1720 
createBufferAccessTests(tcu::TestContext & testCtx)1721 tcu::TestCaseGroup* createBufferAccessTests (tcu::TestContext& testCtx)
1722 {
1723 	de::MovePtr<tcu::TestCaseGroup> bufferAccessTests	(new tcu::TestCaseGroup(testCtx, "buffer_access", ""));
1724 
1725 	addBufferAccessTests(testCtx, bufferAccessTests.get(), false);
1726 
1727 	return bufferAccessTests.release();
1728 }
1729 
1730 #ifndef CTS_USES_VULKANSC
createPipelineRobustnessBufferAccessTests(tcu::TestContext & testCtx)1731 tcu::TestCaseGroup* createPipelineRobustnessBufferAccessTests (tcu::TestContext& testCtx)
1732 {
1733 	de::MovePtr<tcu::TestCaseGroup> bufferAccessTests	(new tcu::TestCaseGroup(testCtx, "pipeline_robustness_buffer_access", ""));
1734 	addBufferAccessTests(testCtx, bufferAccessTests.get(), true);
1735 
1736 	return bufferAccessTests.release();
1737 }
1738 #endif
1739 
1740 } // robustness
1741 } // vkt
1742