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