1/*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2016 The Khronos Group Inc.
6 * Copyright (c) 2014 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 Scissor multi viewport tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktFragmentOperationsScissorMultiViewportTests.hpp"
26#include "vktTestCaseUtil.hpp"
27#include "vktFragmentOperationsMakeUtil.hpp"
28
29#include "vkDefs.hpp"
30#include "vkRefUtil.hpp"
31#include "vkTypeUtil.hpp"
32#include "vkMemUtil.hpp"
33#include "vkPrograms.hpp"
34#include "vkImageUtil.hpp"
35#include "vkQueryUtil.hpp"
36
37#include "tcuTestLog.hpp"
38#include "tcuVector.hpp"
39#include "tcuImageCompare.hpp"
40#include "tcuTextureUtil.hpp"
41
42#include "deUniquePtr.hpp"
43#include "deMath.h"
44
45namespace vkt
46{
47namespace FragmentOperations
48{
49using namespace vk;
50using de::UniquePtr;
51using de::MovePtr;
52using tcu::Vec4;
53using tcu::Vec2;
54using tcu::IVec2;
55using tcu::IVec4;
56
57namespace
58{
59
60enum Constants
61{
62	MIN_MAX_VIEWPORTS = 16,		//!< Minimum number of viewports for an implementation supporting multiViewport.
63};
64
65template<typename T>
66inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
67{
68	return vec.size() * sizeof(vec[0]);
69}
70
71VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const IVec2& size, VkImageUsageFlags usage)
72{
73	const VkImageCreateInfo imageParams =
74	{
75		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
76		DE_NULL,										// const void*				pNext;
77		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
78		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
79		format,											// VkFormat					format;
80		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
81		1u,												// deUint32					mipLevels;
82		1u,												// deUint32					arrayLayers;
83		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
84		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
85		usage,											// VkImageUsageFlags		usage;
86		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
87		0u,												// deUint32					queueFamilyIndexCount;
88		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
89		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
90	};
91	return imageParams;
92}
93
94//! A single-attachment, single-subpass render pass.
95Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
96								   const VkDevice			device,
97								   const VkFormat			colorFormat)
98{
99	const VkAttachmentDescription colorAttachmentDescription =
100	{
101		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
102		colorFormat,										// VkFormat							format;
103		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
104		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
105		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
106		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
107		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
108		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
109		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
110	};
111
112	const VkAttachmentReference colorAttachmentRef =
113	{
114		0u,													// deUint32			attachment;
115		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
116	};
117
118	const VkSubpassDescription subpassDescription =
119	{
120		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
121		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
122		0u,													// deUint32							inputAttachmentCount;
123		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
124		1u,													// deUint32							colorAttachmentCount;
125		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
126		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
127		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
128		0u,													// deUint32							preserveAttachmentCount;
129		DE_NULL												// const deUint32*					pPreserveAttachments;
130	};
131
132	const VkRenderPassCreateInfo renderPassInfo =
133	{
134		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
135		DE_NULL,											// const void*						pNext;
136		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
137		1u,													// deUint32							attachmentCount;
138		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
139		1u,													// deUint32							subpassCount;
140		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
141		0u,													// deUint32							dependencyCount;
142		DE_NULL												// const VkSubpassDependency*		pDependencies;
143	};
144
145	return createRenderPass(vk, device, &renderPassInfo);
146}
147
148Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
149									   const VkDevice				device,
150									   const VkPipelineLayout		pipelineLayout,
151									   const VkRenderPass			renderPass,
152									   const VkShaderModule			vertexModule,
153									   const VkShaderModule			geometryModule,
154									   const VkShaderModule			fragmentModule,
155									   const IVec2					renderSize,
156									   const int					numViewports,
157									   const std::vector<IVec4>		scissors)
158{
159	const VkVertexInputBindingDescription vertexInputBindingDescription =
160	{
161		0u,								// uint32_t				binding;
162		sizeof(Vec4),					// uint32_t				stride;
163		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
164	};
165
166	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
167	{
168		{
169			0u,									// uint32_t			location;
170			0u,									// uint32_t			binding;
171			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
172			0u,									// uint32_t			offset;
173		},
174	};
175
176	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
177	{
178		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
179		DE_NULL,														// const void*                                 pNext;
180		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
181		1u,																// uint32_t                                    vertexBindingDescriptionCount;
182		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
183		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
184		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
185	};
186
187	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
188	{
189		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
190		DE_NULL,														// const void*                                 pNext;
191		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
192		VK_PRIMITIVE_TOPOLOGY_POINT_LIST,								// VkPrimitiveTopology                         topology;
193		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
194	};
195
196	const VkViewport defaultViewport = makeViewport(
197		0.0f, 0.0f,
198		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
199		0.0f, 1.0f);
200	const std::vector<VkViewport> viewports(numViewports, defaultViewport);
201
202	DE_ASSERT(numViewports == static_cast<int>(scissors.size()));
203
204	std::vector<VkRect2D> rectScissors;
205	rectScissors.reserve(numViewports);
206
207	for (std::vector<IVec4>::const_iterator it = scissors.begin(); it != scissors.end(); ++it)
208	{
209		const VkRect2D rect =
210		{
211			makeOffset2D(it->x(), it->y()),
212			makeExtent2D(static_cast<deUint32>(it->z()), static_cast<deUint32>(it->w())),
213		};
214		rectScissors.push_back(rect);
215	}
216
217	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
218	{
219		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
220		DE_NULL,														// const void*                                 pNext;
221		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
222		static_cast<deUint32>(numViewports),							// uint32_t                                    viewportCount;
223		&viewports[0],													// const VkViewport*                           pViewports;
224		static_cast<deUint32>(numViewports),							// uint32_t                                    scissorCount;
225		&rectScissors[0],												// const VkRect2D*                             pScissors;
226	};
227
228	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
229	{
230		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
231		DE_NULL,														// const void*                              pNext;
232		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
233		VK_FALSE,														// VkBool32                                 depthClampEnable;
234		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
235		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
236		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
237		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
238		VK_FALSE,														// VkBool32									depthBiasEnable;
239		0.0f,															// float									depthBiasConstantFactor;
240		0.0f,															// float									depthBiasClamp;
241		0.0f,															// float									depthBiasSlopeFactor;
242		1.0f,															// float									lineWidth;
243	};
244
245	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
246	{
247		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
248		DE_NULL,														// const void*								pNext;
249		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
250		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
251		VK_FALSE,														// VkBool32									sampleShadingEnable;
252		0.0f,															// float									minSampleShading;
253		DE_NULL,														// const VkSampleMask*						pSampleMask;
254		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
255		VK_FALSE														// VkBool32									alphaToOneEnable;
256	};
257
258	const VkStencilOpState stencilOpState = makeStencilOpState(
259		VK_STENCIL_OP_KEEP,				// stencil fail
260		VK_STENCIL_OP_KEEP,				// depth & stencil pass
261		VK_STENCIL_OP_KEEP,				// depth only fail
262		VK_COMPARE_OP_ALWAYS,			// compare op
263		0u,								// compare mask
264		0u,								// write mask
265		0u);							// reference
266
267	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
268	{
269		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
270		DE_NULL,														// const void*								pNext;
271		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
272		VK_FALSE,														// VkBool32									depthTestEnable;
273		VK_FALSE,														// VkBool32									depthWriteEnable;
274		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
275		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
276		VK_FALSE,														// VkBool32									stencilTestEnable;
277		stencilOpState,													// VkStencilOpState							front;
278		stencilOpState,													// VkStencilOpState							back;
279		0.0f,															// float									minDepthBounds;
280		1.0f,															// float									maxDepthBounds;
281	};
282
283	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
284	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
285	{
286		VK_FALSE,						// VkBool32					blendEnable;
287		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
288		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
289		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
290		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
291		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
292		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
293		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
294	};
295
296	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
297	{
298		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
299		DE_NULL,														// const void*									pNext;
300		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
301		VK_FALSE,														// VkBool32										logicOpEnable;
302		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
303		1u,																// deUint32										attachmentCount;
304		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
305		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
306	};
307
308	const VkPipelineShaderStageCreateInfo pShaderStages[] =
309	{
310		{
311			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
312			DE_NULL,													// const void*							pNext;
313			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
314			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
315			vertexModule,												// VkShaderModule						module;
316			"main",														// const char*							pName;
317			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
318		},
319		{
320			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
321			DE_NULL,													// const void*							pNext;
322			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
323			VK_SHADER_STAGE_GEOMETRY_BIT,								// VkShaderStageFlagBits				stage;
324			geometryModule,												// VkShaderModule						module;
325			"main",														// const char*							pName;
326			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
327		},
328		{
329			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
330			DE_NULL,													// const void*							pNext;
331			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
332			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
333			fragmentModule,												// VkShaderModule						module;
334			"main",														// const char*							pName;
335			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
336		},
337	};
338
339	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
340	{
341		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
342		DE_NULL,											// const void*										pNext;
343		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
344		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
345		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
346		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
347		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
348		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
349		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
350		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
351		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
352		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
353		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
354		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
355		pipelineLayout,										// VkPipelineLayout									layout;
356		renderPass,											// VkRenderPass										renderPass;
357		0u,													// deUint32											subpass;
358		DE_NULL,											// VkPipeline										basePipelineHandle;
359		0,													// deInt32											basePipelineIndex;
360	};
361
362	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
363}
364
365void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
366{
367	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
368	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
369}
370
371void requireFeatureMultiViewport (const InstanceInterface& vki, const VkPhysicalDevice physDevice)
372{
373	const VkPhysicalDeviceFeatures	features	= getPhysicalDeviceFeatures(vki, physDevice);
374	const VkPhysicalDeviceLimits	limits		= getPhysicalDeviceProperties(vki, physDevice).limits;
375
376	if (!features.geometryShader)
377		TCU_THROW(NotSupportedError, "Required feature is not supported: geometryShader");
378
379	if (!features.multiViewport)
380		TCU_THROW(NotSupportedError, "Required feature is not supported: multiViewport");
381
382	if (limits.maxViewports < MIN_MAX_VIEWPORTS)
383		TCU_THROW(NotSupportedError, "Implementation doesn't support minimum required number of viewports");
384}
385
386std::vector<IVec4> generateScissors (const int numScissors, const IVec2& renderSize)
387{
388	// Scissor rects will be arranged in a grid-like fashion.
389
390	const int numCols		= deCeilFloatToInt32(deFloatSqrt(static_cast<float>(numScissors)));
391	const int numRows		= deCeilFloatToInt32(static_cast<float>(numScissors) / static_cast<float>(numCols));
392	const int rectWidth		= renderSize.x() / numCols;
393	const int rectHeight	= renderSize.y() / numRows;
394
395	std::vector<IVec4> scissors;
396	scissors.reserve(numScissors);
397
398	int x = 0;
399	int y = 0;
400
401	for (int scissorNdx = 0; scissorNdx < numScissors; ++scissorNdx)
402	{
403		const bool nextRow = (scissorNdx != 0) && (scissorNdx % numCols == 0);
404		if (nextRow)
405		{
406			x  = 0;
407			y += rectHeight;
408		}
409
410		scissors.push_back(IVec4(x, y, rectWidth, rectHeight));
411
412		x += rectWidth;
413	}
414
415	return scissors;
416}
417
418std::vector<Vec4> generateColors (const int numColors)
419{
420	const Vec4 colors[] =
421	{
422		Vec4(0.18f, 0.42f, 0.17f, 1.0f),
423		Vec4(0.29f, 0.62f, 0.28f, 1.0f),
424		Vec4(0.59f, 0.84f, 0.44f, 1.0f),
425		Vec4(0.96f, 0.95f, 0.72f, 1.0f),
426		Vec4(0.94f, 0.55f, 0.39f, 1.0f),
427		Vec4(0.82f, 0.19f, 0.12f, 1.0f),
428		Vec4(0.46f, 0.15f, 0.26f, 1.0f),
429		Vec4(0.24f, 0.14f, 0.24f, 1.0f),
430		Vec4(0.49f, 0.31f, 0.26f, 1.0f),
431		Vec4(0.78f, 0.52f, 0.33f, 1.0f),
432		Vec4(0.94f, 0.82f, 0.31f, 1.0f),
433		Vec4(0.98f, 0.65f, 0.30f, 1.0f),
434		Vec4(0.22f, 0.65f, 0.53f, 1.0f),
435		Vec4(0.67f, 0.81f, 0.91f, 1.0f),
436		Vec4(0.43f, 0.44f, 0.75f, 1.0f),
437		Vec4(0.26f, 0.24f, 0.48f, 1.0f),
438	};
439
440	DE_ASSERT(numColors <= DE_LENGTH_OF_ARRAY(colors));
441
442	return std::vector<Vec4>(colors, colors + numColors);
443}
444
445//! Renders a colorful grid of rectangles.
446tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat	format,
447										  const IVec2&				renderSize,
448										  const Vec4&				clearColor,
449										  const std::vector<IVec4>&	scissors,
450										  const std::vector<Vec4>&	scissorColors)
451{
452	DE_ASSERT(scissors.size() == scissorColors.size());
453
454	tcu::TextureLevel image(format, renderSize.x(), renderSize.y());
455	tcu::clear(image.getAccess(), clearColor);
456
457	for (std::size_t i = 0; i < scissors.size(); ++i)
458	{
459		tcu::clear(
460			tcu::getSubregion(image.getAccess(), scissors[i].x(), scissors[i].y(), scissors[i].z(), scissors[i].w()),
461			scissorColors[i]);
462	}
463
464	return image;
465}
466
467void initPrograms (SourceCollections& programCollection, const int numViewports)
468{
469	DE_UNREF(numViewports);
470
471	// Vertex 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("vert") << glu::VertexSource(src.str());
485	}
486
487	// Geometry shader
488	{
489		// Each input point generates a fullscreen quad.
490
491		std::ostringstream src;
492		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
493			<< "\n"
494			<< "layout(points) in;\n"
495			<< "layout(triangle_strip, max_vertices=4) out;\n"
496			<< "\n"
497			<< "out gl_PerVertex {\n"
498			<< "    vec4 gl_Position;\n"
499			<< "};\n"
500			<< "\n"
501			<< "layout(location = 0) in  vec4 in_color[];\n"
502			<< "layout(location = 0) out vec4 out_color;\n"
503			<< "\n"
504			<< "void main(void)\n"
505			<< "{\n"
506			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
507			<< "    gl_Position      = vec4(-1.0, -1.0, 0.0, 1.0);\n"
508			<< "    out_color        = in_color[0];\n"
509			<< "    EmitVertex();"
510			<< "\n"
511			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
512			<< "    gl_Position      = vec4(-1.0, 1.0, 0.0, 1.0);\n"
513			<< "    out_color        = in_color[0];\n"
514			<< "    EmitVertex();"
515			<< "\n"
516			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
517			<< "    gl_Position      = vec4(1.0, -1.0, 0.0, 1.0);\n"
518			<< "    out_color        = in_color[0];\n"
519			<< "    EmitVertex();"
520			<< "\n"
521			<< "    gl_ViewportIndex = gl_PrimitiveIDIn;\n"
522			<< "    gl_Position      = vec4(1.0, 1.0, 0.0, 1.0);\n"
523			<< "    out_color        = in_color[0];\n"
524			<< "    EmitVertex();"
525			<< "}\n";
526
527		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
528	}
529
530	// Fragment shader
531	{
532		std::ostringstream src;
533		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
534			<< "\n"
535			<< "layout(location = 0) in  vec4 in_color;\n"
536			<< "layout(location = 0) out vec4 out_color;\n"
537			<< "\n"
538			<< "void main(void)\n"
539			<< "{\n"
540			<< "    out_color = in_color;\n"
541			<< "}\n";
542
543		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
544	}
545}
546
547class ScissorRenderer
548{
549public:
550	ScissorRenderer (Context&					context,
551					 const IVec2&				renderSize,
552					 const int					numViewports,
553					 const std::vector<IVec4>&	scissors,
554					 const VkFormat				colorFormat,
555					 const Vec4&				clearColor,
556					 const std::vector<Vec4>&	vertices)
557		: m_renderSize				(renderSize)
558		, m_colorFormat				(colorFormat)
559		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
560		, m_clearColor				(clearColor)
561		, m_numViewports			(numViewports)
562		, m_vertexBufferSize		(sizeInBytes(vertices))
563	{
564		const DeviceInterface&		vk					= context.getDeviceInterface();
565		const VkDevice				device				= context.getDevice();
566		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
567		Allocator&					allocator			= context.getDefaultAllocator();
568
569		m_colorImage		= makeImage				(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
570		m_colorImageAlloc	= bindImage				(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
571		m_colorAttachment	= makeImageView			(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
572
573		m_vertexBuffer		= makeBuffer			(vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
574		m_vertexBufferAlloc	= bindBuffer			(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
575
576		{
577			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
578			flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
579		}
580
581		m_vertexModule		= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
582		m_geometryModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("geom"), 0u);
583		m_fragmentModule	= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
584		m_renderPass		= makeRenderPass		(vk, device, m_colorFormat);
585		m_framebuffer		= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
586													 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
587		m_pipelineLayout	= makePipelineLayout	(vk, device);
588		m_pipeline			= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_geometryModule, *m_fragmentModule,
589													 m_renderSize, m_numViewports, scissors);
590		m_cmdPool			= makeCommandPool		(vk, device, queueFamilyIndex);
591		m_cmdBuffer			= makeCommandBuffer		(vk, device, *m_cmdPool);
592	}
593
594	void draw (Context& context, const VkBuffer colorBuffer) const
595	{
596		const DeviceInterface&		vk			= context.getDeviceInterface();
597		const VkDevice				device		= context.getDevice();
598		const VkQueue				queue		= context.getUniversalQueue();
599
600		beginCommandBuffer(vk, *m_cmdBuffer);
601
602		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
603		const VkRect2D				renderArea	=
604		{
605			makeOffset2D(0, 0),
606			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
607		};
608		const VkRenderPassBeginInfo renderPassBeginInfo =
609		{
610			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
611			DE_NULL,										// const void*             pNext;
612			*m_renderPass,									// VkRenderPass            renderPass;
613			*m_framebuffer,									// VkFramebuffer           framebuffer;
614			renderArea,										// VkRect2D                renderArea;
615			1u,												// uint32_t                clearValueCount;
616			&clearValue,									// const VkClearValue*     pClearValues;
617		};
618		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
619
620		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
621		{
622			const VkDeviceSize vertexBufferOffset = 0ull;
623			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
624		}
625		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_numViewports), 1u, 0u, 0u);	// one vertex per viewport
626		vk.cmdEndRenderPass(*m_cmdBuffer);
627
628		// Prepare color image for copy
629		{
630			const VkImageMemoryBarrier barriers[] =
631			{
632				{
633					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
634					DE_NULL,													// const void*				pNext;
635					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
636					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
637					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
638					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
639					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
640					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
641					*m_colorImage,												// VkImage					image;
642					m_colorSubresourceRange,									// VkImageSubresourceRange	subresourceRange;
643				},
644			};
645
646			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
647				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
648		}
649		// Color image -> host buffer
650		{
651			const VkBufferImageCopy region =
652			{
653				0ull,																		// VkDeviceSize                bufferOffset;
654				0u,																			// uint32_t                    bufferRowLength;
655				0u,																			// uint32_t                    bufferImageHeight;
656				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),			// VkImageSubresourceLayers    imageSubresource;
657				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
658				makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),						// VkExtent3D                  imageExtent;
659			};
660
661			vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
662		}
663		// Buffer write barrier
664		{
665			const VkBufferMemoryBarrier barriers[] =
666			{
667				{
668					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
669					DE_NULL,										// const void*        pNext;
670					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
671					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
672					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
673					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
674					colorBuffer,									// VkBuffer           buffer;
675					0ull,											// VkDeviceSize       offset;
676					VK_WHOLE_SIZE,									// VkDeviceSize       size;
677				},
678			};
679
680			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
681				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
682		}
683
684		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
685		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
686	}
687
688private:
689	const IVec2						m_renderSize;
690	const VkFormat					m_colorFormat;
691	const VkImageSubresourceRange	m_colorSubresourceRange;
692	const Vec4						m_clearColor;
693	const int						m_numViewports;
694	const VkDeviceSize				m_vertexBufferSize;
695
696	Move<VkImage>					m_colorImage;
697	MovePtr<Allocation>				m_colorImageAlloc;
698	Move<VkImageView>				m_colorAttachment;
699	Move<VkBuffer>					m_vertexBuffer;
700	MovePtr<Allocation>				m_vertexBufferAlloc;
701	Move<VkShaderModule>			m_vertexModule;
702	Move<VkShaderModule>			m_geometryModule;
703	Move<VkShaderModule>			m_fragmentModule;
704	Move<VkRenderPass>				m_renderPass;
705	Move<VkFramebuffer>				m_framebuffer;
706	Move<VkPipelineLayout>			m_pipelineLayout;
707	Move<VkPipeline>				m_pipeline;
708	Move<VkCommandPool>				m_cmdPool;
709	Move<VkCommandBuffer>			m_cmdBuffer;
710
711	// "deleted"
712						ScissorRenderer	(const ScissorRenderer&);
713	ScissorRenderer&	operator=		(const ScissorRenderer&);
714};
715
716tcu::TestStatus test (Context& context, const int numViewports)
717{
718	requireFeatureMultiViewport(context.getInstanceInterface(), context.getPhysicalDevice());
719
720	const DeviceInterface&			vk					= context.getDeviceInterface();
721	const VkDevice					device				= context.getDevice();
722	Allocator&						allocator			= context.getDefaultAllocator();
723
724	const IVec2						renderSize			(128, 128);
725	const VkFormat					colorFormat			= VK_FORMAT_R8G8B8A8_UNORM;
726	const Vec4						clearColor			(0.5f, 0.5f, 0.5f, 1.0f);
727	const std::vector<Vec4>			vertexColors		= generateColors(numViewports);
728	const std::vector<IVec4>		scissors			= generateScissors(numViewports, renderSize);
729
730	const VkDeviceSize				colorBufferSize		= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
731	const Unique<VkBuffer>			colorBuffer			(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
732	const UniquePtr<Allocation>		colorBufferAlloc	(bindBuffer(vk, device, allocator, *colorBuffer, MemoryRequirement::HostVisible));
733
734	zeroBuffer(vk, device, *colorBufferAlloc, colorBufferSize);
735
736	{
737		context.getTestContext().getLog()
738			<< tcu::TestLog::Message << "Rendering a colorful grid of " << numViewports << " rectangle(s)." << tcu::TestLog::EndMessage
739			<< tcu::TestLog::Message << "Not covered area will be filled with a gray color." << tcu::TestLog::EndMessage;
740	}
741
742	// Draw
743	{
744		const ScissorRenderer renderer (context, renderSize, numViewports, scissors, colorFormat, clearColor, vertexColors);
745		renderer.draw(context, *colorBuffer);
746	}
747
748	// Log image
749	{
750		invalidateMappedMemoryRange(vk, device, colorBufferAlloc->getMemory(), 0ull, colorBufferSize);
751
752		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferAlloc->getHostPtr());
753		const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), renderSize, clearColor, scissors, vertexColors);
754
755		// Images should now match.
756		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
757			return tcu::TestStatus::fail("Rendered image is not correct");
758	}
759
760	return tcu::TestStatus::pass("OK");
761}
762
763} // anonymous
764
765tcu::TestCaseGroup* createScissorMultiViewportTests	(tcu::TestContext& testCtx)
766{
767	MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "multi_viewport", ""));
768
769	for (int numViewports = 1; numViewports <= MIN_MAX_VIEWPORTS; ++numViewports)
770		addFunctionCaseWithPrograms(group.get(), "scissor_" + de::toString(numViewports), "", initPrograms, test, numViewports);
771
772	return group.release();
773}
774
775} // FragmentOperations
776} // vkt
777