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