1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2018 The Khronos Group Inc.
6  * Copyright (c) 2018 The Android Open Source Project
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Use of gl_ViewportIndex in Vertex and Tessellation Shaders
23  *        (part of VK_EXT_ShaderViewportIndexLayer)
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktDrawShaderViewportIndexTests.hpp"
27 
28 #include "vktDrawBaseClass.hpp"
29 #include "vktTestCaseUtil.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkRef.hpp"
33 #include "vkRefUtil.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkMemUtil.hpp"
36 #include "vkPrograms.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 
42 #include "tcuTestLog.hpp"
43 #include "tcuVector.hpp"
44 #include "tcuImageCompare.hpp"
45 #include "tcuTextureUtil.hpp"
46 
47 #include "deUniquePtr.hpp"
48 #include "deMath.h"
49 
50 #include <vector>
51 
52 namespace vkt
53 {
54 namespace Draw
55 {
56 using namespace vk;
57 using de::UniquePtr;
58 using de::MovePtr;
59 using de::SharedPtr;
60 using tcu::Vec4;
61 using tcu::Vec2;
62 using tcu::UVec2;
63 using tcu::UVec4;
64 
65 namespace
66 {
67 
68 enum Constants
69 {
70 	MIN_MAX_VIEWPORTS = 16,		//!< Minimum number of viewports for an implementation supporting multiViewport.
71 };
72 
73 template<typename T>
sizeInBytes(const std::vector<T> & vec)74 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
75 {
76 	return vec.size() * sizeof(vec[0]);
77 }
78 
makeBufferCreateInfo(const VkDeviceSize bufferSize,const VkBufferUsageFlags usage)79 VkBufferCreateInfo makeBufferCreateInfo (const VkDeviceSize			bufferSize,
80 										 const VkBufferUsageFlags	usage)
81 {
82 	const VkBufferCreateInfo bufferCreateInfo =
83 	{
84 		VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
85 		DE_NULL,								// const void*			pNext;
86 		(VkBufferCreateFlags)0,					// VkBufferCreateFlags	flags;
87 		bufferSize,								// VkDeviceSize			size;
88 		usage,									// VkBufferUsageFlags	usage;
89 		VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
90 		0u,										// deUint32				queueFamilyIndexCount;
91 		DE_NULL,								// const deUint32*		pQueueFamilyIndices;
92 	};
93 	return bufferCreateInfo;
94 }
95 
makePipelineLayout(const DeviceInterface & vk,const VkDevice device)96 Move<VkPipelineLayout> makePipelineLayout (const DeviceInterface&		vk,
97 										   const VkDevice				device)
98 {
99 	const VkPipelineLayoutCreateInfo info =
100 	{
101 		VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
102 		DE_NULL,											// const void*					pNext;
103 		(VkPipelineLayoutCreateFlags)0,						// VkPipelineLayoutCreateFlags	flags;
104 		0u,													// deUint32						setLayoutCount;
105 		DE_NULL,											// const VkDescriptorSetLayout*	pSetLayouts;
106 		0u,													// deUint32						pushConstantRangeCount;
107 		DE_NULL,											// const VkPushConstantRange*	pPushConstantRanges;
108 	};
109 	return createPipelineLayout(vk, device, &info);
110 }
111 
makeImageView(const DeviceInterface & vk,const VkDevice vkDevice,const VkImage image,const VkImageViewType viewType,const VkFormat format,const VkImageSubresourceRange subresourceRange)112 Move<VkImageView> makeImageView (const DeviceInterface&			vk,
113 								 const VkDevice					vkDevice,
114 								 const VkImage					image,
115 								 const VkImageViewType			viewType,
116 								 const VkFormat					format,
117 								 const VkImageSubresourceRange	subresourceRange)
118 {
119 	const VkImageViewCreateInfo imageViewParams =
120 	{
121 		VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,		// VkStructureType			sType;
122 		DE_NULL,										// const void*				pNext;
123 		(VkImageViewCreateFlags)0,						// VkImageViewCreateFlags	flags;
124 		image,											// VkImage					image;
125 		viewType,										// VkImageViewType			viewType;
126 		format,											// VkFormat					format;
127 		makeComponentMappingRGBA(),						// VkComponentMapping		components;
128 		subresourceRange,								// VkImageSubresourceRange	subresourceRange;
129 	};
130 	return createImageView(vk, vkDevice, &imageViewParams);
131 }
132 
makeFramebuffer(const DeviceInterface & vk,const VkDevice device,const VkRenderPass renderPass,const deUint32 attachmentCount,const VkImageView * pAttachments,const deUint32 width,const deUint32 height,const deUint32 layers=1u)133 Move<VkFramebuffer> makeFramebuffer (const DeviceInterface&		vk,
134 									 const VkDevice				device,
135 									 const VkRenderPass			renderPass,
136 									 const deUint32				attachmentCount,
137 									 const VkImageView*			pAttachments,
138 									 const deUint32				width,
139 									 const deUint32				height,
140 									 const deUint32				layers = 1u)
141 {
142 	const VkFramebufferCreateInfo framebufferInfo = {
143 		VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,		// VkStructureType                             sType;
144 		DE_NULL,										// const void*                                 pNext;
145 		(VkFramebufferCreateFlags)0,					// VkFramebufferCreateFlags                    flags;
146 		renderPass,										// VkRenderPass                                renderPass;
147 		attachmentCount,								// uint32_t                                    attachmentCount;
148 		pAttachments,									// const VkImageView*                          pAttachments;
149 		width,											// uint32_t                                    width;
150 		height,											// uint32_t                                    height;
151 		layers,											// uint32_t                                    layers;
152 	};
153 
154 	return createFramebuffer(vk, device, &framebufferInfo);
155 }
156 
bindImage(const DeviceInterface & vk,const VkDevice device,Allocator & allocator,const VkImage image,const MemoryRequirement requirement)157 MovePtr<Allocation> bindImage (const DeviceInterface& vk, const VkDevice device, Allocator& allocator, const VkImage image, const MemoryRequirement requirement)
158 {
159 	MovePtr<Allocation> alloc = allocator.allocate(getImageMemoryRequirements(vk, device, image), requirement);
160 	VK_CHECK(vk.bindImageMemory(device, image, alloc->getMemory(), alloc->getOffset()));
161 	return alloc;
162 }
163 
makeImage(const vk::DeviceInterface & vk,const vk::VkDevice device,const vk::VkImageCreateInfo & createInfo)164 inline vk::Move<vk::VkImage> makeImage (const vk::DeviceInterface& vk, const vk::VkDevice device, const vk::VkImageCreateInfo& createInfo)
165 {
166 	return createImage(vk, device, &createInfo);
167 }
168 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)169 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, VkImageUsageFlags usage)
170 {
171 	const VkImageCreateInfo imageParams =
172 	{
173 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
174 		DE_NULL,										// const void*				pNext;
175 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
176 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
177 		format,											// VkFormat					format;
178 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
179 		1u,												// deUint32					mipLevels;
180 		1u,												// deUint32					arrayLayers;
181 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
182 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
183 		usage,											// VkImageUsageFlags		usage;
184 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
185 		0u,												// deUint32					queueFamilyIndexCount;
186 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
187 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
188 	};
189 	return imageParams;
190 }
191 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule tessellationControlModule,const VkShaderModule tessellationEvaluationModule,const VkShaderModule fragmentModule,const UVec2 renderSize,const int numViewports,const std::vector<UVec4> cells)192 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
193 									   const VkDevice				device,
194 									   const VkPipelineLayout		pipelineLayout,
195 									   const VkRenderPass			renderPass,
196 									   const VkShaderModule			vertexModule,
197 									   const VkShaderModule			tessellationControlModule,
198 									   const VkShaderModule			tessellationEvaluationModule,
199 									   const VkShaderModule			fragmentModule,
200 									   const UVec2					renderSize,
201 									   const int					numViewports,
202 									   const std::vector<UVec4>		cells)
203 {
204 	const VkVertexInputBindingDescription vertexInputBindingDescription =
205 	{
206 		0u,								// uint32_t				binding;
207 		sizeof(PositionColorVertex),	// uint32_t				stride;
208 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
209 	};
210 
211 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
212 	{
213 		{
214 			0u,									// uint32_t			location;
215 			0u,									// uint32_t			binding;
216 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
217 			0u,									// uint32_t			offset;
218 		},
219 		{
220 			1u,									// uint32_t			location;
221 			0u,									// uint32_t			binding;
222 			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
223 			sizeof(Vec4),						// uint32_t			offset;
224 		},
225 	};
226 
227 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
228 	{
229 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
230 		DE_NULL,														// const void*                                 pNext;
231 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
232 		1u,																// uint32_t                                    vertexBindingDescriptionCount;
233 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
234 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
235 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
236 	};
237 
238 	const bool useTessellationShaders = (tessellationControlModule != DE_NULL) && (tessellationEvaluationModule != DE_NULL);
239 
240 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
241 	{
242 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,										// VkStructureType                             sType;
243 		DE_NULL,																							// const void*                                 pNext;
244 		(VkPipelineInputAssemblyStateCreateFlags)0,															// VkPipelineInputAssemblyStateCreateFlags     flags;
245 		useTessellationShaders ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	// VkPrimitiveTopology                         topology;
246 		VK_FALSE,																							// VkBool32                                    primitiveRestartEnable;
247 	};
248 
249 	DE_ASSERT(numViewports == static_cast<int>(cells.size()));
250 
251 	std::vector<VkViewport> viewports;
252 	viewports.reserve(numViewports);
253 
254 	std::vector<VkRect2D> rectScissors;
255 	rectScissors.reserve(numViewports);
256 
257 	for (std::vector<UVec4>::const_iterator it = cells.begin(); it != cells.end(); ++it) {
258 		const VkViewport viewport = makeViewport(float(it->x()), float(it->y()), float(it->z()), float(it->w()), 0.0f, 1.0f);
259 		viewports.push_back(viewport);
260 		const VkRect2D rect = makeRect2D(renderSize);
261 		rectScissors.push_back(rect);
262 	}
263 
264 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
265 	{
266 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
267 		DE_NULL,														// const void*                                 pNext;
268 		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
269 		static_cast<deUint32>(numViewports),							// uint32_t                                    viewportCount;
270 		&viewports[0],													// const VkViewport*                           pViewports;
271 		static_cast<deUint32>(numViewports),							// uint32_t                                    scissorCount;
272 		&rectScissors[0],												// const VkRect2D*                             pScissors;
273 	};
274 
275 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
276 	{
277 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
278 		DE_NULL,														// const void*                              pNext;
279 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
280 		VK_FALSE,														// VkBool32                                 depthClampEnable;
281 		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
282 		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
283 		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
284 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
285 		VK_FALSE,														// VkBool32									depthBiasEnable;
286 		0.0f,															// float									depthBiasConstantFactor;
287 		0.0f,															// float									depthBiasClamp;
288 		0.0f,															// float									depthBiasSlopeFactor;
289 		1.0f,															// float									lineWidth;
290 	};
291 
292 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
293 	{
294 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
295 		DE_NULL,														// const void*								pNext;
296 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
297 		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
298 		VK_FALSE,														// VkBool32									sampleShadingEnable;
299 		0.0f,															// float									minSampleShading;
300 		DE_NULL,														// const VkSampleMask*						pSampleMask;
301 		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
302 		VK_FALSE														// VkBool32									alphaToOneEnable;
303 	};
304 
305 	const VkStencilOpState stencilOpState = makeStencilOpState(
306 		VK_STENCIL_OP_KEEP,				// stencil fail
307 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
308 		VK_STENCIL_OP_KEEP,				// depth only fail
309 		VK_COMPARE_OP_ALWAYS,			// compare op
310 		0u,								// compare mask
311 		0u,								// write mask
312 		0u);							// reference
313 
314 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
315 	{
316 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
317 		DE_NULL,														// const void*								pNext;
318 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
319 		VK_FALSE,														// VkBool32									depthTestEnable;
320 		VK_FALSE,														// VkBool32									depthWriteEnable;
321 		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
322 		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
323 		VK_FALSE,														// VkBool32									stencilTestEnable;
324 		stencilOpState,													// VkStencilOpState							front;
325 		stencilOpState,													// VkStencilOpState							back;
326 		0.0f,															// float									minDepthBounds;
327 		1.0f,															// float									maxDepthBounds;
328 	};
329 
330 	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
331 	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
332 	{
333 		VK_FALSE,						// VkBool32					blendEnable;
334 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
335 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
336 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
337 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
338 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
339 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
340 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
341 	};
342 
343 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
344 	{
345 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
346 		DE_NULL,														// const void*									pNext;
347 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
348 		VK_FALSE,														// VkBool32										logicOpEnable;
349 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
350 		1u,																// deUint32										attachmentCount;
351 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
352 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
353 	};
354 
355 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
356 	{
357 		{
358 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
359 			DE_NULL,													// const void*							pNext;
360 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
361 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
362 			vertexModule,												// VkShaderModule						module;
363 			"main",														// const char*							pName;
364 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
365 		},
366 		{
367 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
368 			DE_NULL,													// const void*							pNext;
369 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
370 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
371 			fragmentModule,												// VkShaderModule						module;
372 			"main",														// const char*							pName;
373 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
374 		},
375 		{
376 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
377 			DE_NULL,													// const void*							pNext;
378 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
379 			VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,					// VkShaderStageFlagBits				stage;
380 			tessellationControlModule,									// VkShaderModule						module;
381 			"main",														// const char*							pName;
382 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
383 		},
384 		{
385 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
386 			DE_NULL,													// const void*							pNext;
387 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
388 			VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,				// VkShaderStageFlagBits				stage;
389 			tessellationEvaluationModule,								// VkShaderModule						module;
390 			"main",														// const char*							pName;
391 			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
392 		},
393 	};
394 
395 	const VkPipelineTessellationStateCreateInfo pipelineTessellationStateInfo =
396 	{
397 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,		// VkStructureType							sType;
398 		DE_NULL,														// const void*								pNext;
399 		(VkPipelineTessellationStateCreateFlags)0,						// VkPipelineTessellationStateCreateFlags	flags;
400 		3,																// uint32_t									patchControlPoints;
401 	};
402 
403 	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
404 	{
405 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,					// VkStructureType									sType;
406 		DE_NULL,															// const void*										pNext;
407 		(VkPipelineCreateFlags)0,											// VkPipelineCreateFlags							flags;
408 		useTessellationShaders ? deUint32(4) : deUint32(2),					// deUint32											stageCount;
409 		pShaderStages,														// const VkPipelineShaderStageCreateInfo*			pStages;
410 		&vertexInputStateInfo,												// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
411 		&pipelineInputAssemblyStateInfo,									// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
412 		useTessellationShaders ? &pipelineTessellationStateInfo : DE_NULL,	// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
413 		&pipelineViewportStateInfo,											// const VkPipelineViewportStateCreateInfo*			pViewportState;
414 		&pipelineRasterizationStateInfo,									// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
415 		&pipelineMultisampleStateInfo,										// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
416 		&pipelineDepthStencilStateInfo,										// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
417 		&pipelineColorBlendStateInfo,										// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
418 		DE_NULL,															// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
419 		pipelineLayout,														// VkPipelineLayout									layout;
420 		renderPass,															// VkRenderPass										renderPass;
421 		0u,																	// deUint32											subpass;
422 		DE_NULL,															// VkPipeline										basePipelineHandle;
423 		0,																	// deInt32											basePipelineIndex;
424 	};
425 
426 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
427 }
428 
generateGrid(const int numCells,const UVec2 & renderSize)429 std::vector<UVec4> generateGrid (const int numCells, const UVec2& renderSize)
430 {
431 	const int numCols		= deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numCells)));
432 	const int numRows		= deCeilFloatToInt32(static_cast<float>(numCells) / static_cast<float>(numCols));
433 	const int rectWidth		= renderSize.x() / numCols;
434 	const int rectHeight	= renderSize.y() / numRows;
435 
436 	std::vector<UVec4> cells;
437 	cells.reserve(numCells);
438 
439 	int x = 0;
440 	int y = 0;
441 
442 	for (int cellNdx = 0; cellNdx < numCells; ++cellNdx)
443 	{
444 		const bool nextRow = (cellNdx != 0) && (cellNdx % numCols == 0);
445 		if (nextRow)
446 		{
447 			x  = 0;
448 			y += rectHeight;
449 		}
450 
451 		cells.push_back(UVec4(x, y, rectWidth, rectHeight));
452 
453 		x += rectWidth;
454 	}
455 
456 	return cells;
457 }
458 
generateColors(const int numColors)459 std::vector<Vec4> generateColors (const int numColors)
460 {
461 	const Vec4 colors[] =
462 	{
463 		Vec4(0.18f, 0.42f, 0.17f, 1.0f),
464 		Vec4(0.29f, 0.62f, 0.28f, 1.0f),
465 		Vec4(0.59f, 0.84f, 0.44f, 1.0f),
466 		Vec4(0.96f, 0.95f, 0.72f, 1.0f),
467 		Vec4(0.94f, 0.55f, 0.39f, 1.0f),
468 		Vec4(0.82f, 0.19f, 0.12f, 1.0f),
469 		Vec4(0.46f, 0.15f, 0.26f, 1.0f),
470 		Vec4(0.24f, 0.14f, 0.24f, 1.0f),
471 		Vec4(0.49f, 0.31f, 0.26f, 1.0f),
472 		Vec4(0.78f, 0.52f, 0.33f, 1.0f),
473 		Vec4(0.94f, 0.82f, 0.31f, 1.0f),
474 		Vec4(0.98f, 0.65f, 0.30f, 1.0f),
475 		Vec4(0.22f, 0.65f, 0.53f, 1.0f),
476 		Vec4(0.67f, 0.81f, 0.91f, 1.0f),
477 		Vec4(0.43f, 0.44f, 0.75f, 1.0f),
478 		Vec4(0.26f, 0.24f, 0.48f, 1.0f),
479 	};
480 
481 	DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
482 
483 	return std::vector<Vec4>(colors, colors + numColors);
484 }
485 
486 //! Renders a colorful grid of rectangles.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const Vec4 & clearColor,const std::vector<UVec4> & cells,const std::vector<Vec4> & cellColors)487 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat	format,
488 										  const UVec2&				renderSize,
489 										  const Vec4&				clearColor,
490 										  const std::vector<UVec4>&	cells,
491 										  const std::vector<Vec4>&	cellColors)
492 {
493 	DE_ASSERT(cells.size() == cellColors.size());
494 
495 	tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
496 	tcu::clear(image.getAccess(), clearColor);
497 
498 	for (std::size_t i = 0; i < cells.size(); ++i)
499 	{
500 		const UVec4& cell = cells[i];
501 		tcu::clear(
502 			tcu::getSubregion(image.getAccess(), cell.x(), cell.y(), cell.z(), cell.w()),
503 			cellColors[i]);
504 	}
505 
506 	return image;
507 }
508 
initVertexTestPrograms(SourceCollections & programCollection,const int numViewports)509 void initVertexTestPrograms (SourceCollections& programCollection, const int numViewports)
510 {
511 	DE_UNREF(numViewports);
512 
513 	// Vertex shader
514 	{
515 		std::ostringstream src;
516 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
517 			<< "#extension GL_ARB_shader_viewport_layer_array : require\n"
518 			<< "\n"
519 			<< "layout(location = 0) in  vec4 in_position;\n"
520 			<< "layout(location = 1) in  vec4 in_color;\n"
521 			<< "layout(location = 0) out vec4 out_color;\n"
522 			<< "\n"
523 			<< "void main(void)\n"
524 			<< "{\n"
525 			<< "    gl_ViewportIndex = gl_VertexIndex / 6;\n"
526 			<< "    gl_Position = in_position;\n"
527 			<< "    out_color = in_color;\n"
528 			<< "}\n";
529 
530 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
531 	}
532 
533 	// Fragment shader
534 	{
535 		std::ostringstream src;
536 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
537 			<< "\n"
538 			<< "layout(location = 0) in  vec4 in_color;\n"
539 			<< "layout(location = 0) out vec4 out_color;\n"
540 			<< "\n"
541 			<< "void main(void)\n"
542 			<< "{\n"
543 			<< "    out_color = in_color;\n"
544 			<< "}\n";
545 
546 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
547 	}
548 }
549 
initTessellationTestPrograms(SourceCollections & programCollection,const int numViewports)550 void initTessellationTestPrograms (SourceCollections& programCollection, const int numViewports)
551 {
552 	DE_UNREF(numViewports);
553 
554 	// Vertex shader
555 	{
556 		std::ostringstream src;
557 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
558 			<< "\n"
559 			<< "layout(location = 0) in  vec4 in_position;\n"
560 			<< "layout(location = 1) in  vec4 in_color;\n"
561 			<< "layout(location = 0) out vec4 out_color;\n"
562 			<< "\n"
563 			<< "void main(void)\n"
564 			<< "{\n"
565 			<< "    gl_Position = in_position;\n"
566 			<< "    out_color = in_color;\n"
567 			<< "}\n";
568 
569 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
570 	}
571 
572 	// Tessellation control shader
573 	{
574 		std::ostringstream src;
575 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
576 			<< "\n"
577 			<< "layout(vertices = 3) out;\n"
578 			<< "\n"
579 			<< "layout(location = 0) in  vec4 in_color[];\n"
580 			<< "layout(location = 0) out vec4 out_color[];\n"
581 			<< "\n"
582 			<< "void main(void)\n"
583 			<< "{\n"
584 			<< "    if (gl_InvocationID == 0) {\n"
585 			<< "        gl_TessLevelInner[0] = 1.0;\n"
586 			<< "        gl_TessLevelInner[1] = 1.0;\n"
587 			<< "        gl_TessLevelOuter[0] = 1.0;\n"
588 			<< "        gl_TessLevelOuter[1] = 1.0;\n"
589 			<< "        gl_TessLevelOuter[2] = 1.0;\n"
590 			<< "        gl_TessLevelOuter[3] = 1.0;\n"
591 			<< "    }\n"
592 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
593 			<< "    out_color[gl_InvocationID] = in_color[gl_InvocationID];\n"
594 			<< "}\n";
595 
596 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
597 	}
598 
599 	// Tessellation evaluation shader
600 	{
601 		std::ostringstream src;
602 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
603 			<< "#extension GL_ARB_shader_viewport_layer_array : require\n"
604 			<< "\n"
605 			<< "layout(triangles, equal_spacing, cw) in;\n"
606 			<< "\n"
607 			<< "layout(location = 0) in  vec4 in_color[];\n"
608 			<< "layout(location = 0) out vec4 out_color;\n"
609 			<< "\n"
610 			<< "void main(void)\n"
611 			<< "{\n"
612 			<< "    gl_ViewportIndex = gl_PrimitiveID / 2;\n"
613 			<< "    gl_Position = gl_in[0].gl_Position * gl_TessCoord.x +\n"
614 			<< "                  gl_in[1].gl_Position * gl_TessCoord.y +\n"
615 			<< "                  gl_in[2].gl_Position * gl_TessCoord.z;\n"
616 			<< "\n"
617 			<< "    out_color = in_color[0] * gl_TessCoord.x +\n"
618 			<< "                in_color[1] * gl_TessCoord.y +\n"
619 			<< "                in_color[2] * gl_TessCoord.z;\n"
620 			<< "}\n";
621 
622 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
623 	}
624 
625 	// Fragment shader
626 	{
627 		std::ostringstream src;
628 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
629 			<< "\n"
630 			<< "layout(location = 0) in  vec4 in_color;\n"
631 			<< "layout(location = 0) out vec4 out_color;\n"
632 			<< "\n"
633 			<< "void main(void)\n"
634 			<< "{\n"
635 			<< "    out_color = in_color;\n"
636 			<< "}\n";
637 
638 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
639 	}
640 }
641 
generateVertices(const std::vector<Vec4> & colors)642 std::vector<PositionColorVertex> generateVertices (const std::vector<Vec4>& colors)
643 {
644 	// Two triangles for each color (viewport).
645 	std::size_t total = colors.size() * 6;
646 
647 	std::vector<PositionColorVertex> result;
648 	result.reserve(total);
649 
650 	for (std::size_t i = 0; i < total; ++i)
651 	{
652 		Vec4 pos;
653 		pos.z() = 0.0;
654 		pos.w() = 1.0;
655 
656 		switch (i % 6) {
657 		case 0: pos.xy() = Vec2(-1.0,  1.0); break;
658 		case 1: pos.xy() = Vec2( 1.0,  1.0); break;
659 		case 2: pos.xy() = Vec2(-1.0, -1.0); break;
660 		case 3: pos.xy() = Vec2( 1.0, -1.0); break;
661 		case 4: pos.xy() = Vec2( 1.0,  1.0); break;
662 		case 5: pos.xy() = Vec2(-1.0, -1.0); break;
663 		}
664 
665 		result.push_back(PositionColorVertex(pos, colors[i/6]));
666 	}
667 
668 	return result;
669 }
670 
671 // Renderer generates two triangles per viewport, each pair using a different color. The
672 // numViewports are positioned to form a grid.
673 class Renderer
674 {
675 public:
676 	enum Shader {
677 		VERTEX,
678 		TESSELLATION,
679 	};
680 
Renderer(Context & context,const UVec2 & renderSize,const int numViewports,const std::vector<UVec4> & cells,const VkFormat colorFormat,const Vec4 & clearColor,const std::vector<Vec4> & colors,const Shader shader)681 	Renderer (Context&						context,
682 			  const UVec2&					renderSize,
683 			  const int						numViewports,
684 			  const std::vector<UVec4>&		cells,
685 			  const VkFormat				colorFormat,
686 			  const Vec4&					clearColor,
687 			  const std::vector<Vec4>&		colors,
688 			  const Shader					shader)
689 		: m_renderSize				(renderSize)
690 		, m_colorFormat				(colorFormat)
691 		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
692 		, m_clearColor				(clearColor)
693 		, m_numViewports			(numViewports)
694 		, m_vertices				(generateVertices(colors))
695 	{
696 		const DeviceInterface&		vk					= context.getDeviceInterface();
697 		const VkDevice				device				= context.getDevice();
698 		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
699 		Allocator&					allocator			= context.getDefaultAllocator();
700 		const VkDeviceSize			vertexBufferSize    = sizeInBytes(m_vertices);
701 
702 		m_colorImage		= makeImage					(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
703 		m_colorImageAlloc	= bindImage					(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
704 		m_colorAttachment	= makeImageView				(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
705 
706 		m_vertexBuffer		= Buffer::createAndAlloc	(vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible);
707 
708 		{
709 			deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), &m_vertices[0], static_cast<std::size_t>(vertexBufferSize));
710 			flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
711 		}
712 
713 		if (shader == TESSELLATION)
714 		{
715 			m_tessellationControlModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("tesc"), 0u);
716 			m_tessellationEvaluationModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("tese"), 0u);
717 		}
718 
719 		m_vertexModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
720 		m_fragmentModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
721 		m_renderPass		= makeRenderPass		(vk, device, m_colorFormat);
722 		m_framebuffer		= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
723 													 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
724 		m_pipelineLayout	= makePipelineLayout	(vk, device);
725 		m_pipeline			= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_tessellationControlModule,
726 													 *m_tessellationEvaluationModule, *m_fragmentModule, m_renderSize, m_numViewports, cells);
727 		m_cmdPool			= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
728 		m_cmdBuffer			= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
729 	}
730 
draw(Context & context,const VkBuffer colorBuffer) const731 	void draw (Context& context, const VkBuffer colorBuffer) const
732 	{
733 		const DeviceInterface&		vk			= context.getDeviceInterface();
734 		const VkDevice				device		= context.getDevice();
735 		const VkQueue				queue		= context.getUniversalQueue();
736 
737 		beginCommandBuffer(vk, *m_cmdBuffer);
738 
739 		beginRenderPass(vk, *m_cmdBuffer, *m_renderPass, *m_framebuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()), m_clearColor);
740 
741 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
742 		{
743 			const VkBuffer vertexBuffer = m_vertexBuffer->object();
744 			const VkDeviceSize vertexBufferOffset = 0ull;
745 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
746 		}
747 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports * 6), 1u, 0u, 0u);	// two triangles per viewport
748 		endRenderPass(vk, *m_cmdBuffer);
749 
750 		copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, colorBuffer, tcu::IVec2(m_renderSize.x(), m_renderSize.y()));
751 
752 		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
753 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
754 	}
755 
756 private:
757 	const UVec2								m_renderSize;
758 	const VkFormat							m_colorFormat;
759 	const VkImageSubresourceRange			m_colorSubresourceRange;
760 	const Vec4								m_clearColor;
761 	const int								m_numViewports;
762 	const std::vector<PositionColorVertex>	m_vertices;
763 
764 	Move<VkImage>							m_colorImage;
765 	MovePtr<Allocation>						m_colorImageAlloc;
766 	Move<VkImageView>						m_colorAttachment;
767 	SharedPtr<Buffer>						m_vertexBuffer;
768 	Move<VkShaderModule>					m_vertexModule;
769 	Move<VkShaderModule>					m_tessellationControlModule;
770 	Move<VkShaderModule>					m_tessellationEvaluationModule;
771 	Move<VkShaderModule>					m_fragmentModule;
772 	Move<VkRenderPass>						m_renderPass;
773 	Move<VkFramebuffer>						m_framebuffer;
774 	Move<VkPipelineLayout>					m_pipelineLayout;
775 	Move<VkPipeline>						m_pipeline;
776 	Move<VkCommandPool>						m_cmdPool;
777 	Move<VkCommandBuffer>					m_cmdBuffer;
778 
779 	// "deleted"
780 				Renderer	(const Renderer&);
781 	Renderer&	operator=	(const Renderer&);
782 };
783 
requireShaderViewportIndexLayer(const Context & context)784 void requireShaderViewportIndexLayer (const Context& context)
785 {
786 	const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
787 	const VkPhysicalDeviceLimits	limits		= getPhysicalDeviceProperties(context.getInstanceInterface(), context.getPhysicalDevice()).limits;
788 
789 	if (!features.multiViewport)
790 		TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
791 
792 	if (limits.maxViewports < MIN_MAX_VIEWPORTS)
793 		TCU_FAIL("multiViewport supported but maxViewports is less than the minimum required");
794 
795 	const std::vector<std::string>&		extensions	= context.getDeviceExtensions();
796 	if (!isDeviceExtensionSupported(context.getUsedApiVersion(), extensions, "VK_EXT_shader_viewport_index_layer"))
797 		TCU_THROW(NotSupportedError, "Extension VK_EXT_shader_viewport_index_layer not supported");
798 
799 }
800 
testVertexShader(Context & context,const int numViewports)801 tcu::TestStatus testVertexShader (Context& context, const int numViewports)
802 {
803 	requireShaderViewportIndexLayer(context);
804 
805 	const DeviceInterface&			vk					= context.getDeviceInterface();
806 	const VkDevice					device				= context.getDevice();
807 	Allocator&						allocator			= context.getDefaultAllocator();
808 
809 	const UVec2						renderSize			(128, 128);
810 	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
811 	const Vec4						clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
812 	const std::vector<Vec4>			colors				= generateColors(numViewports);
813 	const std::vector<UVec4>		cells				= generateGrid(numViewports, renderSize);
814 
815 	const VkDeviceSize				colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
816 
817 	const SharedPtr<Buffer>			colorBuffer			= Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
818 
819 	// Zero buffer.
820 	{
821 		const Allocation alloc = colorBuffer->getBoundMemory();
822 		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
823 		flushAlloc(vk, device, alloc);
824 	}
825 
826 	{
827 		context.getTestContext().getLog()
828 			<< tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
829 			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
830 	}
831 
832 	// Draw
833 	{
834 		const Renderer renderer (context, renderSize, numViewports, cells, colorFormat, clearColor, colors, Renderer::VERTEX);
835 		renderer.draw(context, colorBuffer->object());
836 	}
837 
838 	// Log image
839 	{
840 		const Allocation alloc = colorBuffer->getBoundMemory();
841 		invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0ull, colorBufferSize);
842 
843 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
844 		const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
845 
846 		// Images should now match.
847 		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
848 			TCU_FAIL("Rendered image is not correct");
849 	}
850 
851 	return tcu::TestStatus::pass("OK");
852 }
853 
testTessellationShader(Context & context,const int numViewports)854 tcu::TestStatus testTessellationShader (Context& context, const int numViewports)
855 {
856 	requireShaderViewportIndexLayer(context);
857 
858 	const VkPhysicalDeviceFeatures&		features	= context.getDeviceFeatures();
859 	if (!features.tessellationShader)
860 		TCU_THROW(NotSupportedError, "Required feature is not supported: tessellationShader");
861 
862 	const DeviceInterface&			vk					= context.getDeviceInterface();
863 	const VkDevice					device				= context.getDevice();
864 	Allocator&						allocator			= context.getDefaultAllocator();
865 
866 	const UVec2						renderSize			(128, 128);
867 	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
868 	const Vec4						clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
869 	const std::vector<Vec4>			colors				= generateColors(numViewports);
870 	const std::vector<UVec4>		cells				= generateGrid(numViewports, renderSize);
871 
872 	const VkDeviceSize				colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
873 
874 	const SharedPtr<Buffer>			colorBuffer			= Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
875 
876 	// Zero buffer.
877 	{
878 		const Allocation alloc = colorBuffer->getBoundMemory();
879 		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
880 		flushAlloc(vk, device, alloc);
881 	}
882 
883 	{
884 		context.getTestContext().getLog()
885 			<< tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
886 			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
887 	}
888 
889 	// Draw
890 	{
891 		const Renderer renderer (context, renderSize, numViewports, cells, colorFormat, clearColor, colors, Renderer::TESSELLATION);
892 		renderer.draw(context, colorBuffer->object());
893 	}
894 
895 	// Log image
896 	{
897 		const Allocation alloc = colorBuffer->getBoundMemory();
898 		invalidateMappedMemoryRange(vk, device, alloc.getMemory(), 0ull, colorBufferSize);
899 
900 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, alloc.getHostPtr());
901 		const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, cells, colors);
902 
903 		// Images should now match.
904 		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
905 			TCU_FAIL("Rendered image is not correct");
906 	}
907 
908 	return tcu::TestStatus::pass("OK");
909 }
910 
911 
912 } // anonymous
913 
createShaderViewportIndexTests(tcu::TestContext & testCtx)914 tcu::TestCaseGroup* createShaderViewportIndexTests	(tcu::TestContext& testCtx)
915 {
916 	MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_viewport_index", ""));
917 
918 	for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
919 		addFunctionCaseWithPrograms(group.get(), "vertex_shader_" + de::toString(numViewports), "", initVertexTestPrograms, testVertexShader, numViewports);
920 
921 	for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
922 		addFunctionCaseWithPrograms(group.get(), "tessellation_shader_" + de::toString(numViewports), "", initTessellationTestPrograms, testTessellationShader, numViewports);
923 
924 	return group.release();
925 }
926 
927 } // Draw
928 } // vkt
929