1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2023 The Khronos Group Inc.
6  * Copyright (c) 2023 Google LLC.
7  * Copyright (c) 2023 LunarG, Inc.
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 Test robustness with pipeline cache
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktPipelineRobustnessCacheTests.hpp"
27 
28 #include "vktTestCase.hpp"
29 #include "vktTestGroupUtil.hpp"
30 
31 #include "vkBufferWithMemory.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBuilderUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkPipelineConstructionUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38 
39 namespace vkt
40 {
41 namespace pipeline
42 {
43 
44 enum RobustnessBehaviour
45 {
46 	ROBUSTNESS = 0,
47 	ROBUSTNESS_2 = 1,
48 };
49 
50 enum RobustnessType
51 {
52 	STORAGE = 0,
53 	UNIFORM,
54 	VERTEX_INPUT,
55 	IMAGE,
56 };
57 
58 namespace
59 {
60 
makeBufferForImage(const vk::DeviceInterface& vk, const vk::VkDevice device, vk::Allocator& allocator, vk::VkFormat imageFormat, vk::VkExtent2D imageExtent)61 std::unique_ptr<vk::BufferWithMemory> makeBufferForImage(const vk::DeviceInterface& vk, const vk::VkDevice device, vk::Allocator& allocator, vk::VkFormat imageFormat, vk::VkExtent2D imageExtent)
62 {
63 	const auto	tcuFormat = mapVkFormat(imageFormat);
64 	const auto	outBufferSize = static_cast<vk::VkDeviceSize>(static_cast<uint32_t>(tcu::getPixelSize(tcuFormat)) * imageExtent.width * imageExtent.height);
65 	const auto	outBufferUsage = vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT;
66 	const auto	outBufferInfo = vk::makeBufferCreateInfo(outBufferSize, outBufferUsage);
67 
68 	auto outBuffer = std::unique_ptr<vk::BufferWithMemory>(new vk::BufferWithMemory(vk, device, allocator, outBufferInfo, vk::MemoryRequirement::HostVisible));
69 
70 	return outBuffer;
71 }
72 
makeImageCreateInfo(vk::VkFormat format, vk::VkExtent3D extent, vk::VkImageUsageFlags usage)73 vk::VkImageCreateInfo makeImageCreateInfo(vk::VkFormat format, vk::VkExtent3D extent, vk::VkImageUsageFlags usage)
74 {
75 	const vk::VkImageCreateInfo imageCreateInfo =
76 	{
77 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
78 		nullptr,									//	const void*				pNext;
79 		(vk::VkImageCreateFlags)0u,						//	VkImageCreateFlags		flags;
80 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
81 		format,										//	VkFormat				format;
82 		extent,										//	VkExtent3D				extent;
83 		1u,											//	deUint32				mipLevels;
84 		1u,											//	deUint32				arrayLayers;
85 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
86 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
87 		usage,										//	VkImageUsageFlags		usage;
88 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
89 		0u,											//	deUint32				queueFamilyIndexCount;
90 		nullptr,									//	const deUint32*			pQueueFamilyIndices;
91 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
92 	};
93 
94 	return imageCreateInfo;
95 }
96 
makeSampler(const vk::DeviceInterface& vk, const vk::VkDevice device)97 vk::Move<vk::VkSampler>	makeSampler(const vk::DeviceInterface& vk, const vk::VkDevice device)
98 {
99 	const vk::VkSamplerCreateInfo		samplerInfo =
100 	{
101 		vk::VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,	// sType
102 		DE_NULL,									// pNext
103 		0u,											// flags
104 		vk::VK_FILTER_NEAREST,						// magFilter
105 		vk::VK_FILTER_NEAREST,						// minFilter
106 		vk::VK_SAMPLER_MIPMAP_MODE_NEAREST,			// mipmapMode
107 		vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,	// addressModeU
108 		vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,	// addressModeV
109 		vk::VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,	// addressModeW
110 		0.0f,										// mipLodBias
111 		VK_FALSE,									// anisotropyEnable
112 		1.0f,										// maxAnisotropy
113 		DE_FALSE,									// compareEnable
114 		vk::VK_COMPARE_OP_ALWAYS,					// compareOp
115 		0.0f,										// minLod
116 		1.0f,										// maxLod
117 		vk::VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,// borderColor
118 		VK_FALSE,									// unnormalizedCoords
119 	};
120 
121 	return createSampler(vk, device, &samplerInfo);
122 }
123 
124 class PipelineCacheTestInstance : public vkt::TestInstance
125 {
126 public:
PipelineCacheTestInstance(vkt::Context& context, vk::PipelineConstructionType pipelineConstructionType, RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)127 	PipelineCacheTestInstance (vkt::Context& context, vk::PipelineConstructionType pipelineConstructionType, RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)
128 		: vkt::TestInstance				(context)
129 		, m_pipelineConstructionType	(pipelineConstructionType)
130 		, m_robustnessBufferBehaviour	(robustnessBufferBehaviour)
131 		, m_type						(type)
132 		, m_extent						()
133 	{
134 	}
135 
136 private:
137 	void						draw		(const vk::GraphicsPipelineWrapper& pipeline);
138 	bool						verifyImage	(tcu::Vec4 value, bool oob);
139 	tcu::TestStatus				iterate		(void);
140 
141 	const vk::PipelineConstructionType		m_pipelineConstructionType;
142 	const RobustnessBehaviour				m_robustnessBufferBehaviour;
143 	const RobustnessType					m_type;
144 
145 	vk::VkExtent2D							m_extent;
146 	vk::Move	<vk::VkCommandPool>			m_cmdPool;
147 	vk::Move<vk::VkCommandBuffer>			m_cmdBuffer;
148 	de::MovePtr<vk::BufferWithMemory>		m_buffer;
149 	vk::RenderPassWrapper					m_renderPass;
150 	vk::PipelineLayoutWrapper				m_pipelineLayout;
151 	vk::Move<vk::VkDescriptorPool>			m_descriptorPool;
152 	vk::Move<vk::VkDescriptorSet>			m_descriptorSet;
153 	de::MovePtr<vk::ImageWithMemory>		m_colorAttachment;
154 	std::unique_ptr<vk::BufferWithMemory>	m_outBuffer;
155 };
156 
draw(const vk::GraphicsPipelineWrapper& pipeline)157 void PipelineCacheTestInstance::draw (const vk::GraphicsPipelineWrapper& pipeline)
158 {
159 	const vk::DeviceInterface&					vk		= m_context.getDeviceInterface();
160 	const vk::VkDevice							device	= m_context.getDevice();
161 	const vk::VkQueue							queue	= m_context.getUniversalQueue();
162 
163 	const tcu::Vec4								clearColor(0.0f, 0.0f, 0.0f, 1.0f);
164 
165 	vk::beginCommandBuffer(vk, *m_cmdBuffer);
166 	if (m_type == VERTEX_INPUT)
167 	{
168 		vk::VkDeviceSize offset = 0u;
169 		vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, 1, &**m_buffer, &offset);
170 	}
171 	m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(m_extent), clearColor);
172 	vk.cmdBindDescriptorSets(*m_cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0, 1, &*m_descriptorSet, 0, DE_NULL);
173 	pipeline.bind(*m_cmdBuffer);
174 	vk.cmdDraw(*m_cmdBuffer, 4, 1, 0, 0);
175 	m_renderPass.end(vk, *m_cmdBuffer);
176 	vk::endCommandBuffer(vk, *m_cmdBuffer);
177 
178 	vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
179 
180 	vk::beginCommandBuffer(vk, *m_cmdBuffer);
181 	vk::copyImageToBuffer(vk, *m_cmdBuffer, m_colorAttachment->get(), (*m_outBuffer).get(), tcu::IVec2(m_extent.width, m_extent.height));
182 	vk::endCommandBuffer(vk, *m_cmdBuffer);
183 	vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
184 }
185 
verifyImage(tcu::Vec4 value, bool oob)186 bool PipelineCacheTestInstance::verifyImage (tcu::Vec4 value, bool oob)
187 {
188 	const vk::DeviceInterface&					vk				= m_context.getDeviceInterface();
189 	const vk::VkDevice							device			= m_context.getDevice();
190 
191 	auto&										outBufferAlloc	= m_outBuffer->getAllocation();
192 
193 	invalidateAlloc(vk, device, outBufferAlloc);
194 	const tcu::ConstPixelBufferAccess result(vk::mapVkFormat(vk::VK_FORMAT_R32G32B32A32_SFLOAT), tcu::IVec3(m_extent.width, m_extent.height, 1), (const char*)outBufferAlloc.getHostPtr());
195 
196 	const deUint32 h = result.getHeight();
197 	const deUint32 w = result.getWidth();
198 	for (deUint32 y = 0; y < h; y++)
199 	{
200 		for (deUint32 x = 0; x < w; x++)
201 		{
202 			tcu::Vec4	pix = result.getPixel(x, y);
203 
204 			if (oob && m_type == IMAGE)
205 			{
206 				for (deUint32 i = 0; i < 4; ++i)
207 					if (pix[i] != 0.0f && pix[i] != 1.0f)
208 						return false;
209 			}
210 			else if (pix != value)
211 				return false;
212 		}
213 	}
214 	return true;
215 }
216 
iterate(void)217 tcu::TestStatus PipelineCacheTestInstance::iterate (void)
218 {
219 	const vk::InstanceInterface&				vki						= m_context.getInstanceInterface();
220 	const vk::DeviceInterface&					vk						= m_context.getDeviceInterface();
221 	const vk::VkPhysicalDevice					physicalDevice			= m_context.getPhysicalDevice();
222 	const vk::VkDevice							device					= m_context.getDevice();
223 	const deUint32								queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
224 	const vk::VkQueue							queue					= m_context.getUniversalQueue();
225 	auto&										alloc					= m_context.getDefaultAllocator();
226 	const auto&									deviceExtensions		= m_context.getDeviceExtensions();
227 
228 	m_extent		= {32, 32};
229 	const deUint32								bufferSize				= sizeof(float) * 4u;
230 	const deUint32								indexBufferSize			= sizeof(deUint32);
231 
232 	const auto									subresourceRange		= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
233 
234 	m_cmdPool		= createCommandPool(vk, device, vk::VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
235 	m_cmdBuffer		= (allocateCommandBuffer(vk, device, *m_cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY));
236 
237 	m_buffer		= de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vk, device, alloc, vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_TRANSFER_SRC_BIT | vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT | vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | vk::VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), vk::MemoryRequirement::HostVisible));
238 
239 	de::MovePtr<vk::BufferWithMemory>			indexBuffer				= de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vk, device, alloc, vk::makeBufferCreateInfo(indexBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT | vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), vk::MemoryRequirement::HostVisible));
240 	de::MovePtr<vk::ImageWithMemory>			image					= de::MovePtr<vk::ImageWithMemory>(new vk::ImageWithMemory(vk, device, alloc, makeImageCreateInfo(vk::VK_FORMAT_R32G32B32A32_SFLOAT, {1, 1, 1}, vk::VK_IMAGE_USAGE_STORAGE_BIT | vk::VK_IMAGE_USAGE_TRANSFER_DST_BIT), vk::MemoryRequirement::Any));
241 	const auto									imageView				= makeImageView(vk, device, image->get(), vk::VK_IMAGE_VIEW_TYPE_2D, vk::VK_FORMAT_R32G32B32A32_SFLOAT, subresourceRange);
242 	const auto									sampler					= makeSampler(vk, device);
243 
244 	auto&										bufferAlloc				= m_buffer->getAllocation();
245 	auto&										indexBufferAlloc		= indexBuffer->getAllocation();
246 	const float									values[4]				= { 0.5f, 0.5f, 0.5f, 0.5f };
247 	deMemcpy(bufferAlloc.getHostPtr(), values, sizeof(float) * 4);
248 	flushAlloc(vk, device, bufferAlloc);
249 	const deUint32								index					= 0u;
250 	deMemcpy(indexBufferAlloc.getHostPtr(), &index, sizeof(deUint32));
251 	flushAlloc(vk, device, indexBufferAlloc);
252 
253 	const vk::VkDescriptorBufferInfo			descriptorBufferInfo	(makeDescriptorBufferInfo(m_buffer->get(), 0, bufferSize));
254 	const vk::VkDescriptorImageInfo				descriptorImageInfo		(makeDescriptorImageInfo(sampler.get(), imageView.get(), vk::VK_IMAGE_LAYOUT_GENERAL));
255 	const vk::VkDescriptorBufferInfo			indexBufferInfo			(makeDescriptorBufferInfo(indexBuffer->get(), 0, indexBufferSize));
256 
257 	const std::vector<vk::VkViewport>			viewports				{ makeViewport(m_extent) };
258 	const std::vector<vk::VkRect2D>				scissors				{ makeRect2D(m_extent) };
259 
260 	vk::ShaderWrapper							vert					= vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("vert"));
261 	vk::ShaderWrapper							frag					= vk::ShaderWrapper(vk, device, m_context.getBinaryCollection().get("frag"));
262 
263 	vk::VkDescriptorType						descriptorType			= vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
264 	if (m_type == STORAGE)
265 	{
266 		descriptorType = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
267 	}
268 	else if (m_type == UNIFORM)
269 	{
270 		descriptorType = vk::VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
271 	}
272 	else if (m_type == IMAGE)
273 	{
274 		descriptorType = vk::VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
275 	}
276 
277 	const auto									descriptorSetLayout		(vk::DescriptorSetLayoutBuilder()
278 		.addSingleBinding(descriptorType, vk::VK_SHADER_STAGE_FRAGMENT_BIT)
279 		.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT)
280 		.build(vk, device));
281 
282 	m_pipelineLayout		= vk::PipelineLayoutWrapper(m_pipelineConstructionType, vk, device, *descriptorSetLayout);
283 
284 	m_descriptorPool		= (vk::DescriptorPoolBuilder()
285 		.addType(descriptorType)
286 		.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
287 		.build(vk, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1));
288 												m_descriptorSet			= makeDescriptorSet(vk, device, *m_descriptorPool, *descriptorSetLayout);
289 	vk::DescriptorSetUpdateBuilder				builder;
290 	if (m_type == STORAGE || m_type == UNIFORM)
291 		builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &descriptorBufferInfo);
292 	if (m_type == IMAGE)
293 		builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(0u), descriptorType, &descriptorImageInfo);
294 	builder.writeSingle(*m_descriptorSet, vk::DescriptorSetUpdateBuilder::Location::binding(1u), vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &indexBufferInfo);
295 	builder.update(vk, device);;
296 
297 	//buffer to read the output image
298 	m_outBuffer				= makeBufferForImage(vk, device, alloc, vk::VK_FORMAT_R32G32B32A32_SFLOAT, m_extent);
299 
300 	const auto									vertModule				= vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"));
301 	const auto									fragModule				= vk::createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"));
302 
303 	// Color attachment.
304 	const vk::VkImageCreateInfo					imageCreateInfo			=
305 	{
306 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
307 		nullptr,									//	const void*				pNext;
308 		0u,											//	VkImageCreateFlags		flags;
309 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
310 		vk::VK_FORMAT_R32G32B32A32_SFLOAT,			//	VkFormat				format;
311 		{ m_extent.width, m_extent.height, 1},		//	VkExtent3D				extent;
312 		1u,											//	deUint32				mipLevels;
313 		1u,											//	deUint32				arrayLayers;
314 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
315 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
316 		vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT,	//	VkImageUsageFlags		usage;
317 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
318 		0u,											//	deUint32				queueFamilyIndexCount;
319 		DE_NULL,									//	const deUint32*			pQueueFamilyIndices;
320 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
321 	};
322 
323 	m_colorAttachment		= de::MovePtr<vk::ImageWithMemory>(new vk::ImageWithMemory(vk, device, alloc, imageCreateInfo, vk::MemoryRequirement::Any));
324 	const auto									colorAttachmentView		= makeImageView(vk, device, m_colorAttachment->get(), vk::VK_IMAGE_VIEW_TYPE_2D, vk::VK_FORMAT_R32G32B32A32_SFLOAT, subresourceRange);
325 
326 	m_renderPass			= vk::RenderPassWrapper(m_pipelineConstructionType, vk, device, vk::VK_FORMAT_R32G32B32A32_SFLOAT);
327 	m_renderPass.createFramebuffer(vk, device, **m_colorAttachment, *colorAttachmentView, 32, 32);
328 
329 	vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
330 	{
331 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
332 		nullptr,														//	const void*									pNext;
333 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
334 		0u,																//	deUint32									vertexBindingDescriptionCount;
335 		DE_NULL,														//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
336 		0u,																//	deUint32									vertexAttributeDescriptionCount;
337 		DE_NULL,														//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
338 	};
339 
340 	vk::VkVertexInputBindingDescription bindingDescription;
341 	bindingDescription.binding = 0;
342 	bindingDescription.stride = sizeof(float);
343 	bindingDescription.inputRate = vk::VK_VERTEX_INPUT_RATE_INSTANCE;
344 
345 	std::vector<vk::VkVertexInputAttributeDescription> attributeDescriptions(16);
346 	for (deUint32 i = 0; i < (deUint32)attributeDescriptions.size(); ++i)
347 	{
348 		attributeDescriptions[i].location = i;
349 		attributeDescriptions[i].binding = 0;
350 		attributeDescriptions[i].format = vk::VK_FORMAT_R32G32B32A32_SFLOAT;
351 		attributeDescriptions[i].offset = (deUint32)(sizeof(float) * i);
352 	}
353 
354 	if (m_type == VERTEX_INPUT)
355 	{
356 		vertexInputStateCreateInfo.vertexBindingDescriptionCount = 1u;
357 		vertexInputStateCreateInfo.pVertexBindingDescriptions = &bindingDescription;
358 		vertexInputStateCreateInfo.vertexAttributeDescriptionCount = (deUint32)attributeDescriptions.size();
359 		vertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
360 	}
361 
362 	// Input assembly.
363 	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
364 	{
365 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
366 		nullptr,															//	const void*								pNext;
367 		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
368 		vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,							//	VkPrimitiveTopology						topology;
369 		DE_FALSE,															//	VkBool32								primitiveRestartEnable;
370 	};
371 
372 	const vk::VkPipelineCacheCreateInfo			pipelineCacheCreateInfo =
373 	{
374 		vk::VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,		// VkStructureType				sType;
375 		DE_NULL,												// const void*					pNext;
376 		0u,														// VkPipelineCacheCreateFlags	flags;
377 		0u,														// deUintptr					initialDataSize;
378 		DE_NULL,												// const void*					pInitialData;
379 	};
380 
381 	vk::Move<vk::VkPipelineCache>				pipelineCache			= createPipelineCache(vk, device, &pipelineCacheCreateInfo);
382 
383 	vk::GraphicsPipelineWrapper					graphicsPipeline		(vki, vk, physicalDevice, device, deviceExtensions, m_pipelineConstructionType);
384 	graphicsPipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
385 					.setDefaultRasterizationState()
386 					.setDefaultMultisampleState()
387 					.setDefaultDepthStencilState()
388 					.setDefaultColorBlendState()
389 					.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
390 					.setupPreRasterizationShaderState(viewports,
391 						scissors,
392 						m_pipelineLayout,
393 						*m_renderPass,
394 						0u,
395 						vert)
396 					.setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, frag)
397 					.setupFragmentOutputState(*m_renderPass)
398 					.setMonolithicPipelineLayout(m_pipelineLayout)
399 					.buildPipeline(*pipelineCache);
400 
401 	vk::VkPipelineRobustnessCreateInfoEXT		pipelineRobustnessInfo = vk::initVulkanStructure();
402 
403 	if (m_robustnessBufferBehaviour == ROBUSTNESS)
404 	{
405 		if (m_type == STORAGE) pipelineRobustnessInfo.storageBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
406 		else if (m_type == UNIFORM) pipelineRobustnessInfo.uniformBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
407 		else if (m_type == VERTEX_INPUT) pipelineRobustnessInfo.vertexInputs = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
408 		else if (m_type == IMAGE) pipelineRobustnessInfo.images = vk::VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_EXT;
409 	}
410 	else
411 	{
412 		if (m_type == STORAGE) pipelineRobustnessInfo.storageBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
413 		else if (m_type == UNIFORM) pipelineRobustnessInfo.uniformBuffers = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
414 		else if (m_type == VERTEX_INPUT) pipelineRobustnessInfo.vertexInputs = vk::VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2_EXT;
415 		else if (m_type == IMAGE) pipelineRobustnessInfo.images = vk::VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2_EXT;
416 	}
417 
418 	vk::GraphicsPipelineWrapper					robustPipeline			(vki, vk, physicalDevice, device, deviceExtensions, m_pipelineConstructionType);
419 	robustPipeline.setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
420 					.setDefaultRasterizationState()
421 					.setDefaultMultisampleState()
422 					.setDefaultDepthStencilState()
423 					.setDefaultColorBlendState()
424 					.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
425 					.setupPreRasterizationShaderState(viewports,
426 						scissors,
427 						m_pipelineLayout,
428 						*m_renderPass,
429 						0u,
430 						vert)
431 					.setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, frag)
432 					.setupFragmentOutputState(*m_renderPass)
433 					.setMonolithicPipelineLayout(m_pipelineLayout)
434 					.buildPipeline(*pipelineCache, 0, 0, vk::PipelineCreationFeedbackCreateInfoWrapper(), &pipelineRobustnessInfo);
435 
436 	if (m_type == IMAGE)
437 	{
438 		// Initialize image
439 		const vk::VkImageMemoryBarrier		preImageBarrier =
440 		{
441 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
442 			DE_NULL,										// const void*				pNext;
443 			0u,												// VkAccessFlags			srcAccessMask;
444 			vk::VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags			dstAccessMask;
445 			vk::VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
446 			vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,		// VkImageLayout			newLayout;
447 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
448 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					dstQueueFamilyIndex;
449 			**image,										// VkImage					image;
450 			{												// VkImageSubresourceRange	subresourceRange;
451 				vk::VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags	aspect;
452 				0u,								// deUint32				baseMipLevel;
453 				1u,								// deUint32				mipLevels;
454 				0u,								// deUint32				baseArraySlice;
455 				1u,								// deUint32				arraySize;
456 			}
457 		};
458 
459 		const vk::VkImageMemoryBarrier		postImageBarrier =
460 		{
461 			vk::VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
462 			DE_NULL,										// const void*				pNext;
463 			vk::VK_ACCESS_TRANSFER_WRITE_BIT,				// VkAccessFlags			srcAccessMask;
464 			vk::VK_ACCESS_SHADER_READ_BIT,					// VkAccessFlags			dstAccessMask;
465 			vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,		// VkImageLayout			oldLayout;
466 			vk::VK_IMAGE_LAYOUT_GENERAL,					// VkImageLayout			newLayout;
467 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					srcQueueFamilyIndex;
468 			VK_QUEUE_FAMILY_IGNORED,						// deUint32					dstQueueFamilyIndex;
469 			**image,										// VkImage					image;
470 			{												// VkImageSubresourceRange	subresourceRange;
471 				vk::VK_IMAGE_ASPECT_COLOR_BIT,	// VkImageAspectFlags	aspect;
472 				0u,								// deUint32				baseMipLevel;
473 				1u,								// deUint32				mipLevels;
474 				0u,								// deUint32				baseArraySlice;
475 				1u,								// deUint32				arraySize;
476 			}
477 		};
478 
479 		const vk::VkBufferImageCopy	copyRegion =
480 		{
481 			0u,											// VkDeviceSize				bufferOffset;
482 			0u,											// deUint32					bufferRowLength;
483 			0u,											// deUint32					bufferImageHeight;
484 			{
485 				vk::VK_IMAGE_ASPECT_COLOR_BIT,				// VkImageAspectFlags	aspect;
486 				0u,											// deUint32				mipLevel;
487 				0u,											// deUint32				baseArrayLayer;
488 				1u,											// deUint32				layerCount;
489 			},											// VkImageSubresourceLayers	imageSubresource;
490 			{ 0, 0, 0 },								// VkOffset3D				imageOffset;
491 			{ 1, 1, 1 },								// VkExtent3D				imageExtent;
492 		};
493 
494 		vk::beginCommandBuffer(vk, *m_cmdBuffer);
495 		vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL,
496 			0u, DE_NULL, 1u, &preImageBarrier);
497 		vk.cmdCopyBufferToImage(*m_cmdBuffer, **m_buffer, **image, vk::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &copyRegion);
498 		vk.cmdPipelineBarrier(*m_cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, (vk::VkDependencyFlags)0, 0, (const vk::VkMemoryBarrier*)DE_NULL, 0, (const vk::VkBufferMemoryBarrier*)DE_NULL, 1, &postImageBarrier);
499 		vk::endCommandBuffer(vk, *m_cmdBuffer);
500 		vk::submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
501 	}
502 
503 	draw(graphicsPipeline);
504 
505 	if (!verifyImage(tcu::Vec4(values[0]), false))
506 		return tcu::TestStatus::fail("Fail");
507 
508 	deUint32 invalidIndex = m_type == VERTEX_INPUT ? 15u : 999u;
509 	deMemcpy(indexBufferAlloc.getHostPtr(), &invalidIndex, sizeof(deUint32));
510 	flushAlloc(vk, device, indexBufferAlloc);
511 
512 	draw(robustPipeline);
513 
514 	if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
515 	{
516 		if (!verifyImage(tcu::Vec4(0.0f), true))
517 			return tcu::TestStatus::fail("Fail");
518 	}
519 
520 	return tcu::TestStatus::pass("Pass");
521 }
522 
523 class PipelineCacheTestCase : public vkt::TestCase
524 {
525 public:
PipelineCacheTestCase(tcu::TestContext& context, const char* name, vk::PipelineConstructionType pipelineConstructionType, RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)526 	PipelineCacheTestCase (tcu::TestContext& context, const char* name, vk::PipelineConstructionType pipelineConstructionType, RobustnessBehaviour robustnessBufferBehaviour, RobustnessType type)
527 		: TestCase						(context, name)
528 		, m_pipelineConstructionType	(pipelineConstructionType)
529 		, m_robustnessBufferBehaviour	(robustnessBufferBehaviour)
530 		, m_type						(type)
531 	{
532 	}
533 private:
534 	void					checkSupport	(vkt::Context& context) const;
535 	void					initPrograms	(vk::SourceCollections& programCollection) const;
createInstance(vkt::Context& context) const536 	vkt::TestInstance*		createInstance	(vkt::Context& context) const { return new PipelineCacheTestInstance(context, m_pipelineConstructionType, m_robustnessBufferBehaviour, m_type); }
537 
538 	const vk::PipelineConstructionType		m_pipelineConstructionType;
539 	const RobustnessBehaviour				m_robustnessBufferBehaviour;
540 	const RobustnessType					m_type;
541 };
542 
checkSupport(vkt::Context& context) const543 void PipelineCacheTestCase::checkSupport (vkt::Context& context) const
544 {
545 	if (m_robustnessBufferBehaviour == ROBUSTNESS)
546 		context.requireDeviceFunctionality("VK_EXT_pipeline_robustness");
547 	if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
548 		context.requireDeviceFunctionality("VK_EXT_robustness2");
549 
550 	vk::VkPhysicalDevicePipelineRobustnessFeaturesEXT pipelineRobustnessFeatures = vk::initVulkanStructure();
551 	vk::VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = vk::initVulkanStructure(&pipelineRobustnessFeatures);
552 	vk::VkPhysicalDeviceFeatures2 features2;
553 
554 	features2.sType = vk::VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
555 	features2.pNext = &robustness2Features;
556 
557 	context.getInstanceInterface().getPhysicalDeviceFeatures2(context.getPhysicalDevice(), &features2);
558 
559 	if (pipelineRobustnessFeatures.pipelineRobustness == DE_FALSE)
560 		TCU_THROW(NotSupportedError, "VkPhysicalDevicePipelineRobustnessFeaturesEXT::pipelineRobustness feature not supported");
561 
562 	if (m_robustnessBufferBehaviour == ROBUSTNESS_2)
563 	{
564 		if (m_type == IMAGE)
565 		{
566 			if (robustness2Features.robustImageAccess2 == DE_FALSE)
567 				TCU_THROW(NotSupportedError, "VkPhysicalDeviceRobustness2FeaturesEXT::robustImageAccess2 feature not supported");
568 		}
569 		else
570 		{
571 			if (robustness2Features.robustBufferAccess2 == DE_FALSE)
572 				TCU_THROW(NotSupportedError, "VkPhysicalDeviceRobustness2FeaturesEXT::robustBufferAccess2 feature not supported");
573 		}
574 	}
575 
576 	vk::checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(), m_pipelineConstructionType);
577 }
578 
initPrograms(vk::SourceCollections& programCollection) const579 void PipelineCacheTestCase::initPrograms(vk::SourceCollections& programCollection) const
580 {
581 	if (m_type == VERTEX_INPUT)
582 	{
583 		{
584 			std::ostringstream vert;
585 			vert
586 				<< "#version 450\n"
587 				<< "layout(location = 0) in float in_values[16];\n"
588 				<< "layout(location = 0) out float out_value;\n"
589 				<< "layout (set=0, binding=1) restrict readonly buffer IndexBuffer {\n"
590 				<< "    uint index;\n"
591 				<< "};\n"
592 				<< "void main()\n"
593 				<< "{\n"
594 				<< "    vec2 vertex = vec2(gl_VertexIndex & 1u, (gl_VertexIndex >> 1u) & 1u);\n"
595 				<< "    gl_Position = vec4(vertex * 2.0f - 1.0f, 0.0f, 1.0f);\n"
596 				<< "    out_value = in_values[index];\n"
597 				<< "}\n"
598 				;
599 
600 			programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
601 		}
602 		{
603 			std::ostringstream frag;
604 			frag
605 				<< "#version 450\n"
606 				<< "layout (location=0) in float in_value;\n"
607 				<< "layout (location=0) out vec4 out_color;\n"
608 				<< "void main()\n"
609 				<< "{\n"
610 				<< "    out_color = vec4(in_value);\n"
611 				<< "}\n"
612 				;
613 
614 			programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
615 		}
616 	}
617 	else
618 	{
619 		{
620 			std::ostringstream vert;
621 			vert
622 				<< "#version 450\n"
623 				<< "void main()\n"
624 				<< "{\n"
625 				<< "    vec2 vertex = vec2(gl_VertexIndex & 1u, (gl_VertexIndex >> 1u) & 1u);\n"
626 				<< "    gl_Position = vec4(vertex * 2.0f - 1.0f, 0.0f, 1.0f);\n"
627 				<< "}\n"
628 				;
629 
630 			programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
631 		}
632 		{
633 			std::string descriptor = {};
634 			std::string write = {};
635 			if (m_type == STORAGE)
636 			{
637 				descriptor =
638 					"layout (set=0, binding=0) restrict readonly buffer StorageBuffer {\n"
639 					"    float values[];\n"
640 					"};\n";
641 				write = "    out_color = vec4(values[index]);\n";
642 			}
643 			else if (m_type == UNIFORM)
644 			{
645 				descriptor =
646 					"layout (std140, set=0, binding=0) restrict uniform UniformBuffer {\n"
647 					"	float values[1000];\n"
648 					"};\n";
649 				write = "    out_color = vec4(values[index]);\n";
650 			}
651 			else if (m_type == IMAGE)
652 			{
653 				descriptor = "layout (set=0, binding=0, rgba32f) uniform image2D tex;\n";
654 				write = "    out_color = imageLoad(tex, ivec2(index, 0));\n";
655 			}
656 
657 			std::ostringstream frag;
658 			frag
659 				<< "#version 450\n"
660 				<< "layout (location=0) out vec4 out_color;\n"
661 				<< descriptor
662 				<< "layout (set=0, binding=1) restrict readonly buffer IndexBuffer {\n"
663 				<< "    uint index;\n"
664 				<< "};\n"
665 				<< "void main()\n"
666 				<< "{\n"
667 				<< write
668 				<< "}\n"
669 				;
670 
671 			programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
672 		}
673 	}
674 }
675 
676 } // anonymous
677 
createPipelineRobustnessCacheTests(tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)678 tcu::TestCaseGroup* createPipelineRobustnessCacheTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
679 {
680 	// Test pipeline cache with different robustness enabled
681 	de::MovePtr<tcu::TestCaseGroup> testGroup	(new tcu::TestCaseGroup(testCtx, "pipeline_cache"));
682 
683 	const struct
684 	{
685 		RobustnessBehaviour	robustnessBehaviour;
686 		const char* name;
687 	} robustnessTests[] =
688 	{
689 		{ ROBUSTNESS,			"robustness"		},
690 		{ ROBUSTNESS_2,			"robustness2"		},
691 	};
692 
693 	const struct
694 	{
695 		RobustnessType	type;
696 		const char* name;
697 	} typeTests[] =
698 	{
699 		{ STORAGE,			"storage"		},
700 		{ UNIFORM,			"uniform"		},
701 		{ VERTEX_INPUT,		"vertex_input"	},
702 		{ IMAGE,			"image"		},
703 	};
704 
705 	for (const auto& robustnessTest : robustnessTests)
706 	{
707 		de::MovePtr<tcu::TestCaseGroup> robustnessGroup(new tcu::TestCaseGroup(testCtx, robustnessTest.name));
708 		for (const auto& typeTest : typeTests)
709 		{
710 			robustnessGroup->addChild(new PipelineCacheTestCase(testCtx, typeTest.name, pipelineConstructionType, robustnessTest.robustnessBehaviour, typeTest.type));
711 		}
712 		testGroup->addChild(robustnessGroup.release());
713 	}
714 
715 	return testGroup.release();
716 }
717 
718 } // pipeline
719 } // vkt
720