• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 TestParams
77 {
78 	int						numViewports;
79 	bool					writeFromVertex;
80 	const SharedGroupParams	groupParams;
81 	bool					useTessellationShader;
82 };
83 
84 template<typename T>
sizeInBytes(const std::vector<T> & vec)85 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
86 {
87 	return vec.size() * sizeof(vec[0]);
88 }
89 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)90 VkImageCreateInfo 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 
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)113 Move<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 
generateGrid(const int numCells,const UVec2 & renderSize)368 std::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 
generateColors(const int numColors)398 std::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.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const Vec4 & clearColor,const std::vector<UVec4> & cells,const std::vector<Vec4> & cellColors)426 tcu::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 
initVertexTestPrograms(SourceCollections & programCollection,const TestParams)448 void 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 
initFragmentTestPrograms(SourceCollections & programCollection,const TestParams testParams)488 void 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 
initTessellationTestPrograms(SourceCollections & programCollection,const TestParams)532 void 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 
generateVertices(const std::vector<Vec4> & colors)624 std::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.
655 class Renderer
656 {
657 public:
658 	enum Shader {
659 		VERTEX,
660 		TESSELLATION,
661 		FRAGMENT,
662 	};
663 
Renderer(Context & context,const UVec2 & renderSize,const TestParams & testParams,const std::vector<UVec4> & cells,const VkFormat colorFormat,const Vec4 & clearColor,const std::vector<Vec4> & colors,const Shader shader)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 
draw(Context & context,const VkBuffer colorBuffer)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 
810 protected:
811 
812 #ifndef CTS_USES_VULKANSC
beginSecondaryCmdBuffer(Context & context,VkCommandBuffer cmdBuffer,VkRenderingFlagsKHR renderingFlags=0u) const813 	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 
preRenderCommands(Context & context,VkCommandBuffer cmdBuffer) const846 	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 
postRenderCommands(Context & context,VkBuffer colorBuffer) const856 	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 
drawCommands(Context & context,VkCommandBuffer cmdBuffer)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 
906 private:
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 
testVertexFragmentShader(Context & context,const TestParams & testParams,Renderer::Shader shader)942 tcu::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 
testVertexShader(Context & context,const TestParams testParams)993 tcu::TestStatus testVertexShader (Context& context, const TestParams testParams)
994 {
995 	return testVertexFragmentShader(context, testParams, Renderer::VERTEX);
996 }
997 
testFragmentShader(Context & context,const TestParams testParams)998 tcu::TestStatus testFragmentShader (Context& context, const TestParams testParams)
999 {
1000 	return testVertexFragmentShader(context, testParams, Renderer::FRAGMENT);
1001 }
1002 
testTessellationShader(Context & context,const TestParams testParams)1003 tcu::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 
checkSupport(Context & context,TestParams params)1054 void 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 
createShaderViewportIndexTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1071 tcu::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