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