• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2016 The Android Open Source Project
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 SPIR-V Assembly Tests for PhysicalStorageBuffer.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktSpvAsmPhysicalStorageBufferPointerTests.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vkBarrierUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkCmdUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkQueryUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "deSharedPtr.hpp"
37 #include "deUniquePtr.hpp"
38 #include "tcuTextureUtil.hpp"
39 #include "tcuVectorUtil.hpp"
40 
41 #include <iterator>
42 
43 using namespace vk;
44 using de::MovePtr;
45 using de::SharedPtr;
46 
47 namespace vkt
48 {
49 namespace SpirVAssembly
50 {
51 
52 namespace
53 {
54 
55 enum class PassMethod
56 {
57 	PUSH_CONSTANTS,
58 	PUSH_CONSTANTS_FUNCTION,
59 	VERTEX_IN_OUT_IN,
60 	ADDRESSES_IN_SSBO
61 };
62 
63 struct TestParams
64 {
65 	PassMethod	method;
66 	deUint32	elements;
67 };
68 
69 typedef SharedPtr<const TestParams>	TestParamsPtr;
70 
71 namespace ut
72 {
73 
74 class Buffer
75 {
76 public:
77 					Buffer			(Context& ctx, VkBufferUsageFlags usage, VkDeviceSize size, bool address = false);
78 					Buffer			(const Buffer& src);
79 
getBuffer(void) const80 	VkBuffer		getBuffer		(void) const { return **m_buffer; }
getSize(void) const81 	VkDeviceSize	getSize			(void) const { return m_size; }
getData(void) const82 	void*			getData			(void) const { return (*m_bufferMemory)->getHostPtr(); }
83 	deUint64		getDeviceAddress(void) const;
84 	void			zero			(bool flushAfter = false);
85 	void			flush			(void);
86 	void			invalidate		(void);
87 
88 protected:
89 	Context&						m_context;
90 	const VkDeviceSize				m_size;
91 	const bool						m_address;
92 	SharedPtr<Move<VkBuffer>>		m_buffer;
93 	SharedPtr<MovePtr<Allocation>>	m_bufferMemory;
94 };
95 
96 template<class X> class TypedBuffer : public Buffer
97 {
98 public:
99 				TypedBuffer		(Context&					ctx,
100 								 VkBufferUsageFlags			usage,
101 								 deUint32					nelements,
102 								 bool						address = false);
103 				TypedBuffer		(Context&					ctx,
104 								 VkBufferUsageFlags			usage,
105 								 std::initializer_list<X>	items,
106 								 bool						address = false);
107 				TypedBuffer		(const TypedBuffer&			src);
108 				TypedBuffer		(const Buffer&				src);
109 
getElements(void) const110 	deUint32	getElements		(void) const { return m_elements; }
getData(void) const111 	X*			getData			(void) const { return reinterpret_cast<X*>(Buffer::getData()); }
112 	void		iota			(X start, bool flushAfter = false);
113 	X&			operator[]		(deUint32 at);
114 
115 	struct iterator;
begin()116 	iterator	begin			() { return iterator(getData()); }
end()117 	iterator	end				() { return iterator(&getData()[m_elements]); }
118 
119 private:
120 	const deUint32				m_elements;
121 };
122 
123 class Image
124 {
125 public:
126 										Image				(Context&			ctx,
127 															 deUint32			width,
128 															 deUint32			height,
129 															 VkFormat			format);
130 										Image				(const Image&) = delete;
131 										Image				(Image&&) = delete;
132 
133 	Move<VkRenderPass>					createRenderPass	(void) const;
134 	Move<VkFramebuffer>					createFramebuffer	(VkRenderPass		rp) const;
135 
136 	template<class X> TypedBuffer<X>	getBuffer			(void);
137 	void								downloadAfterDraw	(VkCommandBuffer	cmdBuffer);
138 
139 private:
140 	Context&				m_context;
141 	const deUint32			m_width;
142 	const deUint32			m_height;
143 	const VkFormat			m_format;
144 	VkImageLayout			m_layout;
145 	Buffer					m_buffer;
146 
147 	Move<VkImage>			m_image;
148 	Move<VkImageView>		m_view;
149 	de::MovePtr<Allocation>	m_imageMemory;
150 };
151 
makeShared(Move<X> move)152 template<class X> SharedPtr<Move<X>> makeShared(Move<X> move)
153 {
154 	return SharedPtr<Move<X>>(new Move<X>(move));
155 }
156 
makeShared(MovePtr<X> move)157 template<class X> SharedPtr<MovePtr<X>> makeShared(MovePtr<X> move)
158 {
159 	return SharedPtr<MovePtr<X>>(new MovePtr<X>(move));
160 }
161 
Buffer(Context & ctx,VkBufferUsageFlags usage,VkDeviceSize size,bool address)162 Buffer::Buffer	(Context& ctx, VkBufferUsageFlags usage, VkDeviceSize size, bool address)
163 	: m_context		(ctx)
164 	, m_size		(size)
165 	, m_address		(address)
166 {
167 	const DeviceInterface&			vki					= m_context.getDeviceInterface();
168 	const VkDevice					dev					= m_context.getDevice();
169 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
170 	Allocator&						allocator			= m_context.getDefaultAllocator();
171 
172 	const VkBufferUsageFlags		bufferUsageFlags	= address ? (usage | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) : usage;
173 	const MemoryRequirement			requirements		= MemoryRequirement::Coherent | MemoryRequirement::HostVisible | (address ? MemoryRequirement::DeviceAddress : MemoryRequirement::Any);
174 
175 	const VkBufferCreateInfo		bufferCreateInfo
176 	{
177 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,			// VkStructureType			sType;
178 		DE_NULL,										// const void*				pNext;
179 		0u,												// VkBufferCreateFlags		flags;
180 		size,											// VkDeviceSize				size;
181 		bufferUsageFlags,								// VkBufferUsageFlags		usage;
182 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
183 		1u,												// deUint32					queueFamilyIndexCount;
184 		&queueFamilyIndex								// const deUint32*			pQueueFamilyIndices;
185 	};
186 
187 	m_buffer		= makeShared(createBuffer(vki, dev, &bufferCreateInfo));
188 	m_bufferMemory	= makeShared(allocator.allocate(getBufferMemoryRequirements(vki, dev, **m_buffer), requirements));
189 
190 	VK_CHECK(vki.bindBufferMemory(dev, **m_buffer, (*m_bufferMemory)->getMemory(), (*m_bufferMemory)->getOffset()));
191 }
192 
Buffer(const Buffer & src)193 Buffer::Buffer (const Buffer& src)
194 	: m_context		(src.m_context)
195 	, m_size		(src.m_size)
196 	, m_address		(src.m_address)
197 	, m_buffer		(src.m_buffer)
198 	, m_bufferMemory(src.m_bufferMemory)
199 {
200 }
201 
getDeviceAddress(void) const202 deUint64 Buffer::getDeviceAddress (void) const
203 {
204 	DE_ASSERT(m_address);
205 
206 	const DeviceInterface&				vki	= m_context.getDeviceInterface();
207 	const VkDevice						dev	= m_context.getDevice();
208 	const VkBufferDeviceAddressInfo		info
209 	{
210 		VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO,	// VkStructureType	sType;
211 		DE_NULL,										// const void*		pNext;
212 		**m_buffer										// VkBuffer			buffer;
213 	};
214 
215 	return vki.getBufferDeviceAddress(dev, &info);
216 }
217 
zero(bool flushAfter)218 void Buffer::zero (bool flushAfter)
219 {
220 	deMemset(getData(), 0, static_cast<size_t>(m_size));
221 	if (flushAfter) flush();
222 }
223 
flush(void)224 void Buffer::flush (void)
225 {
226 	const DeviceInterface&	vki	= m_context.getDeviceInterface();
227 	const VkDevice			dev	= m_context.getDevice();
228 	flushAlloc(vki, dev, **m_bufferMemory);
229 }
230 
invalidate(void)231 void Buffer::invalidate (void)
232 {
233 	const DeviceInterface&	vki	= m_context.getDeviceInterface();
234 	const VkDevice			dev	= m_context.getDevice();
235 	invalidateAlloc(vki, dev, **m_bufferMemory);
236 }
237 
238 template<class X> struct TypedBuffer<X>::iterator
239 {
240 	typedef std::forward_iterator_tag	iterator_category;
241 	typedef std::ptrdiff_t				difference_type;
242 	typedef X							value_type;
243 	typedef X&							reference;
244 	typedef X*							pointer;
245 
iteratorvkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator246 				iterator	(pointer p) : m_p(p)			{ DE_ASSERT(p); }
operator *vkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator247 	reference	operator*	()								{ return *m_p; }
operator ++vkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator248 	iterator&	operator++	()								{ ++m_p; return *this; }
operator ++vkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator249 	iterator	operator++	(int)							{ return iterator(m_p++); }
operator ==vkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator250 	bool		operator==	(const iterator& other) const	{ return (m_p == other.m_p); }
operator !=vkt::SpirVAssembly::__anon1f7687710111::ut::TypedBuffer::iterator251 	bool		operator!=	(const iterator& other) const	{ return (m_p != other.m_p); }
252 
253 private:
254 	pointer m_p;
255 };
256 
TypedBuffer(Context & ctx,VkBufferUsageFlags usage,deUint32 nelements,bool address)257 template<class X> TypedBuffer<X>::TypedBuffer (Context& ctx, VkBufferUsageFlags usage, deUint32 nelements, bool address)
258 	: Buffer		(ctx, usage, (nelements * sizeof(X)), address)
259 	, m_elements	(nelements)
260 {
261 }
262 
TypedBuffer(Context & ctx,VkBufferUsageFlags usage,std::initializer_list<X> items,bool address)263 template<class X> TypedBuffer<X>::TypedBuffer (Context& ctx, VkBufferUsageFlags usage, std::initializer_list<X> items, bool address)
264 	: Buffer		(ctx, usage, (items.size() * sizeof(X)), address)
265 	, m_elements	(static_cast<deUint32>(items.size()))
266 {
267 	std::copy(items.begin(), items.end(), begin());
268 }
269 
TypedBuffer(const TypedBuffer & src)270 template<class X> TypedBuffer<X>::TypedBuffer (const TypedBuffer& src)
271 	: Buffer	(src)
272 	, m_elements(src.m_elements)
273 {
274 }
275 
TypedBuffer(const Buffer & src)276 template<class X> TypedBuffer<X>::TypedBuffer (const Buffer& src)
277 	: Buffer	(src)
278 	, m_elements(static_cast<deUint32>(m_size/sizeof(X)))
279 {
280 }
281 
iota(X start,bool flushAfter)282 template<class X> void TypedBuffer<X>::iota (X start, bool flushAfter)
283 {
284 	X* data = getData();
285 	for (deUint32 i = 0; i < m_elements; ++i)
286 		data[i] = start++;
287 	if (flushAfter) flush();
288 }
289 
operator [](deUint32 at)290 template<class X> X& TypedBuffer<X>::operator[] (deUint32 at)
291 {
292 	DE_ASSERT(at < m_elements);
293 	return getData()[at];
294 }
295 
Image(Context & ctx,deUint32 width,deUint32 height,VkFormat format)296 Image::Image (Context& ctx, deUint32 width, deUint32 height, VkFormat format)
297 	: m_context	(ctx)
298 	, m_width	(width)
299 	, m_height	(height)
300 	, m_format	(format)
301 	, m_layout	(VK_IMAGE_LAYOUT_UNDEFINED)
302 	, m_buffer	(ctx, (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT), (m_width * m_height * vk::mapVkFormat(m_format).getPixelSize()), false)
303 {
304 	const DeviceInterface&			vki					= m_context.getDeviceInterface();
305 	const VkDevice					dev					= m_context.getDevice();
306 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
307 	const VkImageUsageFlags			imageUsageFlags		= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
308 	const VkImageSubresourceRange	viewResourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
309 	Allocator&						allocator			= m_context.getDefaultAllocator();
310 
311 	const VkImageCreateInfo			imageCreateInfo		=
312 	{
313 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
314 		DE_NULL,										// const void*				pNext;
315 		0u,												// VkImageCreateFlags		flags;
316 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
317 		m_format,										// VkFormat					format;
318 		{ m_width, m_height, 1u },						// VkExtent3D				extent;
319 		1u,												// deUint32					mipLevels;
320 		1u,												// deUint32					arrayLayers;
321 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
322 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
323 		imageUsageFlags,								// VkImageUsageFlags		usage;
324 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
325 		1u,												// deUint32					queueFamilyIndexCount;
326 		&queueFamilyIndex,								// const deUint32*			pQueueFamilyIndices;
327 		m_layout										// VkImageLayout			initialLayout;
328 	};
329 
330 	m_image			= createImage(vki, dev, &imageCreateInfo);
331 
332 	m_imageMemory	= allocator.allocate(getImageMemoryRequirements(vki, dev, *m_image), MemoryRequirement::Any);
333 	VK_CHECK(vki.bindImageMemory(dev, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
334 
335 	m_view			= makeImageView(vki, dev, *m_image, VK_IMAGE_VIEW_TYPE_2D, m_format, viewResourceRange);
336 }
337 
getBuffer(void)338 template<class X> TypedBuffer<X> Image::getBuffer (void)
339 {
340 	m_buffer.invalidate();
341 	return TypedBuffer<X>(m_buffer);
342 }
343 
createRenderPass(void) const344 Move<VkRenderPass> Image::createRenderPass (void) const
345 {
346 	const DeviceInterface&			vki						= m_context.getDeviceInterface();
347 	const VkDevice					dev						= m_context.getDevice();
348 
349 	const VkAttachmentDescription	attachmentDescription	=
350 	{
351 		(VkAttachmentDescriptionFlags)0,			// VkAttachmentDescriptionFlags    flags
352 		m_format,									// VkFormat                        format
353 		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits           samples
354 		VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp              loadOp
355 		VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp             storeOp
356 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp              stencilLoadOp
357 		VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp             stencilStoreOp
358 		m_layout,									// VkImageLayout                   initialLayout
359 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout                   finalLayout
360 	};
361 
362 	const VkAttachmentReference		attachmentReference		=
363 	{
364 		0u,											// deUint32							attachment
365 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout					layout
366 	};
367 
368 	const VkSubpassDescription		subpassDescription		=
369 	{
370 		(VkSubpassDescriptionFlags)0,				// VkSubpassDescriptionFlags       flags
371 		VK_PIPELINE_BIND_POINT_GRAPHICS,			// VkPipelineBindPoint             pipelineBindPoint
372 		0u,											// deUint32                        inputAttachmentCount
373 		DE_NULL,									// const VkAttachmentReference*    pInputAttachments
374 		1u,											// deUint32                        colorAttachmentCount
375 		&attachmentReference,						// const VkAttachmentReference*    pColorAttachments
376 		DE_NULL,									// const VkAttachmentReference*    pResolveAttachments
377 		DE_NULL,									// const VkAttachmentReference*    pDepthStencilAttachment
378 		0u,											// deUint32                        preserveAttachmentCount
379 		DE_NULL										// const deUint32*                 pPreserveAttachments
380 	};
381 
382 	const VkRenderPassCreateInfo	renderPassInfo			=
383 	{
384 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	// VkStructureType                   sType
385 		DE_NULL,									// const void*                       pNext
386 		(VkRenderPassCreateFlags)0,					// VkRenderPassCreateFlags           flags
387 		1u,											// deUint32                          attachmentCount
388 		&attachmentDescription,						// const VkAttachmentDescription*    pAttachments
389 		1u,											// deUint32                          subpassCount
390 		&subpassDescription,						// const VkSubpassDescription*       pSubpasses
391 		0u,											// deUint32                          dependencyCount
392 		DE_NULL										// const VkSubpassDependency*        pDependencies
393 	};
394 
395 	return vk::createRenderPass(vki, dev, &renderPassInfo);
396 }
397 
createFramebuffer(VkRenderPass rp) const398 Move<VkFramebuffer> Image::createFramebuffer (VkRenderPass	rp) const
399 {
400 	const DeviceInterface&	vki	= m_context.getDeviceInterface();
401 	const VkDevice			dev	= m_context.getDevice();
402 
403 	return makeFramebuffer(vki, dev, rp, 1u, &m_view.get(), m_width, m_height, 1u);
404 }
405 
downloadAfterDraw(VkCommandBuffer cmdBuffer)406 void Image::downloadAfterDraw (VkCommandBuffer cmdBuffer)
407 {
408 	const DeviceInterface&	vki	= m_context.getDeviceInterface();
409 	vk::copyImageToBuffer(vki, cmdBuffer, *m_image, m_buffer.getBuffer(), { deInt32(m_width), deInt32(m_height) });
410 	m_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
411 }
412 
413 } // ut
414 
415 class SpvAsmPhysicalStorageBufferTestInstance : public TestInstance
416 {
417 public:
SpvAsmPhysicalStorageBufferTestInstance(Context & ctx)418 	SpvAsmPhysicalStorageBufferTestInstance	(Context&	ctx)
419 		: TestInstance	(ctx)
420 	{
421 	}
422 };
423 
424 class SpvAsmPhysicalStorageBufferVertexInOutInTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
425 {
426 public:
SpvAsmPhysicalStorageBufferVertexInOutInTestInstance(Context & ctx,const TestParamsPtr params)427 									SpvAsmPhysicalStorageBufferVertexInOutInTestInstance	(Context&				ctx,
428 																							 const TestParamsPtr	params)
429 										: SpvAsmPhysicalStorageBufferTestInstance	(ctx)
430 										, m_params									(params)
431 									{
432 									}
433 	tcu::TestStatus					iterate													(void);
434 	static void						initPrograms											(vk::SourceCollections&	programCollection,
435 																							 const TestParamsPtr	params);
436 	struct alignas(16) Attribute
437 	{
438 		tcu::Vec4	position;
439 		deUint64	address;
440 	};
441 	ut::TypedBuffer<tcu::Vec4>		prepareColorBuffer										(bool					flushAfter = true) const;
442 	ut::TypedBuffer<Attribute>		prepareVertexAttributes									(deUint64				address) const;
443 	Move<VkPipeline>				createGraphicsPipeline									(VkPipelineLayout		pipelineLayout,
444 																							 VkRenderPass			renderPass,
445 																							 VkShaderModule			vertexModule,
446 																							 VkShaderModule			fragmentModule) const;
447 
448 private:
449 	const TestParamsPtr		m_params;
450 };
451 
452 class SpvAsmPhysicalStorageBufferPushConstantsTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
453 {
454 public:
SpvAsmPhysicalStorageBufferPushConstantsTestInstance(Context & ctx,const TestParamsPtr params)455 						SpvAsmPhysicalStorageBufferPushConstantsTestInstance	(Context&				ctx,
456 																				 const TestParamsPtr	params)
457 							: SpvAsmPhysicalStorageBufferTestInstance	(ctx)
458 							, m_params									(params)
459 						{
460 						}
461 	tcu::TestStatus		iterate													(void);
462 	static void			initPrograms											(vk::SourceCollections&	programCollection,
463 																				 const TestParamsPtr	params);
464 
465 private:
466 	const TestParamsPtr		m_params;
467 };
468 
469 class SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance : public SpvAsmPhysicalStorageBufferTestInstance
470 {
471 public:
SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance(Context & ctx,const TestParamsPtr params)472 						SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance	(Context&				ctx,
473 																			 const TestParamsPtr	params)
474 							: SpvAsmPhysicalStorageBufferTestInstance	(ctx)
475 							, m_params									(params)
476 						{
477 						}
478 	tcu::TestStatus		iterate												(void);
479 	static void			initPrograms										(vk::SourceCollections&	programCollection,
480 																			 const TestParamsPtr	params);
481 
482 private:
483 	const TestParamsPtr		m_params;
484 };
485 
486 class SpvAsmPhysicalStorageBufferTestCase : public TestCase
487 {
488 public:
SpvAsmPhysicalStorageBufferTestCase(tcu::TestContext & testCtx,const std::string & name,const TestParamsPtr params)489 						SpvAsmPhysicalStorageBufferTestCase		(tcu::TestContext&		testCtx,
490 																 const std::string&		name,
491 																 const TestParamsPtr	params)
492 							: TestCase	(testCtx, name, std::string())
493 							, m_params	(params)
494 						{
495 						}
496 	void				checkSupport							(Context&				context) const;
497 	void				initPrograms							(vk::SourceCollections&	programCollection) const;
498 	TestInstance*		createInstance							(Context&				ctx) const;
499 
500 private:
501 	const TestParamsPtr		m_params;
502 };
503 
checkSupport(Context & context) const504 void SpvAsmPhysicalStorageBufferTestCase::checkSupport (Context& context) const
505 {
506 	context.requireInstanceFunctionality(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); // "VK_KHR_get_physical_device_properties2"
507 
508 	if (!context.isBufferDeviceAddressSupported())
509 		TCU_THROW(NotSupportedError, "Request physical storage buffer feature not supported");
510 
511 	if (m_params->method == PassMethod::ADDRESSES_IN_SSBO)
512 	{
513 		if (!context.getDeviceFeatures().shaderInt64)
514 			TCU_THROW(NotSupportedError, "Int64 not supported");
515 	}
516 
517 	if (m_params->method == PassMethod::VERTEX_IN_OUT_IN)
518 	{
519 		if (!context.getDeviceFeatures().shaderInt64)
520 			TCU_THROW(NotSupportedError, "Int64 not supported");
521 
522 		VkFormatProperties2 properties	{ VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, DE_NULL, {} };
523 		context.getInstanceInterface().getPhysicalDeviceFormatProperties2(context.getPhysicalDevice(), VK_FORMAT_R64_UINT, &properties);
524 		if ((properties.formatProperties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
525 			TCU_THROW(NotSupportedError, "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT not supported");
526 	}
527 }
528 
createInstance(Context & ctx) const529 TestInstance* SpvAsmPhysicalStorageBufferTestCase::createInstance (Context& ctx) const
530 {
531 	switch (m_params->method)
532 	{
533 		case PassMethod::PUSH_CONSTANTS:
534 		case PassMethod::PUSH_CONSTANTS_FUNCTION:
535 			return new SpvAsmPhysicalStorageBufferPushConstantsTestInstance(ctx, m_params);
536 
537 		case PassMethod::VERTEX_IN_OUT_IN:
538 			return new SpvAsmPhysicalStorageBufferVertexInOutInTestInstance(ctx, m_params);
539 
540 		case PassMethod::ADDRESSES_IN_SSBO:
541 			return new SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance(ctx, m_params);
542 	}
543 
544 	DE_ASSERT(DE_FALSE);
545 	return DE_NULL;
546 }
547 
initPrograms(vk::SourceCollections & programCollection) const548 void SpvAsmPhysicalStorageBufferTestCase::initPrograms (vk::SourceCollections& programCollection) const
549 {
550 	switch (m_params->method)
551 	{
552 		case PassMethod::PUSH_CONSTANTS:
553 		case PassMethod::PUSH_CONSTANTS_FUNCTION:
554 			SpvAsmPhysicalStorageBufferPushConstantsTestInstance::initPrograms(programCollection, m_params);
555 			break;
556 
557 		case PassMethod::VERTEX_IN_OUT_IN:
558 			SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::initPrograms(programCollection, m_params);
559 			break;
560 
561 		case PassMethod::ADDRESSES_IN_SSBO:
562 			SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::initPrograms(programCollection, m_params);
563 			break;
564 	}
565 }
566 
initPrograms(SourceCollections & programCollection,const TestParamsPtr params)567 void SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::initPrograms (SourceCollections &programCollection, const TestParamsPtr params)
568 {
569 	DE_UNREF(params);
570 
571 	const std::string vert(R"(
572 		OpCapability Shader
573 		OpCapability PhysicalStorageBufferAddresses
574 
575 		OpExtension "SPV_KHR_physical_storage_buffer"
576 		OpMemoryModel PhysicalStorageBuffer64 GLSL450
577 
578 		OpEntryPoint Vertex %vert "main" %gl_PerVertex %in_pos %out_idx %gl_VertexIndex %in_addr %out_addr
579 
580 		OpDecorate %PerVertex Block
581 		OpDecorate %gl_VertexIndex BuiltIn VertexIndex
582 		OpDecorate %in_pos Location 0
583 		OpDecorate %in_addr Location 1
584 		OpDecorate %in_addr RestrictPointerEXT
585 		OpDecorate %out_addr RestrictPointerEXT
586 		OpDecorate %out_idx Location 0
587 		OpDecorate %out_addr Location 1
588 
589 		OpMemberDecorate %PerVertex 0 BuiltIn Position
590 		OpMemberDecorate %PerVertex 1 BuiltIn PointSize
591 		OpMemberDecorate %PerVertex 2 BuiltIn ClipDistance
592 		OpMemberDecorate %PerVertex 3 BuiltIn CullDistance
593 
594 		OpDecorate %srta Block
595 		OpMemberDecorate %srta 0 Offset 0
596 
597 		OpDecorate %rta ArrayStride 16
598 
599 		%void		= OpTypeVoid
600 		%voidf		= OpTypeFunction %void
601 
602 		%int		= OpTypeInt 32 1
603 		%flt		= OpTypeFloat 32
604 		%vec4		= OpTypeVector %flt 4
605 		%rta		= OpTypeRuntimeArray %vec4
606 
607 		%zero		= OpConstant %int 0
608 		%one		= OpConstant %int 1
609 
610 		%srta		= OpTypeStruct %rta
611 		%srta_psb	= OpTypePointer PhysicalStorageBuffer %srta
612 	%srta_psb_in	= OpTypePointer Input %srta_psb
613 	%srta_psb_out	= OpTypePointer Output %srta_psb
614 		%in_addr	= OpVariable %srta_psb_in Input
615 		%out_addr	= OpVariable %srta_psb_out Output
616 
617 		%vec4_in	= OpTypePointer Input %vec4
618 		%vec4_out	= OpTypePointer Output %vec4
619 		%vec4_psb	= OpTypePointer PhysicalStorageBuffer %vec4
620 		%in_pos		= OpVariable %vec4_in Input
621 
622 		%int_in		= OpTypePointer Input %int
623 		%int_out	= OpTypePointer Output %int
624 	%gl_VertexIndex	= OpVariable %int_in Input
625 		%out_idx	= OpVariable %int_out Output
626 
627 		%flt_arr_1	= OpTypeArray %flt %one
628 		%PerVertex	= OpTypeStruct %vec4 %flt %flt_arr_1 %flt_arr_1
629 		%pv_out		= OpTypePointer Output %PerVertex
630 	%gl_PerVertex	= OpVariable %pv_out Output
631 
632 
633 		%vert		= OpFunction %void None %voidf
634 		%vert_begin	= OpLabel
635 
636 		%vpos		= OpLoad %vec4 %in_pos
637 	%gl_Position	= OpAccessChain %vec4_out %gl_PerVertex %zero
638 					OpStore %gl_Position %vpos
639 
640 		%vidx		= OpLoad %int %gl_VertexIndex
641 					OpStore %out_idx %vidx
642 
643 		%vaddr		= OpLoad %srta_psb %in_addr Aligned 8
644 					OpStore %out_addr %vaddr
645 
646 					OpReturn
647 					OpFunctionEnd
648 	)");
649 
650 	const std::string frag(R"(
651 		OpCapability Shader
652 		OpCapability PhysicalStorageBufferAddresses
653 
654 		OpExtension "SPV_KHR_physical_storage_buffer"
655 		OpMemoryModel PhysicalStorageBuffer64 GLSL450
656 
657 		OpEntryPoint Fragment %frag "main" %in_idx %in_addr %dEQP_FragColor
658 		OpExecutionMode %frag OriginUpperLeft
659 
660 		OpDecorate %in_idx Location 0
661 		OpDecorate %in_idx Flat
662 		OpDecorate %in_addr Location 1
663 		OpDecorate %in_addr AliasedPointerEXT
664 		OpDecorate %in_addr Flat
665 		OpDecorate %dEQP_FragColor Location 0
666 
667 		OpDecorate %rta ArrayStride 16
668 		OpDecorate %vec4_psb ArrayStride 16
669 		OpDecorate %srta Block
670 		OpMemberDecorate %srta 0 Offset 0
671 
672 		%void		= OpTypeVoid
673 		%voidf		= OpTypeFunction %void
674 
675 		%int		= OpTypeInt 32 1
676 		%flt		= OpTypeFloat 32
677 		%vec4		= OpTypeVector %flt 4
678 		%rta		= OpTypeRuntimeArray %vec4
679 
680 		%zero		= OpConstant %int 0
681 
682 		%int_in		= OpTypePointer Input %int
683 		%in_idx		= OpVariable %int_in Input
684 
685 		%vec4_out	= OpTypePointer Output %vec4
686 	%dEQP_FragColor	= OpVariable %vec4_out Output
687 
688 		%srta		= OpTypeStruct %rta
689 		%srta_psb	= OpTypePointer PhysicalStorageBuffer %srta
690 	%srta_psb_in	= OpTypePointer Input %srta_psb
691 		%in_addr	= OpVariable %srta_psb_in Input
692 		%rta_psb	= OpTypePointer PhysicalStorageBuffer %rta
693 		%rta_in		= OpTypePointer Input %rta
694 		%vec4_psb	= OpTypePointer PhysicalStorageBuffer %vec4
695 
696 		%frag		= OpFunction %void None %voidf
697 		%frag_begin	= OpLabel
698 
699 		%vidx		= OpLoad %int %in_idx
700 		%vaddr		= OpLoad %srta_psb %in_addr
701 		%pcolor		= OpAccessChain %vec4_psb %vaddr %zero %vidx
702 		%color		= OpLoad %vec4 %pcolor Aligned 16
703 					OpStore %dEQP_FragColor %color
704 		OpReturn
705 		OpFunctionEnd
706 	)");
707 
708 	programCollection.spirvAsmSources.add("vert")
709 			<< vert
710 			<< vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
711 	programCollection.spirvAsmSources.add("frag")
712 			<< frag
713 			<< vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
714 }
715 
prepareColorBuffer(bool flushAfter) const716 ut::TypedBuffer<tcu::Vec4> SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::prepareColorBuffer (bool flushAfter) const
717 {
718 	const deUint32	colorCount		= 21;
719 	tcu::Vec4		colors			[colorCount];
720 	tcu::Vec4		color			(-1.0f, +1.0f, +1.0f, -1.0f);
721 
722 	for (deUint32 c = 0; c < colorCount; ++c)
723 	{
724 		colors[c]	= color;
725 
726 		color[0]	+= 0.1f;
727 		color[1]	-= 0.1f;
728 		color[2]	-= 0.1f;
729 		color[3]	+= 0.1f;
730 	}
731 
732 	ut::TypedBuffer<tcu::Vec4> buffer(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, (m_params->elements * m_params->elements), true);
733 	for (auto j = buffer.begin(), begin = j; j != buffer.end(); ++j)
734 	{
735 		 *j = colors[std::distance(begin, j) % colorCount];
736 	}
737 
738 	if (flushAfter) buffer.flush();
739 	return  buffer;
740 }
741 
742 ut::TypedBuffer<SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::Attribute>
prepareVertexAttributes(deUint64 address) const743 	SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::prepareVertexAttributes (deUint64 address) const
744 {
745 	const float					xStep	= 2.0f / static_cast<float>(m_params->elements);
746 	const float					yStep	= 2.0f / static_cast<float>(m_params->elements);
747 	const float					xStart	= -1.0f + xStep / 2.0f;
748 	const float					yStart	= -1.0f + yStep / 2.0f;
749 
750 	float						x		= xStart;
751 	float						y		= yStart;
752 
753 	ut::TypedBuffer<Attribute>	attrs	(m_context, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, (m_params->elements * m_params->elements));
754 
755 	for (deUint32 row = 0; row < m_params->elements; ++row)
756 	{
757 		for (deUint32 col = 0; col < m_params->elements; ++col)
758 		{
759 			Attribute& attr	= attrs[(row*m_params->elements)+col];
760 			attr.position	= tcu::Vec4(x, y, 0.0f, 1.0f);
761 			attr.address	= address;
762 
763 			x += xStep;
764 		}
765 		y += yStep;
766 		x = xStart;
767 	}
768 
769 	attrs.flush();
770 
771 	return  attrs;
772 }
773 
createGraphicsPipeline(VkPipelineLayout pipelineLayout,VkRenderPass renderPass,VkShaderModule vertexModule,VkShaderModule fragmentModule) const774 Move<VkPipeline> SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::createGraphicsPipeline (VkPipelineLayout	pipelineLayout,
775 																							   VkRenderPass		renderPass,
776 																							   VkShaderModule	vertexModule,
777 																							   VkShaderModule	fragmentModule) const
778 {
779 	const DeviceInterface&							vk					= m_context.getDeviceInterface();
780 	const VkDevice									device				= m_context.getDevice();
781 	const std::vector<VkRect2D>						scissors			(1, makeRect2D(m_params->elements, m_params->elements));
782 	const std::vector<VkViewport>					viewports			(1, makeViewport(m_params->elements, m_params->elements));
783 
784 	const VkVertexInputBindingDescription		bindingDescriptions[]	=
785 	{
786 		{
787 			0u,													// binding
788 			sizeof(Attribute),									// stride
789 			VK_VERTEX_INPUT_RATE_VERTEX,						// inputRate
790 		},
791 	};
792 
793 	const VkVertexInputAttributeDescription		attributeDescriptions[]	=
794 	{
795 		{
796 			0u,													// location
797 			0u,													// binding
798 			VK_FORMAT_R32G32B32A32_SFLOAT,						// format
799 			0u													// offset
800 		},
801 		{
802 			1u,													// location
803 			0u,													// binding
804 			VK_FORMAT_R64_UINT,									// format
805 			static_cast<deUint32>(sizeof(Attribute::position))	// offset
806 		},
807 	};
808 
809 	const VkPipelineVertexInputStateCreateInfo	vertexInputStateCreateInfo	=
810 	{
811 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
812 		DE_NULL,
813 		(VkPipelineVertexInputStateCreateFlags)0,	// flags
814 		DE_LENGTH_OF_ARRAY(bindingDescriptions),	// vertexBindingDescriptionCount
815 		bindingDescriptions,						// pVertexBindingDescriptions
816 		DE_LENGTH_OF_ARRAY(attributeDescriptions),	// vertexAttributeDescriptionCount
817 		attributeDescriptions						// pVertexAttributeDescriptions
818 	};
819 
820 	return vk::makeGraphicsPipeline(
821 		vk,												// vk
822 		device,											// device
823 		pipelineLayout,									// pipelineLayout
824 		vertexModule,									// vertexShaderModule
825 		DE_NULL,										// tessellationControlModule
826 		DE_NULL,										// tessellationEvalModule
827 		DE_NULL,										// geometryShaderModule
828 		fragmentModule,									// fragmentShaderModule
829 		renderPass,										// renderPass
830 		viewports,										// viewports
831 		scissors,										// scissors
832 		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,				// topology
833 		0U,												// subpass
834 		0U,												// patchControlPoints
835 		&vertexInputStateCreateInfo,					// vertexInputStateCreateInfo
836 		DE_NULL,										// rasterizationStateCreateInfo
837 		DE_NULL,										// multisampleStateCreateInfo
838 		DE_NULL,										// depthStencilStateCreateInfo
839 		DE_NULL,										// colorBlendStateCreateInfo
840 		DE_NULL);										// dynamicStateCreateInfo
841 }
842 
iterate(void)843 tcu::TestStatus SpvAsmPhysicalStorageBufferVertexInOutInTestInstance::iterate (void)
844 {
845 	const DeviceInterface&			vki					= m_context.getDeviceInterface();
846 	const VkDevice					dev					= m_context.getDevice();
847 	const VkQueue					queue				= m_context.getUniversalQueue();
848 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
849 	const VkFormat					format				= VK_FORMAT_R32G32B32A32_SFLOAT;
850 	const VkRect2D					renderArea			= makeRect2D(m_params->elements, m_params->elements);
851 
852 	Move<VkCommandPool>				cmdPool				= createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
853 	Move<VkCommandBuffer>			cmdBuffer			= allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
854 
855 	ut::Image						image				(m_context, m_params->elements, m_params->elements, format);
856 	Move<VkRenderPass>				renderPass			= image.createRenderPass();
857 	Move<VkFramebuffer>				framebuffer			= image.createFramebuffer(*renderPass);
858 
859 	Move<VkShaderModule>			vertexModule		= createShaderModule(vki, dev, m_context.getBinaryCollection().get("vert"), 0);
860 	Move<VkShaderModule>			fragmentModule		= createShaderModule(vki, dev, m_context.getBinaryCollection().get("frag"), 0);
861 	Move<VkPipelineLayout>			pipelineLayout		= makePipelineLayout(vki, dev, 0u, DE_NULL);
862 	Move<VkPipeline>				pipeline			= createGraphicsPipeline(*pipelineLayout, *renderPass, *vertexModule, *fragmentModule);
863 
864 	ut::TypedBuffer<tcu::Vec4>		colorBuffer			= prepareColorBuffer();
865 	ut::TypedBuffer<Attribute>		attributes			= prepareVertexAttributes(colorBuffer.getDeviceAddress());
866 	const VkBuffer					vertexBuffers[]		= { attributes.getBuffer() };
867 	const VkDeviceSize				vertexOffsets[]		= { 0u };
868 	const tcu::Vec4					clearColor			(-1.0f);
869 
870 	beginCommandBuffer(vki, *cmdBuffer);
871 		vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
872 		vki.cmdBindVertexBuffers(*cmdBuffer, 0, 1, vertexBuffers, vertexOffsets);
873 		beginRenderPass(vki, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
874 			vki.cmdDraw(*cmdBuffer, (m_params->elements * m_params->elements), 1u, 0u, 0u);
875 		endRenderPass(vki, *cmdBuffer);
876 		image.downloadAfterDraw(*cmdBuffer);
877 	endCommandBuffer(vki, *cmdBuffer);
878 
879 	submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
880 
881 	ut::TypedBuffer<tcu::Vec4>		resultBuffer		= image.getBuffer<tcu::Vec4>();
882 
883 	return std::equal(resultBuffer.begin(), resultBuffer.end(), colorBuffer.begin()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
884 }
885 
initPrograms(vk::SourceCollections & programCollection,const TestParamsPtr params)886 void SpvAsmPhysicalStorageBufferPushConstantsTestInstance::initPrograms (vk::SourceCollections& programCollection, const TestParamsPtr params)
887 {
888 	DE_UNREF(params);
889 
890 	const std::string program(R"(
891 	OpCapability Shader
892 	OpCapability PhysicalStorageBufferAddresses
893 
894 	OpExtension "SPV_KHR_physical_storage_buffer"
895 	OpMemoryModel PhysicalStorageBuffer64 GLSL450
896 
897 	OpEntryPoint GLCompute %main "main" %id %str
898 
899 	OpExecutionMode %main LocalSize 1 1 1
900 	OpSource GLSL 450
901 	OpName %main	"main"
902 	OpName %id		"gl_GlobalInvocationID"
903 	OpName %src		"source"
904 	OpName %dst		"destination"
905 	OpName %src_buf	"source"
906 	OpName %dst_buf	"destination"
907 	OpDecorate %id BuiltIn GlobalInvocationId
908 
909 	OpDecorate %str_t Block
910 	OpMemberDecorate %str_t 0 Offset 0
911 	OpMemberDecorate %str_t 1 Offset 8
912 	OpMemberDecorate %str_t 2 Offset 16
913 	OpMemberDecorate %str_t 3 Offset 20
914 
915 	OpDecorate %src_buf Restrict
916 	OpDecorate %dst_buf Restrict
917 
918 	OpDecorate %int_arr ArrayStride 4
919 
920 			%int = OpTypeInt 32 1
921 		%int_ptr = OpTypePointer PhysicalStorageBuffer %int
922 	   %int_fptr = OpTypePointer Function %int
923 		   %zero = OpConstant %int 0
924 			%one = OpConstant %int 1
925 			%two = OpConstant %int 2
926 		  %three = OpConstant %int 3
927 
928 		   %uint = OpTypeInt 32 0
929 	   %uint_ptr = OpTypePointer Input %uint
930 	  %uint_fptr = OpTypePointer Function %uint
931 		  %uvec3 = OpTypeVector %uint 3
932 	  %uvec3ptr  = OpTypePointer Input %uvec3
933 		  %uzero = OpConstant %uint 0
934 			 %id = OpVariable %uvec3ptr Input
935 
936 		%int_arr = OpTypeRuntimeArray %int
937 
938 		%buf_ptr = OpTypePointer PhysicalStorageBuffer %int_arr
939 		  %str_t = OpTypeStruct %buf_ptr %buf_ptr %int %int
940 		%str_ptr = OpTypePointer PushConstant %str_t
941 			%str = OpVariable %str_ptr PushConstant
942 	%buf_ptr_fld = OpTypePointer PushConstant %buf_ptr
943 		%int_fld = OpTypePointer PushConstant %int
944 
945 		   %bool = OpTypeBool
946 		   %void = OpTypeVoid
947 		  %voidf = OpTypeFunction %void
948 	   %cpbuffsf = OpTypeFunction %void %buf_ptr %buf_ptr %int
949 
950 		%cpbuffs = OpFunction %void None %cpbuffsf
951 		%src_buf = OpFunctionParameter %buf_ptr
952 		%dst_buf = OpFunctionParameter %buf_ptr
953 	   %elements = OpFunctionParameter %int
954 	   %cp_begin = OpLabel
955 			  %j = OpVariable %int_fptr Function
956 				   OpStore %j %zero
957 				   OpBranch %for
958 			%for = OpLabel
959 			 %vj = OpLoad %int %j
960 			 %cj = OpULessThan %bool %vj %elements
961 				   OpLoopMerge %for_end %incj None
962 				   OpBranchConditional %cj %for_body %for_end
963 	   %for_body = OpLabel
964 	 %src_el_lnk = OpAccessChain %int_ptr %src_buf %vj
965 	 %dst_el_lnk = OpAccessChain %int_ptr %dst_buf %vj
966 		 %src_el = OpLoad %int %src_el_lnk Aligned 4
967 				   OpStore %dst_el_lnk %src_el Aligned 4
968 				   OpBranch %incj
969 		   %incj = OpLabel
970 			 %nj = OpIAdd %int %vj %one
971 				   OpStore %j %nj
972 				   OpBranch %for
973 		%for_end = OpLabel
974 				   OpReturn
975 				   OpFunctionEnd
976 
977 		   %main = OpFunction %void None %voidf
978 		  %begin = OpLabel
979 			  %i = OpVariable %int_fptr Function
980 				   OpStore %i %zero
981 		%src_lnk = OpAccessChain %buf_ptr_fld %str %zero
982 		%dst_lnk = OpAccessChain %buf_ptr_fld %str %one
983 		%cnt_lnk = OpAccessChain %int_fld %str %two
984 	%use_fun_lnk = OpAccessChain %int_fld %str %three
985 			%src = OpLoad %buf_ptr %src_lnk
986 			%dst = OpLoad %buf_ptr %dst_lnk
987 			%cnt = OpLoad %int %cnt_lnk
988 		%use_fun = OpLoad %int %use_fun_lnk
989 
990 			%cuf = OpINotEqual %bool %use_fun %zero
991 				   OpSelectionMerge %use_fun_end None
992 				   OpBranchConditional %cuf %copy %loop
993 		   %copy = OpLabel
994 		 %unused = OpFunctionCall %void %cpbuffs %src %dst %cnt
995 				   OpBranch %use_fun_end
996 		   %loop = OpLabel
997 			 %vi = OpLoad %int %i
998 			 %ci = OpSLessThan %bool %vi %cnt
999 				   OpLoopMerge %loop_end %inci None
1000 				   OpBranchConditional %ci %loop_body %loop_end
1001 	  %loop_body = OpLabel
1002 	 %src_px_lnk = OpAccessChain %int_ptr %src %vi
1003 	 %dst_px_lnk = OpAccessChain %int_ptr %dst %vi
1004 		 %src_px = OpLoad %int %src_px_lnk Aligned 4
1005 				   OpStore %dst_px_lnk %src_px Aligned 4
1006 				   OpBranch %inci
1007 		   %inci = OpLabel
1008 			 %ni = OpIAdd %int %vi %one
1009 				   OpStore %i %ni
1010 				   OpBranch %loop
1011 	   %loop_end = OpLabel
1012 				   OpBranch %use_fun_end
1013 	%use_fun_end = OpLabel
1014 
1015 				   OpReturn
1016 				   OpFunctionEnd
1017 	)");
1018 
1019 	programCollection.spirvAsmSources.add("comp")
1020 			<< program
1021 			<< vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
1022 }
1023 
iterate(void)1024 tcu::TestStatus SpvAsmPhysicalStorageBufferPushConstantsTestInstance::iterate (void)
1025 {
1026 	const DeviceInterface&			vki					= m_context.getDeviceInterface();
1027 	const VkDevice					dev					= m_context.getDevice();
1028 	const VkQueue					queue				= m_context.getUniversalQueue();
1029 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1030 
1031 	Move<VkCommandPool>				cmdPool				= createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1032 	Move<VkCommandBuffer>			cmdBuffer			= allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1033 	Move<VkShaderModule>			shaderModule		= createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
1034 
1035 	struct PushConstant
1036 	{
1037 		deUint64	src;
1038 		deUint64	dst;
1039 		deInt32		cnt;
1040 		deBool		use_fun;
1041 	};
1042 
1043 	VkPushConstantRange				pushConstantRange	=
1044 	{
1045 		VK_SHADER_STAGE_COMPUTE_BIT,	// VkShaderStageFlags	stageFlags;
1046 		0,								// deUint32				offset;
1047 		sizeof(PushConstant)			// deUint32				size;
1048 	};
1049 
1050 	Move<VkPipelineLayout>			pipelineLayout		= makePipelineLayout(vki, dev, 0, DE_NULL, 1, &pushConstantRange);
1051 	Move<VkPipeline>				pipeline			= makeComputePipeline(vki, dev, *pipelineLayout, 0, *shaderModule, 0, DE_NULL);
1052 
1053 	ut::TypedBuffer<deInt32>		src					(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1054 	ut::TypedBuffer<deInt32>		dst					(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1055 
1056 	src.iota(m_params->elements, true);
1057 	dst.zero(true);
1058 
1059 	const PushConstant				 pc					= { src.getDeviceAddress(), dst.getDeviceAddress(), deInt32(m_params->elements), (m_params->method == PassMethod::PUSH_CONSTANTS_FUNCTION ? 1 : 0) };
1060 
1061 	beginCommandBuffer(vki, *cmdBuffer);
1062 		vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1063 		vki.cmdPushConstants(*cmdBuffer, *pipelineLayout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(pc), &pc);
1064 		vki.cmdDispatch(*cmdBuffer, 1, 1, 1);
1065 	endCommandBuffer(vki, *cmdBuffer);
1066 
1067 	submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
1068 
1069 	dst.invalidate();
1070 
1071 	return std::equal(src.begin(), src.end(), dst.begin()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1072 }
1073 
initPrograms(vk::SourceCollections & programCollection,const TestParamsPtr params)1074 void SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::initPrograms (vk::SourceCollections& programCollection, const TestParamsPtr params)
1075 {
1076 	DE_UNREF(params);
1077 
1078 	const std::string comp(R"(
1079 	OpCapability Shader
1080 	OpCapability Int64
1081 	OpCapability PhysicalStorageBufferAddresses
1082 
1083 	OpExtension "SPV_KHR_physical_storage_buffer"
1084 	OpMemoryModel PhysicalStorageBuffer64 GLSL450
1085 
1086 	OpEntryPoint GLCompute %comp "main" %id %ssbo
1087 
1088 	OpExecutionMode %comp LocalSize 1 1 1
1089 	OpDecorate %id BuiltIn GlobalInvocationId
1090 
1091 	OpDecorate %sssbo Block
1092 	OpMemberDecorate %sssbo 0 Offset 0
1093 	OpMemberDecorate %sssbo 1 Offset 8
1094 	OpMemberDecorate %sssbo 2 Offset 16
1095 	OpMemberDecorate %sssbo 3 Offset 24
1096 
1097 	OpDecorate %ssbo DescriptorSet 0
1098 	OpDecorate %ssbo Binding 0
1099 
1100 	OpDecorate %rta ArrayStride 4
1101 
1102 	%bool	= OpTypeBool
1103 	%int	= OpTypeInt 32 1
1104 	%uint	= OpTypeInt 32 0
1105 	%ulong	= OpTypeInt 64 0
1106 
1107 	%zero	= OpConstant %int 0
1108 	%one	= OpConstant %int 1
1109 	%two	= OpConstant %int 2
1110 	%three	= OpConstant %int 3
1111 
1112 	%uvec3	= OpTypeVector %uint 3
1113 	%rta	= OpTypeRuntimeArray %int
1114 
1115 	%rta_psb	= OpTypePointer PhysicalStorageBuffer %rta
1116 	%sssbo		= OpTypeStruct %rta_psb %ulong %rta_psb %ulong
1117 	%sssbo_buf	= OpTypePointer StorageBuffer %sssbo
1118 	%ssbo		= OpVariable %sssbo_buf StorageBuffer
1119 	%rta_psb_sb	= OpTypePointer StorageBuffer %rta_psb
1120 	%int_psb	= OpTypePointer PhysicalStorageBuffer %int
1121 	%ulong_sb	= OpTypePointer StorageBuffer %ulong
1122 
1123 	%uvec3_in	= OpTypePointer Input %uvec3
1124 	%id			= OpVariable %uvec3_in Input
1125 	%uint_in	= OpTypePointer Input %uint
1126 
1127 	%void		= OpTypeVoid
1128 	%voidf		= OpTypeFunction %void
1129 
1130 	%comp = OpFunction %void None %voidf
1131 	%comp_begin = OpLabel
1132 
1133 		%pgid_x	= OpAccessChain %uint_in %id %zero
1134 		%gid_x	= OpLoad %uint %pgid_x
1135 		%mod2	= OpSMod %int %gid_x %two
1136 		%even	= OpIEqual %bool %mod2 %zero
1137 
1138 		%psrc_buff_p	= OpAccessChain %rta_psb_sb %ssbo %zero
1139 		%pdst_buff_p	= OpAccessChain %rta_psb_sb %ssbo %two
1140 		%src_buff_p		= OpLoad %rta_psb %psrc_buff_p
1141 		%dst_buff_p		= OpLoad %rta_psb %pdst_buff_p
1142 
1143 		%psrc_buff_u	= OpAccessChain %ulong_sb %ssbo %one
1144 		%psrc_buff_v	= OpLoad %ulong %psrc_buff_u
1145 		%src_buff_v		= OpConvertUToPtr %rta_psb %psrc_buff_v
1146 		%pdst_buff_u	= OpAccessChain %ulong_sb %ssbo %three
1147 		%pdst_buff_v	= OpLoad %ulong %pdst_buff_u
1148 		%dst_buff_v		= OpConvertUToPtr %rta_psb %pdst_buff_v
1149 
1150 		%src	= OpSelect %rta_psb %even %src_buff_p %src_buff_v
1151 		%dst	= OpSelect %rta_psb %even %dst_buff_v %dst_buff_p
1152 
1153 		%psrc_color	= OpAccessChain %int_psb %src %gid_x
1154 		%src_color	= OpLoad %int %psrc_color Aligned 4
1155 		%pdst_color	= OpAccessChain %int_psb %dst %gid_x
1156 		OpStore %pdst_color %src_color Aligned 4
1157 
1158 	OpReturn
1159 	OpFunctionEnd
1160 	)");
1161 
1162 	programCollection.spirvAsmSources.add("comp")
1163 			<< comp
1164 			<< vk::SpirVAsmBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, true);
1165 }
1166 
1167 /*
1168  Below test does not add anything new. The main purpose of this test is to show that both PhysicalStorageBuffer
1169  and 64-bit integer value can coexist in one array one next to the other. In the both cases, when the one address
1170  has its own dedicated storage class and the other is regular integer, the shader is responsible for how to interpret
1171  and use input addresses. Regardless of the shader, the application always passes them as 64-bit integers.
1172 */
iterate(void)1173 tcu::TestStatus SpvAsmPhysicalStorageBufferAddrsInSSBOTestInstance::iterate (void)
1174 {
1175 	const DeviceInterface&			vki					= m_context.getDeviceInterface();
1176 	const VkDevice					dev					= m_context.getDevice();
1177 	const VkQueue					queue				= m_context.getUniversalQueue();
1178 	const deUint32					queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
1179 
1180 	Move<VkCommandPool>				cmdPool				= createCommandPool(vki, dev, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1181 	Move<VkCommandBuffer>			cmdBuffer			= allocateCommandBuffer(vki, dev, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1182 	Move<VkShaderModule>			shaderModule		= createShaderModule(vki, dev, m_context.getBinaryCollection().get("comp"), 0);
1183 
1184 	Move<VkDescriptorSetLayout>		descriptorSetLayout	= DescriptorSetLayoutBuilder()
1185 															.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_COMPUTE_BIT)
1186 															.build(vki, dev);
1187 	Move<VkDescriptorPool>			descriptorPool		= DescriptorPoolBuilder()
1188 															.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
1189 															.build(vki, dev, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
1190 	Move<VkDescriptorSet>			descriptorSet		= makeDescriptorSet(vki, dev, *descriptorPool, *descriptorSetLayout);
1191 	Move<VkPipelineLayout>			pipelineLayout		= makePipelineLayout(vki, dev, 1u, &descriptorSetLayout.get());
1192 	Move<VkPipeline>				pipeline			= makeComputePipeline(vki, dev, *pipelineLayout, 0, *shaderModule, 0, DE_NULL);
1193 
1194 
1195 	ut::TypedBuffer<deInt32>		src					(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1196 	ut::TypedBuffer<deInt32>		dst					(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, m_params->elements, true);
1197 
1198 	struct SSBO
1199 	{
1200 		deUint64	srcAsBuff;
1201 		deUint64	srcAsUint;
1202 		deUint64	dstAsBuff;
1203 		deUint64	dstAsUint;
1204 	};
1205 	ut::TypedBuffer<SSBO>			ssbo				(m_context, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, {
1206 															 {
1207 																 src.getDeviceAddress(),
1208 																 src.getDeviceAddress(),
1209 																 dst.getDeviceAddress(),
1210 																 dst.getDeviceAddress()
1211 															 }
1212 														 });
1213 	VkDescriptorBufferInfo			ssboBufferInfo		= makeDescriptorBufferInfo(ssbo.getBuffer(), 0, ssbo.getSize());
1214 	DescriptorSetUpdateBuilder		()					.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboBufferInfo)
1215 															.update(vki, dev);
1216 
1217 	src.iota(m_params->elements, true);
1218 	dst.zero(true);
1219 
1220 	beginCommandBuffer(vki, *cmdBuffer);
1221 		vki.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1222 			vki.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1223 		vki.cmdDispatch(*cmdBuffer, m_params->elements, 1, 1);
1224 	endCommandBuffer(vki, *cmdBuffer);
1225 
1226 	submitCommandsAndWait(vki, dev, queue, *cmdBuffer);
1227 
1228 	dst.invalidate();
1229 
1230 	return std::equal(src.begin(), src.end(), dst.begin()) ? tcu::TestStatus::pass("") : tcu::TestStatus::fail("");
1231 }
1232 
1233 } // unnamed
1234 
createPhysicalStorageBufferTestGroup(tcu::TestContext & testCtx)1235 tcu::TestCaseGroup*	createPhysicalStorageBufferTestGroup (tcu::TestContext& testCtx)
1236 {
1237 	struct
1238 	{
1239 		PassMethod	method;
1240 		std::string	testName;
1241 	}
1242 	const				methods[]	=
1243 	{
1244 		{ PassMethod::PUSH_CONSTANTS,			"push_constants"			},
1245 		{ PassMethod::PUSH_CONSTANTS_FUNCTION,	"push_constants_function"	},
1246 		{ PassMethod::VERTEX_IN_OUT_IN,			"vertex_in_out_in"			},
1247 		{ PassMethod::ADDRESSES_IN_SSBO,		"addrs_in_ssbo"				},
1248 	};
1249 
1250 	tcu::TestCaseGroup* group		= new tcu::TestCaseGroup(testCtx, "physical_storage_buffer", "Various methods of PhysicalStorageBuffer passing");
1251 
1252 	for (const auto& method : methods)
1253 	{
1254 		group->addChild(new SpvAsmPhysicalStorageBufferTestCase(testCtx, method.testName, TestParamsPtr(new TestParams({method.method, 64}))));
1255 	}
1256 
1257 	return group;
1258 }
1259 
1260 } // SpirVAssembly
1261 } // vkt
1262 
1263