1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2019 Valve Corporation.
6  * Copyright (c) 2019 The Khronos Group Inc.
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 EXT_discard_rectangles tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawDiscardRectanglesTests.hpp"
26 
27 #include "vkDefs.hpp"
28 #include "vkRef.hpp"
29 #include "vkRefUtil.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkImageUtil.hpp"
32 #include "vkMemUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkCmdUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vktTestGroupUtil.hpp"
37 #include "vktTestCase.hpp"
38 #include "vktDrawBufferObjectUtil.hpp"
39 
40 #include "tcuTestCase.hpp"
41 #include "tcuVector.hpp"
42 #include "tcuTextureUtil.hpp"
43 #include "tcuTextureUtil.hpp"
44 #include "tcuImageCompare.hpp"
45 
46 #include "deUniquePtr.hpp"
47 #include "deSharedPtr.hpp"
48 
49 namespace vkt
50 {
51 namespace Draw
52 {
53 
54 namespace
55 {
56 using namespace vk;
57 using de::UniquePtr;
58 using de::SharedPtr;
59 using de::MovePtr;
60 using tcu::Vec4;
61 using tcu::Vec2;
62 using tcu::UVec2;
63 using tcu::UVec4;
64 
65 enum TestMode
66 {
67 	TEST_MODE_INCLUSIVE = 0,
68 	TEST_MODE_EXCLUSIVE,
69 	TEST_MODE_COUNT
70 };
71 
72 enum TestScissorMode
73 {
74 	TEST_SCISSOR_MODE_NONE = 0,
75 	TEST_SCISSOR_MODE_STATIC,
76 	TEST_SCISSOR_MODE_DYNAMIC,
77 	TEST_SCISSOR_MODE_COUNT
78 };
79 
80 #define NUM_RECT_TESTS 6
81 #define NUM_DYNAMIC_DISCARD_TYPE_TESTS 2
82 
83 struct TestParams
84 {
85 	TestMode		testMode;
86 	deUint32		numRectangles;
87 	deBool			dynamicDiscardRectangles;
88 	TestScissorMode	scissorMode;
89 };
90 
91 template<typename T>
sizeInBytes(const std::vector<T> & vec)92 inline VkDeviceSize sizeInBytes(const std::vector<T>& vec)
93 {
94 	return vec.size() * sizeof(vec[0]);
95 }
96 
makeImageCreateInfo(const VkFormat format,const UVec2 & size,VkImageUsageFlags usage)97 VkImageCreateInfo makeImageCreateInfo (const VkFormat format, const UVec2& size, VkImageUsageFlags usage)
98 {
99 	const VkImageCreateInfo imageParams =
100 	{
101 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// VkStructureType			sType;
102 		DE_NULL,										// const void*				pNext;
103 		(VkImageCreateFlags)0,							// VkImageCreateFlags		flags;
104 		VK_IMAGE_TYPE_2D,								// VkImageType				imageType;
105 		format,											// VkFormat					format;
106 		makeExtent3D(size.x(), size.y(), 1),			// VkExtent3D				extent;
107 		1u,												// deUint32					mipLevels;
108 		1u,												// deUint32					arrayLayers;
109 		VK_SAMPLE_COUNT_1_BIT,							// VkSampleCountFlagBits	samples;
110 		VK_IMAGE_TILING_OPTIMAL,						// VkImageTiling			tiling;
111 		usage,											// VkImageUsageFlags		usage;
112 		VK_SHARING_MODE_EXCLUSIVE,						// VkSharingMode			sharingMode;
113 		0u,												// deUint32					queueFamilyIndexCount;
114 		DE_NULL,										// const deUint32*			pQueueFamilyIndices;
115 		VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			initialLayout;
116 	};
117 	return imageParams;
118 }
119 
makeDiscardRectangleStateCreateInfo(const deBool dynamicDiscardRectangle,const VkDiscardRectangleModeEXT discardRectangleMode,const deUint32 discardRectangleCount,const VkRect2D * pDiscardRectangles)120 VkPipelineDiscardRectangleStateCreateInfoEXT makeDiscardRectangleStateCreateInfo (const deBool						dynamicDiscardRectangle,
121 																				  const VkDiscardRectangleModeEXT	discardRectangleMode,
122 																				  const deUint32					discardRectangleCount,
123 																				  const VkRect2D					*pDiscardRectangles)
124 {
125 	const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectanglesCreateInfo =
126 	{
127 		VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT,		// VkStructureType									sType;
128 		DE_NULL,																// const void*										pNext;
129 		0u,																		// VkPipelineDiscardRectangleStateCreateFlagsEXT	flags;
130 		discardRectangleMode,													// VkDiscardRectangleModeEXT						discardRectangleMode;
131 		discardRectangleCount,													// deUint32											discardRectangleCount;
132 		dynamicDiscardRectangle ? DE_NULL : pDiscardRectangles					// const VkRect2D*									pDiscardRectangles;
133 	};
134 	return discardRectanglesCreateInfo;
135 }
136 
makeGraphicsPipeline(const DeviceInterface & vk,const VkDevice device,const VkPipelineLayout pipelineLayout,const VkRenderPass renderPass,const VkShaderModule vertexModule,const VkShaderModule fragmentModule,const UVec2 renderSize,const deBool dynamicDiscardRectangle,const VkDiscardRectangleModeEXT discardRectangleMode,const deUint32 discardRectangleCount,const VkRect2D * pDiscardRectangles,const TestScissorMode scissorMode,const VkRect2D rectScissor)137 Move<VkPipeline> makeGraphicsPipeline (const DeviceInterface&			vk,
138 									   const VkDevice					device,
139 									   const VkPipelineLayout			pipelineLayout,
140 									   const VkRenderPass				renderPass,
141 									   const VkShaderModule				vertexModule,
142 									   const VkShaderModule				fragmentModule,
143 									   const UVec2						renderSize,
144 									   const deBool						dynamicDiscardRectangle,
145 									   const VkDiscardRectangleModeEXT	discardRectangleMode,
146 									   const deUint32					discardRectangleCount,
147 									   const VkRect2D*					pDiscardRectangles,
148 									   const TestScissorMode			scissorMode,
149 									   const VkRect2D					rectScissor)
150 {
151 	const VkVertexInputBindingDescription vertexInputBindingDescription =
152 	{
153 		0u,								// uint32_t				binding;
154 		sizeof(Vec4),					// uint32_t				stride;
155 		VK_VERTEX_INPUT_RATE_VERTEX,	// VkVertexInputRate	inputRate;
156 	};
157 
158 	const VkVertexInputAttributeDescription vertexInputAttributeDescriptions[] =
159 	{
160 		{
161 			0u,								// uint32_t			location;
162 			0u,								// uint32_t			binding;
163 			VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat			format;
164 			0u,								// uint32_t			offset;
165 		},
166 	};
167 
168 	const VkPipelineVertexInputStateCreateInfo vertexInputStateInfo =
169 	{
170 		VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType								sType;
171 		DE_NULL,														// const void*									pNext;
172 		(VkPipelineVertexInputStateCreateFlags)0,						// VkPipelineVertexInputStateCreateFlags		flags;
173 		1u,																// uint32_t										vertexBindingDescriptionCount;
174 		&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
175 		DE_LENGTH_OF_ARRAY(vertexInputAttributeDescriptions),			// uint32_t										vertexAttributeDescriptionCount;
176 		vertexInputAttributeDescriptions,								// const VkVertexInputAttributeDescription*		pVertexAttributeDescriptions;
177 	};
178 
179 	const VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo =
180 	{
181 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	// VkStructureType								sType;
182 		DE_NULL,														// const void*									pNext;
183 		(VkPipelineInputAssemblyStateCreateFlags)0,						// VkPipelineInputAssemblyStateCreateFlags		flags;
184 		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,							// VkPrimitiveTopology							topology;
185 		VK_FALSE,														// VkBool32										primitiveRestartEnable;
186 	};
187 
188 
189 	VkViewport		viewport				= makeViewport(0.0f, 0.0f, static_cast<float>(renderSize.x()), static_cast<float>(renderSize.y()), 0.0f, 1.0f);
190 	const VkRect2D	rectScissorRenderSize	= { { 0, 0 }, { renderSize.x(), renderSize.y() } };
191 
192 	const VkPipelineViewportStateCreateInfo pipelineViewportStateInfo =
193 	{
194 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,							// VkStructureType								sType;
195 		DE_NULL,																		// const void*									pNext;
196 		(VkPipelineViewportStateCreateFlags)0,											// VkPipelineViewportStateCreateFlags			flags;
197 		1u,																				// uint32_t										viewportCount;
198 		&viewport,																		// const VkViewport*							pViewports;
199 		1u,																				// uint32_t										scissorCount;
200 		scissorMode != TEST_SCISSOR_MODE_NONE ? &rectScissor : &rectScissorRenderSize,	// const VkRect2D*								pScissors;
201 	};
202 
203 	const VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo =
204 	{
205 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType								sType;
206 		DE_NULL,														// const void*									pNext;
207 		(VkPipelineRasterizationStateCreateFlags)0,						// VkPipelineRasterizationStateCreateFlags		flags;
208 		VK_FALSE,														// VkBool32										depthClampEnable;
209 		VK_FALSE,														// VkBool32										rasterizerDiscardEnable;
210 		VK_POLYGON_MODE_FILL,											// VkPolygonMode								polygonMode;
211 		VK_CULL_MODE_NONE,												// VkCullModeFlags								cullMode;
212 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace									frontFace;
213 		VK_FALSE,														// VkBool32										depthBiasEnable;
214 		0.0f,															// float										depthBiasConstantFactor;
215 		0.0f,															// float										depthBiasClamp;
216 		0.0f,															// float										depthBiasSlopeFactor;
217 		1.0f,															// float										lineWidth;
218 	};
219 
220 	const VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo =
221 	{
222 		VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType								sType;
223 		DE_NULL,														// const void*									pNext;
224 		(VkPipelineMultisampleStateCreateFlags)0,						// VkPipelineMultisampleStateCreateFlags		flags;
225 		VK_SAMPLE_COUNT_1_BIT,											// VkSampleCountFlagBits						rasterizationSamples;
226 		VK_FALSE,														// VkBool32										sampleShadingEnable;
227 		0.0f,															// float										minSampleShading;
228 		DE_NULL,														// const VkSampleMask*							pSampleMask;
229 		VK_FALSE,														// VkBool32										alphaToCoverageEnable;
230 		VK_FALSE														// VkBool32										alphaToOneEnable;
231 	};
232 
233 	const VkStencilOpState stencilOpState = makeStencilOpState(
234 		VK_STENCIL_OP_KEEP,				// stencil fail
235 		VK_STENCIL_OP_KEEP,				// depth & stencil pass
236 		VK_STENCIL_OP_KEEP,				// depth only fail
237 		VK_COMPARE_OP_ALWAYS,			// compare op
238 		0u,								// compare mask
239 		0u,								// write mask
240 		0u);							// reference
241 
242 	VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateInfo =
243 	{
244 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		// VkStructureType								sType;
245 		DE_NULL,														// const void*									pNext;
246 		(VkPipelineDepthStencilStateCreateFlags)0,						// VkPipelineDepthStencilStateCreateFlags		flags;
247 		VK_FALSE,														// VkBool32										depthTestEnable;
248 		VK_FALSE,														// VkBool32										depthWriteEnable;
249 		VK_COMPARE_OP_LESS,												// VkCompareOp									depthCompareOp;
250 		VK_FALSE,														// VkBool32										depthBoundsTestEnable;
251 		VK_FALSE,														// VkBool32										stencilTestEnable;
252 		stencilOpState,													// VkStencilOpState								front;
253 		stencilOpState,													// VkStencilOpState								back;
254 		0.0f,															// float										minDepthBounds;
255 		1.0f,															// float										maxDepthBounds;
256 	};
257 
258 	const VkColorComponentFlags					colorComponentsAll					= VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
259 	const VkPipelineColorBlendAttachmentState	pipelineColorBlendAttachmentState	=
260 	{
261 		VK_FALSE,						// VkBool32					blendEnable;
262 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcColorBlendFactor;
263 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstColorBlendFactor;
264 		VK_BLEND_OP_ADD,				// VkBlendOp				colorBlendOp;
265 		VK_BLEND_FACTOR_ONE,			// VkBlendFactor			srcAlphaBlendFactor;
266 		VK_BLEND_FACTOR_ZERO,			// VkBlendFactor			dstAlphaBlendFactor;
267 		VK_BLEND_OP_ADD,				// VkBlendOp				alphaBlendOp;
268 		colorComponentsAll,				// VkColorComponentFlags	colorWriteMask;
269 	};
270 
271 	const VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo =
272 	{
273 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,		// VkStructureType								sType;
274 		DE_NULL,														// const void*									pNext;
275 		(VkPipelineColorBlendStateCreateFlags)0,						// VkPipelineColorBlendStateCreateFlags			flags;
276 		VK_FALSE,														// VkBool32										logicOpEnable;
277 		VK_LOGIC_OP_COPY,												// VkLogicOp									logicOp;
278 		1u,																// deUint32										attachmentCount;
279 		&pipelineColorBlendAttachmentState,								// const VkPipelineColorBlendAttachmentState*	pAttachments;
280 		{ 0.0f, 0.0f, 0.0f, 0.0f },										// float										blendConstants[4];
281 	};
282 
283 	const VkPipelineShaderStageCreateInfo pShaderStages[] =
284 	{
285 		{
286 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType								sType;
287 			DE_NULL,													// const void*									pNext;
288 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags				flags;
289 			VK_SHADER_STAGE_VERTEX_BIT,									// VkShaderStageFlagBits						stage;
290 			vertexModule,												// VkShaderModule								module;
291 			"main",														// const char*									pName;
292 			DE_NULL,													// const VkSpecializationInfo*					pSpecializationInfo;
293 		},
294 		{
295 			VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,		// VkStructureType								sType;
296 			DE_NULL,													// const void*									pNext;
297 			(VkPipelineShaderStageCreateFlags)0,						// VkPipelineShaderStageCreateFlags				flags;
298 			VK_SHADER_STAGE_FRAGMENT_BIT,								// VkShaderStageFlagBits						stage;
299 			fragmentModule,												// VkShaderModule								module;
300 			"main",														// const char*									pName;
301 			DE_NULL,													// const VkSpecializationInfo*					pSpecializationInfo;
302 		},
303 	};
304 
305 	const VkPipelineDiscardRectangleStateCreateInfoEXT discardRectangleStateCreateInfo = makeDiscardRectangleStateCreateInfo(dynamicDiscardRectangle, discardRectangleMode, discardRectangleCount, pDiscardRectangles);
306 
307 	const VkDynamicState dynamicStateDiscardRectangles	= VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT;
308 	const VkDynamicState dynamicStateScissor			= VK_DYNAMIC_STATE_SCISSOR;
309 	std::vector<VkDynamicState> dynamicStates;
310 
311 	if (dynamicDiscardRectangle)
312 		dynamicStates.push_back(dynamicStateDiscardRectangles);
313 	if (scissorMode == TEST_SCISSOR_MODE_DYNAMIC)
314 		dynamicStates.push_back(dynamicStateScissor);
315 
316 	const VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo =
317 	{
318 		VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,			// VkStructureType								sType;
319 		DE_NULL,														// const void*									pNext;
320 		0u,																// VkPipelineDynamicStateCreateFlags			flags;
321 	    (deUint32)dynamicStates.size(),									// deUint32										dynamicStateCount;
322 		dynamicStates.data()											// const VkDynamicState*						pDynamicStates;
323 	};
324 
325 	const VkGraphicsPipelineCreateInfo graphicsPipelineInfo =
326 	{
327 		VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,				// VkStructureType									sType;
328 		&discardRectangleStateCreateInfo,								// const void*										pNext;
329 		(VkPipelineCreateFlags)0,										// VkPipelineCreateFlags							flags;
330 		2u,																// deUint32											stageCount;
331 		pShaderStages,													// const VkPipelineShaderStageCreateInfo*			pStages;
332 		&vertexInputStateInfo,											// const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
333 		&pipelineInputAssemblyStateInfo,								// const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
334 		DE_NULL,														// const VkPipelineTessellationStateCreateInfo*		pTessellationState;
335 		&pipelineViewportStateInfo,										// const VkPipelineViewportStateCreateInfo*			pViewportState;
336 		&pipelineRasterizationStateInfo,								// const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
337 		&pipelineMultisampleStateInfo,									// const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
338 		&pipelineDepthStencilStateInfo,									// const VkPipelineDepthStencilStateCreateInfo*		pDepthStencilState;
339 		&pipelineColorBlendStateInfo,									// const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
340 		&pipelineDynamicStateCreateInfo,								// const VkPipelineDynamicStateCreateInfo*			pDynamicState;
341 		pipelineLayout,													// VkPipelineLayout									layout;
342 		renderPass,														// VkRenderPass										renderPass;
343 		0u,																// deUint32											subpass;
344 		DE_NULL,														// VkPipeline										basePipelineHandle;
345 		0,																// deInt32											basePipelineIndex;
346 	};
347 
348 	return createGraphicsPipeline(vk, device, DE_NULL, &graphicsPipelineInfo);
349 }
350 
generateDiscardRectangles(const UVec2 & renderSize,deUint32 numRect,std::vector<VkRect2D> & rectangles)351 void generateDiscardRectangles(const UVec2& renderSize, deUint32 numRect, std::vector<VkRect2D>& rectangles)
352 {
353 	deUint32 cellHight = renderSize.y() - 10;
354 	deUint32 cellWidth = (renderSize.x() - 10) / (2 * numRect - 1);
355 
356 	DE_ASSERT(rectangles.size() == 0);
357 
358 	for (deUint32 i = 0; i < numRect; i++)
359 	{
360 		VkRect2D rect;
361 		rect.extent.height = cellHight;
362 		rect.extent.width = cellWidth;
363 		rect.offset.x = 5u + i * 2 * cellWidth;
364 		rect.offset.y = 5u;
365 		rectangles.push_back(rect);
366 	}
367 }
368 
369 //! Renders a colorful grid of rectangles.
generateReferenceImage(const tcu::TextureFormat format,const UVec2 & renderSize,const TestMode testMode,const Vec4 & color,const deUint32 numRectangles,const std::vector<VkRect2D> rectangles,const deBool enableScissor,const VkRect2D scissor)370 tcu::TextureLevel generateReferenceImage (const tcu::TextureFormat		format,
371 										  const UVec2&					renderSize,
372 										  const TestMode				testMode,
373 										  const Vec4&					color,
374 										  const deUint32				numRectangles,
375 										  const std::vector<VkRect2D>	rectangles,
376 										  const deBool					enableScissor,
377 										  const VkRect2D				scissor)
378 {
379 	tcu::TextureLevel	image(format, renderSize.x(), renderSize.y());
380 	const Vec4			rectColor	= testMode == TEST_MODE_INCLUSIVE ? Vec4(0.0f, 1.0f, 0.0f, 1.0f)	: color;
381 	const Vec4			clearColor	= testMode == TEST_MODE_INCLUSIVE ? color							: Vec4(0.0f, 1.0f, 0.0f, 1.0f);
382 
383 	if (!enableScissor)
384 	{
385 		// Clear the image with clearColor
386 		tcu::clear(image.getAccess(), clearColor);
387 
388 		// Now draw the discard rectangles taking into account the selected mode.
389 		for (deUint32 i = 0; i < numRectangles; i++)
390 		{
391 			tcu::clear(tcu::getSubregion(image.getAccess(), rectangles[i].offset.x, rectangles[i].offset.y,
392 										 rectangles[i].extent.width, rectangles[i].extent.height),
393 					   rectColor);
394 		}
395 	}
396 	else
397 	{
398 		// Clear the image with the original clear color
399 		tcu::clear(image.getAccess(), color);
400 		// Clear the scissor are with the clearColor which depends on the selected mode
401 		tcu::clear(tcu::getSubregion(image.getAccess(), scissor.offset.x, scissor.offset.y,
402 									 scissor.extent.width, scissor.extent.height),
403 				   clearColor);
404 
405 		// Now draw the discard rectangles taking into account both the scissor area and
406 		// the selected mode.
407 		for (deUint32 rect = 0; rect < numRectangles; rect++)
408 		{
409 			for (deUint32 x = rectangles[rect].offset.x; x < (rectangles[rect].offset.x + rectangles[rect].extent.width); x++)
410 			{
411 				for(deUint32 y = rectangles[rect].offset.y; y < (rectangles[rect].offset.y + rectangles[rect].extent.height); y++)
412 				{
413 					if ((x >= (deUint32)scissor.offset.x) && (x < (scissor.offset.x + scissor.extent.width)) &&
414 						(y >= (deUint32)scissor.offset.y) && (y < (scissor.offset.y + scissor.extent.height)))
415 					{
416 						image.getAccess().setPixel(rectColor, x, y);
417 					}
418 				}
419 			}
420 		}
421 	}
422 	return image;
423 }
424 
425 class DiscardRectanglesTestInstance : public TestInstance
426 {
427 public:
428 							DiscardRectanglesTestInstance		(Context& context,
429 																 TestParams params);
~DiscardRectanglesTestInstance(void)430 	virtual					~DiscardRectanglesTestInstance		(void) {};
431 	virtual tcu::TestStatus	iterate								(void);
432 
433 private:
434 	const TestParams			m_params;
435 	const Vec4					m_clearColor;
436 	const UVec2					m_renderSize;
437 	std::vector<Vec4>			m_vertices;
438 	std::vector<VkRect2D>		m_rectangles;
439 
440 	Move<VkImage>				m_colorImage;
441 	MovePtr<Allocation>			m_colorImageAlloc;
442 	Move<VkImageView>			m_colorAttachment;
443 	SharedPtr<Buffer>			m_colorBuffer;
444 	SharedPtr<Buffer>			m_vertexBuffer;
445 	Move<VkShaderModule>		m_vertexModule;
446 	Move<VkShaderModule>		m_fragmentModule;
447 	Move<VkRenderPass>			m_renderPass;
448 	Move<VkFramebuffer>			m_framebuffer;
449 	Move<VkPipelineLayout>		m_pipelineLayout;
450 	Move<VkPipeline>			m_pipeline;
451 	Move<VkCommandPool>			m_cmdPool;
452 	Move<VkCommandBuffer>		m_cmdBuffer;
453 };
454 
DiscardRectanglesTestInstance(Context & context,TestParams params)455 DiscardRectanglesTestInstance::DiscardRectanglesTestInstance (Context& context,
456 															  TestParams params)
457 	: TestInstance	(context)
458 	, m_params		(params)
459 	, m_clearColor	(Vec4(1.0f, 0.0f, 0.0f, 1.0f))
460 	, m_renderSize	(UVec2(340, 100))
461 {
462 }
463 
iterate(void)464 tcu::TestStatus DiscardRectanglesTestInstance::iterate	(void)
465 {
466 	const DeviceInterface&			vk						= m_context.getDeviceInterface();
467 	const InstanceInterface&		vki						= m_context.getInstanceInterface();
468 	const VkPhysicalDevice			physicalDevice			= m_context.getPhysicalDevice();
469 	const VkDevice					device					= m_context.getDevice();
470 	const VkQueue					queue					= m_context.getUniversalQueue();
471 	const deUint32					queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
472 	Allocator&						allocator				= m_context.getDefaultAllocator();
473 	const VkDiscardRectangleModeEXT	discardRectangleMode	= m_params.testMode == TEST_MODE_EXCLUSIVE ? VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT : VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT;
474 	const VkRect2D					rectScissor				= { { 90, 25 }, { 160, 50} };
475 	const VkImageSubresourceRange	colorSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
476 	const VkFormat					colorFormat				= VK_FORMAT_R8G8B8A8_UNORM;
477 	const VkDeviceSize				colorBufferSize			= m_renderSize.x() * m_renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
478 
479 	// Check for VK_EXT_discard_rectangles support and maximum number of active discard rectangles
480 	{
481 		VkPhysicalDeviceDiscardRectanglePropertiesEXT discardRectangleProperties;
482 		deMemset(&discardRectangleProperties, 0, sizeof(VkPhysicalDeviceDiscardRectanglePropertiesEXT));
483 		discardRectangleProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT;
484 
485 		VkPhysicalDeviceProperties2 physicalDeviceProperties;
486 		physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
487 		physicalDeviceProperties.pNext = &discardRectangleProperties;
488 
489 		vki.getPhysicalDeviceProperties2(physicalDevice, &physicalDeviceProperties);
490 
491 		if (discardRectangleProperties.maxDiscardRectangles == 0)
492 		{
493 			throw tcu::NotSupportedError("Implementation doesn't support discard rectangles");
494 		}
495 
496 		if (discardRectangleProperties.maxDiscardRectangles < 4)
497 		{
498 			std::ostringstream message;
499 			message << "Implementation doesn't support the minimum value for maxDiscardRectangles: " << discardRectangleProperties.maxDiscardRectangles << " < 4";
500 			return tcu::TestStatus::fail(message.str());
501 		}
502 
503 		if (discardRectangleProperties.maxDiscardRectangles < m_params.numRectangles)
504 		{
505 			std::ostringstream message;
506 			message << "Implementation doesn't support the required number of discard rectangles: " << discardRectangleProperties.maxDiscardRectangles << " < " << m_params.numRectangles;
507 			throw tcu::NotSupportedError(message.str());
508 		}
509 	}
510 
511 	// Color attachment
512 	{
513 		m_colorImage		= makeImage(vk, device, makeImageCreateInfo(colorFormat, m_renderSize, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT));
514 		m_colorImageAlloc	= bindImage(vk, device, allocator, *m_colorImage, MemoryRequirement::Any);
515 		m_colorBuffer		= Buffer::createAndAlloc(vk, device, makeBufferCreateInfo(colorBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT), allocator, MemoryRequirement::HostVisible);
516 		m_colorAttachment	= makeImageView(vk, device, *m_colorImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange);
517 
518 		// Zero colorBuffer.
519 		const Allocation alloc = m_colorBuffer->getBoundMemory();
520 		deMemset(alloc.getHostPtr(), 0, static_cast<std::size_t>(colorBufferSize));
521 		flushAlloc(vk, device, alloc);
522 	}
523 
524 	// Initialize the pipeline and other variables
525 	{
526 		// Draw a quad covering the whole framebuffer
527 		m_vertices.push_back(Vec4(-1.0f,  1.0f, 0.0f, 1.0f));
528 		m_vertices.push_back(Vec4(-1.0f, -1.0f, 0.0f, 1.0f));
529 		m_vertices.push_back(Vec4( 1.0f,  1.0f, 0.0f, 1.0f));
530 		m_vertices.push_back(Vec4( 1.0f, -1.0f, 0.0f, 1.0f));
531 		VkDeviceSize vertexBufferSize	= sizeInBytes(m_vertices);
532 		m_vertexBuffer					= Buffer::createAndAlloc	(vk, device, makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), allocator, MemoryRequirement::HostVisible);
533 
534 
535 		deMemcpy(m_vertexBuffer->getBoundMemory().getHostPtr(), m_vertices.data(), static_cast<std::size_t>(vertexBufferSize));
536 		flushAlloc(vk, device, m_vertexBuffer->getBoundMemory());
537 
538 		m_vertexModule				= createShaderModule	(vk, device, m_context.getBinaryCollection().get("vert"), 0u);
539 		m_fragmentModule			= createShaderModule	(vk, device, m_context.getBinaryCollection().get("frag"), 0u);
540 		m_renderPass				= makeRenderPass		(vk, device, colorFormat);
541 		m_framebuffer				= makeFramebuffer		(vk, device, *m_renderPass, m_colorAttachment.get(),
542 															 static_cast<deUint32>(m_renderSize.x()),
543 															 static_cast<deUint32>(m_renderSize.y()));
544 		m_pipelineLayout			= makePipelineLayout	(vk, device);
545 
546 		generateDiscardRectangles(m_renderSize, m_params.numRectangles, m_rectangles);
547 		m_pipeline					= makeGraphicsPipeline	(vk, device, *m_pipelineLayout, *m_renderPass, *m_vertexModule, *m_fragmentModule, m_renderSize,
548 															 m_params.dynamicDiscardRectangles, discardRectangleMode, m_params.numRectangles,
549 															 m_rectangles.data(), m_params.scissorMode, rectScissor);
550 		m_cmdPool					= createCommandPool		(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
551 		m_cmdBuffer					= allocateCommandBuffer	(vk, device, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
552 	}
553 
554 	// Write command buffer and submit it
555 	{
556 		beginCommandBuffer(vk, *m_cmdBuffer);
557 
558 		const VkClearValue			clearValue	= makeClearValueColor(m_clearColor);
559 		const VkRect2D				renderArea	=
560 		{
561 			makeOffset2D(0, 0),
562 			makeExtent2D(m_renderSize.x(), m_renderSize.y()),
563 		};
564 		const VkRenderPassBeginInfo renderPassBeginInfo =
565 		{
566 			VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,		// VkStructureType         sType;
567 			DE_NULL,										// const void*             pNext;
568 			*m_renderPass,									// VkRenderPass            renderPass;
569 			*m_framebuffer,									// VkFramebuffer           framebuffer;
570 			renderArea,										// VkRect2D                renderArea;
571 			1u,												// uint32_t                clearValueCount;
572 			&clearValue,									// const VkClearValue*     pClearValues;
573 		};
574 		vk.cmdBeginRenderPass(*m_cmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
575 
576 		vk.cmdBindPipeline(*m_cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipeline);
577 		{
578 			const VkBuffer vertexBuffer = m_vertexBuffer->object();
579 			const VkDeviceSize vertexBufferOffset = 0ull;
580 			vk.cmdBindVertexBuffers(*m_cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
581 		}
582 		if (m_params.dynamicDiscardRectangles)
583 		{
584 			vk.cmdSetDiscardRectangleEXT(*m_cmdBuffer, 0u, m_params.numRectangles, m_rectangles.data());
585 		}
586 		if (m_params.scissorMode == TEST_SCISSOR_MODE_DYNAMIC)
587 		{
588 			vk.cmdSetScissor(*m_cmdBuffer, 0u, 1u, &rectScissor);
589 		}
590 		vk.cmdDraw(*m_cmdBuffer, static_cast<deUint32>(m_vertices.size()), 1u, 0u, 0u);	// two triangles
591 		vk.cmdEndRenderPass(*m_cmdBuffer);
592 
593 		copyImageToBuffer(vk, *m_cmdBuffer, *m_colorImage, m_colorBuffer->object(), tcu::IVec2(m_renderSize.x(), m_renderSize.y()), VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, colorSubresourceRange.layerCount);
594 
595 		VK_CHECK(vk.endCommandBuffer(*m_cmdBuffer));
596 		submitCommandsAndWait(vk, device, queue, *m_cmdBuffer);
597 	}
598 
599 	// Verify results
600 	{
601 		const Allocation alloc = m_colorBuffer->getBoundMemory();
602 		invalidateAlloc(vk, device, alloc);
603 
604 		const tcu::ConstPixelBufferAccess	resultImage		(mapVkFormat(colorFormat), m_renderSize.x(), m_renderSize.y(), 1u, alloc.getHostPtr());
605 		const tcu::TextureLevel				referenceImage	= generateReferenceImage(mapVkFormat(colorFormat), m_renderSize, m_params.testMode, m_clearColor,
606 																					 m_params.numRectangles, m_rectangles, m_params.scissorMode != TEST_SCISSOR_MODE_NONE, rectScissor);
607 		if (!tcu::floatThresholdCompare(m_context.getTestContext().getLog(), "Compare", "Result comparison", referenceImage.getAccess(), resultImage, Vec4(0.02f), tcu::COMPARE_LOG_RESULT))
608 			TCU_FAIL("Rendered image is not correct");
609 	}
610 	return tcu::TestStatus::pass("OK");
611 }
612 
613 class DiscardRectanglesTestCase : public TestCase
614 {
615 public:
616 								DiscardRectanglesTestCase	(tcu::TestContext &context,
617 															 const char *name,
618 															 const char *description,
619 															 TestParams params);
~DiscardRectanglesTestCase(void)620 	virtual						~DiscardRectanglesTestCase	(void) {};
621 
622 	virtual TestInstance*		createInstance				(Context& context)	const;
623 	virtual void				initPrograms				(SourceCollections& programCollection) const;
624 	virtual void				checkSupport				(Context& context) const;
625 
626 private:
627 	const TestParams			m_params;
628 };
629 
DiscardRectanglesTestCase(tcu::TestContext & context,const char * name,const char * description,TestParams params)630 DiscardRectanglesTestCase::DiscardRectanglesTestCase	(tcu::TestContext &context,
631 														 const char *name,
632 														 const char *description,
633 														 TestParams params)
634 	: TestCase		(context, name, description)
635 	, m_params		(params)
636 {
637 }
638 
initPrograms(SourceCollections & programCollection) const639 void DiscardRectanglesTestCase::initPrograms(SourceCollections& programCollection) const
640 {
641 	// Vertex
642 	{
643 		std::ostringstream src;
644 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
645 			<< "\n"
646 			<< "layout(location = 0) in highp vec4 position;\n"
647 			<< "layout(location = 0) out highp vec4 vsColor;\n"
648 			<< "\n"
649 			<< "out gl_PerVertex {\n"
650 			<< "   vec4 gl_Position;\n"
651 			<< "};\n"
652 			<< "\n"
653 			<< "void main (void)\n"
654 			<< "{\n"
655 			<< "    gl_Position = position;\n"
656 			<< "    vsColor     = vec4(0.0f, 1.0f, 0.0f, 1.0f);\n"
657 			<< "}\n";
658 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
659 	}
660 
661 	// Fragment
662 	{
663 		std::ostringstream src;
664 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_440) << "\n"
665 			<< "\n"
666 			<< "layout(location = 0) in highp vec4 vsColor;\n"
667 			<< "layout(location = 0) out highp vec4 fsColor;\n"
668 			<< "\n"
669 			<< "void main (void)\n"
670 			<< "{\n"
671 			<< "    fsColor     = vsColor;\n"
672 			<< "}\n";
673 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
674 	}
675 }
676 
checkSupport(Context & context) const677 void DiscardRectanglesTestCase::checkSupport (Context& context) const
678 {
679 	context.requireDeviceFunctionality("VK_EXT_discard_rectangles");
680 }
681 
createInstance(Context & context) const682 TestInstance* DiscardRectanglesTestCase::createInstance (Context& context) const
683 {
684 	return new DiscardRectanglesTestInstance(context, m_params);
685 }
686 
createTests(tcu::TestCaseGroup * testGroup)687 void createTests (tcu::TestCaseGroup* testGroup)
688 {
689 	tcu::TestContext&	testCtx											= testGroup->getTestContext();
690 	deUint32			numRect [NUM_RECT_TESTS]						= { 1, 2, 3, 4,  8, 16};
691 	std::string			modeName [TEST_MODE_COUNT]						= { "inclusive_", "exclusive_" };
692 	std::string			scissorName [TEST_SCISSOR_MODE_COUNT]			= { "", "scissor_", "dynamic_scissor_" };
693 	std::string			dynamicName [NUM_DYNAMIC_DISCARD_TYPE_TESTS]	= { "", "dynamic_discard_" };
694 
695 	for (deUint32 dynamic = 0 ; dynamic < NUM_DYNAMIC_DISCARD_TYPE_TESTS; dynamic++)
696 	{
697 		for (deUint32 scissor = 0 ; scissor < TEST_SCISSOR_MODE_COUNT; scissor++)
698 		{
699 			for (deUint32 mode = 0; mode < TEST_MODE_COUNT; mode++)
700 			{
701 				for (deUint32 rect = 0; rect < NUM_RECT_TESTS; rect++)
702 				{
703 					std::ostringstream	name;
704 					TestParams			params;
705 
706 					params.testMode						= (TestMode) mode;
707 					params.dynamicDiscardRectangles		= dynamic ? DE_TRUE : DE_FALSE;
708 					params.scissorMode					= (TestScissorMode) scissor;
709 					params.numRectangles				= numRect[rect];
710 					name << dynamicName[dynamic] << scissorName[scissor] << modeName[mode] << "rect_" << numRect[rect];
711 
712 					testGroup->addChild(new DiscardRectanglesTestCase(testCtx, name.str().c_str(), "", params));
713 				}
714 			}
715 		}
716 	}
717 }
718 }	// Anonymous
719 
createDiscardRectanglesTests(tcu::TestContext & testCtx)720 tcu::TestCaseGroup* createDiscardRectanglesTests (tcu::TestContext& testCtx)
721 {
722 	return createTestGroup(testCtx, "discard_rectangles", "Discard Rectangles tests", createTests);
723 }
724 
725 }	// Draw
726 }	//vkt
727