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 tests
23 *//*--------------------------------------------------------------------*/
24
25#include "vktFragmentOperationsScissorTests.hpp"
26#include "vktFragmentOperationsScissorMultiViewportTests.hpp"
27#include "vktTestCaseUtil.hpp"
28#include "vktTestGroupUtil.hpp"
29#include "vktFragmentOperationsMakeUtil.hpp"
30
31#include "vkDefs.hpp"
32#include "vkRefUtil.hpp"
33#include "vkTypeUtil.hpp"
34#include "vkMemUtil.hpp"
35#include "vkPrograms.hpp"
36#include "vkImageUtil.hpp"
37
38#include "tcuTestLog.hpp"
39#include "tcuVector.hpp"
40#include "tcuImageCompare.hpp"
41
42#include "deUniquePtr.hpp"
43#include "deRandom.hpp"
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
60//! What primitives will be drawn by the test case.
61enum TestPrimitive
62{
63	TEST_PRIMITIVE_POINTS,			//!< Many points.
64	TEST_PRIMITIVE_LINES,			//!< Many short lines.
65	TEST_PRIMITIVE_TRIANGLES,		//!< Many small triangles.
66	TEST_PRIMITIVE_BIG_LINE,		//!< One line crossing the whole render area.
67	TEST_PRIMITIVE_BIG_TRIANGLE,	//!< One triangle covering the whole render area.
68};
69
70struct VertexData
71{
72	Vec4	position;
73	Vec4	color;
74};
75
76//! Parameters used by the test case.
77struct CaseDef
78{
79	Vec4			renderArea;		//!< (ox, oy, w, h), where origin (0,0) is the top-left corner of the viewport. Width and height are in range [0, 1].
80	Vec4			scissorArea;	//!< scissored area (ox, oy, w, h)
81	TestPrimitive	primitive;
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 IVec2& 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
113//! A single-attachment, single-subpass render pass.
114Move<VkRenderPass> makeRenderPass (const DeviceInterface&	vk,
115								   const VkDevice			device,
116								   const VkFormat			colorFormat)
117{
118	const VkAttachmentDescription colorAttachmentDescription =
119	{
120		(VkAttachmentDescriptionFlags)0,					// VkAttachmentDescriptionFlags		flags;
121		colorFormat,										// VkFormat							format;
122		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
123		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
124		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
125		VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
126		VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
127		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout					initialLayout;
128		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,			// VkImageLayout					finalLayout;
129	};
130
131	const VkAttachmentReference colorAttachmentRef =
132	{
133		0u,													// deUint32			attachment;
134		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL			// VkImageLayout	layout;
135	};
136
137	const VkSubpassDescription subpassDescription =
138	{
139		(VkSubpassDescriptionFlags)0,						// VkSubpassDescriptionFlags		flags;
140		VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
141		0u,													// deUint32							inputAttachmentCount;
142		DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
143		1u,													// deUint32							colorAttachmentCount;
144		&colorAttachmentRef,								// const VkAttachmentReference*		pColorAttachments;
145		DE_NULL,											// const VkAttachmentReference*		pResolveAttachments;
146		DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
147		0u,													// deUint32							preserveAttachmentCount;
148		DE_NULL												// const deUint32*					pPreserveAttachments;
149	};
150
151	const VkRenderPassCreateInfo renderPassInfo =
152	{
153		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
154		DE_NULL,											// const void*						pNext;
155		(VkRenderPassCreateFlags)0,							// VkRenderPassCreateFlags			flags;
156		1u,													// deUint32							attachmentCount;
157		&colorAttachmentDescription,						// const VkAttachmentDescription*	pAttachments;
158		1u,													// deUint32							subpassCount;
159		&subpassDescription,								// const VkSubpassDescription*		pSubpasses;
160		0u,													// deUint32							dependencyCount;
161		DE_NULL												// const VkSubpassDependency*		pDependencies;
162	};
163
164	return createRenderPass(vk, device, &renderPassInfo);
165}
166
167Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&		vk,
168									   const VkDevice				device,
169									   const VkPipelineLayout		pipelineLayout,
170									   const VkRenderPass			renderPass,
171									   const VkShaderModule			vertexModule,
172									   const VkShaderModule			fragmentModule,
173									   const IVec2					renderSize,
174									   const IVec4					scissorArea,	//!< (ox, oy, w, h)
175									   const VkPrimitiveTopology	topology)
176{
177	const VkVertexInputBindingDescription vertexInputBindingDescription =
178	{
179		0u,								// uint32_t				binding;
180		sizeof(VertexData),				// uint32_t				stride;
181		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
182	};
183
184	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
185	{
186		{
187			0u,									// uint32_t			location;
188			0u,									// uint32_t			binding;
189			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
190			0u,									// uint32_t			offset;
191		},
192		{
193			1u,									// uint32_t			location;
194			0u,									// uint32_t			binding;
195			VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat			format;
196			sizeof(Vec4),						// uint32_t			offset;
197		},
198	};
199
200	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
201	{
202		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType                             sType;
203		DE_NULL,														// const void*                                 pNext;
204		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags       flags;
205		1u,																// uint32_t                                    vertexBindingDescriptionCount;
206		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
207		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t                                    vertexAttributeDescriptionCount;
208		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
209	};
210
211	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
212	{
213		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType                             sType;
214		DE_NULL,														// const void*                                 pNext;
215		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags     flags;
216		topology,														// VkPrimitiveTopology                         topology;
217		VK_FALSE,														// VkBool32                                    primitiveRestartEnable;
218	};
219
220	const VkViewport viewport = makeViewport(
221		0.0f, 0.0f,
222		static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()),
223		0.0f, 1.0f);
224
225	const VkRect2D scissor = {
226		makeOffset2D(scissorArea.x(), scissorArea.y()),
227		makeExtent2D(static_cast<deUint32>(scissorArea.z()), static_cast<deUint32>(scissorArea.w())),
228	};
229
230	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
231	{
232		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,			// VkStructureType                             sType;
233		DE_NULL,														// const void*                                 pNext;
234		(VkPipelineViewportStateCreateFlags)0,							// VkPipelineViewportStateCreateFlags          flags;
235		1u,																// uint32_t                                    viewportCount;
236		&viewport,														// const VkViewport*                           pViewports;
237		1u,																// uint32_t                                    scissorCount;
238		&scissor,														// const VkRect2D*                             pScissors;
239	};
240
241	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
242	{
243		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType                          sType;
244		DE_NULL,														// const void*                              pNext;
245		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags  flags;
246		VK_FALSE,														// VkBool32                                 depthClampEnable;
247		VK_FALSE,														// VkBool32                                 rasterizerDiscardEnable;
248		VK_POLYGON_MODE_FILL,											// VkPolygonMode							polygonMode;
249		VK_CULL_MODE_NONE,												// VkCullModeFlags							cullMode;
250		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
251		VK_FALSE,														// VkBool32									depthBiasEnable;
252		0.0f,															// float									depthBiasConstantFactor;
253		0.0f,															// float									depthBiasClamp;
254		0.0f,															// float									depthBiasSlopeFactor;
255		1.0f,															// float									lineWidth;
256	};
257
258	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
259	{
260		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
261		DE_NULL,														// const void*								pNext;
262		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags	flags;
263		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits					rasterizationSamples;
264		VK_FALSE,														// VkBool32									sampleShadingEnable;
265		0.0f,															// float									minSampleShading;
266		DE_NULL,														// const VkSampleMask*						pSampleMask;
267		VK_FALSE,														// VkBool32									alphaToCoverageEnable;
268		VK_FALSE														// VkBool32									alphaToOneEnable;
269	};
270
271	const VkStencilOpState stencilOpState = makeStencilOpState(
272		VK_STENCIL_OP_KEEP,				// stencil fail
273		VK_STENCIL_OP_KEEP,				// depth & stencil pass
274		VK_STENCIL_OP_KEEP,				// depth only fail
275		VK_COMPARE_OP_ALWAYS,			// compare op
276		0u,								// compare mask
277		0u,								// write mask
278		0u);							// reference
279
280	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
281	{
282		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType							sType;
283		DE_NULL,														// const void*								pNext;
284		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags	flags;
285		VK_FALSE,														// VkBool32									depthTestEnable;
286		VK_FALSE,														// VkBool32									depthWriteEnable;
287		VK_COMPARE_OP_LESS,												// VkCompareOp								depthCompareOp;
288		VK_FALSE,														// VkBool32									depthBoundsTestEnable;
289		VK_FALSE,														// VkBool32									stencilTestEnable;
290		stencilOpState,													// VkStencilOpState							front;
291		stencilOpState,													// VkStencilOpState							back;
292		0.0f,															// float									minDepthBounds;
293		1.0f,															// float									maxDepthBounds;
294	};
295
296	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
297	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
298	{
299		VK_FALSE,						// VkBool32					blendEnable;
300		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
301		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
302		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
303		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
304		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
305		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
306		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
307	};
308
309	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
310	{
311		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
312		DE_NULL,														// const void*									pNext;
313		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
314		VK_FALSE,														// VkBool32										logicOpEnable;
315		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
316		1u,																// deUint32										attachmentCount;
317		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
318		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
319	};
320
321	const VkPipelineShaderStageCreateInfo pShaderStages[] =
322	{
323		{
324			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
325			DE_NULL,													// const void*							pNext;
326			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
327			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits				stage;
328			vertexModule,												// VkShaderModule						module;
329			"main",														// const char*							pName;
330			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
331		},
332		{
333			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType						sType;
334			DE_NULL,													// const void*							pNext;
335			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags		flags;
336			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits				stage;
337			fragmentModule,												// VkShaderModule						module;
338			"main",														// const char*							pName;
339			DE_NULL,													// const VkSpecializationInfo*			pSpecializationInfo;
340		}
341	};
342
343	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
344	{
345		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	// VkStructureType									sType;
346		DE_NULL,											// const void*										pNext;
347		(VkPipelineCreateFlags)0,							// VkPipelineCreateFlags							flags;
348		DE_LENGTH_OF_ARRAY(pShaderStages),					// deUint32											stageCount;
349		pShaderStages,										// const VkPipelineShaderStageCreateInfo*			pStages;
350		&vertexInputStateInfo,								// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
351		&pipelineInputAssemblyStateInfo,					// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
352		DE_NULL,											// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
353		&pipelineViewportStateInfo,							// const VkPipelineViewportStateCreateInfo*			pViewportState;
354		&pipelineRasterizationStateInfo,					// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
355		&pipelineMultisampleStateInfo,						// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
356		&pipelineDepthStencilStateInfo,						// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
357		&pipelineColorBlendStateInfo,						// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
358		DE_NULL,											// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
359		pipelineLayout,										// VkPipelineLayout									layout;
360		renderPass,											// VkRenderPass										renderPass;
361		0u,													// deUint32											subpass;
362		DE_NULL,											// VkPipeline										basePipelineHandle;
363		0,													// deInt32											basePipelineIndex;
364	};
365
366	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
367}
368
369inline VertexData makeVertex (const float x, const float y, const Vec4& color)
370{
371	const VertexData data = { Vec4(x, y, 0.0f, 1.0f), color };
372	return data;
373}
374
375std::vector<VertexData> genVertices (const TestPrimitive primitive, const Vec4& renderArea, const Vec4& primitiveColor)
376{
377	std::vector<VertexData> vertices;
378	de::Random				rng			(1234);
379
380	const float	x0		= 2.0f * renderArea.x() - 1.0f;
381	const float y0		= 2.0f * renderArea.y() - 1.0f;
382	const float	rx		= 2.0f * renderArea.z();
383	const float	ry		= 2.0f * renderArea.w();
384	const float	size	= 0.2f;
385
386	switch (primitive)
387	{
388		case TEST_PRIMITIVE_POINTS:
389			for (int i = 0; i < 50; ++i)
390			{
391				const float x = x0 + rng.getFloat(0.0f, rx);
392				const float y = y0 + rng.getFloat(0.0f, ry);
393				vertices.push_back(makeVertex(x, y, primitiveColor));
394			}
395			break;
396
397		case TEST_PRIMITIVE_LINES:
398			for (int i = 0; i < 30; ++i)
399			{
400				const float x = x0 + rng.getFloat(0.0f, rx - size);
401				const float y = y0 + rng.getFloat(0.0f, ry - size);
402				vertices.push_back(makeVertex(x,        y,        primitiveColor));
403				vertices.push_back(makeVertex(x + size, y + size, primitiveColor));
404			}
405			break;
406
407		case TEST_PRIMITIVE_TRIANGLES:
408			for (int i = 0; i < 20; ++i)
409			{
410				const float x = x0 + rng.getFloat(0.0f, rx - size);
411				const float y = y0 + rng.getFloat(0.0f, ry - size);
412				vertices.push_back(makeVertex(x,             y,        primitiveColor));
413				vertices.push_back(makeVertex(x + size/2.0f, y + size, primitiveColor));
414				vertices.push_back(makeVertex(x + size,      y,        primitiveColor));
415			}
416			break;
417
418		case TEST_PRIMITIVE_BIG_LINE:
419			vertices.push_back(makeVertex(x0,      y0,      primitiveColor));
420			vertices.push_back(makeVertex(x0 + rx, y0 + ry, primitiveColor));
421			break;
422
423		case TEST_PRIMITIVE_BIG_TRIANGLE:
424			vertices.push_back(makeVertex(x0,           y0,      primitiveColor));
425			vertices.push_back(makeVertex(x0 + rx/2.0f, y0 + ry, primitiveColor));
426			vertices.push_back(makeVertex(x0 + rx,      y0,      primitiveColor));
427			break;
428	}
429
430	return vertices;
431}
432
433VkPrimitiveTopology	getTopology (const TestPrimitive primitive)
434{
435	switch (primitive)
436	{
437		case TEST_PRIMITIVE_POINTS:			return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
438
439		case TEST_PRIMITIVE_LINES:
440		case TEST_PRIMITIVE_BIG_LINE:		return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
441
442		case TEST_PRIMITIVE_TRIANGLES:
443		case TEST_PRIMITIVE_BIG_TRIANGLE:	return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
444
445		default:
446			DE_ASSERT(0);
447			return VK_PRIMITIVE_TOPOLOGY_LAST;
448	}
449}
450
451void zeroBuffer (const DeviceInterface& vk, const VkDevice device, const Allocation& alloc, const VkDeviceSize size)
452{
453	deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(size));
454	flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), size);
455}
456
457//! Transform from normalized coords to framebuffer space.
458inline IVec4 getAreaRect (const Vec4& area, const int width, const int height)
459{
460	return IVec4(static_cast<deInt32>(static_cast<float>(width)  * area.x()),
461				 static_cast<deInt32>(static_cast<float>(height) * area.y()),
462				 static_cast<deInt32>(static_cast<float>(width)  * area.z()),
463				 static_cast<deInt32>(static_cast<float>(height) * area.w()));
464}
465
466void applyScissor (tcu::PixelBufferAccess imageAccess, const Vec4& floatScissorArea, const Vec4& clearColor)
467{
468	const IVec4	scissorRect	(getAreaRect(floatScissorArea, imageAccess.getWidth(), imageAccess.getHeight()));
469	const int	sx0			= scissorRect.x();
470	const int	sx1			= scissorRect.x() + scissorRect.z();
471	const int	sy0			= scissorRect.y();
472	const int	sy1			= scissorRect.y() + scissorRect.w();
473
474	for (int y = 0; y < imageAccess.getHeight(); ++y)
475	for (int x = 0; x < imageAccess.getWidth(); ++x)
476	{
477		// Fragments outside fail the scissor test.
478		if (x < sx0 || x >= sx1 || y < sy0 || y >= sy1)
479			imageAccess.setPixel(clearColor, x, y);
480	}
481}
482
483void initPrograms (SourceCollections& programCollection, const CaseDef caseDef)
484{
485	DE_UNREF(caseDef);
486
487	// Vertex shader
488	{
489		const bool usePointSize = (caseDef.primitive == TEST_PRIMITIVE_POINTS);
490
491		std::ostringstream src;
492		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
493			<< "\n"
494			<< "layout(location = 0) in  vec4 in_position;\n"
495			<< "layout(location = 1) in  vec4 in_color;\n"
496			<< "layout(location = 0) out vec4 o_color;\n"
497			<< "\n"
498			<< "out gl_PerVertex {\n"
499			<< "    vec4  gl_Position;\n"
500			<< (usePointSize ? "    float gl_PointSize;\n" : "")
501			<< "};\n"
502			<< "\n"
503			<< "void main(void)\n"
504			<< "{\n"
505			<< "    gl_Position  = in_position;\n"
506			<< (usePointSize ? "    gl_PointSize = 1.0;\n" : "")
507			<< "    o_color      = in_color;\n"
508			<< "}\n";
509
510		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
511	}
512
513	// Fragment shader
514	{
515		std::ostringstream src;
516		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
517			<< "\n"
518			<< "layout(location = 0) in  vec4 in_color;\n"
519			<< "layout(location = 0) out vec4 o_color;\n"
520			<< "\n"
521			<< "void main(void)\n"
522			<< "{\n"
523			<< "    o_color = in_color;\n"
524			<< "}\n";
525
526		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
527	}
528}
529
530class ScissorRenderer
531{
532public:
533	ScissorRenderer (Context& context, const CaseDef caseDef, const IVec2& renderSize, const VkFormat colorFormat, const Vec4& primitiveColor, const Vec4& clearColor)
534		: m_renderSize				(renderSize)
535		, m_colorFormat				(colorFormat)
536		, m_colorSubresourceRange	(makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u))
537		, m_primitiveColor			(primitiveColor)
538		, m_clearColor				(clearColor)
539		, m_vertices				(genVertices(caseDef.primitive, caseDef.renderArea, m_primitiveColor))
540		, m_vertexBufferSize		(sizeInBytes(m_vertices))
541		, m_topology				(getTopology(caseDef.primitive))
542	{
543		const DeviceInterface&		vk					= context.getDeviceInterface();
544		const VkDevice				device				= context.getDevice();
545		const deUint32				queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
546		Allocator&					allocator			= context.getDefaultAllocator();
547
548		m_colorImage			= makeImage(vk, device, makeImageCreateInfo(m_colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
549		m_colorImageAlloc		= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
550		m_colorAttachment		= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, m_colorFormat, m_colorSubresourceRange);
551
552		m_vertexBuffer			= makeBuffer(vk, device, makeBufferCreateInfo(m_vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
553		m_vertexBufferAlloc		= bindBuffer(vk, device, allocator, *m_vertexBuffer, MemoryRequirement::HostVisible);
554
555		{
556			deMemcpy(m_vertexBufferAlloc->getHostPtr(), &m_vertices[0], static_cast<std::size_t>(m_vertexBufferSize));
557			flushMappedMemoryRange(vk, device, m_vertexBufferAlloc->getMemory(), m_vertexBufferAlloc->getOffset(), m_vertexBufferSize);
558		}
559
560		m_vertexModule				= createShaderModule	(vk, device, context.getBinaryCollection().get("vert"), 0u);
561		m_fragmentModule			= createShaderModule	(vk, device, context.getBinaryCollection().get("frag"), 0u);
562		m_renderPass				= makeRenderPass		(vk, device, m_colorFormat);
563		m_framebuffer				= makeFramebuffer		(vk, device, *m_renderPass, 1u, &m_colorAttachment.get(),
564															 static_cast<deUint32>(m_renderSize.x()),  static_cast<deUint32>(m_renderSize.y()));
565		m_pipelineLayout			= makePipelineLayout	(vk, device);
566		m_cmdPool					= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
567		m_cmdBuffer					= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
568
569	}
570
571	void draw (Context& context, const Vec4& scissorAreaFloat, const VkBuffer colorBuffer) const
572	{
573		const DeviceInterface&		vk			= context.getDeviceInterface();
574		const VkDevice				device		= context.getDevice();
575		const VkQueue				queue		= context.getUniversalQueue();
576
577		// New pipeline, because we're modifying scissor (we don't use dynamic state).
578		const Unique<VkPipeline>	pipeline	(makeGraphicsPipeline(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule,
579												 m_renderSize, getAreaRect(scissorAreaFloat, m_renderSize.x(), m_renderSize.y()), m_topology));
580
581		beginCommandBuffer(vk, *m_cmdBuffer);
582
583		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
584		const VkRect2D				renderArea	=
585		{
586			makeOffset2D(0, 0),
587			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
588		};
589		const VkRenderPassBeginInfo renderPassBeginInfo =
590		{
591			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
592			DE_NULL,										// const void*             pNext;
593			*m_renderPass,									// VkRenderPass            renderPass;
594			*m_framebuffer,									// VkFramebuffer           framebuffer;
595			renderArea,										// VkRect2D                renderArea;
596			1u,												// uint32_t                clearValueCount;
597			&clearValue,									// const VkClearValue*     pClearValues;
598		};
599		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
600
601		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
602		{
603			const VkDeviceSize vertexBufferOffset = 0ull;
604			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &m_vertexBuffer.get(), &vertexBufferOffset);
605		}
606
607		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);
608		vk.cmdEndRenderPass(*m_cmdBuffer);
609
610		// Prepare color image for copy
611		{
612			const VkImageMemoryBarrier barriers[] =
613			{
614				{
615					VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,						// VkStructureType			sType;
616					DE_NULL,													// const void*				pNext;
617					VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,						// VkAccessFlags			outputMask;
618					VK_ACCESS_TRANSFER_READ_BIT,								// VkAccessFlags			inputMask;
619					VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,					// VkImageLayout			oldLayout;
620					VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,						// VkImageLayout			newLayout;
621					VK_QUEUE_FAMILY_IGNORED,									// deUint32					srcQueueFamilyIndex;
622					VK_QUEUE_FAMILY_IGNORED,									// deUint32					destQueueFamilyIndex;
623					*m_colorImage,												// VkImage					image;
624					m_colorSubresourceRange,									// VkImageSubresourceRange	subresourceRange;
625				},
626			};
627
628			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
629				0u, DE_NULL, 0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers);
630		}
631		// Color image -> host buffer
632		{
633			const VkBufferImageCopy region =
634			{
635				0ull,																		// VkDeviceSize                bufferOffset;
636				0u,																			// uint32_t                    bufferRowLength;
637				0u,																			// uint32_t                    bufferImageHeight;
638				makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u),			// VkImageSubresourceLayers    imageSubresource;
639				makeOffset3D(0, 0, 0),														// VkOffset3D                  imageOffset;
640				makeExtent3D(m_renderSize.x(), m_renderSize.y(), 1u),						// VkExtent3D                  imageExtent;
641			};
642
643			vk.cmdCopyImageToBuffer(*m_cmdBuffer, *m_colorImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer, 1u, &region);
644		}
645		// Buffer write barrier
646		{
647			const VkBufferMemoryBarrier barriers[] =
648			{
649				{
650					VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,		// VkStructureType    sType;
651					DE_NULL,										// const void*        pNext;
652					VK_ACCESS_TRANSFER_WRITE_BIT,					// VkAccessFlags      srcAccessMask;
653					VK_ACCESS_HOST_READ_BIT,						// VkAccessFlags      dstAccessMask;
654					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           srcQueueFamilyIndex;
655					VK_QUEUE_FAMILY_IGNORED,						// uint32_t           dstQueueFamilyIndex;
656					colorBuffer,									// VkBuffer           buffer;
657					0ull,											// VkDeviceSize       offset;
658					VK_WHOLE_SIZE,									// VkDeviceSize       size;
659				},
660			};
661
662			vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
663				0u, DE_NULL, DE_LENGTH_OF_ARRAY(barriers), barriers, DE_NULL, 0u);
664		}
665
666		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
667		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
668	}
669
670private:
671	const IVec2						m_renderSize;
672	const VkFormat					m_colorFormat;
673	const VkImageSubresourceRange	m_colorSubresourceRange;
674	const Vec4						m_primitiveColor;
675	const Vec4						m_clearColor;
676	const std::vector<VertexData>	m_vertices;
677	const VkDeviceSize				m_vertexBufferSize;
678	const VkPrimitiveTopology		m_topology;
679
680	Move<VkImage>					m_colorImage;
681	MovePtr<Allocation>				m_colorImageAlloc;
682	Move<VkImageView>				m_colorAttachment;
683	Move<VkBuffer>					m_vertexBuffer;
684	MovePtr<Allocation>				m_vertexBufferAlloc;
685	Move<VkShaderModule>			m_vertexModule;
686	Move<VkShaderModule>			m_fragmentModule;
687	Move<VkRenderPass>				m_renderPass;
688	Move<VkFramebuffer>				m_framebuffer;
689	Move<VkPipelineLayout>			m_pipelineLayout;
690	Move<VkCommandPool>				m_cmdPool;
691	Move<VkCommandBuffer>			m_cmdBuffer;
692
693	// "deleted"
694						ScissorRenderer	(const ScissorRenderer&);
695	ScissorRenderer&	operator=		(const ScissorRenderer&);
696};
697
698tcu::TestStatus test (Context& context, const CaseDef caseDef)
699{
700	const DeviceInterface&			vk							= context.getDeviceInterface();
701	const VkDevice					device						= context.getDevice();
702	Allocator&						allocator					= context.getDefaultAllocator();
703
704	const IVec2						renderSize					(128, 128);
705	const VkFormat					colorFormat					= VK_FORMAT_R8G8B8A8_UNORM;
706	const Vec4						scissorFullArea				(0.0f, 0.0f, 1.0f, 1.0f);
707	const Vec4						primitiveColor				(1.0f, 1.0f, 1.0f, 1.0f);
708	const Vec4						clearColor					(0.5f, 0.5f, 1.0f, 1.0f);
709
710	const VkDeviceSize				colorBufferSize				= renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
711	const Unique<VkBuffer>			colorBufferFull				(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
712	const UniquePtr<Allocation>		colorBufferFullAlloc		(bindBuffer(vk, device, allocator, *colorBufferFull, MemoryRequirement::HostVisible));
713
714	const Unique<VkBuffer>			colorBufferScissored		(makeBuffer(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT)));
715	const UniquePtr<Allocation>		colorBufferScissoredAlloc	(bindBuffer(vk, device, allocator, *colorBufferScissored, MemoryRequirement::HostVisible));
716
717	zeroBuffer(vk, device, *colorBufferFullAlloc, colorBufferSize);
718	zeroBuffer(vk, device, *colorBufferScissoredAlloc, colorBufferSize);
719
720	// Draw
721	{
722		const ScissorRenderer renderer (context, caseDef, renderSize, colorFormat, primitiveColor, clearColor);
723
724		renderer.draw(context, scissorFullArea, *colorBufferFull);
725		renderer.draw(context, caseDef.scissorArea, *colorBufferScissored);
726	}
727
728	// Log image
729	{
730		invalidateMappedMemoryRange(vk, device, colorBufferFullAlloc->getMemory(), 0ull, colorBufferSize);
731		invalidateMappedMemoryRange(vk, device, colorBufferScissoredAlloc->getMemory(), 0ull, colorBufferSize);
732
733		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferScissoredAlloc->getHostPtr());
734		tcu::PixelBufferAccess				referenceImage	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1u, colorBufferFullAlloc->getHostPtr());
735
736		// Apply scissor to the full image, so we can compare it with the result image.
737		applyScissor (referenceImage, caseDef.scissorArea, clearColor);
738
739		// Images should now match.
740		if (!tcu::floatThresholdCompare(context.getTestContext().getLog(), "color", "Image compare", referenceImage, resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
741			return tcu::TestStatus::fail("Rendered image is not correct");
742	}
743
744	return tcu::TestStatus::pass("OK");
745}
746
747//! \note The ES 2.0 scissoring tests included color/depth/stencil clear cases, but these operations are not affected by scissor test in Vulkan.
748//!       Scissor is part of the pipeline state and pipeline only affects the drawing commands.
749void createTestsInGroup (tcu::TestCaseGroup* scissorGroup)
750{
751	tcu::TestContext& testCtx = scissorGroup->getTestContext();
752
753	struct TestSpec
754	{
755		const char*		name;
756		const char*		description;
757		CaseDef			caseDef;
758	};
759
760	const Vec4	areaFull			(0.0f, 0.0f, 1.0f, 1.0f);
761	const Vec4	areaCropped			(0.2f, 0.2f, 0.6f, 0.6f);
762	const Vec4	areaCroppedMore		(0.4f, 0.4f, 0.2f, 0.2f);
763	const Vec4	areaLeftHalf		(0.0f, 0.0f, 0.5f, 1.0f);
764	const Vec4	areaRightHalf		(0.5f, 0.0f, 0.5f, 1.0f);
765
766	// Points
767	{
768		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "points", ""));
769
770		const TestSpec	cases[] =
771		{
772			{ "inside",				"Points fully inside the scissor area",		{ areaFull,		areaFull,		TEST_PRIMITIVE_POINTS } },
773			{ "partially_inside",	"Points partially inside the scissor area",	{ areaFull,		areaCropped,	TEST_PRIMITIVE_POINTS } },
774			{ "outside",			"Points fully outside the scissor area",	{ areaLeftHalf,	areaRightHalf,	TEST_PRIMITIVE_POINTS } },
775		};
776
777		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
778			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
779
780		scissorGroup->addChild(primitiveGroup.release());
781	}
782
783	// Lines
784	{
785		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "lines", ""));
786
787		const TestSpec	cases[] =
788		{
789			{ "inside",				"Lines fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_LINES	} },
790			{ "partially_inside",	"Lines partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_LINES	} },
791			{ "outside",			"Lines fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_LINES	} },
792			{ "crossing",			"A line crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_LINE	} },
793		};
794
795		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
796			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
797
798		scissorGroup->addChild(primitiveGroup.release());
799	}
800
801	// Triangles
802	{
803		MovePtr<tcu::TestCaseGroup> primitiveGroup (new tcu::TestCaseGroup(testCtx, "triangles", ""));
804
805		const TestSpec	cases[] =
806		{
807			{ "inside",				"Triangles fully inside the scissor area",		{ areaFull,		areaFull,			TEST_PRIMITIVE_TRIANGLES	} },
808			{ "partially_inside",	"Triangles partially inside the scissor area",	{ areaFull,		areaCropped,		TEST_PRIMITIVE_TRIANGLES	} },
809			{ "outside",			"Triangles fully outside the scissor area",		{ areaLeftHalf,	areaRightHalf,		TEST_PRIMITIVE_TRIANGLES	} },
810			{ "crossing",			"A triangle crossing the scissor area",			{ areaFull,		areaCroppedMore,	TEST_PRIMITIVE_BIG_TRIANGLE	} },
811		};
812
813		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
814			addFunctionCaseWithPrograms(primitiveGroup.get(), cases[i].name, cases[i].description, initPrograms, test, cases[i].caseDef);
815
816		scissorGroup->addChild(primitiveGroup.release());
817	}
818
819	// Mulit-viewport scissor
820	{
821		scissorGroup->addChild(createScissorMultiViewportTests(testCtx));
822	}
823}
824
825} // anonymous
826
827tcu::TestCaseGroup* createScissorTests (tcu::TestContext& testCtx)
828{
829	return createTestGroup(testCtx, "scissor", "Scissor tests", createTestsInGroup);
830}
831
832} // FragmentOperations
833} // vkt
834