• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Multisample image Tests
22  *//*--------------------------------------------------------------------*/
23 
24 #include "vktPipelineMultisampleImageTests.hpp"
25 #include "vktPipelineMakeUtil.hpp"
26 #include "vktTestCase.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vktPipelineVertexUtil.hpp"
29 #include "vktTestGroupUtil.hpp"
30 
31 #include "vkMemUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkTypeUtil.hpp"
34 #include "vkRefUtil.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkImageUtil.hpp"
38 
39 #include "tcuTextureUtil.hpp"
40 #include "tcuTestLog.hpp"
41 
42 #include "deUniquePtr.hpp"
43 #include "deSharedPtr.hpp"
44 
45 #include <string>
46 
47 namespace vkt
48 {
49 namespace pipeline
50 {
51 namespace
52 {
53 using namespace vk;
54 using de::UniquePtr;
55 using de::MovePtr;
56 using de::SharedPtr;
57 using tcu::IVec2;
58 using tcu::Vec4;
59 
60 typedef SharedPtr<Unique<VkImageView> >	ImageViewSp;
61 typedef SharedPtr<Unique<VkPipeline> >	PipelineSp;
62 
63 //! Test case parameters
64 struct CaseDef
65 {
66 	IVec2					renderSize;
67 	int						numLayers;
68 	VkFormat				colorFormat;
69 	VkSampleCountFlagBits	numSamples;
70 };
71 
72 template<typename T>
makeSharedPtr(Move<T> move)73 inline SharedPtr<Unique<T> > makeSharedPtr (Move<T> move)
74 {
75 	return SharedPtr<Unique<T> >(new Unique<T>(move));
76 }
77 
78 template<typename T>
sizeInBytes(const std::vector<T> & vec)79 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
80 {
81 	return vec.size() * sizeof(vec[0]);
82 }
83 
84 //! Create a vector of derived pipelines, each with an increasing subpass index
makeGraphicsPipelines(const DeviceInterface & vk,const VkDevice device,const deUint32 numSubpasses,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const IVec2 renderSize,const VkSampleCountFlagBits numSamples,const VkPrimitiveTopology topology)85 std::vector<PipelineSp> makeGraphicsPipelines (const DeviceInterface&		vk,
86 											   const VkDevice				device,
87 											   const deUint32				numSubpasses,
88 											   const VkPipelineLayout		pipelineLayout,
89 											   const VkRenderPass			renderPass,
90 											   const VkShaderModule			vertexModule,
91 											   const VkShaderModule			fragmentModule,
92 											   const IVec2					renderSize,
93 											   const VkSampleCountFlagBits	numSamples,
94 											   const VkPrimitiveTopology	topology)
95 {
96 	const VkVertexInputBindingDescription vertexInputBindingDescription =
97 	{
98 		0u,								// uint32_t				binding;
99 		sizeof(Vertex4RGBA),			// uint32_t				stride;
100 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
101 	};
102 
103 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
104 	{
105 		{
106 			0u,									// uint32_t			location;
107 			0u,									// uint32_t			binding;
108 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
109 			0u,									// uint32_t			offset;
110 		},
111 		{
112 			1u,									// uint32_t			location;
113 			0u,									// uint32_t			binding;
114 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
115 			sizeof(Vec4),						// uint32_t			offset;
116 		},
117 	};
118 
119 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
120 	{
121 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
122 		DE_NULL,														// const void*                                 pNext;
123 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
124 		1u,																// uint32_t                                    vertexBindingDescriptionCount;
125 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
126 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
127 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
128 	};
129 
130 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
131 	{
132 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
133 		DE_NULL,														// const void*                                 pNext;
134 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
135 		topology,														// VkPrimitiveTopology                         topology;
136 		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
137 	};
138 
139 	const VkViewport viewport = makeViewport(
140 		0.0f, 0.0f,
141 		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
142 		0.0f, 1.0f);
143 
144 	const VkRect2D scissor = {
145 		makeOffset2D(0, 0),
146 		makeExtent2D(renderSize.x(), renderSize.y()),
147 	};
148 
149 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
150 	{
151 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
152 		DE_NULL,														// const void*                                 pNext;
153 		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
154 		1u,																// uint32_t                                    viewportCount;
155 		&viewport,														// const VkViewport*                           pViewports;
156 		1u,																// uint32_t                                    scissorCount;
157 		&scissor,														// const VkRect2D*                             pScissors;
158 	};
159 
160 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
161 	{
162 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
163 		DE_NULL,														// const void*                              pNext;
164 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
165 		VK_FALSE,														// VkBool32                                 depthClampEnable;
166 		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
167 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
168 		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
169 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
170 		VK_FALSE,														// VkBool32									depthBiasEnable;
171 		0.0f,															// float									depthBiasConstantFactor;
172 		0.0f,															// float									depthBiasClamp;
173 		0.0f,															// float									depthBiasSlopeFactor;
174 		1.0f,															// float									lineWidth;
175 	};
176 
177 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
178 	{
179 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
180 		DE_NULL,														// const void*								pNext;
181 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
182 		numSamples,														// VkSampleCountFlagBits					rasterizationSamples;
183 		VK_FALSE,														// VkBool32									sampleShadingEnable;
184 		0.0f,															// float									minSampleShading;
185 		DE_NULL,														// const VkSampleMask*						pSampleMask;
186 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
187 		VK_FALSE														// VkBool32									alphaToOneEnable;
188 	};
189 
190 	const VkStencilOpState stencilOpState = makeStencilOpState(
191 		VK_STENCIL_OP_KEEP,				// stencil fail
192 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
193 		VK_STENCIL_OP_KEEP,				// depth only fail
194 		VK_COMPARE_OP_ALWAYS,			// compare op
195 		0u,								// compare mask
196 		0u,								// write mask
197 		0u);							// reference
198 
199 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
200 	{
201 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
202 		DE_NULL,														// const void*								pNext;
203 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
204 		VK_FALSE,														// VkBool32									depthTestEnable;
205 		VK_FALSE,														// VkBool32									depthWriteEnable;
206 		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
207 		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
208 		VK_FALSE,														// VkBool32									stencilTestEnable;
209 		stencilOpState,													// VkStencilOpState							front;
210 		stencilOpState,													// VkStencilOpState							back;
211 		0.0f,															// float									minDepthBounds;
212 		1.0f,															// float									maxDepthBounds;
213 	};
214 
215 	const VkColorComponentFlags colorComponentsAll = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
216 	// Number of blend attachments must equal the number of color attachments during any subpass.
217 	const VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState =
218 	{
219 		VK_FALSE,						// VkBool32					blendEnable;
220 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
221 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
222 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
223 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
224 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
225 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
226 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
227 	};
228 
229 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
230 	{
231 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
232 		DE_NULL,														// const void*									pNext;
233 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
234 		VK_FALSE,														// VkBool32										logicOpEnable;
235 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
236 		1u,																// deUint32										attachmentCount;
237 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
238 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
239 	};
240 
241 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
242 	{
243 		{
244 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
245 			DE_NULL,													// const void*							pNext;
246 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
247 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
248 			vertexModule,												// VkShaderModule						module;
249 			"main",														// const char*							pName;
250 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
251 		},
252 		{
253 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
254 			DE_NULL,													// const void*							pNext;
255 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
256 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
257 			fragmentModule,												// VkShaderModule						module;
258 			"main",														// const char*							pName;
259 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
260 		}
261 	};
262 
263 	DE_ASSERT(numSubpasses > 0u);
264 
265 	std::vector<VkGraphicsPipelineCreateInfo>	graphicsPipelineInfos	(0);
266 	std::vector<VkPipeline>						rawPipelines			(numSubpasses, DE_NULL);
267 
268 	{
269 		const VkPipelineCreateFlags firstPipelineFlags = (numSubpasses > 1u ? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
270 																			: (VkPipelineCreateFlagBits)0);
271 
272 		VkGraphicsPipelineCreateInfo createInfo =
273 		{
274 			VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
275 			DE_NULL,											// const void*										pNext;
276 			firstPipelineFlags,									// VkPipelineCreateFlags							flags;
277 			DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
278 			pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
279 			&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
280 			&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
281 			DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
282 			&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
283 			&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
284 			&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
285 			&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
286 			&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
287 			DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
288 			pipelineLayout,										// VkPipelineLayout									layout;
289 			renderPass,											// VkRenderPass										renderPass;
290 			0u,													// deUint32											subpass;
291 			DE_NULL,											// VkPipeline										basePipelineHandle;
292 			-1,													// deInt32											basePipelineIndex;
293 		};
294 
295 		graphicsPipelineInfos.push_back(createInfo);
296 
297 		createInfo.flags				= VK_PIPELINE_CREATE_DERIVATIVE_BIT;
298 		createInfo.basePipelineIndex	= 0;
299 
300 		for (deUint32 subpassNdx = 1u; subpassNdx < numSubpasses; ++subpassNdx)
301 		{
302 			createInfo.subpass = subpassNdx;
303 			graphicsPipelineInfos.push_back(createInfo);
304 		}
305 	}
306 
307 	VK_CHECK(vk.createGraphicsPipelines(device, DE_NULL, static_cast<deUint32>(graphicsPipelineInfos.size()), &graphicsPipelineInfos[0], DE_NULL, &rawPipelines[0]));
308 
309 	std::vector<PipelineSp>	pipelines;
310 
311 	for (std::vector<VkPipeline>::const_iterator it = rawPipelines.begin(); it != rawPipelines.end(); ++it)
312 		pipelines.push_back(makeSharedPtr(Move<VkPipeline>(check<VkPipeline>(*it), Deleter<VkPipeline>(vk, device, DE_NULL))));
313 
314 	return pipelines;
315 }
316 
317 //! Make a render pass with one subpass per color attachment and one attachment per image layer.
makeMultisampleRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat,const VkSampleCountFlagBits numSamples,const deUint32 numLayers)318 Move<VkRenderPass> makeMultisampleRenderPass (const DeviceInterface&		vk,
319 											  const VkDevice				device,
320 											  const VkFormat				colorFormat,
321 											  const VkSampleCountFlagBits	numSamples,
322 											  const deUint32				numLayers)
323 {
324 	const VkAttachmentDescription colorAttachmentDescription =
325 	{
326 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
327 		colorFormat,										// VkFormat							format;
328 		numSamples,											// VkSampleCountFlagBits			samples;
329 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
330 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
331 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
332 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
333 		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
334 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
335 	};
336 	const std::vector<VkAttachmentDescription> attachmentDescriptions(numLayers, colorAttachmentDescription);
337 
338 	// Create a subpass for each attachment (each attachement is a layer of an arrayed image).
339 
340 	std::vector<VkAttachmentReference>	colorAttachmentReferences(numLayers);
341 	std::vector<VkSubpassDescription>	subpasses;
342 
343 	for (deUint32 i = 0; i < numLayers; ++i)
344 	{
345 		const VkAttachmentReference attachmentRef =
346 		{
347 			i,												// deUint32			attachment;
348 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL		// VkImageLayout	layout;
349 		};
350 		colorAttachmentReferences[i] = attachmentRef;
351 
352 		const VkSubpassDescription subpassDescription =
353 		{
354 			(VkSubpassDescriptionFlags)0,					// VkSubpassDescriptionFlags		flags;
355 			VK_PIPELINE_BIND_POINT_GRAPHICS,				// VkPipelineBindPoint				pipelineBindPoint;
356 			0u,												// deUint32							inputAttachmentCount;
357 			DE_NULL,										// const VkAttachmentReference*		pInputAttachments;
358 			1u,												// deUint32							colorAttachmentCount;
359 			&colorAttachmentReferences[i],					// const VkAttachmentReference*		pColorAttachments;
360 			DE_NULL,										// const VkAttachmentReference*		pResolveAttachments;
361 			DE_NULL,										// const VkAttachmentReference*		pDepthStencilAttachment;
362 			0u,												// deUint32							preserveAttachmentCount;
363 			DE_NULL											// const deUint32*					pPreserveAttachments;
364 		};
365 		subpasses.push_back(subpassDescription);
366 	}
367 
368 	const VkRenderPassCreateInfo renderPassInfo =
369 	{
370 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType					sType;
371 		DE_NULL,												// const void*						pNext;
372 		(VkRenderPassCreateFlags)0,								// VkRenderPassCreateFlags			flags;
373 		static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32							attachmentCount;
374 		&attachmentDescriptions[0],								// const VkAttachmentDescription*	pAttachments;
375 		static_cast<deUint32>(subpasses.size()),				// deUint32							subpassCount;
376 		&subpasses[0],											// const VkSubpassDescription*		pSubpasses;
377 		0u,														// deUint32							dependencyCount;
378 		DE_NULL													// const VkSubpassDependency*		pDependencies;
379 	};
380 
381 	return createRenderPass(vk, device, &renderPassInfo);
382 }
383 
384 //! A single-attachment, single-subpass render pass.
makeSimpleRenderPass(const DeviceInterface & vk,const VkDevice device,const VkFormat colorFormat)385 Move<VkRenderPass> makeSimpleRenderPass (const DeviceInterface&	vk,
386 									     const VkDevice			device,
387 										 const VkFormat			colorFormat)
388 {
389 	const VkAttachmentDescription colorAttachmentDescription =
390 	{
391 		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
392 		colorFormat,										// VkFormat							format;
393 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
394 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
395 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
396 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
397 		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
398 		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
399 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
400 	};
401 
402 	const VkAttachmentReference colorAttachmentRef =
403 	{
404 		0u,													// deUint32			attachment;
405 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
406 	};
407 
408 	const VkSubpassDescription subpassDescription =
409 	{
410 		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
411 		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
412 		0u,													// deUint32							inputAttachmentCount;
413 		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
414 		1u,													// deUint32							colorAttachmentCount;
415 		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
416 		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
417 		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
418 		0u,													// deUint32							preserveAttachmentCount;
419 		DE_NULL												// const deUint32*					pPreserveAttachments;
420 	};
421 
422 	const VkRenderPassCreateInfo renderPassInfo =
423 	{
424 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
425 		DE_NULL,											// const void*						pNext;
426 		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
427 		1u,													// deUint32							attachmentCount;
428 		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
429 		1u,													// deUint32							subpassCount;
430 		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
431 		0u,													// deUint32							dependencyCount;
432 		DE_NULL												// const VkSubpassDependency*		pDependencies;
433 	};
434 
435 	return createRenderPass(vk, device, &renderPassInfo);
436 }
437 
makeImage(const DeviceInterface & vk,const VkDevice device,const VkFormat format,const IVec2 & size,const deUint32 numLayers,const VkSampleCountFlagBits samples,const VkImageUsageFlags usage)438 Move<VkImage> makeImage (const DeviceInterface& vk, const VkDevice device, const VkFormat format, const IVec2& size, const deUint32 numLayers, const VkSampleCountFlagBits samples, const VkImageUsageFlags usage)
439 {
440 	const VkImageCreateInfo imageParams =
441 	{
442 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
443 		DE_NULL,										// const void*				pNext;
444 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
445 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
446 		format,											// VkFormat					format;
447 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
448 		1u,												// deUint32					mipLevels;
449 		numLayers,										// deUint32					arrayLayers;
450 		samples,										// VkSampleCountFlagBits	samples;
451 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
452 		usage,											// VkImageUsageFlags		usage;
453 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
454 		0u,												// deUint32					queueFamilyIndexCount;
455 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
456 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
457 	};
458 	return createImage(vk, device, &imageParams);
459 }
460 
461 //! Make a simplest sampler.
makeSampler(const DeviceInterface & vk,const VkDevice device)462 Move<VkSampler> makeSampler (const DeviceInterface& vk, const VkDevice device)
463 {
464 	const VkSamplerCreateInfo samplerParams =
465 	{
466 		VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,			// VkStructureType         sType;
467 		DE_NULL,										// const void*             pNext;
468 		(VkSamplerCreateFlags)0,						// VkSamplerCreateFlags    flags;
469 		VK_FILTER_NEAREST,								// VkFilter                magFilter;
470 		VK_FILTER_NEAREST,								// VkFilter                minFilter;
471 		VK_SAMPLER_MIPMAP_MODE_NEAREST,					// VkSamplerMipmapMode     mipmapMode;
472 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeU;
473 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeV;
474 		VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,			// VkSamplerAddressMode    addressModeW;
475 		0.0f,											// float                   mipLodBias;
476 		VK_FALSE,										// VkBool32                anisotropyEnable;
477 		1.0f,											// float                   maxAnisotropy;
478 		VK_FALSE,										// VkBool32                compareEnable;
479 		VK_COMPARE_OP_ALWAYS,							// VkCompareOp             compareOp;
480 		0.0f,											// float                   minLod;
481 		0.0f,											// float                   maxLod;
482 		VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK,		// VkBorderColor           borderColor;
483 		VK_FALSE,										// VkBool32                unnormalizedCoordinates;
484 	};
485 	return createSampler(vk, device, &samplerParams);
486 }
487 
makeBuffer(const DeviceInterface & vk,const VkDevice device,const VkDeviceSize bufferSize,const VkBufferUsageFlags usage)488 inline Move<VkBuffer> makeBuffer (const DeviceInterface& vk, const VkDevice device, const VkDeviceSize bufferSize, const VkBufferUsageFlags usage)
489 {
490 	const VkBufferCreateInfo bufferCreateInfo = makeBufferCreateInfo(bufferSize, usage);
491 	return createBuffer(vk, device, &bufferCreateInfo);
492 }
493 
makeColorSubresourceRange(const int baseArrayLayer,const int layerCount)494 inline VkImageSubresourceRange makeColorSubresourceRange (const int baseArrayLayer, const int layerCount)
495 {
496 	return makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount));
497 }
498 
makeColorSubresourceLayers(const int baseArrayLayer,const int layerCount)499 inline VkImageSubresourceLayers makeColorSubresourceLayers (const int baseArrayLayer, const int layerCount)
500 {
501 	return makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, static_cast<deUint32>(baseArrayLayer), static_cast<deUint32>(layerCount));
502 }
503 
checkImageFormatRequirements(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const VkSampleCountFlagBits sampleCount,const VkFormat format,const VkImageUsageFlags usage)504 void checkImageFormatRequirements (const InstanceInterface&		vki,
505 								   const VkPhysicalDevice		physDevice,
506 								   const VkSampleCountFlagBits	sampleCount,
507 								   const VkFormat				format,
508 								   const VkImageUsageFlags		usage)
509 {
510 	VkPhysicalDeviceFeatures	features;
511 	vki.getPhysicalDeviceFeatures(physDevice, &features);
512 
513 	if (((usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) && !features.shaderStorageImageMultisample)
514 		TCU_THROW(NotSupportedError, "Multisampled storage images are not supported");
515 
516 	VkImageFormatProperties		imageFormatProperties;
517 	const VkResult				imageFormatResult		= vki.getPhysicalDeviceImageFormatProperties(
518 		physDevice, format, VK_IMAGE_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, usage, (VkImageCreateFlags)0, &imageFormatProperties);
519 
520 	if (imageFormatResult == VK_ERROR_FORMAT_NOT_SUPPORTED)
521 		TCU_THROW(NotSupportedError, "Image format is not supported");
522 
523 	if ((imageFormatProperties.sampleCounts & sampleCount) != sampleCount)
524 		TCU_THROW(NotSupportedError, "Requested sample count is not supported");
525 }
526 
zeroBuffer(const DeviceInterface & vk,const VkDevice device,const Allocation & alloc,const VkDeviceSize bufferSize)527 void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize bufferSize)
528 {
529 	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(bufferSize));
530 	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), bufferSize);
531 }
532 
533 //! The default foreground color.
getPrimitiveColor(void)534 inline Vec4 getPrimitiveColor (void)
535 {
536 	return Vec4(1.0f, 0.0f, 0.0f, 1.0f);
537 }
538 
539 //! Get a reference clear value based on color format.
getClearValue(const VkFormat format)540 VkClearValue getClearValue (const VkFormat format)
541 {
542 	if (isUintFormat(format) || isIntFormat(format))
543 		return makeClearValueColorU32(16, 32, 64, 96);
544 	else
545 		return makeClearValueColorF32(0.0f, 0.0f, 1.0f, 1.0f);
546 }
547 
getColorFormatStr(const int numComponents,const bool isUint,const bool isSint)548 std::string getColorFormatStr (const int numComponents, const bool isUint, const bool isSint)
549 {
550 	std::ostringstream str;
551 	if (numComponents == 1)
552 		str << (isUint ? "uint" : isSint ? "int" : "float");
553 	else
554 		str << (isUint ? "u" : isSint ? "i" : "") << "vec" << numComponents;
555 
556 	return str.str();
557 }
558 
getSamplerTypeStr(const int numLayers,const bool isUint,const bool isSint)559 std::string getSamplerTypeStr (const int numLayers, const bool isUint, const bool isSint)
560 {
561 	std::ostringstream str;
562 	str << (isUint ? "u" : isSint ? "i" : "") << "sampler2DMS" << (numLayers > 1 ? "Array" : "");
563 	return str.str();
564 }
565 
566 //! Generate a gvec4 color literal.
567 template<typename T>
getColorStr(const T * data,int numComponents,const bool isUint,const bool isSint)568 std::string getColorStr (const T* data, int numComponents, const bool isUint, const bool isSint)
569 {
570 	const int maxIndex = 3;  // 4 components max
571 
572 	std::ostringstream str;
573 	str << (isUint ? "u" : isSint ? "i" : "") << "vec4(";
574 
575 	for (int i = 0; i < numComponents; ++i)
576 	{
577 		str << data[i]
578 			<< (i < maxIndex ? ", " : "");
579 	}
580 
581 	for (int i = numComponents; i < maxIndex + 1; ++i)
582 	{
583 		str << (i == maxIndex ? 1 : 0)
584 			<< (i <  maxIndex ? ", " : "");
585 	}
586 
587 	str << ")";
588 	return str.str();
589 }
590 
591 //! Clear color literal value used by the sampling shader.
getReferenceClearColorStr(const VkFormat format,const int numComponents,const bool isUint,const bool isSint)592 std::string getReferenceClearColorStr (const VkFormat format, const int numComponents, const bool isUint, const bool isSint)
593 {
594 	const VkClearColorValue clearColor = getClearValue(format).color;
595 	if (isUint)
596 		return getColorStr(clearColor.uint32, numComponents, isUint, isSint);
597 	else if (isSint)
598 		return getColorStr(clearColor.int32, numComponents, isUint, isSint);
599 	else
600 		return getColorStr(clearColor.float32, numComponents, isUint, isSint);
601 }
602 
603 //! Primitive color literal value used by the sampling shader.
getReferencePrimitiveColorStr(int numComponents,const bool isUint,const bool isSint)604 std::string getReferencePrimitiveColorStr (int numComponents, const bool isUint, const bool isSint)
605 {
606 	const Vec4 color = getPrimitiveColor();
607 	return getColorStr(color.getPtr(), numComponents, isUint, isSint);
608 }
609 
getNumSamples(const VkSampleCountFlagBits samples)610 inline int getNumSamples (const VkSampleCountFlagBits samples)
611 {
612 	return static_cast<int>(samples);	// enum bitmask actually matches the number of samples
613 }
614 
615 //! A flat-colored shape with sharp angles to make antialiasing visible.
genTriangleVertices(void)616 std::vector<Vertex4RGBA> genTriangleVertices (void)
617 {
618 	static const Vertex4RGBA data[] =
619 	{
620 		{
621 			Vec4(-1.0f, 0.0f, 0.0f, 1.0f),
622 			getPrimitiveColor(),
623 		},
624 		{
625 			Vec4(0.8f, 0.2f, 0.0f, 1.0f),
626 			getPrimitiveColor(),
627 		},
628 		{
629 			Vec4(0.8f, -0.2f, 0.0f, 1.0f),
630 			getPrimitiveColor(),
631 		},
632 	};
633 	return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
634 }
635 
636 //! A full-viewport quad. Use with TRIANGLE_STRIP topology.
genFullQuadVertices(void)637 std::vector<Vertex4RGBA> genFullQuadVertices (void)
638 {
639 	static const Vertex4RGBA data[] =
640 	{
641 		{
642 			Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
643 			Vec4(), // unused
644 		},
645 		{
646 			Vec4(-1.0f, 1.0f, 0.0f, 1.0f),
647 			Vec4(), // unused
648 		},
649 		{
650 			Vec4(1.0f, -1.0f, 0.0f, 1.0f),
651 			Vec4(), // unused
652 		},
653 		{
654 			Vec4(1.0f, 1.0f, 0.0f, 1.0f),
655 			Vec4(), // unused
656 		},
657 	};
658 	return std::vector<Vertex4RGBA>(data, data + DE_LENGTH_OF_ARRAY(data));
659 }
660 
getShaderImageFormatQualifier(const tcu::TextureFormat & format)661 std::string getShaderImageFormatQualifier (const tcu::TextureFormat& format)
662 {
663 	const char* orderPart;
664 	const char* typePart;
665 
666 	switch (format.order)
667 	{
668 		case tcu::TextureFormat::R:		orderPart = "r";	break;
669 		case tcu::TextureFormat::RG:	orderPart = "rg";	break;
670 		case tcu::TextureFormat::RGB:	orderPart = "rgb";	break;
671 		case tcu::TextureFormat::RGBA:	orderPart = "rgba";	break;
672 
673 		default:
674 			DE_ASSERT(false);
675 			orderPart = DE_NULL;
676 	}
677 
678 	switch (format.type)
679 	{
680 		case tcu::TextureFormat::FLOAT:				typePart = "32f";		break;
681 		case tcu::TextureFormat::HALF_FLOAT:		typePart = "16f";		break;
682 
683 		case tcu::TextureFormat::UNSIGNED_INT32:	typePart = "32ui";		break;
684 		case tcu::TextureFormat::UNSIGNED_INT16:	typePart = "16ui";		break;
685 		case tcu::TextureFormat::UNSIGNED_INT8:		typePart = "8ui";		break;
686 
687 		case tcu::TextureFormat::SIGNED_INT32:		typePart = "32i";		break;
688 		case tcu::TextureFormat::SIGNED_INT16:		typePart = "16i";		break;
689 		case tcu::TextureFormat::SIGNED_INT8:		typePart = "8i";		break;
690 
691 		case tcu::TextureFormat::UNORM_INT16:		typePart = "16";		break;
692 		case tcu::TextureFormat::UNORM_INT8:		typePart = "8";			break;
693 
694 		case tcu::TextureFormat::SNORM_INT16:		typePart = "16_snorm";	break;
695 		case tcu::TextureFormat::SNORM_INT8:		typePart = "8_snorm";	break;
696 
697 		default:
698 			DE_ASSERT(false);
699 			typePart = DE_NULL;
700 	}
701 
702 	return std::string() + orderPart + typePart;
703 }
704 
getShaderMultisampledImageType(const tcu::TextureFormat & format,const int numLayers)705 std::string getShaderMultisampledImageType (const tcu::TextureFormat& format, const int numLayers)
706 {
707 	const std::string formatPart = tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER ? "u" :
708 								   tcu::getTextureChannelClass(format.type) == tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER   ? "i" : "";
709 
710 	std::ostringstream str;
711 	str << formatPart << "image2DMS" << (numLayers > 1 ? "Array" : "");
712 
713 	return str.str();
714 }
715 
addSimpleVertexAndFragmentPrograms(SourceCollections & programCollection,const CaseDef caseDef)716 void addSimpleVertexAndFragmentPrograms (SourceCollections& programCollection, const CaseDef caseDef)
717 {
718 	const int	numComponents	= tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
719 	const bool	isUint			= isUintFormat(caseDef.colorFormat);
720 	const bool	isSint			= isIntFormat(caseDef.colorFormat);
721 
722 	// Vertex shader
723 	{
724 		std::ostringstream src;
725 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
726 			<< "\n"
727 			<< "layout(location = 0) in  vec4 in_position;\n"
728 			<< "layout(location = 1) in  vec4 in_color;\n"
729 			<< "layout(location = 0) out vec4 o_color;\n"
730 			<< "\n"
731 			<< "out gl_PerVertex {\n"
732 			<< "    vec4 gl_Position;\n"
733 			<< "};\n"
734 			<< "\n"
735 			<< "void main(void)\n"
736 			<< "{\n"
737 			<< "    gl_Position = in_position;\n"
738 			<< "    o_color     = in_color;\n"
739 			<< "}\n";
740 
741 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
742 	}
743 
744 	// Fragment shader
745 	{
746 		const std::string colorFormat = getColorFormatStr(numComponents, isUint, isSint);
747 
748 		std::ostringstream src;
749 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
750 			<< "\n"
751 			<< "layout(location = 0) in  vec4 in_color;\n"
752 			<< "layout(location = 0) out " << colorFormat << " o_color;\n"
753 			<< "\n"
754 			<< "void main(void)\n"
755 			<< "{\n"
756 			<< "    o_color = " << colorFormat << "("		// float color will be converted to int/uint here if needed
757 			<< (numComponents == 1 ? "in_color.r"   :
758 				numComponents == 2 ? "in_color.rg"  :
759 				numComponents == 3 ? "in_color.rgb" : "in_color") << ");\n"
760 			<< "}\n";
761 
762 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
763 	}
764 }
765 
766 //! Synchronously render to a multisampled color image.
renderMultisampledImage(Context & context,const CaseDef & caseDef,const VkImage colorImage)767 void renderMultisampledImage (Context& context, const CaseDef& caseDef, const VkImage colorImage)
768 {
769 	const DeviceInterface&			vk					= context.getDeviceInterface();
770 	const VkDevice					device				= context.getDevice();
771 	const VkQueue					queue				= context.getUniversalQueue();
772 	const deUint32					queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
773 	Allocator&						allocator			= context.getDefaultAllocator();
774 
775 	const Unique<VkCommandPool>		cmdPool				(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
776 	const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
777 
778 	const VkRect2D renderArea = {
779 		makeOffset2D(0, 0),
780 		makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
781 	};
782 
783 	{
784 		// Create an image view (attachment) for each layer of the image
785 		std::vector<ImageViewSp>	colorAttachments;
786 		std::vector<VkImageView>	attachmentHandles;
787 		for (int i = 0; i < caseDef.numLayers; ++i)
788 		{
789 			colorAttachments.push_back(makeSharedPtr(makeImageView(
790 				vk, device, colorImage, VK_IMAGE_VIEW_TYPE_2D, caseDef.colorFormat, makeColorSubresourceRange(i, 1))));
791 			attachmentHandles.push_back(**colorAttachments.back());
792 		}
793 
794 		// Vertex buffer
795 		const std::vector<Vertex4RGBA>	vertices			= genTriangleVertices();
796 		const VkDeviceSize				vertexBufferSize	= sizeInBytes(vertices);
797 		const Unique<VkBuffer>			vertexBuffer		(makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
798 		const UniquePtr<Allocation>		vertexBufferAlloc	(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
799 
800 		{
801 			deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
802 			flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
803 		}
804 
805 		const Unique<VkShaderModule>	vertexModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("vert"), 0u));
806 		const Unique<VkShaderModule>	fragmentModule	(createShaderModule			(vk, device, context.getBinaryCollection().get("frag"), 0u));
807 		const Unique<VkRenderPass>		renderPass		(makeMultisampleRenderPass	(vk, device, caseDef.colorFormat, caseDef.numSamples, caseDef.numLayers));
808 		const Unique<VkFramebuffer>		framebuffer		(makeFramebuffer			(vk, device, *renderPass, caseDef.numLayers, &attachmentHandles[0],
809 																					 static_cast<deUint32>(caseDef.renderSize.x()),  static_cast<deUint32>(caseDef.renderSize.y())));
810 		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout			(vk, device));
811 		const std::vector<PipelineSp>	pipelines		(makeGraphicsPipelines		(vk, device, caseDef.numLayers, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
812 																					 caseDef.renderSize, caseDef.numSamples, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST));
813 
814 		beginCommandBuffer(vk, *cmdBuffer);
815 
816 		const std::vector<VkClearValue> clearValues(caseDef.numLayers, getClearValue(caseDef.colorFormat));
817 
818 		const VkRenderPassBeginInfo renderPassBeginInfo = {
819 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
820 			DE_NULL,										// const void*             pNext;
821 			*renderPass,									// VkRenderPass            renderPass;
822 			*framebuffer,									// VkFramebuffer           framebuffer;
823 			renderArea,										// VkRect2D                renderArea;
824 			static_cast<deUint32>(clearValues.size()),		// uint32_t                clearValueCount;
825 			&clearValues[0],								// const VkClearValue*     pClearValues;
826 		};
827 		vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
828 
829 		{
830 			const VkDeviceSize vertexBufferOffset = 0ull;
831 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
832 		}
833 
834 		for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
835 		{
836 			if (layerNdx != 0)
837 				vk.cmdNextSubpass(*cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
838 
839 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines[layerNdx]);
840 
841 			vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
842 		}
843 
844 		vk.cmdEndRenderPass(*cmdBuffer);
845 
846 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
847 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
848 	}
849 }
850 
851 namespace SampledImage
852 {
853 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)854 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
855 {
856 	// Pass 1: Render to texture
857 
858 	addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
859 
860 	// Pass 2: Sample texture
861 
862 	// Vertex shader
863 	{
864 		std::ostringstream src;
865 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
866 			<< "\n"
867 			<< "layout(location = 0) in  vec4  in_position;\n"
868 			<< "\n"
869 			<< "out gl_PerVertex {\n"
870 			<< "    vec4 gl_Position;\n"
871 			<< "};\n"
872 			<< "\n"
873 			<< "void main(void)\n"
874 			<< "{\n"
875 			<< "    gl_Position = in_position;\n"
876 			<< "}\n";
877 
878 		programCollection.glslSources.add("sample_vert") << glu::VertexSource(src.str());
879 	}
880 
881 	// Fragment shader
882 	{
883 		const int			numComponents		= tcu::getNumUsedChannels(mapVkFormat(caseDef.colorFormat).order);
884 		const bool			isUint				= isUintFormat(caseDef.colorFormat);
885 		const bool			isSint				= isIntFormat(caseDef.colorFormat);
886 		const std::string	texelFormatStr		= (isUint ? "uvec4" : isSint ? "ivec4" : "vec4");
887 		const std::string	refClearColor		= getReferenceClearColorStr(caseDef.colorFormat, numComponents, isUint, isSint);
888 		const std::string	refPrimitiveColor	= getReferencePrimitiveColorStr(numComponents, isUint, isSint);
889 		const std::string	samplerTypeStr		= getSamplerTypeStr(caseDef.numLayers, isUint, isSint);
890 
891 		std::ostringstream src;
892 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
893 			<< "\n"
894 			<< "layout(location = 0) out int o_status;\n"
895 			<< "\n"
896 			<< "layout(set = 0, binding = 0) uniform " << samplerTypeStr << " colorTexture;\n"
897 			<< "\n"
898 			<< "void main(void)\n"
899 			<< "{\n"
900 			<< "    int checksum = 0;\n"
901 			<< "\n";
902 
903 		if (caseDef.numLayers == 1)
904 			src << "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
905 				<< "        " << texelFormatStr << " color = texelFetch(colorTexture, ivec2(gl_FragCoord.xy), sampleNdx);\n"
906 				<< "        if (color == " << refClearColor << " || color == " << refPrimitiveColor << ")\n"
907 				<< "            ++checksum;\n"
908 				<< "    }\n";
909 		else
910 			src << "    for (int layerNdx = 0; layerNdx < " << caseDef.numLayers << "; ++layerNdx)\n"
911 				<< "    for (int sampleNdx = 0; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
912 				<< "        " << texelFormatStr << " color = texelFetch(colorTexture, ivec3(gl_FragCoord.xy, layerNdx), sampleNdx);\n"
913 				<< "        if (color == " << refClearColor << " || color == " << refPrimitiveColor << ")\n"
914 				<< "            ++checksum;\n"
915 				<< "    }\n";
916 
917 		src << "\n"
918 			<< "    o_status = checksum;\n"
919 			<< "}\n";
920 
921 		programCollection.glslSources.add("sample_frag") << glu::FragmentSource(src.str());
922 	}
923 }
924 
test(Context & context,const CaseDef caseDef)925 tcu::TestStatus test (Context& context, const CaseDef caseDef)
926 {
927 	const DeviceInterface&		vk					= context.getDeviceInterface();
928 	const InstanceInterface&	vki					= context.getInstanceInterface();
929 	const VkDevice				device				= context.getDevice();
930 	const VkPhysicalDevice		physDevice			= context.getPhysicalDevice();
931 	const VkQueue				queue				= context.getUniversalQueue();
932 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
933 	Allocator&					allocator			= context.getDefaultAllocator();
934 
935 	const VkImageUsageFlags		colorImageUsage		= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
936 
937 	checkImageFormatRequirements(vki, physDevice, caseDef.numSamples, caseDef.colorFormat, colorImageUsage);
938 
939 	{
940 		tcu::TestLog& log = context.getTestContext().getLog();
941 		log << tcu::LogSection("Description", "")
942 			<< tcu::TestLog::Message << "Rendering to a multisampled image. Expecting all samples to be either a clear color or a primitive color." << tcu::TestLog::EndMessage
943 			<< tcu::TestLog::Message << "Sampling from the texture with texelFetch (OpImageFetch)." << tcu::TestLog::EndMessage
944 			<< tcu::TestLog::EndSection;
945 	}
946 
947 	// Multisampled color image
948 	const Unique<VkImage>			colorImage		(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, caseDef.numSamples, colorImageUsage));
949 	const UniquePtr<Allocation>		colorImageAlloc	(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
950 
951 	const Unique<VkCommandPool>		cmdPool			(createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
952 	const Unique<VkCommandBuffer>	cmdBuffer		(makeCommandBuffer(vk, device, *cmdPool));
953 
954 	const VkRect2D renderArea = {
955 		makeOffset2D(0, 0),
956 		makeExtent2D(caseDef.renderSize.x(), caseDef.renderSize.y()),
957 	};
958 
959 	// Step 1: Render to texture
960 	{
961 		renderMultisampledImage(context, caseDef, *colorImage);
962 	}
963 
964 	// Step 2: Sample texture
965 	{
966 		// Color image view
967 		const VkImageViewType			colorImageViewType	= (caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY);
968 		const Unique<VkImageView>		colorImageView		(makeImageView(vk, device, *colorImage, colorImageViewType, caseDef.colorFormat, makeColorSubresourceRange(0, caseDef.numLayers)));
969 		const Unique<VkSampler>			colorSampler		(makeSampler(vk, device));
970 
971 		// Checksum image
972 		const VkFormat					checksumFormat		= VK_FORMAT_R32_SINT;
973 		const Unique<VkImage>			checksumImage		(makeImage(vk, device, checksumFormat, caseDef.renderSize, 1u, VK_SAMPLE_COUNT_1_BIT,
974 																	   VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
975 		const UniquePtr<Allocation>		checksumImageAlloc	(bindImage(vk, device, allocator, *checksumImage, MemoryRequirement::Any));
976 		const Unique<VkImageView>		checksumImageView	(makeImageView(vk, device, *checksumImage, VK_IMAGE_VIEW_TYPE_2D, checksumFormat, makeColorSubresourceRange(0, 1)));
977 
978 		// Checksum buffer (for host reading)
979 		const VkDeviceSize				checksumBufferSize	= caseDef.renderSize.x() * caseDef.renderSize.y() * tcu::getPixelSize(mapVkFormat(checksumFormat));
980 		const Unique<VkBuffer>			checksumBuffer		(makeBuffer(vk, device, checksumBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
981 		const UniquePtr<Allocation>		checksumBufferAlloc	(bindBuffer(vk, device, allocator, *checksumBuffer, MemoryRequirement::HostVisible));
982 
983 		zeroBuffer(vk, device, *checksumBufferAlloc, checksumBufferSize);
984 
985 		// Vertex buffer
986 		const std::vector<Vertex4RGBA>	vertices			= genFullQuadVertices();
987 		const VkDeviceSize				vertexBufferSize	= sizeInBytes(vertices);
988 		const Unique<VkBuffer>			vertexBuffer		(makeBuffer(vk, device, vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
989 		const UniquePtr<Allocation>		vertexBufferAlloc	(bindBuffer(vk, device, allocator, *vertexBuffer, MemoryRequirement::HostVisible));
990 
991 		{
992 			deMemcpy(vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(vertexBufferSize));
993 			flushMappedMemoryRange(vk, device, vertexBufferAlloc->getMemory(), vertexBufferAlloc->getOffset(), vertexBufferSize);
994 		}
995 
996 		// Descriptors
997 		// \note OpImageFetch doesn't use a sampler, but in GLSL texelFetch needs a sampler2D which translates to a combined image sampler in Vulkan.
998 
999 		const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
1000 			.addSingleSamplerBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, &colorSampler.get())
1001 			.build(vk, device));
1002 
1003 		const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
1004 			.addType(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
1005 			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1006 
1007 		const Unique<VkDescriptorSet>	descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1008 		const VkDescriptorImageInfo		imageDescriptorInfo	= makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
1009 
1010 		DescriptorSetUpdateBuilder()
1011 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, &imageDescriptorInfo)
1012 			.update(vk, device);
1013 
1014 		const Unique<VkShaderModule>	vertexModule	(createShaderModule		(vk, device, context.getBinaryCollection().get("sample_vert"), 0u));
1015 		const Unique<VkShaderModule>	fragmentModule	(createShaderModule		(vk, device, context.getBinaryCollection().get("sample_frag"), 0u));
1016 		const Unique<VkRenderPass>		renderPass		(makeSimpleRenderPass	(vk, device, checksumFormat));
1017 		const Unique<VkFramebuffer>		framebuffer		(makeFramebuffer		(vk, device, *renderPass, 1u, &checksumImageView.get(),
1018 																				 static_cast<deUint32>(caseDef.renderSize.x()),  static_cast<deUint32>(caseDef.renderSize.y())));
1019 		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout		(vk, device, *descriptorSetLayout));
1020 		const std::vector<PipelineSp>	pipelines		(makeGraphicsPipelines	(vk, device, 1u, *pipelineLayout, *renderPass, *vertexModule, *fragmentModule,
1021 																				 caseDef.renderSize, VK_SAMPLE_COUNT_1_BIT, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP));
1022 
1023 		beginCommandBuffer(vk, *cmdBuffer);
1024 
1025 		// Prepare for sampling in the fragment shader
1026 		{
1027 			const VkImageMemoryBarrier barriers[] =
1028 			{
1029 				{
1030 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1031 					DE_NULL,													// const void*				pNext;
1032 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
1033 					VK_ACCESS_SHADER_READ_BIT,									// VkAccessFlags			inputMask;
1034 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
1035 					VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,					// VkImageLayout			newLayout;
1036 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1037 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1038 					*colorImage,												// VkImage					image;
1039 					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1040 				},
1041 			};
1042 
1043 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
1044 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1045 		}
1046 
1047 		const VkClearValue clearValue = makeClearValueColorU32(0u, 0u, 0u, 0u);
1048 
1049 		const VkRenderPassBeginInfo renderPassBeginInfo = {
1050 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,							// VkStructureType         sType;
1051 			DE_NULL,															// const void*             pNext;
1052 			*renderPass,														// VkRenderPass            renderPass;
1053 			*framebuffer,														// VkFramebuffer           framebuffer;
1054 			renderArea,															// VkRect2D                renderArea;
1055 			1u,																	// uint32_t                clearValueCount;
1056 			&clearValue,														// const VkClearValue*     pClearValues;
1057 		};
1058 		vk.cmdBeginRenderPass(*cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1059 
1060 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, **pipelines.back());
1061 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1062 		{
1063 			const VkDeviceSize vertexBufferOffset = 0ull;
1064 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
1065 		}
1066 
1067 		vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
1068 		vk.cmdEndRenderPass(*cmdBuffer);
1069 
1070 		// Prepare checksum image for copy
1071 		{
1072 			const VkImageMemoryBarrier barriers[] =
1073 			{
1074 				{
1075 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1076 					DE_NULL,													// const void*				pNext;
1077 					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
1078 					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
1079 					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
1080 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
1081 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1082 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1083 					*checksumImage,												// VkImage					image;
1084 					makeColorSubresourceRange(0, 1),							// VkImageSubresourceRange	subresourceRange;
1085 				},
1086 			};
1087 
1088 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1089 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1090 		}
1091 		// Checksum image -> host buffer
1092 		{
1093 			const VkBufferImageCopy region =
1094 			{
1095 				0ull,																		// VkDeviceSize                bufferOffset;
1096 				0u,																			// uint32_t                    bufferRowLength;
1097 				0u,																			// uint32_t                    bufferImageHeight;
1098 				makeColorSubresourceLayers(0, 1),											// VkImageSubresourceLayers    imageSubresource;
1099 				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
1100 				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),			// VkExtent3D                  imageExtent;
1101 			};
1102 
1103 			vk.cmdCopyImageToBuffer(*cmdBuffer, *checksumImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *checksumBuffer, 1u, &region);
1104 		}
1105 		// Buffer write barrier
1106 		{
1107 			const VkBufferMemoryBarrier barriers[] =
1108 			{
1109 				{
1110 					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
1111 					DE_NULL,										// const void*        pNext;
1112 					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
1113 					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
1114 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
1115 					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
1116 					*checksumBuffer,								// VkBuffer           buffer;
1117 					0ull,											// VkDeviceSize       offset;
1118 					checksumBufferSize,								// VkDeviceSize       size;
1119 				},
1120 			};
1121 
1122 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
1123 				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
1124 		}
1125 
1126 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1127 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1128 
1129 		// Verify result
1130 
1131 		{
1132 			invalidateMappedMemoryRange(vk, device, checksumBufferAlloc->getMemory(), 0ull, checksumBufferSize);
1133 
1134 			const tcu::ConstPixelBufferAccess access(mapVkFormat(checksumFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), 1, checksumBufferAlloc->getHostPtr());
1135 			const int numExpectedChecksum = getNumSamples(caseDef.numSamples) * caseDef.numLayers;
1136 
1137 			for (int y = 0; y < caseDef.renderSize.y(); ++y)
1138 			for (int x = 0; x < caseDef.renderSize.x(); ++x)
1139 			{
1140 				if (access.getPixelInt(x, y).x() != numExpectedChecksum)
1141 					return tcu::TestStatus::fail("Some samples have incorrect color");
1142 			}
1143 		}
1144 	}
1145 
1146 	return tcu::TestStatus::pass("OK");
1147 }
1148 
1149 } // SampledImage ns
1150 
1151 namespace StorageImage
1152 {
1153 
initPrograms(SourceCollections & programCollection,const CaseDef caseDef)1154 void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
1155 {
1156 	// Vertex & fragment
1157 
1158 	addSimpleVertexAndFragmentPrograms(programCollection, caseDef);
1159 
1160 	// Compute
1161 	{
1162 		const std::string	imageTypeStr		= getShaderMultisampledImageType(mapVkFormat(caseDef.colorFormat), caseDef.numLayers);
1163 		const std::string	formatQualifierStr	= getShaderImageFormatQualifier(mapVkFormat(caseDef.colorFormat));
1164 		const std::string	signednessPrefix	= isUintFormat(caseDef.colorFormat) ? "u" : isIntFormat(caseDef.colorFormat) ? "i" : "";
1165 		const std::string	gvec4Expr			= signednessPrefix + "vec4";
1166 		const std::string	texelCoordStr		= (caseDef.numLayers == 1 ? "ivec2(gx, gy)" : "ivec3(gx, gy, gz)");
1167 
1168 		std::ostringstream src;
1169 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
1170 			<< "layout(local_size_x = 1) in;\n"
1171 			<< "layout(set = 0, binding = 0, " << formatQualifierStr << ") uniform " << imageTypeStr << " u_msImage;\n"
1172 			<< "\n"
1173 			<< "void main(void)\n"
1174 			<< "{\n"
1175 			<< "    int gx = int(gl_GlobalInvocationID.x);\n"
1176 			<< "    int gy = int(gl_GlobalInvocationID.y);\n"
1177 			<< "    int gz = int(gl_GlobalInvocationID.z);\n"
1178 			<< "\n"
1179 			<< "    " << gvec4Expr << " prevColor = imageLoad(u_msImage, " << texelCoordStr << ", 0);\n"
1180 			<< "    for (int sampleNdx = 1; sampleNdx < " << caseDef.numSamples << "; ++sampleNdx) {\n"
1181 			<< "        " << gvec4Expr << " color = imageLoad(u_msImage, " << texelCoordStr << ", sampleNdx);\n"
1182 			<< "        imageStore(u_msImage, " << texelCoordStr <<", sampleNdx, prevColor);\n"
1183 			<< "        prevColor = color;\n"
1184 			<< "    }\n"
1185 			<< "    imageStore(u_msImage, " << texelCoordStr <<", 0, prevColor);\n"
1186 			<< "}\n";
1187 
1188 		programCollection.glslSources.add("comp") << glu::ComputeSource(src.str());
1189 	}
1190 }
1191 
1192 //! Render a MS image, resolve it, and copy result to resolveBuffer.
renderAndResolve(Context & context,const CaseDef & caseDef,const VkBuffer resolveBuffer,const bool useComputePass)1193 void renderAndResolve (Context& context, const CaseDef& caseDef, const VkBuffer resolveBuffer, const bool useComputePass)
1194 {
1195 	const DeviceInterface&		vk					= context.getDeviceInterface();
1196 	const VkDevice				device				= context.getDevice();
1197 	const VkQueue				queue				= context.getUniversalQueue();
1198 	const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
1199 	Allocator&					allocator			= context.getDefaultAllocator();
1200 
1201 	// Multisampled color image
1202 	const Unique<VkImage>			colorImage			(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, caseDef.numSamples,
1203 																   VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1204 	const UniquePtr<Allocation>		colorImageAlloc		(bindImage(vk, device, allocator, *colorImage, MemoryRequirement::Any));
1205 
1206 	const Unique<VkImage>			resolveImage		(makeImage(vk, device, caseDef.colorFormat, caseDef.renderSize, caseDef.numLayers, VK_SAMPLE_COUNT_1_BIT,
1207 																   VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT));
1208 	const UniquePtr<Allocation>		resolveImageAlloc	(bindImage(vk, device, allocator, *resolveImage, MemoryRequirement::Any));
1209 
1210 	const Unique<VkCommandPool>		cmdPool				(createCommandPool  (vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex));
1211 	const Unique<VkCommandBuffer>	cmdBuffer			(makeCommandBuffer(vk, device, *cmdPool));
1212 
1213 	// Working image barrier, we change it based on which rendering stages were executed so far.
1214 	VkImageMemoryBarrier colorImageBarrier =
1215 	{
1216 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1217 		DE_NULL,													// const void*				pNext;
1218 		(VkAccessFlags)0,											// VkAccessFlags			outputMask;
1219 		(VkAccessFlags)0,											// VkAccessFlags			inputMask;
1220 		VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			oldLayout;
1221 		VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			newLayout;
1222 		VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1223 		VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1224 		*colorImage,												// VkImage					image;
1225 		makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1226 	};
1227 
1228 	// Pass 1: Render an image
1229 	{
1230 		renderMultisampledImage(context, caseDef, *colorImage);
1231 
1232 		colorImageBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1233 		colorImageBarrier.oldLayout		= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1234 	}
1235 
1236 	// Pass 2: Compute shader
1237 	if (useComputePass)
1238 	{
1239 		// Descriptors
1240 
1241 		Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
1242 			.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, VK_SHADER_STAGE_COMPUTE_BIT)
1243 			.build(vk, device));
1244 
1245 		Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
1246 			.addType(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1u)
1247 			.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
1248 
1249 		const Unique<VkImageView>		colorImageView		(makeImageView(vk, device, *colorImage,
1250 																			(caseDef.numLayers == 1 ? VK_IMAGE_VIEW_TYPE_2D : VK_IMAGE_VIEW_TYPE_2D_ARRAY),
1251 																			caseDef.colorFormat, makeColorSubresourceRange(0, caseDef.numLayers)));
1252 		const Unique<VkDescriptorSet>	descriptorSet		(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
1253 		const VkDescriptorImageInfo		descriptorImageInfo	= makeDescriptorImageInfo(DE_NULL, *colorImageView, VK_IMAGE_LAYOUT_GENERAL);
1254 
1255 		DescriptorSetUpdateBuilder()
1256 			.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, &descriptorImageInfo)
1257 			.update(vk, device);
1258 
1259 		const Unique<VkPipelineLayout>	pipelineLayout	(makePipelineLayout	(vk, device, *descriptorSetLayout));
1260 		const Unique<VkShaderModule>	shaderModule	(createShaderModule	(vk, device, context.getBinaryCollection().get("comp"), 0));
1261 		const Unique<VkPipeline>		pipeline		(makeComputePipeline(vk, device, *pipelineLayout, *shaderModule, DE_NULL));
1262 
1263 		beginCommandBuffer(vk, *cmdBuffer);
1264 
1265 		// Image layout for load/stores
1266 		{
1267 			colorImageBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
1268 			colorImageBarrier.newLayout		= VK_IMAGE_LAYOUT_GENERAL;
1269 
1270 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0u,
1271 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorImageBarrier);
1272 
1273 			colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1274 			colorImageBarrier.oldLayout		= colorImageBarrier.newLayout;
1275 		}
1276 		// Dispatch
1277 		{
1278 			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
1279 			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
1280 			vk.cmdDispatch(*cmdBuffer, caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers);
1281 		}
1282 
1283 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1284 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1285 	}
1286 
1287 	// Resolve and verify the image
1288 	{
1289 		beginCommandBuffer(vk, *cmdBuffer);
1290 
1291 		// Prepare for resolve
1292 		{
1293 			colorImageBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
1294 			colorImageBarrier.newLayout		= VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1295 
1296 			const VkImageMemoryBarrier barriers[] =
1297 			{
1298 				colorImageBarrier,
1299 				{
1300 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1301 					DE_NULL,													// const void*				pNext;
1302 					(VkAccessFlags)0,											// VkAccessFlags			outputMask;
1303 					VK_ACCESS_TRANSFER_WRITE_BIT,								// VkAccessFlags			inputMask;
1304 					VK_IMAGE_LAYOUT_UNDEFINED,									// VkImageLayout			oldLayout;
1305 					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,						// VkImageLayout			newLayout;
1306 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1307 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1308 					*resolveImage,												// VkImage					image;
1309 					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1310 				},
1311 			};
1312 
1313 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1314 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1315 
1316 			colorImageBarrier.srcAccessMask = colorImageBarrier.dstAccessMask;
1317 			colorImageBarrier.oldLayout		= colorImageBarrier.newLayout;
1318 		}
1319 		// Resolve the image
1320 		{
1321 			const VkImageResolve resolveRegion =
1322 			{
1323 				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    srcSubresource;
1324 				makeOffset3D(0, 0, 0),												// VkOffset3D                  srcOffset;
1325 				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    dstSubresource;
1326 				makeOffset3D(0, 0, 0),												// VkOffset3D                  dstOffset;
1327 				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),	// VkExtent3D                  extent;
1328 			};
1329 
1330 			vk.cmdResolveImage(*cmdBuffer, *colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *resolveImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1u, &resolveRegion);
1331 		}
1332 		// Prepare resolve image for copy
1333 		{
1334 			const VkImageMemoryBarrier barriers[] =
1335 			{
1336 				{
1337 					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
1338 					DE_NULL,													// const void*				pNext;
1339 					VK_ACCESS_TRANSFER_WRITE_BIT,								// VkAccessFlags			outputMask;
1340 					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
1341 					VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,						// VkImageLayout			oldLayout;
1342 					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
1343 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
1344 					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
1345 					*resolveImage,												// VkImage					image;
1346 					makeColorSubresourceRange(0, caseDef.numLayers),			// VkImageSubresourceRange	subresourceRange;
1347 				},
1348 			};
1349 
1350 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
1351 				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
1352 		}
1353 		// Copy resolved image to host-readable buffer
1354 		{
1355 			const VkBufferImageCopy copyRegion =
1356 			{
1357 				0ull,																// VkDeviceSize                bufferOffset;
1358 				0u,																	// uint32_t                    bufferRowLength;
1359 				0u,																	// uint32_t                    bufferImageHeight;
1360 				makeColorSubresourceLayers(0, caseDef.numLayers),					// VkImageSubresourceLayers    imageSubresource;
1361 				makeOffset3D(0, 0, 0),												// VkOffset3D                  imageOffset;
1362 				makeExtent3D(caseDef.renderSize.x(), caseDef.renderSize.y(), 1u),	// VkExtent3D                  imageExtent;
1363 			};
1364 
1365 			vk.cmdCopyImageToBuffer(*cmdBuffer, *resolveImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, resolveBuffer, 1u, &copyRegion);
1366 		}
1367 
1368 		VK_CHECK(vk.endCommandBuffer(*cmdBuffer));
1369 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
1370 	}
1371 }
1372 
1373 //! Exact image compare, but allow for some error when color format is integer.
compareImages(tcu::TestLog & log,const CaseDef & caseDef,const tcu::ConstPixelBufferAccess layeredReferenceImage,const tcu::ConstPixelBufferAccess layeredActualImage)1374 bool compareImages (tcu::TestLog& log, const CaseDef& caseDef, const tcu::ConstPixelBufferAccess layeredReferenceImage, const tcu::ConstPixelBufferAccess layeredActualImage)
1375 {
1376 	DE_ASSERT(caseDef.numSamples > 1);
1377 
1378 	const Vec4	goodColor			= Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1379 	const Vec4	badColor			= Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1380 	const bool	isAnyIntFormat		= isIntFormat(caseDef.colorFormat) || isUintFormat(caseDef.colorFormat);
1381 
1382 	// There should be no mismatched pixels for non-integer formats. Otherwise we may get a wrong color in a location where sample coverage isn't exactly 0 or 1.
1383 	const int	badPixelTolerance	= (isAnyIntFormat ? 2 * caseDef.renderSize.x() : 0);
1384 	int			goodLayers			= 0;
1385 
1386 	for (int layerNdx = 0; layerNdx < caseDef.numLayers; ++layerNdx)
1387 	{
1388 		const tcu::ConstPixelBufferAccess	referenceImage	= tcu::getSubregion(layeredReferenceImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1389 		const tcu::ConstPixelBufferAccess	actualImage		= tcu::getSubregion(layeredActualImage, 0, 0, layerNdx, caseDef.renderSize.x(), caseDef.renderSize.y(), 1);
1390 		const std::string					imageName		= "color layer " + de::toString(layerNdx);
1391 
1392 		tcu::TextureLevel		errorMaskStorage	(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), caseDef.renderSize.x(), caseDef.renderSize.y());
1393 		tcu::PixelBufferAccess	errorMask			= errorMaskStorage.getAccess();
1394 		int						numBadPixels		= 0;
1395 
1396 		for (int y = 0; y < caseDef.renderSize.y(); ++y)
1397 		for (int x = 0; x < caseDef.renderSize.x(); ++x)
1398 		{
1399 			if (isAnyIntFormat && (referenceImage.getPixelInt(x, y) == actualImage.getPixelInt(x, y)))
1400 				errorMask.setPixel(goodColor, x, y);
1401 			else if (referenceImage.getPixel(x, y) == actualImage.getPixel(x, y))
1402 				errorMask.setPixel(goodColor, x, y);
1403 			else
1404 			{
1405 				++numBadPixels;
1406 				errorMask.setPixel(badColor, x, y);
1407 			}
1408 		}
1409 
1410 		if (numBadPixels <= badPixelTolerance)
1411 		{
1412 			++goodLayers;
1413 
1414 			log << tcu::TestLog::ImageSet(imageName, imageName)
1415 				<< tcu::TestLog::Image("Result",	"Result",		actualImage)
1416 				<< tcu::TestLog::EndImageSet;
1417 		}
1418 		else
1419 		{
1420 			log << tcu::TestLog::ImageSet(imageName, imageName)
1421 				<< tcu::TestLog::Image("Result",	"Result",		actualImage)
1422 				<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
1423 				<< tcu::TestLog::Image("ErrorMask",	"Error mask",	errorMask)
1424 				<< tcu::TestLog::EndImageSet;
1425 		}
1426 	}
1427 
1428 	if (goodLayers == caseDef.numLayers)
1429 	{
1430 		log << tcu::TestLog::Message << "All rendered images are correct." << tcu::TestLog::EndMessage;
1431 		return true;
1432 	}
1433 	else
1434 	{
1435 		log << tcu::TestLog::Message << "FAILED: Some rendered images were incorrect." << tcu::TestLog::EndMessage;
1436 		return false;
1437 	}
1438 }
1439 
test(Context & context,const CaseDef caseDef)1440 tcu::TestStatus test (Context& context, const CaseDef caseDef)
1441 {
1442 	const DeviceInterface&		vk					= context.getDeviceInterface();
1443 	const InstanceInterface&	vki					= context.getInstanceInterface();
1444 	const VkDevice				device				= context.getDevice();
1445 	const VkPhysicalDevice		physDevice			= context.getPhysicalDevice();
1446 	Allocator&					allocator			= context.getDefaultAllocator();
1447 
1448 	checkImageFormatRequirements(vki, physDevice, caseDef.numSamples, caseDef.colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
1449 
1450 	{
1451 		tcu::TestLog& log = context.getTestContext().getLog();
1452 		log << tcu::LogSection("Description", "")
1453 			<< tcu::TestLog::Message << "Rendering to a multisampled image. Image will be processed with a compute shader using OpImageRead and OpImageWrite." << tcu::TestLog::EndMessage
1454 			<< tcu::TestLog::Message << "Expecting the processed image to be roughly the same as the input image (deviation may occur for integer formats)." << tcu::TestLog::EndMessage
1455 			<< tcu::TestLog::EndSection;
1456 	}
1457 
1458 	// Host-readable buffer
1459 	const VkDeviceSize				resolveBufferSize			= caseDef.renderSize.x() * caseDef.renderSize.y() * caseDef.numLayers * tcu::getPixelSize(mapVkFormat(caseDef.colorFormat));
1460 	const Unique<VkBuffer>			resolveImageOneBuffer		(makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1461 	const UniquePtr<Allocation>		resolveImageOneBufferAlloc	(bindBuffer(vk, device, allocator, *resolveImageOneBuffer, MemoryRequirement::HostVisible));
1462 	const Unique<VkBuffer>			resolveImageTwoBuffer		(makeBuffer(vk, device, resolveBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT));
1463 	const UniquePtr<Allocation>		resolveImageTwoBufferAlloc	(bindBuffer(vk, device, allocator, *resolveImageTwoBuffer, MemoryRequirement::HostVisible));
1464 
1465 	zeroBuffer(vk, device, *resolveImageOneBufferAlloc, resolveBufferSize);
1466 	zeroBuffer(vk, device, *resolveImageTwoBufferAlloc, resolveBufferSize);
1467 
1468 	// Render: repeat the same rendering twice to avoid non-essential API calls and layout transitions (e.g. copy).
1469 	{
1470 		renderAndResolve(context, caseDef, *resolveImageOneBuffer, false);	// Pass 1: render a basic multisampled image
1471 		renderAndResolve(context, caseDef, *resolveImageTwoBuffer, true);	// Pass 2: the same but altered with a compute shader
1472 	}
1473 
1474 	// Verify
1475 	{
1476 		invalidateMappedMemoryRange(vk, device, resolveImageOneBufferAlloc->getMemory(), resolveImageOneBufferAlloc->getOffset(), resolveBufferSize);
1477 		invalidateMappedMemoryRange(vk, device, resolveImageTwoBufferAlloc->getMemory(), resolveImageTwoBufferAlloc->getOffset(), resolveBufferSize);
1478 
1479 		const tcu::PixelBufferAccess		layeredImageOne	(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers, resolveImageOneBufferAlloc->getHostPtr());
1480 		const tcu::ConstPixelBufferAccess	layeredImageTwo	(mapVkFormat(caseDef.colorFormat), caseDef.renderSize.x(), caseDef.renderSize.y(), caseDef.numLayers, resolveImageTwoBufferAlloc->getHostPtr());
1481 
1482 		// Check all layers
1483 		if (!compareImages(context.getTestContext().getLog(), caseDef, layeredImageOne, layeredImageTwo))
1484 			return tcu::TestStatus::fail("Rendered images are not correct");
1485 	}
1486 
1487 	return tcu::TestStatus::pass("OK");
1488 }
1489 
1490 } // StorageImage ns
1491 
getSizeLayerString(const IVec2 & size,const int numLayers)1492 std::string getSizeLayerString (const IVec2& size, const int numLayers)
1493 {
1494 	std::ostringstream str;
1495 	str << size.x() << "x" << size.y() << "_" << numLayers;
1496 	return str.str();
1497 }
1498 
getFormatString(const VkFormat format)1499 std::string getFormatString (const VkFormat format)
1500 {
1501 	std::string name(getFormatName(format));
1502 	return de::toLower(name.substr(10));
1503 }
1504 
addTestCasesWithFunctions(tcu::TestCaseGroup * group,FunctionPrograms1<CaseDef>::Function initPrograms,FunctionInstance1<CaseDef>::Function testFunc)1505 void addTestCasesWithFunctions (tcu::TestCaseGroup*						group,
1506 								FunctionPrograms1<CaseDef>::Function	initPrograms,
1507 								FunctionInstance1<CaseDef>::Function	testFunc)
1508 {
1509 	const IVec2 size[] =
1510 	{
1511 		IVec2(64, 64),
1512 		IVec2(79, 31),
1513 	};
1514 	const int numLayers[] =
1515 	{
1516 		1, 4
1517 	};
1518 	const VkSampleCountFlagBits samples[] =
1519 	{
1520 		VK_SAMPLE_COUNT_2_BIT,
1521 		VK_SAMPLE_COUNT_4_BIT,
1522 		VK_SAMPLE_COUNT_8_BIT,
1523 		VK_SAMPLE_COUNT_16_BIT,
1524 		VK_SAMPLE_COUNT_32_BIT,
1525 		VK_SAMPLE_COUNT_64_BIT,
1526 	};
1527 	const VkFormat format[] =
1528 	{
1529 		VK_FORMAT_R8G8B8A8_UNORM,
1530 		VK_FORMAT_R32_UINT,
1531 		VK_FORMAT_R16G16_SINT,
1532 		VK_FORMAT_R32G32B32A32_SFLOAT,
1533 	};
1534 
1535 	for (int sizeNdx = 0; sizeNdx < DE_LENGTH_OF_ARRAY(size); ++sizeNdx)
1536 	for (int layerNdx = 0; layerNdx < DE_LENGTH_OF_ARRAY(numLayers); ++layerNdx)
1537 	{
1538 		MovePtr<tcu::TestCaseGroup>	sizeLayerGroup(new tcu::TestCaseGroup(group->getTestContext(), getSizeLayerString(size[sizeNdx], numLayers[layerNdx]).c_str(), ""));
1539 		for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(format); ++formatNdx)
1540 		{
1541 			MovePtr<tcu::TestCaseGroup>	formatGroup(new tcu::TestCaseGroup(group->getTestContext(), getFormatString(format[formatNdx]).c_str(), ""));
1542 			for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
1543 			{
1544 				std::ostringstream caseName;
1545 				caseName << "samples_" << getNumSamples(samples[samplesNdx]);
1546 
1547 				const CaseDef caseDef =
1548 				{
1549 					size[sizeNdx],			// IVec2					renderSize;
1550 					numLayers[layerNdx],	// int						numLayers;
1551 					format[formatNdx],		// VkFormat					colorFormat;
1552 					samples[samplesNdx],	// VkSampleCountFlagBits	numSamples;
1553 				};
1554 
1555 				addFunctionCaseWithPrograms(formatGroup.get(), caseName.str(), "", initPrograms, testFunc, caseDef);
1556 			}
1557 			sizeLayerGroup->addChild(formatGroup.release());
1558 		}
1559 		group->addChild(sizeLayerGroup.release());
1560 	}
1561 }
1562 
createSampledImageTestsInGroup(tcu::TestCaseGroup * group)1563 void createSampledImageTestsInGroup (tcu::TestCaseGroup* group)
1564 {
1565 	addTestCasesWithFunctions(group, SampledImage::initPrograms, SampledImage::test);
1566 }
1567 
createStorageImageTestsInGroup(tcu::TestCaseGroup * group)1568 void createStorageImageTestsInGroup (tcu::TestCaseGroup* group)
1569 {
1570 	addTestCasesWithFunctions(group, StorageImage::initPrograms, StorageImage::test);
1571 }
1572 
1573 } // anonymous ns
1574 
1575 //! Render to a multisampled image and sample from it in a fragment shader.
createMultisampleSampledImageTests(tcu::TestContext & testCtx)1576 tcu::TestCaseGroup* createMultisampleSampledImageTests (tcu::TestContext& testCtx)
1577 {
1578 	return createTestGroup(testCtx, "sampled_image", "Multisampled image direct sample access", createSampledImageTestsInGroup);
1579 }
1580 
1581 //! Render to a multisampled image and access it with load/stores in a compute shader.
createMultisampleStorageImageTests(tcu::TestContext & testCtx)1582 tcu::TestCaseGroup* createMultisampleStorageImageTests (tcu::TestContext& testCtx)
1583 {
1584 	return createTestGroup(testCtx, "storage_image", "Multisampled image draw and read/write in compute shader", createStorageImageTestsInGroup);
1585 }
1586 
1587 } // pipeline
1588 } // vkt
1589