• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 Google Inc.
7  * Copyright (c) 2018 ARM Limited.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Dynamic Offset Tests
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineDynamicOffsetTests.hpp"
27 #include "vktPipelineClearUtil.hpp"
28 #include "vktPipelineImageUtil.hpp"
29 #include "vktPipelineVertexUtil.hpp"
30 #include "vktPipelineReferenceRenderer.hpp"
31 #include "vktTestCase.hpp"
32 #include "vkImageUtil.hpp"
33 #include "vkMemUtil.hpp"
34 #include "vkPrograms.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkDeviceUtil.hpp"
42 #include "vkBuilderUtil.hpp"
43 #include "tcuImageCompare.hpp"
44 #include "deMemory.h"
45 #include "deUniquePtr.hpp"
46 #include "tcuTestLog.hpp"
47 #include <vector>
48 
49 namespace vkt
50 {
51 namespace pipeline
52 {
53 
54 using namespace vk;
55 using namespace std;
56 
57 namespace
58 {
59 typedef de::SharedPtr<Unique<VkBuffer> >		VkBufferSp;
60 typedef de::SharedPtr<Allocation>				AllocationSp;
61 typedef de::SharedPtr<Unique<VkCommandBuffer> >	VkCommandBufferSp;
62 typedef de::SharedPtr<Unique<VkRenderPass> >	VkRenderPassSp;
63 typedef de::SharedPtr<Unique<VkFramebuffer> >	VkFramebufferSp;
64 typedef de::SharedPtr<Unique<VkPipeline> >		VkPipelineSp;
65 
66 struct TestParams
67 {
68 	VkDescriptorType	descriptorType;
69 	deUint32			numCmdBuffers;
70 	bool				reverseOrder;
71 	deUint32			numDescriptorSetBindings;
72 	deUint32			numDynamicBindings;
73 	deUint32			numNonDynamicBindings;
74 };
75 
createQuads(deUint32 numQuads,float size)76 vector<Vertex4RGBA> createQuads (deUint32 numQuads, float size)
77 {
78 	vector<Vertex4RGBA>	vertices;
79 
80 	for (deUint32 quadNdx = 0; quadNdx < numQuads; quadNdx++)
81 	{
82 		const float			xOffset				= -0.5f + (float)quadNdx;
83 		const tcu::Vec4		color				(0.0f);
84 		const Vertex4RGBA	lowerLeftVertex		= {tcu::Vec4(-size + xOffset, -size, 0.0f, 1.0f), color};
85 		const Vertex4RGBA	lowerRightVertex	= {tcu::Vec4(size + xOffset, -size, 0.0f, 1.0f), color};
86 		const Vertex4RGBA	UpperLeftVertex		= {tcu::Vec4(-size + xOffset, size, 0.0f, 1.0f), color};
87 		const Vertex4RGBA	UpperRightVertex	= {tcu::Vec4(size + xOffset, size, 0.0f, 1.0f), color};
88 
89 		vertices.push_back(lowerLeftVertex);
90 		vertices.push_back(lowerRightVertex);
91 		vertices.push_back(UpperLeftVertex);
92 		vertices.push_back(UpperLeftVertex);
93 		vertices.push_back(lowerRightVertex);
94 		vertices.push_back(UpperRightVertex);
95 	}
96 
97 	return vertices;
98 }
99 
100 static const tcu::Vec4 testColors[] =
101 {
102 	tcu::Vec4(0.3f, 0.0f, 0.0f, 1.0f),
103 	tcu::Vec4(0.0f, 0.3f, 0.0f, 1.0f),
104 	tcu::Vec4(0.0f, 0.0f, 0.3f, 1.0f),
105 	tcu::Vec4(0.3f, 0.3f, 0.0f, 1.0f),
106 	tcu::Vec4(0.0f, 0.3f, 0.3f, 1.0f),
107 	tcu::Vec4(0.3f, 0.0f, 0.3f, 1.0f)
108 };
109 
110 class DynamicOffsetGraphicsTestInstance : public vkt::TestInstance
111 {
112 public:
113 								DynamicOffsetGraphicsTestInstance	(Context& context, const TestParams& params);
114 	virtual						~DynamicOffsetGraphicsTestInstance	(void);
115 	void						init								(void);
116 	virtual tcu::TestStatus		iterate								(void);
117 	tcu::TestStatus				verifyImage							(void);
118 
119 private:
120 	const TestParams			m_params;
121 	const tcu::UVec2			m_renderSize;
122 	const VkFormat				m_colorFormat;
123 	VkImageCreateInfo			m_colorImageCreateInfo;
124 	Move<VkImage>				m_colorImage;
125 	de::MovePtr<Allocation>		m_colorImageAlloc;
126 	Move<VkImageView>			m_colorAttachmentView;
127 	vector<VkRenderPassSp>		m_renderPasses;
128 	vector<VkFramebufferSp>		m_framebuffers;
129 	Move<VkShaderModule>		m_vertexShaderModule;
130 	Move<VkShaderModule>		m_fragmentShaderModule;
131 	Move<VkBuffer>				m_vertexBuffer;
132 	de::MovePtr<Allocation>		m_vertexBufferAlloc;
133 	Move<VkBuffer>				m_buffer;
134 	de::MovePtr<Allocation>		m_bufferAlloc;
135 	Move<VkDescriptorSetLayout>	m_descriptorSetLayout;
136 	Move<VkDescriptorPool>		m_descriptorPool;
137 	Move<VkDescriptorSet>		m_descriptorSet;
138 	Move<VkPipelineLayout>		m_pipelineLayout;
139 	vector<VkPipelineSp>		m_graphicsPipelines;
140 	Move<VkCommandPool>			m_cmdPool;
141 	vector<VkCommandBufferSp>	m_cmdBuffers;
142 	vector<Vertex4RGBA>			m_vertices;
143 };
144 
DynamicOffsetGraphicsTestInstance(Context & context,const TestParams & params)145 DynamicOffsetGraphicsTestInstance::DynamicOffsetGraphicsTestInstance (Context& context, const TestParams& params)
146 	: vkt::TestInstance	(context)
147 	, m_params			(params)
148 	, m_renderSize		(32, 32)
149 	, m_colorFormat		(VK_FORMAT_R8G8B8A8_UNORM)
150 	, m_vertices		(createQuads(m_params.numDescriptorSetBindings * m_params.numCmdBuffers, 0.25f))
151 {
152 }
153 
init(void)154 void DynamicOffsetGraphicsTestInstance::init (void)
155 {
156 	const VkComponentMapping		componentMappingRGBA		= { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
157 	const DeviceInterface&			vk							= m_context.getDeviceInterface();
158 	const VkDevice					vkDevice					= m_context.getDevice();
159 	const deUint32					queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
160 	const deUint32					numBindings					= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
161 	const deUint32					numColors					= DE_LENGTH_OF_ARRAY(testColors);
162 	SimpleAllocator					memAlloc					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
163 	deUint32						offset						= 0;
164 	deUint32						quadNdx						= 0;
165 	const VkPhysicalDeviceLimits	deviceLimits				= getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
166 	const VkDeviceSize				offsetAlignment				= de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
167 	const VkDeviceSize				bufferSize					= offsetAlignment * numColors;
168 	const VkDeviceSize				bindingOffset				= bufferSize / numBindings;
169 	const VkDescriptorType			nonDynamicDescriptorType	= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
170 
171 	// Create color image
172 	{
173 
174 		const VkImageCreateInfo colorImageParams =
175 		{
176 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,									// VkStructureType			sType;
177 			DE_NULL,																// const void*				pNext;
178 			0u,																		// VkImageCreateFlags		flags;
179 			VK_IMAGE_TYPE_2D,														// VkImageType				imageType;
180 			m_colorFormat,															// VkFormat					format;
181 			{ m_renderSize.x(), m_renderSize.y(), 1u },								// VkExtent3D				extent;
182 			1u,																		// deUint32					mipLevels;
183 			1u,																		// deUint32					arrayLayers;
184 			VK_SAMPLE_COUNT_1_BIT,													// VkSampleCountFlagBits	samples;
185 			VK_IMAGE_TILING_OPTIMAL,												// VkImageTiling			tiling;
186 			VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,	// VkImageUsageFlags		usage;
187 			VK_SHARING_MODE_EXCLUSIVE,												// VkSharingMode			sharingMode;
188 			1u,																		// deUint32					queueFamilyIndexCount;
189 			&queueFamilyIndex,														// const deUint32*			pQueueFamilyIndices;
190 			VK_IMAGE_LAYOUT_UNDEFINED,												// VkImageLayout			initialLayout;
191 		};
192 
193 		m_colorImageCreateInfo	= colorImageParams;
194 		m_colorImage			= createImage(vk, vkDevice, &m_colorImageCreateInfo);
195 
196 		// Allocate and bind color image memory
197 		m_colorImageAlloc		= memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
198 		VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(), m_colorImageAlloc->getOffset()));
199 	}
200 
201 	// Create color attachment view
202 	{
203 		const VkImageViewCreateInfo colorAttachmentViewParams =
204 		{
205 			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// VkStructureType				sType;
206 			DE_NULL,										// const void*					pNext;
207 			0u,												// VkImageViewCreateFlags		flags;
208 			*m_colorImage,									// VkImage						image;
209 			VK_IMAGE_VIEW_TYPE_2D,							// VkImageViewType				viewType;
210 			m_colorFormat,									// VkFormat						format;
211 			componentMappingRGBA,							// VkChannelMapping				channels;
212 			{ VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u },	// VkImageSubresourceRange		subresourceRange;
213 		};
214 
215 		m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
216 	}
217 
218 	// Create render passes
219 	for (deUint32 renderPassIdx = 0; renderPassIdx < 2; renderPassIdx++)
220 	{
221 		// The first pass clears the output image, and the second one draws on top of the first pass.
222 		const VkAttachmentLoadOp		loadOps[]				=
223 		{
224 			VK_ATTACHMENT_LOAD_OP_CLEAR,
225 			VK_ATTACHMENT_LOAD_OP_LOAD
226 		};
227 
228 		const VkImageLayout				initialLayouts[]		=
229 		{
230 			VK_IMAGE_LAYOUT_UNDEFINED,
231 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
232 		};
233 
234 		const VkAttachmentDescription	attachmentDescription	=
235 		{
236 			(VkAttachmentDescriptionFlags)0,			// VkAttachmentDescriptionFlags	flags
237 			m_colorFormat,								// VkFormat						format
238 			VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits		samples
239 			loadOps[renderPassIdx],						// VkAttachmentLoadOp			loadOp
240 			VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp			storeOp
241 			VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp			stencilLoadOp
242 			VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp			stencilStoreOp
243 			initialLayouts[renderPassIdx],				// VkImageLayout				initialLayout
244 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout				finalLayout
245 		};
246 
247 		const VkAttachmentReference		attachmentRef			=
248 		{
249 			0u,											// deUint32			attachment
250 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL	// VkImageLayout	layout
251 		};
252 
253 		const VkSubpassDescription		subpassDescription		=
254 		{
255 			(VkSubpassDescriptionFlags)0,		// VkSubpassDescriptionFlags	flags
256 			VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint			pipelineBindPoint
257 			0u,									// deUint32						inputAttachmentCount
258 			DE_NULL,							// const VkAttachmentReference*	pInputAttachments
259 			1u,									// deUint32						colorAttachmentCount
260 			&attachmentRef,						// const VkAttachmentReference*	pColorAttachments
261 			DE_NULL,							// const VkAttachmentReference*	pResolveAttachments
262 			DE_NULL,							// const VkAttachmentReference*	pDepthStencilAttachment
263 			0u,									// deUint32						preserveAttachmentCount
264 			DE_NULL								// const deUint32*				pPreserveAttachments
265 		};
266 
267 		const VkRenderPassCreateInfo	renderPassInfo			=
268 		{
269 			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	// VkStructureTypei					sType
270 			DE_NULL,									// const void*						pNext
271 			(VkRenderPassCreateFlags)0,					// VkRenderPassCreateFlags			flags
272 			1u,											// deUint32							attachmentCount
273 			&attachmentDescription,						// const VkAttachmentDescription*	pAttachments
274 			1u,											// deUint32							subpassCount
275 			&subpassDescription,						// const VkSubpassDescription*		pSubpasses
276 			0u,											// deUint32							dependencyCount
277 			DE_NULL										// const VkSubpassDependency*		pDependencies
278 		};
279 
280 		m_renderPasses.push_back(VkRenderPassSp(new Unique<VkRenderPass>(createRenderPass(vk, vkDevice, &renderPassInfo))));
281 	}
282 
283 	// Create framebuffers
284 	for (deUint32 framebufferIdx = 0; framebufferIdx < 2; framebufferIdx++)
285 	{
286 		const VkImageView				attachmentBindInfos[]	=
287 		{
288 			*m_colorAttachmentView
289 		};
290 
291 		const VkFramebufferCreateInfo	framebufferParams		=
292 		{
293 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// VkStructureType				sType;
294 			DE_NULL,									// const void*					pNext;
295 			0u,											// VkFramebufferCreateFlags		flags;
296 			**m_renderPasses[framebufferIdx],			// VkRenderPass					renderPass;
297 			1u,											// deUint32						attachmentCount;
298 			attachmentBindInfos,						// const VkImageView*			pAttachments;
299 			(deUint32)m_renderSize.x(),					// deUint32						width;
300 			(deUint32)m_renderSize.y(),					// deUint32						height;
301 			1u											// deUint32						layers;
302 		};
303 
304 		m_framebuffers.push_back(VkFramebufferSp(new Unique<VkFramebuffer>(createFramebuffer(vk, vkDevice, &framebufferParams))));
305 	}
306 
307 	// Create pipeline layout
308 	{
309 		// Create descriptor set layout
310 		vector<VkDescriptorSetLayoutBinding>	descriptorSetLayoutBindings;
311 
312 		for (deUint32 binding = 0; binding < numBindings; binding++)
313 		{
314 			const VkDescriptorType					descriptorType					= binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
315 			const VkDescriptorSetLayoutBinding		descriptorSetLayoutBinding		=
316 			{
317 				binding,					// uint32_t				binding;
318 				descriptorType,				// VkDescriptorType		descriptorType;
319 				1u,							// uint32_t				descriptorCount;
320 				VK_SHADER_STAGE_VERTEX_BIT,	// VkShaderStageFlags	stageFlags;
321 				DE_NULL						// const VkSampler*		pImmutableSamplers;
322 			};
323 
324 			descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
325 		}
326 
327 		const VkDescriptorSetLayoutCreateInfo	descriptorSetLayoutCreateInfo	=
328 		{
329 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,	// VkStructureType						sType;
330 			DE_NULL,												// const void*							pNext;
331 			0u,														// VkDescriptorSetLayoutCreateFlags		flags;
332 			numBindings,											// uint32_t								bindingCount;
333 			descriptorSetLayoutBindings.data()						// const VkDescriptorSetLayoutBinding*	pBindings;
334 		};
335 
336 		m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL);
337 
338 		// Create pipeline layout
339 		const VkPipelineLayoutCreateInfo		pipelineLayoutParams			=
340 		{
341 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// VkStructureType				sType;
342 			DE_NULL,										// const void*					pNext;
343 			0u,												// VkPipelineLayoutCreateFlags	flags;
344 			1u,												// deUint32						descriptorSetCount;
345 			&(*m_descriptorSetLayout),						// const VkDescriptorSetLayout*	pSetLayouts;
346 			0u,												// deUint32						pushConstantRangeCount;
347 			DE_NULL											// const VkPushDescriptorRange*	pPushDescriptorRanges;
348 		};
349 
350 		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
351 	}
352 
353 	// Create buffer
354 	{
355 		vector<deUint8> hostBuffer((size_t)bufferSize, 0);
356 		for (deUint32 colorIdx = 0; colorIdx < numColors; colorIdx++)
357 			deMemcpy(&hostBuffer[(deUint32)offsetAlignment * colorIdx], &testColors[colorIdx], 16);
358 
359 		const VkBufferUsageFlags	usageFlags			= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
360 
361 		const VkBufferCreateInfo	bufferCreateInfo	=
362 		{
363 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
364 			DE_NULL,								// const void*			pNext;
365 			0u,										// VkBufferCreateFlags	flags
366 			bufferSize,								// VkDeviceSize			size;
367 			usageFlags,								// VkBufferUsageFlags	usage;
368 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
369 			1u,										// deUint32				queueFamilyCount;
370 			&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
371 		};
372 
373 		m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
374 		m_bufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
375 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
376 
377 		deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
378 		flushAlloc(vk, vkDevice, *m_bufferAlloc);
379 	}
380 
381 	// Create descriptor pool
382 	{
383 		DescriptorPoolBuilder	poolBuilder;
384 		poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
385 		poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
386 		m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
387 	}
388 
389 	// Create descriptor set
390 	{
391 		const VkDescriptorSetAllocateInfo allocInfo =
392 		{
393 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,	// VkStructureType					sType;
394 			DE_NULL,										// const void*						pNext;
395 			*m_descriptorPool,								// VkDescriptorPool					descriptorPool;
396 			1u,												// deUint32							setLayoutCount;
397 			&(*m_descriptorSetLayout),						// const VkDescriptorSetLayout*		pSetLayouts;
398 		};
399 		m_descriptorSet	= allocateDescriptorSet(vk, vkDevice, &allocInfo);
400 	}
401 
402 	// Update descriptor set
403 	for (deUint32 binding = 0; binding < numBindings; ++binding)
404 	{
405 		const VkDescriptorType			descriptorType			= binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
406 		const VkDescriptorBufferInfo	descriptorBufferInfo	=
407 		{
408 			*m_buffer,					// VkBuffer			buffer;
409 			bindingOffset * binding,	// VkDeviceSize		offset;
410 			16u							// VkDeviceSize		range;
411 		};
412 
413 		const VkWriteDescriptorSet		writeDescriptorSet		=
414 		{
415 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,	// VkStructureType					sType;
416 			DE_NULL,								// const void*						pNext;
417 			*m_descriptorSet,						// VkDescriptorSet					dstSet;
418 			binding,								// uint32_t							dstBinding;
419 			0u,										// uint32_t							dstArrayElement;
420 			1u,										// uint32_t							descriptorCount;
421 			descriptorType,							// VkDescriptorType					descriptorType;
422 			DE_NULL,								// const VkDescriptorImageInfo*		pImageInfo;
423 			&descriptorBufferInfo,					// const VkDescriptorBufferInfo*	pBufferInfo;
424 			DE_NULL									// const VkBufferView*				pTexelBufferView;
425 		};
426 
427 		vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
428 	}
429 
430 	// Create shaders
431 	{
432 		m_vertexShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("vert"), 0u);
433 		m_fragmentShaderModule	= createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("frag"), 0u);
434 	}
435 
436 	// Create pipelines
437 	for (deUint32 pipelineIdx = 0; pipelineIdx < 2; pipelineIdx++)
438 	{
439 		const VkVertexInputBindingDescription		vertexInputBindingDescription		=
440 		{
441 			0u,							// deUint32					binding;
442 			sizeof(Vertex4RGBA),		// deUint32					strideInBytes;
443 			VK_VERTEX_INPUT_RATE_VERTEX	// VkVertexInputStepRate	stepRate;
444 		};
445 
446 		const VkVertexInputAttributeDescription		vertexInputAttributeDescriptions[]	=
447 		{
448 			{
449 				0u,									// deUint32	location;
450 				0u,									// deUint32	binding;
451 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
452 				0u									// deUint32	offsetInBytes;
453 			},
454 			{
455 				1u,									// deUint32	location;
456 				0u,									// deUint32	binding;
457 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
458 				DE_OFFSET_OF(Vertex4RGBA, color),	// deUint32	offset;
459 			}
460 		};
461 
462 		const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams				=
463 		{
464 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType							sType;
465 			DE_NULL,													// const void*								pNext;
466 			0u,															// vkPipelineVertexInputStateCreateFlags	flags;
467 			1u,															// deUint32									bindingCount;
468 			&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
469 			2u,															// deUint32									attributeCount;
470 			vertexInputAttributeDescriptions							// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
471 		};
472 
473 		const VkPrimitiveTopology					topology							= VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
474 
475 		const vector<VkViewport>					viewports							(1, makeViewport(m_renderSize));
476 		const vector<VkRect2D>						scissors							(1, makeRect2D(m_renderSize));
477 
478 		m_graphicsPipelines.push_back(VkPipelineSp(new Unique<VkPipeline>(makeGraphicsPipeline(vk,								// const DeviceInterface&						vk
479 																							   vkDevice,						// const VkDevice								device
480 																							   *m_pipelineLayout,				// const VkPipelineLayout						pipelineLayout
481 																							   *m_vertexShaderModule,			// const VkShaderModule							vertexShaderModule
482 																							   DE_NULL,							// const VkShaderModule							tessellationControlShaderModule
483 																							   DE_NULL,							// const VkShaderModule							tessellationEvalShaderModule
484 																							   DE_NULL,							// const VkShaderModule							geometryShaderModule
485 																							   *m_fragmentShaderModule,			// const VkShaderModule							fragmentShaderModule
486 																							   **m_renderPasses[pipelineIdx],	// const VkRenderPass							renderPass
487 																							   viewports,						// const std::vector<VkViewport>&				viewports
488 																							   scissors,						// const std::vector<VkRect2D>&					scissors
489 																							   topology,						// const VkPrimitiveTopology					topology
490 																							   0u,								// const deUint32								subpass
491 																							   0u,								// const deUint32								patchControlPoints
492 																							   &vertexInputStateParams))));		// const VkPipelineVertexInputStateCreateInfo*	vertexInputStateCreateInfo
493 	}
494 
495 	// Create vertex buffer
496 	{
497 		const VkBufferCreateInfo vertexBufferParams =
498 		{
499 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,						// VkStructureType		sType;
500 			DE_NULL,													// const void*			pNext;
501 			0u,															// VkBufferCreateFlags	flags;
502 			(VkDeviceSize)(sizeof(Vertex4RGBA) * m_vertices.size()),	// VkDeviceSize			size;
503 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,							// VkBufferUsageFlags	usage;
504 			VK_SHARING_MODE_EXCLUSIVE,									// VkSharingMode		sharingMode;
505 			1u,															// deUint32				queueFamilyCount;
506 			&queueFamilyIndex											// const deUint32*		pQueueFamilyIndices;
507 		};
508 
509 		m_vertexBuffer		= createBuffer(vk, vkDevice, &vertexBufferParams);
510 		m_vertexBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_vertexBuffer), MemoryRequirement::HostVisible);
511 
512 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_vertexBuffer, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset()));
513 
514 		// Load vertices into vertex buffer
515 		deMemcpy(m_vertexBufferAlloc->getHostPtr(), m_vertices.data(), m_vertices.size() * sizeof(Vertex4RGBA));
516 		flushAlloc(vk, vkDevice, *m_vertexBufferAlloc);
517 	}
518 
519 	// Create command pool
520 	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
521 
522 	// Create command buffers
523 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
524 		m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
525 
526 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
527 	{
528 		const VkClearValue	attachmentClearValue	= defaultClearValue(m_colorFormat);
529 		const VkDeviceSize	vertexBufferOffset		= 0;
530 		const deUint32		idx						= m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
531 
532 		beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
533 		beginRenderPass(vk, **m_cmdBuffers[idx], **m_renderPasses[idx], **m_framebuffers[idx], makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), attachmentClearValue);
534 		vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, **m_graphicsPipelines[idx]);
535 		vk.cmdBindVertexBuffers(**m_cmdBuffers[idx], 0, 1, &m_vertexBuffer.get(), &vertexBufferOffset);
536 
537 		for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
538 		{
539 			vector<deUint32>	offsets;
540 			for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
541 				offsets.push_back(offset + (deUint32)offsetAlignment * dynamicBindingIdx);
542 
543 			vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), m_params.numDynamicBindings, offsets.data());
544 			offset += (deUint32)offsetAlignment;
545 
546 			// Draw quad
547 			vk.cmdDraw(**m_cmdBuffers[idx], 6, 1, 6 * quadNdx, 0);
548 			quadNdx++;
549 		}
550 
551 		endRenderPass(vk, **m_cmdBuffers[idx]);
552 		endCommandBuffer(vk, **m_cmdBuffers[idx]);
553 	}
554 }
555 
~DynamicOffsetGraphicsTestInstance(void)556 DynamicOffsetGraphicsTestInstance::~DynamicOffsetGraphicsTestInstance (void)
557 {
558 }
559 
iterate(void)560 tcu::TestStatus DynamicOffsetGraphicsTestInstance::iterate (void)
561 {
562 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
563 	const VkDevice			vkDevice	= m_context.getDevice();
564 	const VkQueue			queue		= m_context.getUniversalQueue();
565 
566 	init();
567 
568 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
569 		submitCommandsAndWait(vk, vkDevice, queue, **m_cmdBuffers[cmdBufferIdx]);
570 
571 	return verifyImage();
572 }
573 
verifyImage(void)574 tcu::TestStatus DynamicOffsetGraphicsTestInstance::verifyImage (void)
575 {
576 	const DeviceInterface&		vk					= m_context.getDeviceInterface();
577 	const VkDevice				vkDevice			= m_context.getDevice();
578 	const VkQueue				queue				= m_context.getUniversalQueue();
579 	const deUint32				queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
580 	SimpleAllocator				memAlloc			(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
581 	const tcu::TextureFormat	tcuColorFormat		= mapVkFormat(m_colorFormat);
582 	const tcu::TextureFormat	tcuDepthFormat		= tcu::TextureFormat();
583 	const ColorVertexShader		vertexShader;
584 	const ColorFragmentShader	fragmentShader		(tcuColorFormat, tcuDepthFormat);
585 	const rr::Program			program				(&vertexShader, &fragmentShader);
586 	ReferenceRenderer			refRenderer			(m_renderSize.x(), m_renderSize.y(), 1, tcuColorFormat, tcuDepthFormat, &program);
587 	bool						compareOk			= false;
588 
589 	// Render reference image
590 	{
591 		const deUint32	numBindings		= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
592 		const deUint32	numTestColors	= DE_LENGTH_OF_ARRAY(testColors);
593 		const deUint32	bindingOffset	= numTestColors / numBindings;
594 
595 		for (deUint32 quadIdx = 0; quadIdx < m_vertices.size() / 6; quadIdx++)
596 			for (deUint32 vertexIdx = 0; vertexIdx < 6; vertexIdx++)
597 			{
598 				tcu::Vec4 refColor(0.0f);
599 
600 				for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
601 					refColor += testColors[quadIdx + binding * bindingOffset + binding];
602 				for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
603 					refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
604 				refColor.w() = 1.0f;
605 
606 				m_vertices[quadIdx * 6 + vertexIdx].color.xyzw() = refColor;
607 			}
608 
609 		refRenderer.draw(rr::RenderState(refRenderer.getViewportState()), rr::PRIMITIVETYPE_TRIANGLES, m_vertices);
610 	}
611 
612 	// Compare result with reference image
613 	{
614 		de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, memAlloc, *m_colorImage, m_colorFormat, m_renderSize);
615 
616 		compareOk = tcu::intThresholdPositionDeviationCompare(m_context.getTestContext().getLog(),
617 															  "IntImageCompare",
618 															  "Image comparison",
619 															  refRenderer.getAccess(),
620 															  result->getAccess(),
621 															  tcu::UVec4(2, 2, 2, 2),
622 															  tcu::IVec3(1, 1, 0),
623 															  true,
624 															  tcu::COMPARE_LOG_RESULT);
625 	}
626 
627 	if (compareOk)
628 		return tcu::TestStatus::pass("Result image matches reference");
629 	else
630 		return tcu::TestStatus::fail("Image mismatch");
631 }
632 
633 class DynamicOffsetGraphicsTest : public vkt::TestCase
634 {
635 public:
636 						DynamicOffsetGraphicsTest	(tcu::TestContext&	testContext,
637 													 const string&		name,
638 													 const string&		description,
639 													 const TestParams&	params);
640 						~DynamicOffsetGraphicsTest	(void);
641 	void				initPrograms				(SourceCollections& sourceCollections) const;
642 	TestInstance*		createInstance				(Context& context) const;
643 
644 protected:
645 	const TestParams	m_params;
646 };
647 
DynamicOffsetGraphicsTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)648 DynamicOffsetGraphicsTest::DynamicOffsetGraphicsTest (tcu::TestContext&	testContext,
649 													  const string&		name,
650 													  const string&		description,
651 													  const TestParams&	params)
652 	: vkt::TestCase	(testContext, name, description)
653 	, m_params		(params)
654 {
655 }
656 
~DynamicOffsetGraphicsTest(void)657 DynamicOffsetGraphicsTest::~DynamicOffsetGraphicsTest (void)
658 {
659 }
660 
createInstance(Context & context) const661 TestInstance* DynamicOffsetGraphicsTest::createInstance (Context& context) const
662 {
663 	return new DynamicOffsetGraphicsTestInstance(context, m_params);
664 }
665 
initPrograms(SourceCollections & sourceCollections) const666 void DynamicOffsetGraphicsTest::initPrograms (SourceCollections& sourceCollections) const
667 {
668 	const deUint32	numBindings	= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
669 	const string	bufferType	= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "readonly buffer";
670 	string			inputBlocks;
671 	string			inputSum;
672 
673 	for (deUint32 binding = 0; binding < numBindings; binding++)
674 	{
675 		const string b = de::toString(binding);
676 		inputBlocks +=
677 			string("layout(set = 0, binding = ") + b + ") " + bufferType + " Block" + b + "\n"
678 			+ "{\n" + "    vec4 color;\n" + "} inputData" + b + ";\n";
679 		inputSum += string("    vtxColor.rgb += inputData") + b + ".color.rgb;\n";
680 	}
681 
682 	const string	vertexSrc	=
683 		"#version 450\n"
684 		"layout(location = 0) in highp vec4 position;\n"
685 		"layout(location = 1) in highp vec4 color;\n"
686 		"layout(location = 0) out highp vec4 vtxColor;\n"
687 		+ inputBlocks +
688 		"\n"
689 		"out gl_PerVertex { vec4 gl_Position; };\n"
690 		"\n"
691 		"void main()\n"
692 		"{\n"
693 		"    gl_Position = position;\n"
694 		"    vtxColor = vec4(0, 0, 0, 1);\n"
695 		+ inputSum +
696 		"}\n";
697 
698 	const string	fragmentSrc	=
699 		"#version 450\n"
700 		"layout(location = 0) in highp vec4 vtxColor;\n"
701 		"layout(location = 0) out highp vec4 fragColor;\n"
702 		"\n"
703 		"void main (void)\n"
704 		"{\n"
705 		"    fragColor = vtxColor;\n"
706 		"}\n";
707 
708 	sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSrc);
709 	sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragmentSrc);
710 }
711 
712 class DynamicOffsetComputeTestInstance : public vkt::TestInstance
713 {
714 public:
715 								DynamicOffsetComputeTestInstance	(Context& context, const TestParams& params);
716 	virtual						~DynamicOffsetComputeTestInstance	(void);
717 	void						init								(void);
718 	virtual tcu::TestStatus		iterate								(void);
719 	tcu::TestStatus				verifyOutput						(void);
720 
721 private:
722 	const TestParams			m_params;
723 	Move<VkShaderModule>		m_computeShaderModule;
724 	Move<VkBuffer>				m_buffer;
725 	de::MovePtr<Allocation>		m_bufferAlloc;
726 	Move<VkDescriptorSetLayout>	m_descriptorSetLayout;
727 	Move<VkDescriptorPool>		m_descriptorPool;
728 	Move<VkDescriptorSet>		m_descriptorSet;
729 	Move<VkPipelineLayout>		m_pipelineLayout;
730 	Move<VkPipeline>			m_computePipeline;
731 	Move<VkBuffer>				m_outputBuffer;
732 	de::MovePtr<Allocation>		m_outputBufferAlloc;
733 	Move<VkCommandPool>			m_cmdPool;
734 	vector<VkCommandBufferSp>	m_cmdBuffers;
735 };
736 
DynamicOffsetComputeTestInstance(Context & context,const TestParams & params)737 DynamicOffsetComputeTestInstance::DynamicOffsetComputeTestInstance (Context& context, const TestParams& params)
738 	: vkt::TestInstance		(context)
739 	, m_params				(params)
740 {
741 }
742 
init(void)743 void DynamicOffsetComputeTestInstance::init (void)
744 {
745 	const DeviceInterface&			vk							= m_context.getDeviceInterface();
746 	const VkDevice					vkDevice					= m_context.getDevice();
747 	const deUint32					queueFamilyIndex			= m_context.getUniversalQueueFamilyIndex();
748 	const deUint32					numBindings					= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
749 	const deUint32					numColors					= DE_LENGTH_OF_ARRAY(testColors);
750 	SimpleAllocator					memAlloc					(vk, vkDevice, getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
751 	deUint32						offset						= 0;
752 	const VkPhysicalDeviceLimits	deviceLimits				= getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
753 	const VkDeviceSize				offsetAlignment				= de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
754 	const VkDeviceSize				bufferSize					= offsetAlignment * numColors;
755 	const VkDeviceSize				bindingOffset				= bufferSize / numBindings;
756 	const VkDescriptorType			nonDynamicDescriptorType	= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER : VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
757 	const deUint32					numOutputColors				= m_params.numCmdBuffers * m_params.numDescriptorSetBindings;
758 	const VkDeviceSize				outputBufferSize			= offsetAlignment * numOutputColors;
759 
760 	// Create pipeline layout
761 	{
762 		// Create descriptor set layout
763 		vector<VkDescriptorSetLayoutBinding>	descriptorSetLayoutBindings;
764 
765 		for (deUint32 binding = 0; binding < numBindings; binding++)
766 		{
767 			const VkDescriptorType					descriptorType				= binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
768 			const VkDescriptorSetLayoutBinding		descriptorSetLayoutBinding	=
769 			{
770 				binding,						// uint32_t				binding;
771 				descriptorType,					// VkDescriptorType		descriptorType;
772 				1u,								// uint32_t				descriptorCount;
773 				VK_SHADER_STAGE_COMPUTE_BIT,	// VkShaderStageFlags	stageFlags;
774 				DE_NULL							// const VkSampler*		pImmutableSamplers;
775 			};
776 
777 			descriptorSetLayoutBindings.push_back(descriptorSetLayoutBinding);
778 		}
779 
780 		const VkDescriptorSetLayoutBinding		descriptorSetLayoutBindingOutput	=
781 		{
782 			numBindings,								// uint32_t				binding;
783 			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,	// VkDescriptorType		descriptorType;
784 			1u,											// uint32_t				descriptorCount;
785 			VK_SHADER_STAGE_COMPUTE_BIT,				// VkShaderStageFlags	stageFlags;
786 			DE_NULL										// const VkSampler*		pImmutableSamplers;
787 		};
788 
789 		descriptorSetLayoutBindings.push_back(descriptorSetLayoutBindingOutput);
790 
791 		const VkDescriptorSetLayoutCreateInfo	descriptorSetLayoutCreateInfo	=
792 		{
793 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,	// VkStructureType						sType;
794 			DE_NULL,												// const void*							pNext;
795 			0u,														// VkDescriptorSetLayoutCreateFlags		flags;
796 			numBindings + 1,										// uint32_t								bindingCount;
797 			descriptorSetLayoutBindings.data()						// const VkDescriptorSetLayoutBinding*	pBindings;
798 		};
799 
800 		m_descriptorSetLayout = createDescriptorSetLayout(vk, vkDevice, &descriptorSetLayoutCreateInfo, DE_NULL);
801 
802 		// Create pipeline layout
803 		const VkPipelineLayoutCreateInfo		pipelineLayoutParams			=
804 		{
805 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	// VkStructureType				sType;
806 			DE_NULL,										// const void*					pNext;
807 			0u,												// VkPipelineLayoutCreateFlags	flags;
808 			1u,												// deUint32						descriptorSetCount;
809 			&(*m_descriptorSetLayout),						// const VkDescriptorSetLayout*	pSetLayouts;
810 			0u,												// deUint32						pushConstantRangeCount;
811 			DE_NULL											// const VkPushDescriptorRange*	pPushDescriptorRanges;
812 		};
813 
814 		m_pipelineLayout = createPipelineLayout(vk, vkDevice, &pipelineLayoutParams);
815 	}
816 
817 	// Create buffer
818 	{
819 		vector<deUint8> hostBuffer((deUint32)bufferSize, 0);
820 		for (deUint32 colorIdx = 0; colorIdx < numColors; colorIdx++)
821 			deMemcpy(&hostBuffer[(deUint32)offsetAlignment * colorIdx], &testColors[colorIdx], 16);
822 
823 		const VkBufferUsageFlags	usageFlags			= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT : VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
824 
825 		const VkBufferCreateInfo	bufferCreateInfo	=
826 		{
827 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
828 			DE_NULL,								// const void*			pNext;
829 			0u,										// VkBufferCreateFlags	flags
830 			bufferSize,								// VkDeviceSize			size;
831 			usageFlags,								// VkBufferUsageFlags	usage;
832 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
833 			1u,										// deUint32				queueFamilyCount;
834 			&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
835 		};
836 
837 		m_buffer = createBuffer(vk, vkDevice, &bufferCreateInfo);
838 		m_bufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_buffer), MemoryRequirement::HostVisible);
839 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_buffer, m_bufferAlloc->getMemory(), m_bufferAlloc->getOffset()));
840 
841 		deMemcpy(m_bufferAlloc->getHostPtr(), hostBuffer.data(), (size_t)bufferSize);
842 		flushAlloc(vk, vkDevice, *m_bufferAlloc);
843 	}
844 
845 	// Create output buffer
846 	{
847 		const VkBufferCreateInfo bufferCreateInfo =
848 		{
849 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
850 			DE_NULL,								// const void*			pNext;
851 			0u,										// VkBufferCreateFlags	flags
852 			outputBufferSize,						// VkDeviceSize			size;
853 			VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,		// VkBufferUsageFlags	usage;
854 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
855 			1u,										// deUint32				queueFamilyCount;
856 			&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
857 		};
858 
859 		m_outputBuffer		= createBuffer(vk, vkDevice, &bufferCreateInfo);
860 		m_outputBufferAlloc	= memAlloc.allocate(getBufferMemoryRequirements(vk, vkDevice, *m_outputBuffer), MemoryRequirement::HostVisible);
861 		VK_CHECK(vk.bindBufferMemory(vkDevice, *m_outputBuffer, m_outputBufferAlloc->getMemory(), m_outputBufferAlloc->getOffset()));
862 	}
863 
864 	// Create descriptor pool
865 	{
866 		DescriptorPoolBuilder	poolBuilder;
867 		poolBuilder.addType(m_params.descriptorType, m_params.numDynamicBindings);
868 		poolBuilder.addType(nonDynamicDescriptorType, m_params.numNonDynamicBindings);
869 		poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1u);
870 		m_descriptorPool = poolBuilder.build(vk, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
871 	}
872 
873 	// Create descriptor set
874 	{
875 		const VkDescriptorSetAllocateInfo allocInfo =
876 		{
877 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,	// VkStructureType				sType;
878 			DE_NULL,										// const void*					pNext;
879 			*m_descriptorPool,								// VkDescriptorPool				descriptorPool;
880 			1u,												// deUint32						setLayoutCount;
881 			&(*m_descriptorSetLayout),						// const VkDescriptorSetLayout*	pSetLayouts;
882 		};
883 		m_descriptorSet	= allocateDescriptorSet(vk, vkDevice, &allocInfo);
884 	}
885 
886 	// Update input buffer descriptors
887 	for (deUint32 binding = 0; binding < numBindings; ++binding)
888 	{
889 		const VkDescriptorType			descriptorType			= binding >= m_params.numDynamicBindings ? nonDynamicDescriptorType : m_params.descriptorType;
890 		const VkDescriptorBufferInfo	descriptorBufferInfo	=
891 		{
892 			*m_buffer,					// VkBuffer			buffer;
893 			bindingOffset * binding,	// VkDeviceSize		offset;
894 			16u							// VkDeviceSize		range;
895 		};
896 
897 		const VkWriteDescriptorSet		writeDescriptorSet		=
898 		{
899 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,	// VkStructureType					sType;
900 			DE_NULL,								// const void*						pNext;
901 			*m_descriptorSet,						// VkDescriptorSet					dstSet;
902 			binding,								// uint32_t							dstBinding;
903 			0u,										// uint32_t							dstArrayElement;
904 			1u,										// uint32_t							descriptorCount;
905 			descriptorType,							// VkDescriptorType					descriptorType;
906 			DE_NULL,								// const VkDescriptorImageInfo*		pImageInfo;
907 			&descriptorBufferInfo,					// const VkDescriptorBufferInfo*	pBufferInfo;
908 			DE_NULL									// const VkBufferView*				pTexelBufferView;
909 		};
910 
911 		vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
912 	}
913 
914 	// Update output buffer descriptor
915 	{
916 		const VkDescriptorBufferInfo	descriptorBufferInfo	=
917 		{
918 			*m_outputBuffer,	// VkBuffer			buffer;
919 			0u,					// VkDeviceSize		offset;
920 			16u					// VkDeviceSize		range;
921 		};
922 
923 		const VkWriteDescriptorSet		writeDescriptorSet		=
924 		{
925 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,		// VkStructureType					sType;
926 			DE_NULL,									// const void*						pNext;
927 			*m_descriptorSet,							// VkDescriptorSet					dstSet;
928 			numBindings,								// uint32_t							dstBinding;
929 			0u,											// uint32_t							dstArrayElement;
930 			1u,											// uint32_t							descriptorCount;
931 			VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,	// VkDescriptorType					descriptorType;
932 			DE_NULL,									// const VkDescriptorImageInfo*		pImageInfo;
933 			&descriptorBufferInfo,						// const VkDescriptorBufferInfo*	pBufferInfo;
934 			DE_NULL										// const VkBufferView*				pTexelBufferView;
935 		};
936 
937 		vk.updateDescriptorSets(vkDevice, 1u, &writeDescriptorSet, 0u, DE_NULL);
938 	}
939 
940 	// Create shader
941 	{
942 		m_computeShaderModule = createShaderModule(vk, vkDevice, m_context.getBinaryCollection().get("compute"), 0u);
943 	}
944 
945 	// Create pipeline
946 	{
947 		const VkPipelineShaderStageCreateInfo	stageCreateInfo	=
948 		{
949 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	// VkStructureType						sType;
950 			DE_NULL,												// const void*							pNext;
951 			0u,														// VkPipelineShaderStageCreateFlags		flags;
952 			VK_SHADER_STAGE_COMPUTE_BIT,							// VkShaderStageFlagBits				stage;
953 			*m_computeShaderModule,									// VkShaderModule						module;
954 			"main",													// const char*							pName;
955 			DE_NULL													// const VkSpecializationInfo*			pSpecializationInfo;
956 		};
957 
958 		const VkComputePipelineCreateInfo		createInfo		=
959 		{
960 			VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,			// VkStructureType					sType;
961 			DE_NULL,												// const void*						pNext;
962 			0u,														// VkPipelineCreateFlags			flags;
963 			stageCreateInfo,										// VkPipelineShaderStageCreateInfo	stage;
964 			*m_pipelineLayout,										// VkPipelineLayout					layout;
965 			(VkPipeline)0,											// VkPipeline						basePipelineHandle;
966 			0u,														// int32_t							basePipelineIndex;
967 		};
968 
969 		m_computePipeline = createComputePipeline(vk, vkDevice, (vk::VkPipelineCache)0u, &createInfo);
970 	}
971 
972 	// Create command pool
973 	m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
974 
975 	// Create command buffers
976 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
977 		m_cmdBuffers.push_back(VkCommandBufferSp(new Unique<VkCommandBuffer>(allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY))));
978 
979 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
980 	{
981 		const deUint32 idx = m_params.reverseOrder ? m_params.numCmdBuffers - cmdBufferIdx - 1 : cmdBufferIdx;
982 
983 		beginCommandBuffer(vk, **m_cmdBuffers[idx], 0u);
984 		vk.cmdBindPipeline(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_computePipeline);
985 
986 		for (deUint32 i = 0; i < m_params.numDescriptorSetBindings; i++)
987 		{
988 			vector<deUint32> offsets;
989 			for (deUint32 dynamicBindingIdx = 0; dynamicBindingIdx < m_params.numDynamicBindings; dynamicBindingIdx++)
990 				offsets.push_back(offset + (deUint32)offsetAlignment * dynamicBindingIdx);
991 
992 			// Offset for output buffer
993 			offsets.push_back(offset);
994 
995 			vk.cmdBindDescriptorSets(**m_cmdBuffers[idx], VK_PIPELINE_BIND_POINT_COMPUTE, *m_pipelineLayout, 0u, 1u, &m_descriptorSet.get(), (deUint32)offsets.size(), offsets.data());
996 			offset += (deUint32)offsetAlignment;
997 
998 			// Dispatch
999 			vk.cmdDispatch(**m_cmdBuffers[idx], 1, 1, 1);
1000 		}
1001 
1002 		endCommandBuffer(vk, **m_cmdBuffers[idx]);
1003 	}
1004 }
1005 
~DynamicOffsetComputeTestInstance(void)1006 DynamicOffsetComputeTestInstance::~DynamicOffsetComputeTestInstance (void)
1007 {
1008 }
1009 
iterate(void)1010 tcu::TestStatus DynamicOffsetComputeTestInstance::iterate (void)
1011 {
1012 	const DeviceInterface&	vk			= m_context.getDeviceInterface();
1013 	const VkDevice			vkDevice	= m_context.getDevice();
1014 	const VkQueue			queue		= m_context.getUniversalQueue();
1015 
1016 	init();
1017 
1018 	for (deUint32 cmdBufferIdx = 0; cmdBufferIdx < m_params.numCmdBuffers; cmdBufferIdx++)
1019 		submitCommandsAndWait(vk, vkDevice, queue, **m_cmdBuffers[cmdBufferIdx]);
1020 
1021 	return verifyOutput();
1022 }
1023 
verifyOutput(void)1024 tcu::TestStatus DynamicOffsetComputeTestInstance::verifyOutput (void)
1025 {
1026 	const DeviceInterface&			vk					= m_context.getDeviceInterface();
1027 	const VkDevice					vkDevice			= m_context.getDevice();
1028 	const deUint32					numBindings			= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
1029 	const deUint32					numTestColors		= DE_LENGTH_OF_ARRAY(testColors);
1030 	const deUint32					bindingOffset		= numTestColors / numBindings;
1031 	const deUint32					numOutputColors		= m_params.numCmdBuffers * m_params.numDescriptorSetBindings;
1032 	const VkPhysicalDeviceLimits	deviceLimits		= getPhysicalDeviceProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()).limits;
1033 	const VkDeviceSize				offsetAlignment		= de::max((VkDeviceSize)16, m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? deviceLimits.minUniformBufferOffsetAlignment : deviceLimits.minStorageBufferOffsetAlignment);
1034 	vector<tcu::Vec4>				refColors			(numOutputColors);
1035 	vector<tcu::Vec4>				outColors			(numOutputColors);
1036 
1037 	for (deUint32 i = 0; i < numOutputColors; i++)
1038 	{
1039 		tcu::Vec4 refColor(0.0f);
1040 
1041 		for (deUint32 binding = 0; binding < m_params.numDynamicBindings; binding++)
1042 			refColor += testColors[i + binding * bindingOffset + binding];
1043 		for (deUint32 binding = 0; binding < m_params.numNonDynamicBindings; binding++)
1044 			refColor += testColors[(m_params.numDynamicBindings + binding) * bindingOffset];
1045 		refColor.w() = 1.0f;
1046 
1047 		refColors[i] = refColor;
1048 	}
1049 
1050 	invalidateAlloc(vk, vkDevice, *m_outputBufferAlloc);
1051 
1052 	// Grab the output results using offset alignment
1053 	for (deUint32 i = 0; i < numOutputColors; i++)
1054 		outColors[i] = *(tcu::Vec4*)((deUint8*)m_outputBufferAlloc->getHostPtr() + offsetAlignment * i);
1055 
1056 	// Verify results
1057 	for (deUint32 i = 0; i < numOutputColors; i++)
1058 		if (outColors[i] != refColors[i])
1059 			return tcu::TestStatus::fail("Output mismatch");
1060 
1061 	return tcu::TestStatus::pass("Output matches expected values");
1062 }
1063 
1064 class DynamicOffsetComputeTest : public vkt::TestCase
1065 {
1066 public:
1067 						DynamicOffsetComputeTest	(tcu::TestContext&	testContext,
1068 													 const string&		name,
1069 													 const string&		description,
1070 													 const TestParams&	params);
1071 						~DynamicOffsetComputeTest	(void);
1072 	void				initPrograms				(SourceCollections& sourceCollections) const;
1073 	TestInstance*		createInstance				(Context& context) const;
1074 
1075 protected:
1076 	const TestParams	m_params;
1077 };
1078 
DynamicOffsetComputeTest(tcu::TestContext & testContext,const string & name,const string & description,const TestParams & params)1079 DynamicOffsetComputeTest::DynamicOffsetComputeTest (tcu::TestContext&	testContext,
1080 													const string&		name,
1081 													const string&		description,
1082 													const TestParams&	params)
1083 	: vkt::TestCase	(testContext, name, description)
1084 	, m_params		(params)
1085 {
1086 }
1087 
~DynamicOffsetComputeTest(void)1088 DynamicOffsetComputeTest::~DynamicOffsetComputeTest (void)
1089 {
1090 }
1091 
createInstance(Context & context) const1092 TestInstance* DynamicOffsetComputeTest::createInstance (Context& context) const
1093 {
1094 	return new DynamicOffsetComputeTestInstance(context, m_params);
1095 }
1096 
initPrograms(SourceCollections & sourceCollections) const1097 void DynamicOffsetComputeTest::initPrograms (SourceCollections& sourceCollections) const
1098 {
1099 	const deUint32	numBindings	= m_params.numDynamicBindings + m_params.numNonDynamicBindings;
1100 	const string	bufferType	= m_params.descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ? "uniform" : "buffer";
1101 	string			inputBlocks;
1102 	string			inputSum;
1103 
1104 	for (deUint32 binding = 0; binding < numBindings; binding++)
1105 	{
1106 		const string b = de::toString(binding);
1107 		inputBlocks +=
1108 			string("layout(set = 0, binding = ") + b + ") " + bufferType + " Block" + b + "\n"
1109 			+ "{\n" + "    vec4 color;\n" + "} inputData" + b + ";\n";
1110 		inputSum += string("    outData.color.rgb += inputData") + b + ".color.rgb;\n";
1111 	}
1112 
1113 	const string	computeSrc	=
1114 		"#version 450\n"
1115 		+ inputBlocks +
1116 		"layout(set = 0, binding = " + de::toString(numBindings) + ") writeonly buffer Output\n"
1117 		"{\n"
1118 		"	vec4 color;\n"
1119 		"} outData;\n"
1120 		"\n"
1121 		"void main()\n"
1122 		"{\n"
1123 		"    outData.color = vec4(0, 0, 0, 1);\n"
1124 		+ inputSum +
1125 		"}\n";
1126 
1127 	sourceCollections.glslSources.add("compute") << glu::ComputeSource(computeSrc);
1128 }
1129 
1130 } // anonymous
1131 
createDynamicOffsetTests(tcu::TestContext & testCtx)1132 tcu::TestCaseGroup* createDynamicOffsetTests (tcu::TestContext& testCtx)
1133 {
1134 	const char*	pipelineTypes[]			= { "graphics", "compute" };
1135 
1136 	struct
1137 	{
1138 		const char*			name;
1139 		VkDescriptorType	type;
1140 	}
1141 	const descriptorTypes[]				=
1142 	{
1143 		{	"uniform_buffer",	VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC	},
1144 		{	"storage_buffer",	VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC	}
1145 	};
1146 
1147 	struct
1148 	{
1149 		const char*		name;
1150 		deUint32		num;
1151 	}
1152 	const numCmdBuffers[]				=
1153 	{
1154 		{	"numcmdbuffers_1",	1u	},
1155 		{	"numcmdbuffers_2",	2u	}
1156 	};
1157 
1158 	struct
1159 	{
1160 		const char*		name;
1161 		bool			reverse;
1162 	}
1163 	const reverseOrders[]				=
1164 	{
1165 		{	"reverseorder",	true	},
1166 		{	"sameorder",	false	}
1167 	};
1168 
1169 	struct
1170 	{
1171 		const char*		name;
1172 		deUint32		num;
1173 	}
1174 	const numDescriptorSetBindings[]	=
1175 	{
1176 		{	"numdescriptorsetbindings_1",	1u	},
1177 		{	"numdescriptorsetbindings_2",	2u	}
1178 	};
1179 
1180 	struct
1181 	{
1182 		const char*		name;
1183 		deUint32		num;
1184 	}
1185 	const numDynamicBindings[]			=
1186 	{
1187 		{	"numdynamicbindings_1",	1u	},
1188 		{	"numdynamicbindings_2",	2u	}
1189 	};
1190 
1191 	struct
1192 	{
1193 		const char*		name;
1194 		deUint32		num;
1195 	}
1196 	const numNonDynamicBindings[]		=
1197 	{
1198 		{	"numnondynamicbindings_0",	0u	},
1199 		{	"numnondynamicbindings_1",	1u	}
1200 	};
1201 
1202 	de::MovePtr<tcu::TestCaseGroup>	dynamicOffsetTests	(new tcu::TestCaseGroup(testCtx, "dynamic_offset", "Dynamic offset tests"));
1203 	de::MovePtr<tcu::TestCaseGroup>	graphicsTests		(new tcu::TestCaseGroup(testCtx, "graphics", "graphics pipeline"));
1204 
1205 	for (deUint32 pipelineTypeIdx = 0; pipelineTypeIdx < DE_LENGTH_OF_ARRAY(pipelineTypes); pipelineTypeIdx++)
1206 	{
1207 		de::MovePtr<tcu::TestCaseGroup>	pipelineTypeGroup	(new tcu::TestCaseGroup(testCtx, pipelineTypes[pipelineTypeIdx], ""));
1208 
1209 		for (deUint32 descriptorTypeIdx = 0; descriptorTypeIdx < DE_LENGTH_OF_ARRAY(descriptorTypes); descriptorTypeIdx++)
1210 		{
1211 			de::MovePtr<tcu::TestCaseGroup>	descriptorTypeGroup	(new tcu::TestCaseGroup(testCtx, descriptorTypes[descriptorTypeIdx].name, ""));
1212 
1213 			for (deUint32 numCmdBuffersIdx = 0; numCmdBuffersIdx < DE_LENGTH_OF_ARRAY(numCmdBuffers); numCmdBuffersIdx++)
1214 			{
1215 				de::MovePtr<tcu::TestCaseGroup>	numCmdBuffersGroup	(new tcu::TestCaseGroup(testCtx, numCmdBuffers[numCmdBuffersIdx].name, ""));
1216 
1217 				for (deUint32 reverseOrderIdx = 0; reverseOrderIdx < DE_LENGTH_OF_ARRAY(reverseOrders); reverseOrderIdx++)
1218 				{
1219 					if (numCmdBuffers[numCmdBuffersIdx].num < 2 && reverseOrders[reverseOrderIdx].reverse)
1220 						continue;
1221 
1222 					de::MovePtr<tcu::TestCaseGroup>	reverseOrderGroup	(new tcu::TestCaseGroup(testCtx, reverseOrders[reverseOrderIdx].name, ""));
1223 
1224 					for (deUint32 numDescriptorSetBindingsIdx = 0; numDescriptorSetBindingsIdx < DE_LENGTH_OF_ARRAY(numDescriptorSetBindings); numDescriptorSetBindingsIdx++)
1225 					{
1226 						if (numCmdBuffers[numCmdBuffersIdx].num > 1 && numDescriptorSetBindings[numDescriptorSetBindingsIdx].num > 1)
1227 							continue;
1228 
1229 						de::MovePtr<tcu::TestCaseGroup>	numDescriptorSetBindingsGroup	(new tcu::TestCaseGroup(testCtx, numDescriptorSetBindings[numDescriptorSetBindingsIdx].name, ""));
1230 						for (deUint32 numDynamicBindingsIdx = 0; numDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numDynamicBindings); numDynamicBindingsIdx++)
1231 						{
1232 							de::MovePtr<tcu::TestCaseGroup>	numDynamicBindingsGroup	(new tcu::TestCaseGroup(testCtx, numDynamicBindings[numDynamicBindingsIdx].name, ""));
1233 
1234 							for (deUint32 numNonDynamicBindingsIdx = 0; numNonDynamicBindingsIdx < DE_LENGTH_OF_ARRAY(numNonDynamicBindings); numNonDynamicBindingsIdx++)
1235 							{
1236 								TestParams params;
1237 								params.descriptorType			= descriptorTypes[descriptorTypeIdx].type;
1238 								params.numCmdBuffers			= numCmdBuffers[numCmdBuffersIdx].num;
1239 								params.reverseOrder				= reverseOrders[reverseOrderIdx].reverse;
1240 								params.numDescriptorSetBindings	= numDescriptorSetBindings[numDescriptorSetBindingsIdx].num;
1241 								params.numDynamicBindings		= numDynamicBindings[numDynamicBindingsIdx].num;
1242 								params.numNonDynamicBindings	= numNonDynamicBindings[numNonDynamicBindingsIdx].num;
1243 
1244 								if (strcmp(pipelineTypes[pipelineTypeIdx], "graphics") == 0)
1245 									numDynamicBindingsGroup->addChild(new DynamicOffsetGraphicsTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
1246 								else
1247 									numDynamicBindingsGroup->addChild(new DynamicOffsetComputeTest(testCtx, numNonDynamicBindings[numNonDynamicBindingsIdx].name, "", params));
1248 							}
1249 
1250 							numDescriptorSetBindingsGroup->addChild(numDynamicBindingsGroup.release());
1251 						}
1252 
1253 						reverseOrderGroup->addChild(numDescriptorSetBindingsGroup.release());
1254 					}
1255 
1256 					numCmdBuffersGroup->addChild(reverseOrderGroup.release());
1257 				}
1258 
1259 				descriptorTypeGroup->addChild(numCmdBuffersGroup.release());
1260 			}
1261 
1262 			pipelineTypeGroup->addChild(descriptorTypeGroup.release());
1263 		}
1264 		dynamicOffsetTests->addChild(pipelineTypeGroup.release());
1265 	}
1266 
1267 	return dynamicOffsetTests.release();
1268 }
1269 
1270 } // pipeline
1271 } // vkt
1272