• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7  * Copyright (c) 2014 The Android Open Source Project
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  *//*!
22  * \file
23  * \brief Functional rasterization tests.
24  *//*--------------------------------------------------------------------*/
25 
26 #include "vktTestGroupUtil.hpp"
27 #include "vktAmberTestCase.hpp"
28 #include "vktRasterizationTests.hpp"
29 #include "vktRasterizationFragShaderSideEffectsTests.hpp"
30 #include "tcuRasterizationVerifier.hpp"
31 #include "tcuSurface.hpp"
32 #include "tcuRenderTarget.hpp"
33 #include "tcuVectorUtil.hpp"
34 #include "tcuStringTemplate.hpp"
35 #include "tcuTextureUtil.hpp"
36 #include "tcuResultCollector.hpp"
37 #include "tcuFloatFormat.hpp"
38 #include "vkImageUtil.hpp"
39 #include "deStringUtil.hpp"
40 #include "deRandom.hpp"
41 #include "vktTestCase.hpp"
42 #include "vktTestCaseUtil.hpp"
43 #include "vkPrograms.hpp"
44 #include "vkMemUtil.hpp"
45 #include "vkRefUtil.hpp"
46 #include "vkQueryUtil.hpp"
47 #include "vkBuilderUtil.hpp"
48 #include "vkTypeUtil.hpp"
49 #include "vkCmdUtil.hpp"
50 #include "vkObjUtil.hpp"
51 #include "vkBufferWithMemory.hpp"
52 #include "vkImageWithMemory.hpp"
53 #include "vkBarrierUtil.hpp"
54 
55 #include <vector>
56 #include <sstream>
57 
58 using namespace vk;
59 
60 namespace vkt
61 {
62 namespace rasterization
63 {
64 namespace
65 {
66 
67 using tcu::RasterizationArguments;
68 using tcu::TriangleSceneSpec;
69 using tcu::PointSceneSpec;
70 using tcu::LineSceneSpec;
71 using tcu::LineInterpolationMethod;
72 
73 static const char* const s_shaderVertexTemplate =	"#version 310 es\n"
74 													"layout(location = 0) in highp vec4 a_position;\n"
75 													"layout(location = 1) in highp vec4 a_color;\n"
76 													"layout(location = 0) ${INTERPOLATION}out highp vec4 v_color;\n"
77 													"layout (set=0, binding=0) uniform PointSize {\n"
78 													"	highp float u_pointSize;\n"
79 													"};\n"
80 													"void main ()\n"
81 													"{\n"
82 													"	gl_Position = a_position;\n"
83 													"	gl_PointSize = u_pointSize;\n"
84 													"	v_color = a_color;\n"
85 													"}\n";
86 
87 static const char* const s_shaderFragmentTemplate =	"#version 310 es\n"
88 													"layout(location = 0) out highp vec4 fragColor;\n"
89 													"layout(location = 0) ${INTERPOLATION}in highp vec4 v_color;\n"
90 													"void main ()\n"
91 													"{\n"
92 													"	fragColor = v_color;\n"
93 													"}\n";
94 
95 enum InterpolationCaseFlags
96 {
97 	INTERPOLATIONFLAGS_NONE = 0,
98 	INTERPOLATIONFLAGS_PROJECTED = (1 << 1),
99 	INTERPOLATIONFLAGS_FLATSHADE = (1 << 2),
100 };
101 
102 enum ResolutionValues
103 {
104 	RESOLUTION_POT = 256,
105 	RESOLUTION_NPOT = 258
106 };
107 
108 enum PrimitiveWideness
109 {
110 	PRIMITIVEWIDENESS_NARROW = 0,
111 	PRIMITIVEWIDENESS_WIDE,
112 
113 	PRIMITIVEWIDENESS_LAST
114 };
115 
116 enum LineStipple
117 {
118 	LINESTIPPLE_DISABLED = 0,
119 	LINESTIPPLE_STATIC,
120 	LINESTIPPLE_DYNAMIC,
121 
122 	LINESTIPPLE_LAST
123 };
124 
125 static const deUint32 lineStippleFactor = 2;
126 static const deUint32 lineStipplePattern = 0x0F0F;
127 
128 enum PrimitiveStrictness
129 {
130 	PRIMITIVESTRICTNESS_STRICT = 0,
131 	PRIMITIVESTRICTNESS_NONSTRICT,
132 	PRIMITIVESTRICTNESS_IGNORE,
133 
134 	PRIMITIVESTRICTNESS_LAST
135 };
136 
137 
138 class BaseRenderingTestCase : public TestCase
139 {
140 public:
141 								BaseRenderingTestCase	(tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deBool flatshade = DE_FALSE);
142 	virtual						~BaseRenderingTestCase	(void);
143 
144 	virtual void				initPrograms			(vk::SourceCollections& programCollection) const;
145 
146 protected:
147 	const VkSampleCountFlagBits	m_sampleCount;
148 	const deBool				m_flatshade;
149 };
150 
BaseRenderingTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkSampleCountFlagBits sampleCount,deBool flatshade)151 BaseRenderingTestCase::BaseRenderingTestCase (tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount, deBool flatshade)
152 	: TestCase(context, name, description)
153 	, m_sampleCount	(sampleCount)
154 	, m_flatshade	(flatshade)
155 {
156 }
157 
initPrograms(vk::SourceCollections & programCollection) const158 void BaseRenderingTestCase::initPrograms (vk::SourceCollections& programCollection) const
159 {
160 	tcu::StringTemplate					vertexSource	(s_shaderVertexTemplate);
161 	tcu::StringTemplate					fragmentSource	(s_shaderFragmentTemplate);
162 	std::map<std::string, std::string>	params;
163 
164 	params["INTERPOLATION"] = (m_flatshade) ? ("flat ") : ("");
165 
166 	programCollection.glslSources.add("vertext_shader") << glu::VertexSource(vertexSource.specialize(params));
167 	programCollection.glslSources.add("fragment_shader") << glu::FragmentSource(fragmentSource.specialize(params));
168 }
169 
~BaseRenderingTestCase(void)170 BaseRenderingTestCase::~BaseRenderingTestCase (void)
171 {
172 }
173 
174 class BaseRenderingTestInstance : public TestInstance
175 {
176 public:
177 													BaseRenderingTestInstance		(Context& context, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT, deUint32 renderSize = RESOLUTION_POT, VkFormat imageFormat = VK_FORMAT_R8G8B8A8_UNORM, deUint32 additionalRenderSize = 0);
178 													~BaseRenderingTestInstance		(void);
179 
180 protected:
181 	void											addImageTransitionBarrier		(VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const;
182 	virtual void									drawPrimitives					(tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology);
183 	void											drawPrimitives					(tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, const std::vector<tcu::Vec4>& coloDrata, VkPrimitiveTopology primitiveTopology);
184 	void											drawPrimitives					(tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology,
185 																						VkImage image, VkImage resolvedImage, VkFramebuffer frameBuffer, const deUint32 renderSize, VkBuffer resultBuffer, const Allocation& resultBufferMemory);
186 	virtual float									getLineWidth					(void) const;
187 	virtual float									getPointSize					(void) const;
getLineStippleDynamic(void) const188 	virtual bool									getLineStippleDynamic			(void) const { return false; };
189 
190 	virtual
191 	const VkPipelineRasterizationStateCreateInfo*	getRasterizationStateCreateInfo	(void) const;
192 
193 	virtual
194 	VkPipelineRasterizationLineStateCreateInfoEXT	initLineRasterizationStateCreateInfo	(void) const;
195 
196 	virtual
197 	const VkPipelineRasterizationLineStateCreateInfoEXT*	getLineRasterizationStateCreateInfo	(void) const;
198 
199 	virtual
200 	const VkPipelineColorBlendStateCreateInfo*		getColorBlendStateCreateInfo	(void) const;
201 
202 	const tcu::TextureFormat&						getTextureFormat				(void) const;
203 
204 	const deUint32									m_renderSize;
205 	const VkSampleCountFlagBits						m_sampleCount;
206 	deUint32										m_subpixelBits;
207 	const deBool									m_multisampling;
208 
209 	const VkFormat									m_imageFormat;
210 	const tcu::TextureFormat						m_textureFormat;
211 	Move<VkCommandPool>								m_commandPool;
212 
213 	Move<VkImage>									m_image;
214 	de::MovePtr<Allocation>							m_imageMemory;
215 	Move<VkImageView>								m_imageView;
216 
217 	Move<VkImage>									m_resolvedImage;
218 	de::MovePtr<Allocation>							m_resolvedImageMemory;
219 	Move<VkImageView>								m_resolvedImageView;
220 
221 	Move<VkRenderPass>								m_renderPass;
222 	Move<VkFramebuffer>								m_frameBuffer;
223 
224 	Move<VkDescriptorPool>							m_descriptorPool;
225 	Move<VkDescriptorSet>							m_descriptorSet;
226 	Move<VkDescriptorSetLayout>						m_descriptorSetLayout;
227 
228 	Move<VkBuffer>									m_uniformBuffer;
229 	de::MovePtr<Allocation>							m_uniformBufferMemory;
230 	const VkDeviceSize								m_uniformBufferSize;
231 
232 	Move<VkPipelineLayout>							m_pipelineLayout;
233 
234 	Move<VkShaderModule>							m_vertexShaderModule;
235 	Move<VkShaderModule>							m_fragmentShaderModule;
236 
237 	Move<VkBuffer>									m_resultBuffer;
238 	de::MovePtr<Allocation>							m_resultBufferMemory;
239 	const VkDeviceSize								m_resultBufferSize;
240 
241 	const deUint32									m_additionalRenderSize;
242 	const VkDeviceSize								m_additionalResultBufferSize;
243 
244 	VkPipelineRasterizationLineStateCreateInfoEXT	m_lineRasterizationStateInfo;
245 
246 private:
getIteration(void) const247 	virtual int										getIteration					(void) const { TCU_THROW(InternalError, "Iteration undefined in the base class"); }
248 };
249 
BaseRenderingTestInstance(Context & context,VkSampleCountFlagBits sampleCount,deUint32 renderSize,VkFormat imageFormat,deUint32 additionalRenderSize)250 BaseRenderingTestInstance::BaseRenderingTestInstance (Context& context, VkSampleCountFlagBits sampleCount, deUint32 renderSize, VkFormat imageFormat, deUint32 additionalRenderSize)
251 	: TestInstance			(context)
252 	, m_renderSize			(renderSize)
253 	, m_sampleCount			(sampleCount)
254 	, m_subpixelBits		(context.getDeviceProperties().limits.subPixelPrecisionBits)
255 	, m_multisampling		(m_sampleCount != VK_SAMPLE_COUNT_1_BIT)
256 	, m_imageFormat			(imageFormat)
257 	, m_textureFormat		(vk::mapVkFormat(m_imageFormat))
258 	, m_uniformBufferSize	(sizeof(float))
259 	, m_resultBufferSize	(renderSize * renderSize * m_textureFormat.getPixelSize())
260 	, m_additionalRenderSize(additionalRenderSize)
261 	, m_additionalResultBufferSize(additionalRenderSize * additionalRenderSize * m_textureFormat.getPixelSize())
262 	, m_lineRasterizationStateInfo	(initLineRasterizationStateCreateInfo())
263 {
264 	const DeviceInterface&						vkd						= m_context.getDeviceInterface();
265 	const VkDevice								vkDevice				= m_context.getDevice();
266 	const deUint32								queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
267 	Allocator&									allocator				= m_context.getDefaultAllocator();
268 	DescriptorPoolBuilder						descriptorPoolBuilder;
269 	DescriptorSetLayoutBuilder					descriptorSetLayoutBuilder;
270 
271 	deMemset(&m_lineRasterizationStateInfo, 0, sizeof(m_lineRasterizationStateInfo));
272 
273 	// Command Pool
274 	m_commandPool = createCommandPool(vkd, vkDevice, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
275 
276 	// Image
277 	{
278 		const VkImageUsageFlags	imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
279 		VkImageFormatProperties	properties;
280 
281 		if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
282 																					 m_imageFormat,
283 																					 VK_IMAGE_TYPE_2D,
284 																					 VK_IMAGE_TILING_OPTIMAL,
285 																					 imageUsage,
286 																					 0,
287 																					 &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
288 		{
289 			TCU_THROW(NotSupportedError, "Format not supported");
290 		}
291 
292 		if ((properties.sampleCounts & m_sampleCount) != m_sampleCount)
293 		{
294 			TCU_THROW(NotSupportedError, "Format not supported");
295 		}
296 
297 		const VkImageCreateInfo					imageCreateInfo			=
298 		{
299 			VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			sType;
300 			DE_NULL,									// const void*				pNext;
301 			0u,											// VkImageCreateFlags		flags;
302 			VK_IMAGE_TYPE_2D,							// VkImageType				imageType;
303 			m_imageFormat,								// VkFormat					format;
304 			{ m_renderSize,	m_renderSize, 1u },			// VkExtent3D				extent;
305 			1u,											// deUint32					mipLevels;
306 			1u,											// deUint32					arrayLayers;
307 			m_sampleCount,								// VkSampleCountFlagBits	samples;
308 			VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling;
309 			imageUsage,									// VkImageUsageFlags		usage;
310 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode;
311 			1u,											// deUint32					queueFamilyIndexCount;
312 			&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices;
313 			VK_IMAGE_LAYOUT_UNDEFINED					// VkImageLayout			initialLayout;
314 		};
315 
316 		m_image = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
317 
318 		m_imageMemory	= allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_image), MemoryRequirement::Any);
319 		VK_CHECK(vkd.bindImageMemory(vkDevice, *m_image, m_imageMemory->getMemory(), m_imageMemory->getOffset()));
320 	}
321 
322 	// Image View
323 	{
324 		const VkImageViewCreateInfo				imageViewCreateInfo		=
325 		{
326 			VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType				sType;
327 			DE_NULL,									// const void*					pNext;
328 			0u,											// VkImageViewCreateFlags		flags;
329 			*m_image,									// VkImage						image;
330 			VK_IMAGE_VIEW_TYPE_2D,						// VkImageViewType				viewType;
331 			m_imageFormat,								// VkFormat						format;
332 			makeComponentMappingRGBA(),					// VkComponentMapping			components;
333 			{
334 				VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags			aspectMask;
335 				0u,											// deUint32						baseMipLevel;
336 				1u,											// deUint32						mipLevels;
337 				0u,											// deUint32						baseArrayLayer;
338 				1u,											// deUint32						arraySize;
339 			},											// VkImageSubresourceRange		subresourceRange;
340 		};
341 
342 		m_imageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
343 	}
344 
345 	if (m_multisampling)
346 	{
347 		{
348 			// Resolved Image
349 			const VkImageUsageFlags	imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
350 			VkImageFormatProperties	properties;
351 
352 			if ((m_context.getInstanceInterface().getPhysicalDeviceImageFormatProperties(m_context.getPhysicalDevice(),
353 																						 m_imageFormat,
354 																						 VK_IMAGE_TYPE_2D,
355 																						 VK_IMAGE_TILING_OPTIMAL,
356 																						 imageUsage,
357 																						 0,
358 																						 &properties) == VK_ERROR_FORMAT_NOT_SUPPORTED))
359 			{
360 				TCU_THROW(NotSupportedError, "Format not supported");
361 			}
362 
363 			const VkImageCreateInfo					imageCreateInfo			=
364 			{
365 				VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			sType;
366 				DE_NULL,									// const void*				pNext;
367 				0u,											// VkImageCreateFlags		flags;
368 				VK_IMAGE_TYPE_2D,							// VkImageType				imageType;
369 				m_imageFormat,								// VkFormat					format;
370 				{ m_renderSize,	m_renderSize, 1u },			// VkExtent3D				extent;
371 				1u,											// deUint32					mipLevels;
372 				1u,											// deUint32					arrayLayers;
373 				VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples;
374 				VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling;
375 				imageUsage,									// VkImageUsageFlags		usage;
376 				VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode;
377 				1u,											// deUint32					queueFamilyIndexCount;
378 				&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices;
379 				VK_IMAGE_LAYOUT_UNDEFINED					// VkImageLayout			initialLayout;
380 			};
381 
382 			m_resolvedImage			= vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
383 			m_resolvedImageMemory	= allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_resolvedImage), MemoryRequirement::Any);
384 			VK_CHECK(vkd.bindImageMemory(vkDevice, *m_resolvedImage, m_resolvedImageMemory->getMemory(), m_resolvedImageMemory->getOffset()));
385 		}
386 
387 		// Resolved Image View
388 		{
389 			const VkImageViewCreateInfo				imageViewCreateInfo		=
390 			{
391 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType				sType;
392 				DE_NULL,									// const void*					pNext;
393 				0u,											// VkImageViewCreateFlags		flags;
394 				*m_resolvedImage,							// VkImage						image;
395 				VK_IMAGE_VIEW_TYPE_2D,						// VkImageViewType				viewType;
396 				m_imageFormat,								// VkFormat						format;
397 				makeComponentMappingRGBA(),					// VkComponentMapping			components;
398 				{
399 					VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags			aspectMask;
400 					0u,											// deUint32						baseMipLevel;
401 					1u,											// deUint32						mipLevels;
402 					0u,											// deUint32						baseArrayLayer;
403 					1u,											// deUint32						arraySize;
404 				},											// VkImageSubresourceRange		subresourceRange;
405 			};
406 
407 			m_resolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
408 		}
409 
410 	}
411 
412 	// Render Pass
413 	{
414 		const VkImageLayout						imageLayout				= VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
415 		const VkAttachmentDescription			attachmentDesc[]		=
416 		{
417 			{
418 				0u,													// VkAttachmentDescriptionFlags		flags;
419 				m_imageFormat,										// VkFormat							format;
420 				m_sampleCount,										// VkSampleCountFlagBits			samples;
421 				VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp				loadOp;
422 				VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
423 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
424 				VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
425 				imageLayout,										// VkImageLayout					initialLayout;
426 				imageLayout,										// VkImageLayout					finalLayout;
427 			},
428 			{
429 				0u,													// VkAttachmentDescriptionFlags		flags;
430 				m_imageFormat,										// VkFormat							format;
431 				VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits			samples;
432 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				loadOp;
433 				VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp				storeOp;
434 				VK_ATTACHMENT_LOAD_OP_DONT_CARE,					// VkAttachmentLoadOp				stencilLoadOp;
435 				VK_ATTACHMENT_STORE_OP_DONT_CARE,					// VkAttachmentStoreOp				stencilStoreOp;
436 				imageLayout,										// VkImageLayout					initialLayout;
437 				imageLayout,										// VkImageLayout					finalLayout;
438 			}
439 		};
440 
441 		const VkAttachmentReference				attachmentRef			=
442 		{
443 			0u,													// deUint32							attachment;
444 			imageLayout,										// VkImageLayout					layout;
445 		};
446 
447 		const VkAttachmentReference				resolveAttachmentRef	=
448 		{
449 			1u,													// deUint32							attachment;
450 			imageLayout,										// VkImageLayout					layout;
451 		};
452 
453 		const VkSubpassDescription				subpassDesc				=
454 		{
455 			0u,													// VkSubpassDescriptionFlags		flags;
456 			VK_PIPELINE_BIND_POINT_GRAPHICS,					// VkPipelineBindPoint				pipelineBindPoint;
457 			0u,													// deUint32							inputAttachmentCount;
458 			DE_NULL,											// const VkAttachmentReference*		pInputAttachments;
459 			1u,													// deUint32							colorAttachmentCount;
460 			&attachmentRef,										// const VkAttachmentReference*		pColorAttachments;
461 			m_multisampling ? &resolveAttachmentRef : DE_NULL,	// const VkAttachmentReference*		pResolveAttachments;
462 			DE_NULL,											// const VkAttachmentReference*		pDepthStencilAttachment;
463 			0u,													// deUint32							preserveAttachmentCount;
464 			DE_NULL,											// const VkAttachmentReference*		pPreserveAttachments;
465 		};
466 
467 		const VkRenderPassCreateInfo			renderPassCreateInfo	=
468 		{
469 			VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			// VkStructureType					sType;
470 			DE_NULL,											// const void*						pNext;
471 			0u,													// VkRenderPassCreateFlags			flags;
472 			m_multisampling ? 2u : 1u,							// deUint32							attachmentCount;
473 			attachmentDesc,										// const VkAttachmentDescription*	pAttachments;
474 			1u,													// deUint32							subpassCount;
475 			&subpassDesc,										// const VkSubpassDescription*		pSubpasses;
476 			0u,													// deUint32							dependencyCount;
477 			DE_NULL,											// const VkSubpassDependency*		pDependencies;
478 		};
479 
480 		m_renderPass =  createRenderPass(vkd, vkDevice, &renderPassCreateInfo, DE_NULL);
481 	}
482 
483 	// FrameBuffer
484 	{
485 		const VkImageView						attachments[]			=
486 		{
487 			*m_imageView,
488 			*m_resolvedImageView
489 		};
490 
491 		const VkFramebufferCreateInfo			framebufferCreateInfo	=
492 		{
493 			VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// VkStructureType			sType;
494 			DE_NULL,									// const void*				pNext;
495 			0u,											// VkFramebufferCreateFlags	flags;
496 			*m_renderPass,								// VkRenderPass				renderPass;
497 			m_multisampling ? 2u : 1u,					// deUint32					attachmentCount;
498 			attachments,								// const VkImageView*		pAttachments;
499 			m_renderSize,								// deUint32					width;
500 			m_renderSize,								// deUint32					height;
501 			1u,											// deUint32					layers;
502 		};
503 
504 		m_frameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
505 	}
506 
507 	// Uniform Buffer
508 	{
509 		const VkBufferCreateInfo				bufferCreateInfo		=
510 		{
511 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
512 			DE_NULL,									// const void*			pNext;
513 			0u,											// VkBufferCreateFlags	flags;
514 			m_uniformBufferSize,						// VkDeviceSize			size;
515 			VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,			// VkBufferUsageFlags	usage;
516 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
517 			1u,											// deUint32				queueFamilyIndexCount;
518 			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
519 		};
520 
521 		m_uniformBuffer			= createBuffer(vkd, vkDevice, &bufferCreateInfo);
522 		m_uniformBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_uniformBuffer), MemoryRequirement::HostVisible);
523 
524 		VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_uniformBuffer, m_uniformBufferMemory->getMemory(), m_uniformBufferMemory->getOffset()));
525 	}
526 
527 	// Descriptors
528 	{
529 		descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
530 		m_descriptorPool = descriptorPoolBuilder.build(vkd, vkDevice, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
531 
532 		descriptorSetLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_ALL);
533 		m_descriptorSetLayout = descriptorSetLayoutBuilder.build(vkd, vkDevice);
534 
535 		const VkDescriptorSetAllocateInfo		descriptorSetParams		=
536 		{
537 			VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
538 			DE_NULL,
539 			*m_descriptorPool,
540 			1u,
541 			&m_descriptorSetLayout.get(),
542 		};
543 
544 		m_descriptorSet = allocateDescriptorSet(vkd, vkDevice, &descriptorSetParams);
545 
546 		const VkDescriptorBufferInfo			descriptorBufferInfo	=
547 		{
548 			*m_uniformBuffer,							// VkBuffer		buffer;
549 			0u,											// VkDeviceSize	offset;
550 			VK_WHOLE_SIZE								// VkDeviceSize	range;
551 		};
552 
553 		const VkWriteDescriptorSet				writeDescritporSet		=
554 		{
555 			VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,		// VkStructureType					sType;
556 			DE_NULL,									// const void*						pNext;
557 			*m_descriptorSet,							// VkDescriptorSet					destSet;
558 			0,											// deUint32							destBinding;
559 			0,											// deUint32							destArrayElement;
560 			1u,											// deUint32							count;
561 			VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,			// VkDescriptorType					descriptorType;
562 			DE_NULL,									// const VkDescriptorImageInfo*		pImageInfo;
563 			&descriptorBufferInfo,						// const VkDescriptorBufferInfo*	pBufferInfo;
564 			DE_NULL										// const VkBufferView*				pTexelBufferView;
565 		};
566 
567 		vkd.updateDescriptorSets(vkDevice, 1u, &writeDescritporSet, 0u, DE_NULL);
568 	}
569 
570 	// Pipeline Layout
571 	{
572 		const VkPipelineLayoutCreateInfo		pipelineLayoutCreateInfo	=
573 		{
574 			VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,		// VkStructureType				sType;
575 			DE_NULL,											// const void*					pNext;
576 			0u,													// VkPipelineLayoutCreateFlags	flags;
577 			1u,													// deUint32						descriptorSetCount;
578 			&m_descriptorSetLayout.get(),						// const VkDescriptorSetLayout*	pSetLayouts;
579 			0u,													// deUint32						pushConstantRangeCount;
580 			DE_NULL												// const VkPushConstantRange*	pPushConstantRanges;
581 		};
582 
583 		m_pipelineLayout = createPipelineLayout(vkd, vkDevice, &pipelineLayoutCreateInfo);
584 	}
585 
586 	// Shaders
587 	{
588 		m_vertexShaderModule	= createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("vertext_shader"), 0);
589 		m_fragmentShaderModule	= createShaderModule(vkd, vkDevice, m_context.getBinaryCollection().get("fragment_shader"), 0);
590 	}
591 
592 	// Result Buffer
593 	{
594 		const VkBufferCreateInfo				bufferCreateInfo		=
595 		{
596 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
597 			DE_NULL,									// const void*			pNext;
598 			0u,											// VkBufferCreateFlags	flags;
599 			m_resultBufferSize,							// VkDeviceSize			size;
600 			VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// VkBufferUsageFlags	usage;
601 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
602 			1u,											// deUint32				queueFamilyIndexCount;
603 			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
604 		};
605 
606 		m_resultBuffer			= createBuffer(vkd, vkDevice, &bufferCreateInfo);
607 		m_resultBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_resultBuffer), MemoryRequirement::HostVisible);
608 
609 		VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_resultBuffer, m_resultBufferMemory->getMemory(), m_resultBufferMemory->getOffset()));
610 	}
611 
612 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Sample count = " << getSampleCountFlagsStr(m_sampleCount) << tcu::TestLog::EndMessage;
613 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "SUBPIXEL_BITS = " << m_subpixelBits << tcu::TestLog::EndMessage;
614 }
615 
~BaseRenderingTestInstance(void)616 BaseRenderingTestInstance::~BaseRenderingTestInstance (void)
617 {
618 }
619 
620 
addImageTransitionBarrier(VkCommandBuffer commandBuffer,VkImage image,VkPipelineStageFlags srcStageMask,VkPipelineStageFlags dstStageMask,VkAccessFlags srcAccessMask,VkAccessFlags dstAccessMask,VkImageLayout oldLayout,VkImageLayout newLayout) const621 void BaseRenderingTestInstance::addImageTransitionBarrier(VkCommandBuffer commandBuffer, VkImage image, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout) const
622 {
623 
624 	const DeviceInterface&			vkd					= m_context.getDeviceInterface();
625 
626 	const VkImageSubresourceRange	subResourcerange	=
627 	{
628 		VK_IMAGE_ASPECT_COLOR_BIT,		// VkImageAspectFlags	aspectMask;
629 		0,								// deUint32				baseMipLevel;
630 		1,								// deUint32				levelCount;
631 		0,								// deUint32				baseArrayLayer;
632 		1								// deUint32				layerCount;
633 	};
634 
635 	const VkImageMemoryBarrier		imageBarrier		=
636 	{
637 		VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,		// VkStructureType			sType;
638 		DE_NULL,									// const void*				pNext;
639 		srcAccessMask,								// VkAccessFlags			srcAccessMask;
640 		dstAccessMask,								// VkAccessFlags			dstAccessMask;
641 		oldLayout,									// VkImageLayout			oldLayout;
642 		newLayout,									// VkImageLayout			newLayout;
643 		VK_QUEUE_FAMILY_IGNORED,					// deUint32					srcQueueFamilyIndex;
644 		VK_QUEUE_FAMILY_IGNORED,					// deUint32					destQueueFamilyIndex;
645 		image,										// VkImage					image;
646 		subResourcerange							// VkImageSubresourceRange	subresourceRange;
647 	};
648 
649 	vkd.cmdPipelineBarrier(commandBuffer, srcStageMask, dstStageMask, 0, 0, DE_NULL, 0, DE_NULL, 1, &imageBarrier);
650 }
651 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)652 void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
653 {
654 	// default to color white
655 	const std::vector<tcu::Vec4> colorData(vertexData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
656 
657 	drawPrimitives(result, vertexData, colorData, primitiveTopology);
658 }
659 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,const std::vector<tcu::Vec4> & colorData,VkPrimitiveTopology primitiveTopology)660 void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology)
661 {
662 	drawPrimitives(result, positionData, colorData, primitiveTopology, *m_image, *m_resolvedImage, *m_frameBuffer, m_renderSize, *m_resultBuffer, *m_resultBufferMemory);
663 }
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,const std::vector<tcu::Vec4> & colorData,VkPrimitiveTopology primitiveTopology,VkImage image,VkImage resolvedImage,VkFramebuffer frameBuffer,const deUint32 renderSize,VkBuffer resultBuffer,const Allocation & resultBufferMemory)664 void BaseRenderingTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, const std::vector<tcu::Vec4>& colorData, VkPrimitiveTopology primitiveTopology,
665 					VkImage image, VkImage resolvedImage, VkFramebuffer frameBuffer, const deUint32 renderSize, VkBuffer resultBuffer, const Allocation& resultBufferMemory)
666 {
667 	const DeviceInterface&						vkd						= m_context.getDeviceInterface();
668 	const VkDevice								vkDevice				= m_context.getDevice();
669 	const VkQueue								queue					= m_context.getUniversalQueue();
670 	const deUint32								queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
671 	Allocator&									allocator				= m_context.getDefaultAllocator();
672 	const size_t								attributeBatchSize		= positionData.size() * sizeof(tcu::Vec4);
673 
674 	Move<VkCommandBuffer>						commandBuffer;
675 	Move<VkPipeline>							graphicsPipeline;
676 	Move<VkBuffer>								vertexBuffer;
677 	de::MovePtr<Allocation>						vertexBufferMemory;
678 	const VkPhysicalDeviceProperties			properties				= m_context.getDeviceProperties();
679 
680 	if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
681 	{
682 		std::stringstream message;
683 		message << "Larger vertex input attribute offset is needed (" << attributeBatchSize << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
684 		TCU_THROW(NotSupportedError, message.str().c_str());
685 	}
686 
687 	// Create Graphics Pipeline
688 	{
689 		const VkVertexInputBindingDescription	vertexInputBindingDescription =
690 		{
691 			0u,								// deUint32					binding;
692 			sizeof(tcu::Vec4),				// deUint32					strideInBytes;
693 			VK_VERTEX_INPUT_RATE_VERTEX		// VkVertexInputStepRate	stepRate;
694 		};
695 
696 		const VkVertexInputAttributeDescription	vertexInputAttributeDescriptions[2] =
697 		{
698 			{
699 				0u,									// deUint32	location;
700 				0u,									// deUint32	binding;
701 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
702 				0u									// deUint32	offsetInBytes;
703 			},
704 			{
705 				1u,									// deUint32	location;
706 				0u,									// deUint32	binding;
707 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
708 				(deUint32)attributeBatchSize		// deUint32	offsetInBytes;
709 			}
710 		};
711 
712 		const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams =
713 		{
714 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,		// VkStructureType							sType;
715 			DE_NULL,														// const void*								pNext;
716 			0,																// VkPipelineVertexInputStateCreateFlags	flags;
717 			1u,																// deUint32									bindingCount;
718 			&vertexInputBindingDescription,									// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
719 			2u,																// deUint32									attributeCount;
720 			vertexInputAttributeDescriptions								// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
721 		};
722 
723 		const std::vector<VkViewport>	viewports	(1, makeViewport(tcu::UVec2(renderSize)));
724 		const std::vector<VkRect2D>		scissors	(1, makeRect2D(tcu::UVec2(renderSize)));
725 
726 		const VkPipelineMultisampleStateCreateInfo multisampleStateParams =
727 		{
728 			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,		// VkStructureType							sType;
729 			DE_NULL,														// const void*								pNext;
730 			0u,																// VkPipelineMultisampleStateCreateFlags	flags;
731 			m_sampleCount,													// VkSampleCountFlagBits					rasterizationSamples;
732 			VK_FALSE,														// VkBool32									sampleShadingEnable;
733 			0.0f,															// float									minSampleShading;
734 			DE_NULL,														// const VkSampleMask*						pSampleMask;
735 			VK_FALSE,														// VkBool32									alphaToCoverageEnable;
736 			VK_FALSE														// VkBool32									alphaToOneEnable;
737 		};
738 
739 
740 		VkPipelineRasterizationStateCreateInfo rasterizationStateInfo = *getRasterizationStateCreateInfo();
741 
742 		const VkPipelineRasterizationLineStateCreateInfoEXT* lineRasterizationStateInfo = getLineRasterizationStateCreateInfo();
743 
744 		if (lineRasterizationStateInfo != DE_NULL)
745 			appendStructurePtrToVulkanChain(&rasterizationStateInfo.pNext, lineRasterizationStateInfo);
746 
747 		VkPipelineDynamicStateCreateInfo			dynamicStateCreateInfo =
748 		{
749 			VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	// VkStructureType                      sType
750 			DE_NULL,												// const void*                          pNext
751 			0u,														// VkPipelineDynamicStateCreateFlags    flags
752 			0u,														// deUint32                             dynamicStateCount
753 			DE_NULL													// const VkDynamicState*                pDynamicStates
754 		};
755 
756 		VkDynamicState dynamicState = VK_DYNAMIC_STATE_LINE_STIPPLE_EXT;
757 		if (getLineStippleDynamic())
758 		{
759 			dynamicStateCreateInfo.dynamicStateCount = 1;
760 			dynamicStateCreateInfo.pDynamicStates = &dynamicState;
761 		}
762 
763 		graphicsPipeline = makeGraphicsPipeline(vkd,								// const DeviceInterface&                        vk
764 												vkDevice,							// const VkDevice                                device
765 												*m_pipelineLayout,					// const VkPipelineLayout                        pipelineLayout
766 												*m_vertexShaderModule,				// const VkShaderModule                          vertexShaderModule
767 												DE_NULL,							// const VkShaderModule                          tessellationControlShaderModule
768 												DE_NULL,							// const VkShaderModule                          tessellationEvalShaderModule
769 												DE_NULL,							// const VkShaderModule                          geometryShaderModule
770 												*m_fragmentShaderModule,			// const VkShaderModule                          fragmentShaderModule
771 												*m_renderPass,						// const VkRenderPass                            renderPass
772 												viewports,							// const std::vector<VkViewport>&                viewports
773 												scissors,							// const std::vector<VkRect2D>&                  scissors
774 												primitiveTopology,					// const VkPrimitiveTopology                     topology
775 												0u,									// const deUint32                                subpass
776 												0u,									// const deUint32                                patchControlPoints
777 												&vertexInputStateParams,			// const VkPipelineVertexInputStateCreateInfo*   vertexInputStateCreateInfo
778 												&rasterizationStateInfo,			// const VkPipelineRasterizationStateCreateInfo* rasterizationStateCreateInfo
779 												&multisampleStateParams,			// const VkPipelineMultisampleStateCreateInfo*   multisampleStateCreateInfo
780 												DE_NULL,							// const VkPipelineDepthStencilStateCreateInfo*  depthStencilStateCreateInfo,
781 												getColorBlendStateCreateInfo(),		// const VkPipelineColorBlendStateCreateInfo*    colorBlendStateCreateInfo,
782 												&dynamicStateCreateInfo);			// const VkPipelineDynamicStateCreateInfo*       dynamicStateCreateInfo
783 	}
784 
785 	// Create Vertex Buffer
786 	{
787 		const VkBufferCreateInfo			vertexBufferParams		=
788 		{
789 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
790 			DE_NULL,									// const void*			pNext;
791 			0u,											// VkBufferCreateFlags	flags;
792 			attributeBatchSize * 2,						// VkDeviceSize			size;
793 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,			// VkBufferUsageFlags	usage;
794 			VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
795 			1u,											// deUint32				queueFamilyCount;
796 			&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
797 		};
798 
799 		vertexBuffer		= createBuffer(vkd, vkDevice, &vertexBufferParams);
800 		vertexBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
801 
802 		VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
803 
804 		// Load vertices into vertex buffer
805 		deMemcpy(vertexBufferMemory->getHostPtr(), positionData.data(), attributeBatchSize);
806 		deMemcpy(reinterpret_cast<deUint8*>(vertexBufferMemory->getHostPtr()) +  attributeBatchSize, colorData.data(), attributeBatchSize);
807 		flushAlloc(vkd, vkDevice, *vertexBufferMemory);
808 	}
809 
810 	// Create Command Buffer
811 	commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
812 
813 	// Begin Command Buffer
814 	beginCommandBuffer(vkd, *commandBuffer);
815 
816 	addImageTransitionBarrier(*commandBuffer, image,
817 							  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,				// VkPipelineStageFlags		srcStageMask
818 							  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,				// VkPipelineStageFlags		dstStageMask
819 							  0,												// VkAccessFlags			srcAccessMask
820 							  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,				// VkAccessFlags			dstAccessMask
821 							  VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			oldLayout;
822 							  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);		// VkImageLayout			newLayout;
823 
824 	if (m_multisampling) {
825 		addImageTransitionBarrier(*commandBuffer, resolvedImage,
826 								  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,				// VkPipelineStageFlags		srcStageMask
827 								  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,				// VkPipelineStageFlags		dstStageMask
828 								  0,												// VkAccessFlags			srcAccessMask
829 								  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,				// VkAccessFlags			dstAccessMask
830 								  VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			oldLayout;
831 								  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);		// VkImageLayout			newLayout;
832 	}
833 
834 	// Begin Render Pass
835 	beginRenderPass(vkd, *commandBuffer, *m_renderPass, frameBuffer, vk::makeRect2D(0, 0, renderSize, renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
836 
837 	const VkDeviceSize						vertexBufferOffset		= 0;
838 
839 	vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
840 	vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1, &m_descriptorSet.get(), 0u, DE_NULL);
841 	vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset);
842 	if (getLineStippleDynamic())
843 		vkd.cmdSetLineStippleEXT(*commandBuffer, lineStippleFactor, lineStipplePattern);
844 	vkd.cmdDraw(*commandBuffer, (deUint32)positionData.size(), 1, 0, 0);
845 	endRenderPass(vkd, *commandBuffer);
846 
847 	// Copy Image
848 	copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? resolvedImage : image, resultBuffer, tcu::IVec2(renderSize, renderSize));
849 
850 	endCommandBuffer(vkd, *commandBuffer);
851 
852 	// Set Point Size
853 	{
854 		float	pointSize	= getPointSize();
855 		deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
856 		flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
857 	}
858 
859 	// Submit
860 	submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
861 
862 	invalidateAlloc(vkd, vkDevice, resultBufferMemory);
863 	tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(renderSize, renderSize, 1), resultBufferMemory.getHostPtr()));
864 }
865 
getLineWidth(void) const866 float BaseRenderingTestInstance::getLineWidth (void) const
867 {
868 	return 1.0f;
869 }
870 
getPointSize(void) const871 float BaseRenderingTestInstance::getPointSize (void) const
872 {
873 	return 1.0f;
874 }
875 
getRasterizationStateCreateInfo(void) const876 const VkPipelineRasterizationStateCreateInfo* BaseRenderingTestInstance::getRasterizationStateCreateInfo (void) const
877 {
878 	static VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
879 	{
880 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType							sType;
881 		DE_NULL,														// const void*								pNext;
882 		0,																// VkPipelineRasterizationStateCreateFlags	flags;
883 		false,															// VkBool32									depthClipEnable;
884 		false,															// VkBool32									rasterizerDiscardEnable;
885 		VK_POLYGON_MODE_FILL,											// VkFillMode								fillMode;
886 		VK_CULL_MODE_NONE,												// VkCullMode								cullMode;
887 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
888 		VK_FALSE,														// VkBool32									depthBiasEnable;
889 		0.0f,															// float									depthBias;
890 		0.0f,															// float									depthBiasClamp;
891 		0.0f,															// float									slopeScaledDepthBias;
892 		getLineWidth(),													// float									lineWidth;
893 	};
894 
895 	rasterizationStateCreateInfo.lineWidth = getLineWidth();
896 	return &rasterizationStateCreateInfo;
897 }
898 
initLineRasterizationStateCreateInfo(void) const899 VkPipelineRasterizationLineStateCreateInfoEXT BaseRenderingTestInstance::initLineRasterizationStateCreateInfo (void) const
900 {
901 	VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo =
902 	{
903 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT,	// VkStructureType				sType;
904 		DE_NULL,																// const void*					pNext;
905 		VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,									// VkLineRasterizationModeEXT	lineRasterizationMode;
906 		VK_FALSE,																// VkBool32						stippledLineEnable;
907 		1,																		// uint32_t						lineStippleFactor;
908 		0xFFFF,																	// uint16_t						lineStipplePattern;
909 	};
910 
911 	return lineRasterizationStateInfo;
912 }
913 
getLineRasterizationStateCreateInfo(void) const914 const VkPipelineRasterizationLineStateCreateInfoEXT* BaseRenderingTestInstance::getLineRasterizationStateCreateInfo (void) const
915 {
916 	return &m_lineRasterizationStateInfo;
917 }
918 
getColorBlendStateCreateInfo(void) const919 const VkPipelineColorBlendStateCreateInfo* BaseRenderingTestInstance::getColorBlendStateCreateInfo (void) const
920 {
921 	static const VkPipelineColorBlendAttachmentState	colorBlendAttachmentState	=
922 	{
923 		false,														// VkBool32			blendEnable;
924 		VK_BLEND_FACTOR_ONE,										// VkBlend			srcBlendColor;
925 		VK_BLEND_FACTOR_ZERO,										// VkBlend			destBlendColor;
926 		VK_BLEND_OP_ADD,											// VkBlendOp		blendOpColor;
927 		VK_BLEND_FACTOR_ONE,										// VkBlend			srcBlendAlpha;
928 		VK_BLEND_FACTOR_ZERO,										// VkBlend			destBlendAlpha;
929 		VK_BLEND_OP_ADD,											// VkBlendOp		blendOpAlpha;
930 		(VK_COLOR_COMPONENT_R_BIT |
931 		 VK_COLOR_COMPONENT_G_BIT |
932 		 VK_COLOR_COMPONENT_B_BIT |
933 		 VK_COLOR_COMPONENT_A_BIT)									// VkChannelFlags	channelWriteMask;
934 	};
935 
936 	static const VkPipelineColorBlendStateCreateInfo	colorBlendStateParams		=
937 	{
938 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
939 		DE_NULL,													// const void*									pNext;
940 		0,															// VkPipelineColorBlendStateCreateFlags			flags;
941 		false,														// VkBool32										logicOpEnable;
942 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
943 		1u,															// deUint32										attachmentCount;
944 		&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
945 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConst[4];
946 	};
947 
948 	return &colorBlendStateParams;
949 }
950 
getTextureFormat(void) const951 const tcu::TextureFormat& BaseRenderingTestInstance::getTextureFormat (void) const
952 {
953 	return m_textureFormat;
954 }
955 
956 class BaseTriangleTestInstance : public BaseRenderingTestInstance
957 {
958 public:
959 							BaseTriangleTestInstance	(Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount, deUint32 renderSize = RESOLUTION_POT);
960 	virtual tcu::TestStatus	iterate						(void);
961 
962 protected:
getIteration(void) const963 	int						getIteration				(void) const	{ return m_iteration;		}
getIterationCount(void) const964 	int						getIterationCount			(void) const	{ return m_iterationCount;	}
965 
966 private:
967 	virtual void			generateTriangles			(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles) = DE_NULL;
968 	virtual bool			compareAndVerify			(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
969 														 tcu::Surface&									resultImage,
970 														 std::vector<tcu::Vec4>&						drawBuffer);
971 
972 	int						m_iteration;
973 	const int				m_iterationCount;
974 	VkPrimitiveTopology		m_primitiveTopology;
975 	bool					m_allIterationsPassed;
976 };
977 
BaseTriangleTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,VkSampleCountFlagBits sampleCount,deUint32 renderSize)978 BaseTriangleTestInstance::BaseTriangleTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, VkSampleCountFlagBits sampleCount, deUint32 renderSize)
979 	: BaseRenderingTestInstance		(context, sampleCount, renderSize)
980 	, m_iteration					(0)
981 	, m_iterationCount				(3)
982 	, m_primitiveTopology			(primitiveTopology)
983 	, m_allIterationsPassed			(true)
984 {
985 }
986 
iterate(void)987 tcu::TestStatus BaseTriangleTestInstance::iterate (void)
988 {
989 	const std::string								iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
990 	const tcu::ScopedLogSection						section					(m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
991 	tcu::Surface									resultImage				(m_renderSize, m_renderSize);
992 	std::vector<tcu::Vec4>							drawBuffer;
993 	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
994 
995 	generateTriangles(m_iteration, drawBuffer, triangles);
996 
997 	// draw image
998 	drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
999 
1000 	// compare
1001 	{
1002 		const bool compareOk = compareAndVerify(triangles, resultImage, drawBuffer);
1003 
1004 		if (!compareOk)
1005 			m_allIterationsPassed = false;
1006 	}
1007 
1008 	// result
1009 	if (++m_iteration == m_iterationCount)
1010 	{
1011 		if (m_allIterationsPassed)
1012 			return tcu::TestStatus::pass("Pass");
1013 		else
1014 			return tcu::TestStatus::fail("Incorrect rasterization");
1015 	}
1016 	else
1017 		return tcu::TestStatus::incomplete();
1018 }
1019 
compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage,std::vector<tcu::Vec4> &)1020 bool BaseTriangleTestInstance::compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage, std::vector<tcu::Vec4>&)
1021 {
1022 	RasterizationArguments	args;
1023 	TriangleSceneSpec		scene;
1024 
1025 	tcu::IVec4				colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
1026 
1027 	args.numSamples		= m_multisampling ? 1 : 0;
1028 	args.subpixelBits	= m_subpixelBits;
1029 	args.redBits		= colorBits[0];
1030 	args.greenBits		= colorBits[1];
1031 	args.blueBits		= colorBits[2];
1032 
1033 	scene.triangles.swap(triangles);
1034 
1035 	return verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
1036 }
1037 
1038 class BaseLineTestInstance : public BaseRenderingTestInstance
1039 {
1040 public:
1041 								BaseLineTestInstance	(Context&					context,
1042 														 VkPrimitiveTopology		primitiveTopology,
1043 														 PrimitiveWideness			wideness,
1044 														 PrimitiveStrictness		strictness,
1045 														 VkSampleCountFlagBits		sampleCount,
1046 														 LineStipple				stipple,
1047 														 VkLineRasterizationModeEXT	lineRasterizationMode,
1048 														 const deUint32				additionalRenderSize = 0,
1049 														 const deUint32				renderSize = RESOLUTION_POT,
1050 														 const float				narrowLineWidth = 1.0f);
1051 	virtual tcu::TestStatus		iterate					(void);
1052 	virtual float				getLineWidth			(void) const;
getLineStippleEnable(void) const1053 	bool						getLineStippleEnable	(void) const { return m_stipple != LINESTIPPLE_DISABLED; }
getLineStippleDynamic(void) const1054 	virtual bool				getLineStippleDynamic	(void) const { return m_stipple == LINESTIPPLE_DYNAMIC; };
1055 
1056 	virtual
1057 	VkPipelineRasterizationLineStateCreateInfoEXT	initLineRasterizationStateCreateInfo	(void) const;
1058 
1059 	virtual
1060 	const VkPipelineRasterizationLineStateCreateInfoEXT*	getLineRasterizationStateCreateInfo	(void) const;
1061 
1062 protected:
getIteration(void) const1063 	int							getIteration			(void) const	{ return m_iteration;		}
getIterationCount(void) const1064 	int							getIterationCount		(void) const	{ return m_iterationCount;	}
1065 
1066 private:
1067 	virtual void				generateLines			(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines) = DE_NULL;
1068 	virtual bool				compareAndVerify		(std::vector<LineSceneSpec::SceneLine>&	lines,
1069 														 tcu::Surface&							resultImage,
1070 														 std::vector<tcu::Vec4>&				drawBuffer);
1071 
1072 	bool						resultHasAlpha			(tcu::Surface& result);
1073 
1074 	int							m_iteration;
1075 	const int					m_iterationCount;
1076 	VkPrimitiveTopology			m_primitiveTopology;
1077 	const PrimitiveWideness		m_primitiveWideness;
1078 	const PrimitiveStrictness	m_primitiveStrictness;
1079 	bool						m_allIterationsPassed;
1080 	bool						m_qualityWarning;
1081 	float						m_maxLineWidth;
1082 	std::vector<float>			m_lineWidths;
1083 	LineStipple					m_stipple;
1084 	VkLineRasterizationModeEXT	m_lineRasterizationMode;
1085 	Move<VkImage>				m_additionalImage;
1086 	de::MovePtr<Allocation>		m_additionalImageMemory;
1087 	Move<VkImageView>			m_additionalImageView;
1088 	Move<VkImage>				m_additionalResolvedImage;
1089 	de::MovePtr<Allocation>		m_additionalResolvedImageMemory;
1090 	Move<VkImageView>			m_additionalResolvedImageView;
1091 	Move<VkFramebuffer>			m_additionalFrameBuffer;
1092 	Move<VkBuffer>				m_additionalResultBuffer;
1093 	de::MovePtr<Allocation>		m_additionalResultBufferMemory;
1094 };
1095 
BaseLineTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,const deUint32 additionalRenderSize,const deUint32 renderSize,const float narrowLineWidth)1096 BaseLineTestInstance::BaseLineTestInstance (Context&					context,
1097 											VkPrimitiveTopology			primitiveTopology,
1098 											PrimitiveWideness			wideness,
1099 											PrimitiveStrictness			strictness,
1100 											VkSampleCountFlagBits		sampleCount,
1101 											LineStipple					stipple,
1102 											VkLineRasterizationModeEXT	lineRasterizationMode,
1103 											const deUint32				additionalRenderSize,
1104 											const deUint32				renderSize,
1105 											const float					narrowLineWidth)
1106 	: BaseRenderingTestInstance	(context, sampleCount, renderSize, VK_FORMAT_R8G8B8A8_UNORM, additionalRenderSize)
1107 	, m_iteration				(0)
1108 	, m_iterationCount			(3)
1109 	, m_primitiveTopology		(primitiveTopology)
1110 	, m_primitiveWideness		(wideness)
1111 	, m_primitiveStrictness		(strictness)
1112 	, m_allIterationsPassed		(true)
1113 	, m_qualityWarning			(false)
1114 	, m_maxLineWidth			(1.0f)
1115 	, m_stipple					(stipple)
1116 	, m_lineRasterizationMode	(lineRasterizationMode)
1117 {
1118 	DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
1119 
1120 	m_lineRasterizationStateInfo = initLineRasterizationStateCreateInfo();
1121 
1122 	if (m_lineRasterizationMode != VK_LINE_RASTERIZATION_MODE_EXT_LAST)
1123 	{
1124 		if (context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"))
1125 		{
1126 			VkPhysicalDeviceLineRasterizationPropertiesEXT lineRasterizationProperties =
1127 			{
1128 				VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES_EXT,	// VkStructureType	sType;
1129 				DE_NULL,																// void*			pNext;
1130 				0u,																		// deUint32			lineSubPixelPrecisionBits;
1131 			};
1132 
1133 			VkPhysicalDeviceProperties2 deviceProperties2;
1134 			deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
1135 			deviceProperties2.pNext = &lineRasterizationProperties;
1136 
1137 			context.getInstanceInterface().getPhysicalDeviceProperties2(m_context.getPhysicalDevice(), &deviceProperties2);
1138 
1139 			m_subpixelBits = lineRasterizationProperties.lineSubPixelPrecisionBits;
1140 		}
1141 	}
1142 
1143 	// create line widths
1144 	if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1145 	{
1146 		m_lineWidths.resize(m_iterationCount, narrowLineWidth);
1147 
1148 		// Bump up m_maxLineWidth for conservative rasterization
1149 		if (narrowLineWidth > m_maxLineWidth)
1150 			m_maxLineWidth = narrowLineWidth;
1151 	}
1152 	else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1153 	{
1154 		const float*	range = context.getDeviceProperties().limits.lineWidthRange;
1155 
1156 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1157 
1158 		DE_ASSERT(range[1] > 1.0f);
1159 
1160 		// set hand picked sizes
1161 		m_lineWidths.push_back(5.0f);
1162 		m_lineWidths.push_back(10.0f);
1163 
1164 		// Do not pick line width with 0.5 fractional value as rounding direction is not defined.
1165 		if (deFloatFrac(range[1]) == 0.5f)
1166 		{
1167 			m_lineWidths.push_back(range[1] - context.getDeviceProperties().limits.lineWidthGranularity);
1168 		}
1169 		else
1170 		{
1171 			m_lineWidths.push_back(range[1]);
1172 		}
1173 
1174 		DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
1175 
1176 		m_maxLineWidth = range[1];
1177 	}
1178 	else
1179 		DE_ASSERT(false);
1180 
1181 	// Create image, image view and frame buffer for testing at an additional resolution if required.
1182 	if (m_additionalRenderSize != 0)
1183 	{
1184 		const DeviceInterface&						vkd						= m_context.getDeviceInterface();
1185 		const VkDevice								vkDevice				= m_context.getDevice();
1186 		const deUint32								queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();
1187 		Allocator&									allocator				= m_context.getDefaultAllocator();
1188 		DescriptorPoolBuilder						descriptorPoolBuilder;
1189 		DescriptorSetLayoutBuilder					descriptorSetLayoutBuilder;
1190 		{
1191 			const VkImageUsageFlags	imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
1192 			const VkImageCreateInfo					imageCreateInfo			=
1193 			{
1194 				VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			sType;
1195 				DE_NULL,									// const void*				pNext;
1196 				0u,											// VkImageCreateFlags		flags;
1197 				VK_IMAGE_TYPE_2D,							// VkImageType				imageType;
1198 				m_imageFormat,								// VkFormat					format;
1199 				{ m_additionalRenderSize, m_additionalRenderSize, 1u },			// VkExtent3D				extent;
1200 				1u,											// deUint32					mipLevels;
1201 				1u,											// deUint32					arrayLayers;
1202 				m_sampleCount,								// VkSampleCountFlagBits	samples;
1203 				VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling;
1204 				imageUsage,									// VkImageUsageFlags		usage;
1205 				VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode;
1206 				1u,											// deUint32					queueFamilyIndexCount;
1207 				&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices;
1208 				VK_IMAGE_LAYOUT_UNDEFINED					// VkImageLayout			initialLayout;
1209 			};
1210 
1211 			m_additionalImage = vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
1212 
1213 			m_additionalImageMemory	= allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_additionalImage), MemoryRequirement::Any);
1214 			VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalImage, m_additionalImageMemory->getMemory(), m_additionalImageMemory->getOffset()));
1215 		}
1216 
1217 		// Image View
1218 		{
1219 			const VkImageViewCreateInfo				imageViewCreateInfo		=
1220 			{
1221 				VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType				sType;
1222 				DE_NULL,									// const void*					pNext;
1223 				0u,											// VkImageViewCreateFlags		flags;
1224 				*m_additionalImage,							// VkImage						image;
1225 				VK_IMAGE_VIEW_TYPE_2D,						// VkImageViewType				viewType;
1226 				m_imageFormat,								// VkFormat						format;
1227 				makeComponentMappingRGBA(),					// VkComponentMapping			components;
1228 				{
1229 					VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags			aspectMask;
1230 					0u,											// deUint32						baseMipLevel;
1231 					1u,											// deUint32						mipLevels;
1232 					0u,											// deUint32						baseArrayLayer;
1233 					1u,											// deUint32						arraySize;
1234 				},											// VkImageSubresourceRange		subresourceRange;
1235 			};
1236 
1237 			m_additionalImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
1238 		}
1239 
1240 		if (m_multisampling)
1241 		{
1242 			{
1243 				const VkImageUsageFlags	imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
1244 				const VkImageCreateInfo					imageCreateInfo			=
1245 				{
1246 					VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,		// VkStructureType			sType;
1247 					DE_NULL,									// const void*				pNext;
1248 					0u,											// VkImageCreateFlags		flags;
1249 					VK_IMAGE_TYPE_2D,							// VkImageType				imageType;
1250 					m_imageFormat,								// VkFormat					format;
1251 					{ m_additionalRenderSize,	m_additionalRenderSize, 1u },			// VkExtent3D				extent;
1252 					1u,											// deUint32					mipLevels;
1253 					1u,											// deUint32					arrayLayers;
1254 					VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits	samples;
1255 					VK_IMAGE_TILING_OPTIMAL,					// VkImageTiling			tiling;
1256 					imageUsage,									// VkImageUsageFlags		usage;
1257 					VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode			sharingMode;
1258 					1u,											// deUint32					queueFamilyIndexCount;
1259 					&queueFamilyIndex,							// const deUint32*			pQueueFamilyIndices;
1260 					VK_IMAGE_LAYOUT_UNDEFINED					// VkImageLayout			initialLayout;
1261 				};
1262 
1263 				m_additionalResolvedImage			= vk::createImage(vkd, vkDevice, &imageCreateInfo, DE_NULL);
1264 				m_additionalResolvedImageMemory	= allocator.allocate(getImageMemoryRequirements(vkd, vkDevice, *m_additionalResolvedImage), MemoryRequirement::Any);
1265 				VK_CHECK(vkd.bindImageMemory(vkDevice, *m_additionalResolvedImage, m_additionalResolvedImageMemory->getMemory(), m_additionalResolvedImageMemory->getOffset()));
1266 			}
1267 
1268 			// Image view
1269 			{
1270 				const VkImageViewCreateInfo				imageViewCreateInfo		=
1271 				{
1272 					VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,	// VkStructureType				sType;
1273 					DE_NULL,									// const void*					pNext;
1274 					0u,											// VkImageViewCreateFlags		flags;
1275 					*m_additionalResolvedImage,					// VkImage						image;
1276 					VK_IMAGE_VIEW_TYPE_2D,						// VkImageViewType				viewType;
1277 					m_imageFormat,								// VkFormat						format;
1278 					makeComponentMappingRGBA(),					// VkComponentMapping			components;
1279 					{
1280 						VK_IMAGE_ASPECT_COLOR_BIT,					// VkImageAspectFlags			aspectMask;
1281 						0u,											// deUint32						baseMipLevel;
1282 						1u,											// deUint32						mipLevels;
1283 						0u,											// deUint32						baseArrayLayer;
1284 						1u,											// deUint32						arraySize;
1285 					},											// VkImageSubresourceRange		subresourceRange;
1286 				};
1287 				m_additionalResolvedImageView = vk::createImageView(vkd, vkDevice, &imageViewCreateInfo, DE_NULL);
1288 			}
1289 		}
1290 
1291 		{
1292 			const VkImageView						attachments[]			=
1293 			{
1294 				*m_additionalImageView,
1295 				*m_additionalResolvedImageView
1296 			};
1297 
1298 			const VkFramebufferCreateInfo			framebufferCreateInfo	=
1299 			{
1300 				VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	// VkStructureType			sType;
1301 				DE_NULL,									// const void*				pNext;
1302 				0u,											// VkFramebufferCreateFlags	flags;
1303 				*m_renderPass,								// VkRenderPass				renderPass;
1304 				m_multisampling ? 2u : 1u,					// deUint32					attachmentCount;
1305 				attachments,								// const VkImageView*		pAttachments;
1306 				m_additionalRenderSize,						// deUint32					width;
1307 				m_additionalRenderSize,						// deUint32					height;
1308 				1u,											// deUint32					layers;
1309 			};
1310 			m_additionalFrameBuffer = createFramebuffer(vkd, vkDevice, &framebufferCreateInfo, DE_NULL);
1311 		}
1312 
1313 		// Framebuffer
1314 		{
1315 			const VkBufferCreateInfo				bufferCreateInfo		=
1316 			{
1317 				VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,		// VkStructureType		sType;
1318 				DE_NULL,									// const void*			pNext;
1319 				0u,											// VkBufferCreateFlags	flags;
1320 				m_additionalResultBufferSize,							// VkDeviceSize			size;
1321 				VK_BUFFER_USAGE_TRANSFER_DST_BIT,			// VkBufferUsageFlags	usage;
1322 				VK_SHARING_MODE_EXCLUSIVE,					// VkSharingMode		sharingMode;
1323 				1u,											// deUint32				queueFamilyIndexCount;
1324 				&queueFamilyIndex							// const deUint32*		pQueueFamilyIndices;
1325 			};
1326 
1327 			m_additionalResultBuffer			= createBuffer(vkd, vkDevice, &bufferCreateInfo);
1328 			m_additionalResultBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *m_additionalResultBuffer), MemoryRequirement::HostVisible);
1329 
1330 			VK_CHECK(vkd.bindBufferMemory(vkDevice, *m_additionalResultBuffer, m_additionalResultBufferMemory->getMemory(), m_additionalResultBufferMemory->getOffset()));
1331 		}
1332 	}
1333 }
1334 
resultHasAlpha(tcu::Surface & resultImage)1335 bool BaseLineTestInstance::resultHasAlpha(tcu::Surface& resultImage)
1336 {
1337 	bool hasAlpha = false;
1338 	for (int y = 0; y < resultImage.getHeight() && !hasAlpha; ++y)
1339 	for (int x = 0; x < resultImage.getWidth(); ++x)
1340 	{
1341 		const tcu::RGBA		color				= resultImage.getPixel(x, y);
1342 		if (color.getAlpha() > 0 && color.getAlpha() < 0xFF)
1343 		{
1344 			hasAlpha = true;
1345 			break;
1346 		}
1347 	}
1348 	return hasAlpha;
1349 }
1350 
iterate(void)1351 tcu::TestStatus BaseLineTestInstance::iterate (void)
1352 {
1353 	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1354 	const tcu::ScopedLogSection				section					(m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
1355 	const float								lineWidth				= getLineWidth();
1356 	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
1357 	std::vector<tcu::Vec4>					drawBuffer;
1358 	std::vector<LineSceneSpec::SceneLine>	lines;
1359 
1360 	// supported?
1361 	if (lineWidth <= m_maxLineWidth)
1362 	{
1363 		// gen data
1364 		generateLines(m_iteration, drawBuffer, lines);
1365 
1366 		// draw image
1367 		drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
1368 
1369 		// compare
1370 		{
1371 			const bool compareOk = compareAndVerify(lines, resultImage, drawBuffer);
1372 
1373 			if (!compareOk)
1374 				m_allIterationsPassed = false;
1375 		}
1376 	}
1377 	else
1378 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
1379 
1380 	// result
1381 	if (++m_iteration == m_iterationCount)
1382 	{
1383 		if (!m_allIterationsPassed)
1384 			return tcu::TestStatus::fail("Incorrect rasterization");
1385 		else if (m_qualityWarning)
1386 			return tcu::TestStatus(QP_TEST_RESULT_QUALITY_WARNING, "Low-quality line rasterization");
1387 		else
1388 			return tcu::TestStatus::pass("Pass");
1389 	}
1390 	else
1391 		return tcu::TestStatus::incomplete();
1392 }
1393 
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)1394 bool BaseLineTestInstance::compareAndVerify (std::vector<LineSceneSpec::SceneLine>&	lines, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
1395 {
1396 	const float				lineWidth				= getLineWidth();
1397 	bool					result					= true;
1398 	tcu::Surface			additionalResultImage	(m_additionalRenderSize, m_additionalRenderSize);
1399 	RasterizationArguments	args;
1400 	LineSceneSpec			scene;
1401 	tcu::IVec4				colorBits	= tcu::getTextureFormatBitDepth(getTextureFormat());
1402 	bool					strict		= m_primitiveStrictness == PRIMITIVESTRICTNESS_STRICT;
1403 
1404 	args.numSamples		= m_multisampling ? 1 : 0;
1405 	args.subpixelBits	= m_subpixelBits;
1406 	args.redBits		= colorBits[0];
1407 	args.greenBits		= colorBits[1];
1408 	args.blueBits		= colorBits[2];
1409 
1410 	scene.lines.swap(lines);
1411 	scene.lineWidth = lineWidth;
1412 	scene.stippleEnable = getLineStippleEnable();
1413 	scene.stippleFactor = getLineStippleEnable() ? lineStippleFactor : 1;
1414 	scene.stipplePattern = getLineStippleEnable() ? lineStipplePattern : 0xFFFF;
1415 	scene.isStrip = m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
1416 	scene.isSmooth = m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
1417 
1418 	// Choose verification mode. Smooth lines assume mostly over-rasterization (bloated lines with a falloff).
1419 	// Stippled lines lose some precision across segments in a strip, so need a weaker threshold than normal
1420 	// lines. For simple cases, check for an exact match (STRICT).
1421 	if (scene.isSmooth)
1422 		scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
1423 	else if (scene.stippleEnable)
1424 		scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1425 	else
1426 		scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
1427 
1428 	if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT)
1429 	{
1430 		// bresenham is "no AA" in GL, so set numSamples to zero.
1431 		args.numSamples = 0;
1432 		if (!verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog()))
1433 			result = false;
1434 	}
1435 	else
1436 	{
1437 		if (scene.isSmooth)
1438 		{
1439 			// Smooth lines get the fractional coverage multiplied into the alpha component,
1440 			// so do a sanity check to validate that there is at least one pixel in the image
1441 			// with a fractional opacity.
1442 			bool hasAlpha = resultHasAlpha(resultImage);
1443 			if (!hasAlpha)
1444 			{
1445 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "Missing alpha transparency (failed)." << tcu::TestLog::EndMessage;
1446 				result = false;
1447 			}
1448 		}
1449 
1450 		if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
1451 		{
1452 			// Retry with weaker verification. If it passes, consider it a quality warning.
1453 			scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1454 			if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), false, strict))
1455 				result = false;
1456 			else
1457 				m_qualityWarning = true;
1458 		}
1459 
1460 		if (m_additionalRenderSize != 0)
1461 		{
1462 			const std::vector<tcu::Vec4> colorData(drawBuffer.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
1463 
1464 			if (scene.isSmooth)
1465 				scene.verificationMode = tcu::VERIFICATIONMODE_SMOOTH;
1466 			else if (scene.stippleEnable)
1467 				scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1468 			else
1469 				scene.verificationMode = tcu::VERIFICATIONMODE_STRICT;
1470 
1471 			drawPrimitives(additionalResultImage, drawBuffer, colorData, m_primitiveTopology, *m_additionalImage, *m_additionalResolvedImage, *m_additionalFrameBuffer, m_additionalRenderSize, *m_additionalResultBuffer, *m_additionalResultBufferMemory);
1472 
1473 			// Compare
1474 			if (!verifyRelaxedLineGroupRasterization(additionalResultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
1475 			{
1476 				if (strict)
1477 				{
1478 					result = false;
1479 				}
1480 				else
1481 				{
1482 					// Retry with weaker verification. If it passes, consider it a quality warning.
1483 					scene.verificationMode = tcu::VERIFICATIONMODE_WEAKER;
1484 					if (!verifyRelaxedLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), (0 == m_multisampling), strict))
1485 						result = false;
1486 					else
1487 						m_qualityWarning = true;
1488 				}
1489 			}
1490 		}
1491 	}
1492 
1493 	return result;
1494 }
1495 
getLineWidth(void) const1496 float BaseLineTestInstance::getLineWidth (void) const
1497 {
1498 	return m_lineWidths[m_iteration];
1499 }
1500 
initLineRasterizationStateCreateInfo(void) const1501 VkPipelineRasterizationLineStateCreateInfoEXT BaseLineTestInstance::initLineRasterizationStateCreateInfo (void) const
1502 {
1503 	VkPipelineRasterizationLineStateCreateInfoEXT lineRasterizationStateInfo	=
1504 	{
1505 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT,	// VkStructureType				sType;
1506 		DE_NULL,																// const void*					pNext;
1507 		m_lineRasterizationMode,												// VkLineRasterizationModeEXT	lineRasterizationMode;
1508 		getLineStippleEnable() ? VK_TRUE : VK_FALSE,							// VkBool32						stippledLineEnable;
1509 		1,																		// uint32_t						lineStippleFactor;
1510 		0xFFFF,																	// uint16_t						lineStipplePattern;
1511 	};
1512 
1513 	if (m_stipple == LINESTIPPLE_STATIC)
1514 	{
1515 		lineRasterizationStateInfo.lineStippleFactor = lineStippleFactor;
1516 		lineRasterizationStateInfo.lineStipplePattern = lineStipplePattern;
1517 	}
1518 
1519 	return lineRasterizationStateInfo;
1520 }
1521 
getLineRasterizationStateCreateInfo(void) const1522 const VkPipelineRasterizationLineStateCreateInfoEXT* BaseLineTestInstance::getLineRasterizationStateCreateInfo (void) const
1523 {
1524 	if (m_lineRasterizationMode == VK_LINE_RASTERIZATION_MODE_EXT_LAST)
1525 		return DE_NULL;
1526 
1527 	return &m_lineRasterizationStateInfo;
1528 }
1529 
1530 class PointTestInstance : public BaseRenderingTestInstance
1531 {
1532 public:
1533 							PointTestInstance		(Context&					context,
1534 													 PrimitiveWideness			wideness,
1535 													 PrimitiveStrictness		strictness,				// ignored
1536 													 VkSampleCountFlagBits		sampleCount,
1537 													 LineStipple				stipple,				// ignored
1538 													 VkLineRasterizationModeEXT	lineRasterizationMode,	// ignored
1539 													 deUint32					additionalRenderSize,	// ignored
1540 													 deUint32					renderSize				= RESOLUTION_POT,
1541 													 float						pointSizeNarrow			= 1.0f);
1542 	virtual tcu::TestStatus	iterate					(void);
1543 	virtual float			getPointSize			(void) const;
1544 
1545 protected:
getIteration(void) const1546 	int						getIteration				(void) const	{ return m_iteration;		}
getIterationCount(void) const1547 	int						getIterationCount			(void) const	{ return m_iterationCount;	}
1548 
1549 private:
1550 	virtual void			generatePoints			(int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints);
1551 	virtual bool			compareAndVerify		(std::vector<PointSceneSpec::ScenePoint>&	points,
1552 													 tcu::Surface&								resultImage,
1553 													 std::vector<tcu::Vec4>&					drawBuffer);
1554 
1555 	int						m_iteration;
1556 	const int				m_iterationCount;
1557 	const PrimitiveWideness	m_primitiveWideness;
1558 	bool					m_allIterationsPassed;
1559 	float					m_maxPointSize;
1560 	std::vector<float>		m_pointSizes;
1561 };
1562 
PointTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,deUint32 additionalRenderSize,deUint32 renderSize,float pointSizeNarrow)1563 PointTestInstance::PointTestInstance (Context&						context,
1564 									  PrimitiveWideness				wideness,
1565 									  PrimitiveStrictness			strictness,
1566 									  VkSampleCountFlagBits			sampleCount,
1567 									  LineStipple					stipple,
1568 									  VkLineRasterizationModeEXT	lineRasterizationMode,
1569 									  deUint32						additionalRenderSize,
1570 									  deUint32						renderSize,
1571 									  float							pointSizeNarrow)
1572 	: BaseRenderingTestInstance	(context, sampleCount, renderSize)
1573 	, m_iteration				(0)
1574 	, m_iterationCount			(3)
1575 	, m_primitiveWideness		(wideness)
1576 	, m_allIterationsPassed		(true)
1577 	, m_maxPointSize			(pointSizeNarrow)
1578 {
1579 	DE_UNREF(strictness);
1580 	DE_UNREF(stipple);
1581 	DE_UNREF(lineRasterizationMode);
1582 	DE_UNREF(additionalRenderSize);
1583 
1584 	// create point sizes
1585 	if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
1586 	{
1587 		m_pointSizes.resize(m_iterationCount, pointSizeNarrow);
1588 	}
1589 	else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
1590 	{
1591 		const float*	range = context.getDeviceProperties().limits.pointSizeRange;
1592 
1593 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "GL_ALIASED_POINT_SIZE_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
1594 
1595 		DE_ASSERT(range[1] > 1.0f);
1596 
1597 		// set hand picked sizes
1598 		m_pointSizes.push_back(10.0f);
1599 		m_pointSizes.push_back(25.0f);
1600 		m_pointSizes.push_back(range[1]);
1601 		DE_ASSERT((int)m_pointSizes.size() == m_iterationCount);
1602 
1603 		m_maxPointSize = range[1];
1604 	}
1605 	else
1606 		DE_ASSERT(false);
1607 }
1608 
iterate(void)1609 tcu::TestStatus PointTestInstance::iterate (void)
1610 {
1611 	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
1612 	const tcu::ScopedLogSection				section					(m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
1613 	const float								pointSize				= getPointSize();
1614 	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
1615 	std::vector<tcu::Vec4>					drawBuffer;
1616 	std::vector<PointSceneSpec::ScenePoint>	points;
1617 
1618 	// supported?
1619 	if (pointSize <= m_maxPointSize)
1620 	{
1621 		// gen data
1622 		generatePoints(m_iteration, drawBuffer, points);
1623 
1624 		// draw image
1625 		drawPrimitives(resultImage, drawBuffer, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
1626 
1627 		// compare
1628 		{
1629 			const bool compareOk = compareAndVerify(points, resultImage, drawBuffer);
1630 
1631 			if (!compareOk)
1632 				m_allIterationsPassed = false;
1633 		}
1634 	}
1635 	else
1636 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point size " << pointSize << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
1637 
1638 	// result
1639 	if (++m_iteration == m_iterationCount)
1640 	{
1641 		if (m_allIterationsPassed)
1642 			return tcu::TestStatus::pass("Pass");
1643 		else
1644 			return tcu::TestStatus::fail("Incorrect rasterization");
1645 	}
1646 	else
1647 		return tcu::TestStatus::incomplete();
1648 }
1649 
compareAndVerify(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)1650 bool PointTestInstance::compareAndVerify (std::vector<PointSceneSpec::ScenePoint>&	points,
1651 										  tcu::Surface&								resultImage,
1652 										  std::vector<tcu::Vec4>&					drawBuffer)
1653 {
1654 	RasterizationArguments	args;
1655 	PointSceneSpec			scene;
1656 
1657 	tcu::IVec4				colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
1658 
1659 	args.numSamples		= m_multisampling ? 1 : 0;
1660 	args.subpixelBits	= m_subpixelBits;
1661 	args.redBits		= colorBits[0];
1662 	args.greenBits		= colorBits[1];
1663 	args.blueBits		= colorBits[2];
1664 
1665 	scene.points.swap(points);
1666 
1667 	DE_UNREF(drawBuffer);
1668 
1669 	return verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
1670 }
1671 
getPointSize(void) const1672 float PointTestInstance::getPointSize (void) const
1673 {
1674 	return m_pointSizes[m_iteration];
1675 }
1676 
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)1677 void PointTestInstance::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
1678 {
1679 	outData.resize(6);
1680 
1681 	switch (iteration)
1682 	{
1683 		case 0:
1684 			// \note: these values are chosen arbitrarily
1685 			outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
1686 			outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
1687 			outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
1688 			outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
1689 			outData[4] = tcu::Vec4(-0.2f, -0.4f, 0.0f, 1.0f);
1690 			outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
1691 			break;
1692 
1693 		case 1:
1694 			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
1695 			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
1696 			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
1697 			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
1698 			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
1699 			outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
1700 			break;
1701 
1702 		case 2:
1703 			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
1704 			outData[1] = tcu::Vec4(  0.3f, -0.9f, 0.0f, 1.0f);
1705 			outData[2] = tcu::Vec4( -0.4f, -0.1f, 0.0f, 1.0f);
1706 			outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
1707 			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
1708 			outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
1709 			break;
1710 	}
1711 
1712 	outPoints.resize(outData.size());
1713 	for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
1714 	{
1715 		outPoints[pointNdx].position = outData[pointNdx];
1716 		outPoints[pointNdx].pointSize = getPointSize();
1717 	}
1718 
1719 	// log
1720 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outPoints.size() << " point(s): (point size = " << getPointSize() << ")" << tcu::TestLog::EndMessage;
1721 	for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
1722 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Point " << (pointNdx+1) << ":\t" << outPoints[pointNdx].position << tcu::TestLog::EndMessage;
1723 }
1724 
1725 template <typename ConcreteTestInstance>
1726 class PointSizeTestCase : public BaseRenderingTestCase
1727 {
1728 public:
PointSizeTestCase(tcu::TestContext & context,std::string & name,std::string & description,deUint32 renderSize,float pointSize,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)1729 							PointSizeTestCase	(tcu::TestContext&		context,
1730 												 std::string&			name,
1731 												 std::string&			description,
1732 												 deUint32				renderSize,
1733 												 float					pointSize,
1734 												 VkSampleCountFlagBits	sampleCount = VK_SAMPLE_COUNT_1_BIT)
1735 								: BaseRenderingTestCase (context, name, description, sampleCount)
1736 								, m_pointSize	(pointSize)
1737 								, m_renderSize	(renderSize)
1738 							{}
1739 
createInstance(Context & context) const1740 	virtual TestInstance*	createInstance		(Context& context) const
1741 							{
1742 								VkPhysicalDeviceProperties	properties	(context.getDeviceProperties());
1743 
1744 								if (m_renderSize > properties.limits.maxViewportDimensions[0] || m_renderSize > properties.limits.maxViewportDimensions[1])
1745 									TCU_THROW(NotSupportedError , "Viewport dimensions not supported");
1746 
1747 								if (m_renderSize > properties.limits.maxFramebufferWidth || m_renderSize > properties.limits.maxFramebufferHeight)
1748 									TCU_THROW(NotSupportedError , "Framebuffer width/height not supported");
1749 
1750 								return new ConcreteTestInstance(context, m_renderSize, m_pointSize);
1751 							}
1752 
checkSupport(Context & context) const1753 	virtual	void			checkSupport		(Context& context) const
1754 							{
1755 								context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
1756 							}
1757 protected:
1758 	const float				m_pointSize;
1759 	const deUint32			m_renderSize;
1760 };
1761 
1762 class PointSizeTestInstance : public BaseRenderingTestInstance
1763 {
1764 public:
1765 							PointSizeTestInstance	(Context& context, deUint32 renderSize, float pointSize);
1766 	virtual tcu::TestStatus	iterate					(void);
1767 	virtual float			getPointSize			(void) const;
1768 
1769 private:
1770 	void					generatePointData		(PointSceneSpec::ScenePoint& outPoint);
1771 	void					drawPoint				(tcu::PixelBufferAccess& result, tcu::PointSceneSpec::ScenePoint& point);
1772 	bool					verifyPoint				(tcu::TestLog& log, tcu::PixelBufferAccess& access, float pointSize);
1773 	bool					isPointSizeClamped		(float pointSize, float maxPointSizeLimit);
1774 
1775 	const float				m_pointSize;
1776 	const float				m_maxPointSize;
1777 	const deUint32			m_renderSize;
1778 	const VkFormat			m_format;
1779 };
1780 
PointSizeTestInstance(Context & context,deUint32 renderSize,float pointSize)1781 PointSizeTestInstance::PointSizeTestInstance (Context& context, deUint32 renderSize, float pointSize)
1782 	: BaseRenderingTestInstance	(context, vk::VK_SAMPLE_COUNT_1_BIT, renderSize, VK_FORMAT_R8_UNORM)
1783 	, m_pointSize				(pointSize)
1784 	, m_maxPointSize			(context.getDeviceProperties().limits.pointSizeRange[1])
1785 	, m_renderSize				(renderSize)
1786 	, m_format					(VK_FORMAT_R8_UNORM) // Use single-channel format to minimize memory allocation when using large render targets
1787 {
1788 }
1789 
iterate(void)1790 tcu::TestStatus PointSizeTestInstance::iterate (void)
1791 {
1792 	tcu::TextureLevel			resultBuffer	(mapVkFormat(m_format), m_renderSize, m_renderSize);
1793 	tcu::PixelBufferAccess		access			(resultBuffer.getAccess());
1794 	PointSceneSpec::ScenePoint	point;
1795 
1796 	// Generate data
1797 	generatePointData(point);
1798 
1799 	// Draw
1800 	drawPoint(access, point);
1801 
1802 	// Compare
1803 	{
1804 		// pointSize must either be specified pointSize or clamped to device limit pointSizeRange[1]
1805 		const float	pointSize	(deFloatMin(m_pointSize, m_maxPointSize));
1806 		const bool	compareOk	(verifyPoint(m_context.getTestContext().getLog(), access, pointSize));
1807 
1808 		// Result
1809 		if (compareOk)
1810 			return isPointSizeClamped(pointSize, m_maxPointSize) ? tcu::TestStatus::pass("Pass, pointSize clamped to pointSizeRange[1]") : tcu::TestStatus::pass("Pass");
1811 		else
1812 			return tcu::TestStatus::fail("Incorrect rasterization");
1813 	}
1814 }
1815 
getPointSize(void) const1816 float PointSizeTestInstance::getPointSize (void) const
1817 {
1818 	return m_pointSize;
1819 }
1820 
generatePointData(PointSceneSpec::ScenePoint & outPoint)1821 void PointSizeTestInstance::generatePointData (PointSceneSpec::ScenePoint& outPoint)
1822 {
1823 	const tcu::PointSceneSpec::ScenePoint point =
1824 	{
1825 		tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f),	// position
1826 		tcu::Vec4(1.0f, 0.0f, 0.0f, 0.0f),	// color
1827 		m_pointSize							// pointSize
1828 	};
1829 
1830 	outPoint = point;
1831 
1832 	// log
1833 	{
1834 		tcu::TestLog& log = m_context.getTestContext().getLog();
1835 
1836 		log << tcu::TestLog::Message << "Point position: "	<< de::toString(point.position)		<< tcu::TestLog::EndMessage;
1837 		log << tcu::TestLog::Message << "Point color: "		<< de::toString(point.color)		<< tcu::TestLog::EndMessage;
1838 		log << tcu::TestLog::Message << "Point size: "		<< de::toString(point.pointSize)	<< tcu::TestLog::EndMessage;
1839 		log << tcu::TestLog::Message << "Render size: "		<< de::toString(m_renderSize)		<< tcu::TestLog::EndMessage;
1840 		log << tcu::TestLog::Message << "Format: "			<< de::toString(m_format)			<< tcu::TestLog::EndMessage;
1841 	}
1842 }
1843 
drawPoint(tcu::PixelBufferAccess & result,PointSceneSpec::ScenePoint & point)1844 void PointSizeTestInstance::drawPoint (tcu::PixelBufferAccess& result, PointSceneSpec::ScenePoint& point)
1845 {
1846 	const tcu::Vec4			positionData		(point.position);
1847 	const tcu::Vec4			colorData			(point.color);
1848 
1849 	const DeviceInterface&	vkd					(m_context.getDeviceInterface());
1850 	const VkDevice			vkDevice			(m_context.getDevice());
1851 	const VkQueue			queue				(m_context.getUniversalQueue());
1852 	const deUint32			queueFamilyIndex	(m_context.getUniversalQueueFamilyIndex());
1853 	const size_t			attributeBatchSize	(sizeof(tcu::Vec4));
1854 	Allocator&				allocator			(m_context.getDefaultAllocator());
1855 
1856 	Move<VkCommandBuffer>	commandBuffer;
1857 	Move<VkPipeline>		graphicsPipeline;
1858 	Move<VkBuffer>			vertexBuffer;
1859 	de::MovePtr<Allocation>	vertexBufferMemory;
1860 
1861 	// Create Graphics Pipeline
1862 	{
1863 		const std::vector<VkViewport>				viewports							(1, makeViewport(tcu::UVec2(m_renderSize)));
1864 		const std::vector<VkRect2D>					scissors							(1, makeRect2D(tcu::UVec2(m_renderSize)));
1865 
1866 		const VkVertexInputBindingDescription		vertexInputBindingDescription		=
1867 		{
1868 			0u,									// deUint32					binding;
1869 			(deUint32)(2 * sizeof(tcu::Vec4)),	// deUint32					strideInBytes;
1870 			VK_VERTEX_INPUT_RATE_VERTEX			// VkVertexInputStepRate	stepRate;
1871 		};
1872 
1873 		const VkVertexInputAttributeDescription		vertexInputAttributeDescriptions[2]	=
1874 		{
1875 			{
1876 				0u,								// deUint32	location;
1877 				0u,								// deUint32	binding;
1878 				VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat	format;
1879 				0u								// deUint32	offsetInBytes;
1880 			},
1881 			{
1882 				1u,								// deUint32	location;
1883 				0u,								// deUint32	binding;
1884 				VK_FORMAT_R32G32B32A32_SFLOAT,	// VkFormat	format;
1885 				(deUint32)sizeof(tcu::Vec4)		// deUint32	offsetInBytes;
1886 			}
1887 		};
1888 
1889 		const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams				=
1890 		{
1891 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType							sType;
1892 			DE_NULL,													// const void*								pNext;
1893 			0,															// VkPipelineVertexInputStateCreateFlags	flags;
1894 			1u,															// deUint32									bindingCount;
1895 			&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
1896 			2u,															// deUint32									attributeCount;
1897 			vertexInputAttributeDescriptions							// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
1898 		};
1899 
1900 		graphicsPipeline = makeGraphicsPipeline(vkd,								// const DeviceInterface&							 vk
1901 												vkDevice,							// const VkDevice									 device
1902 												*m_pipelineLayout,					// const VkPipelineLayout							 pipelineLayout
1903 												*m_vertexShaderModule,				// const VkShaderModule								 vertexShaderModule
1904 												DE_NULL,							// const VkShaderModule								 tessellationControlShaderModule
1905 												DE_NULL,							// const VkShaderModule								 tessellationEvalShaderModule
1906 												DE_NULL,							// const VkShaderModule								 geometryShaderModule
1907 												*m_fragmentShaderModule,			// const VkShaderModule								 fragmentShaderModule
1908 												*m_renderPass,						// const VkRenderPass								 renderPass
1909 												viewports,							// const std::vector<VkViewport>&					 viewports
1910 												scissors,							// const std::vector<VkRect2D>&						 scissors
1911 												VK_PRIMITIVE_TOPOLOGY_POINT_LIST,	// const VkPrimitiveTopology						 topology
1912 												0u,									// const deUint32									 subpass
1913 												0u,									// const deUint32									 patchControlPoints
1914 												&vertexInputStateParams,			// const VkPipelineVertexInputStateCreateInfo*		 vertexInputStateCreateInfo
1915 												getRasterizationStateCreateInfo(),	// const VkPipelineRasterizationStateCreateInfo*	 rasterizationStateCreateInfo
1916 												DE_NULL,							// const VkPipelineMultisampleStateCreateInfo*		 multisampleStateCreateInfo
1917 												DE_NULL,							// const VkPipelineDepthStencilStateCreateInfo*		 depthStencilStateCreateInfo,
1918 												getColorBlendStateCreateInfo());	// const VkPipelineColorBlendStateCreateInfo*		 colorBlendStateCreateInfo
1919 	}
1920 
1921 	// Create Vertex Buffer
1922 	{
1923 		const VkBufferCreateInfo	vertexBufferParams =
1924 		{
1925 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
1926 			DE_NULL,								// const void*			pNext;
1927 			0u,										// VkBufferCreateFlags	flags;
1928 			attributeBatchSize * 2,					// VkDeviceSize			size;
1929 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
1930 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
1931 			1u,										// deUint32				queueFamilyCount;
1932 			&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
1933 		};
1934 
1935 		vertexBuffer		= createBuffer(vkd, vkDevice, &vertexBufferParams);
1936 		vertexBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
1937 
1938 		VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
1939 
1940 		// Load vertices into vertex buffer
1941 		deMemcpy(vertexBufferMemory->getHostPtr(), &positionData, attributeBatchSize);
1942 		deMemcpy(reinterpret_cast<deUint8*>(vertexBufferMemory->getHostPtr()) +  attributeBatchSize, &colorData, attributeBatchSize);
1943 		flushAlloc(vkd, vkDevice, *vertexBufferMemory);
1944 	}
1945 
1946 	// Create Command Buffer
1947 	commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1948 
1949 	// Begin Command Buffer
1950 	beginCommandBuffer(vkd, *commandBuffer);
1951 
1952 	addImageTransitionBarrier(*commandBuffer, *m_image,
1953 							  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,			// VkPipelineStageFlags		srcStageMask
1954 							  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,			// VkPipelineStageFlags		dstStageMask
1955 							  0,											// VkAccessFlags			srcAccessMask
1956 							  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags			dstAccessMask
1957 							  VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
1958 							  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);	// VkImageLayout			newLayout;
1959 
1960 	// Begin Render Pass
1961 	beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer, vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
1962 
1963 	const VkDeviceSize vertexBufferOffset = 0;
1964 
1965 	vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
1966 	vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1, &m_descriptorSet.get(), 0u, DE_NULL);
1967 	vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset);
1968 	vkd.cmdDraw(*commandBuffer, 1, 1, 0, 0);
1969 	endRenderPass(vkd, *commandBuffer);
1970 
1971 	// Copy Image
1972 	copyImageToBuffer(vkd, *commandBuffer, *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
1973 
1974 	endCommandBuffer(vkd, *commandBuffer);
1975 
1976 	// Set Point Size
1977 	{
1978 		float pointSize = getPointSize();
1979 
1980 		deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
1981 		flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
1982 	}
1983 
1984 	// Submit
1985 	submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
1986 
1987 	invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
1988 	tcu::copy(result, tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr()));
1989 }
1990 
verifyPoint(tcu::TestLog & log,tcu::PixelBufferAccess & image,float pointSize)1991 bool PointSizeTestInstance::verifyPoint (tcu::TestLog& log, tcu::PixelBufferAccess& image, float pointSize)
1992 {
1993 	const float	expectedPointColor				(1.0f);
1994 	const float	expectedBackgroundColor			(0.0f);
1995 	deUint32	pointWidth						(0u);
1996 	deUint32	pointHeight						(0u);
1997 	bool		incorrectlyColoredPixelsFound	(false);
1998 	bool		isOk							(true);
1999 
2000 	// Verify rasterized point width and color
2001 	for (size_t x = 0; x < (deUint32)image.getWidth(); x++)
2002 	{
2003 		float pixelColor = image.getPixel((deUint32)x, image.getHeight() / 2).x();
2004 
2005 		if (pixelColor == expectedPointColor)
2006 			pointWidth++;
2007 
2008 		if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
2009 			incorrectlyColoredPixelsFound = true;
2010 	}
2011 
2012 	// Verify rasterized point height and color
2013 	for (size_t y = 0; y < (deUint32)image.getHeight(); y++)
2014 	{
2015 		float pixelColor = image.getPixel((deUint32)y, image.getWidth() / 2).x();
2016 
2017 		if (pixelColor == expectedPointColor)
2018 			pointHeight++;
2019 
2020 		if ((pixelColor != expectedPointColor) && (pixelColor != expectedBackgroundColor))
2021 			incorrectlyColoredPixelsFound = true;
2022 	}
2023 
2024 	// Compare amount of rasterized point pixels to expected pointSize.
2025 	if ((pointWidth != (deUint32)deRoundFloatToInt32(pointSize)) || (pointHeight != (deUint32)deRoundFloatToInt32(pointSize)))
2026 	{
2027 		log << tcu::TestLog::Message << "Incorrect point size. Expected pointSize: " << de::toString(pointSize)
2028 			<< ". Rasterized point width: " << pointWidth << " pixels, height: "
2029 			<< pointHeight << " pixels." << tcu::TestLog::EndMessage;
2030 
2031 		isOk = false;
2032 	}
2033 
2034 	// Check incorrectly colored pixels
2035 	if (incorrectlyColoredPixelsFound)
2036 	{
2037 		log << tcu::TestLog::Message << "Incorrectly colored pixels found." << tcu::TestLog::EndMessage;
2038 		isOk = false;
2039 	}
2040 
2041 	return isOk;
2042 }
2043 
isPointSizeClamped(float pointSize,float maxPointSizeLimit)2044 bool PointSizeTestInstance::isPointSizeClamped (float pointSize, float maxPointSizeLimit)
2045 {
2046 	return (pointSize == maxPointSizeLimit);
2047 }
2048 
2049 template <typename ConcreteTestInstance>
2050 class BaseTestCase : public BaseRenderingTestCase
2051 {
2052 public:
BaseTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)2053 							BaseTestCase	(tcu::TestContext& context, const std::string& name, const std::string& description, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
2054 								: BaseRenderingTestCase(context, name, description, sampleCount)
2055 							{}
2056 
createInstance(Context & context) const2057 	virtual TestInstance*	createInstance	(Context& context) const
2058 							{
2059 								return new ConcreteTestInstance(context, m_sampleCount);
2060 							}
2061 };
2062 
2063 class TrianglesTestInstance : public BaseTriangleTestInstance
2064 {
2065 public:
TrianglesTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2066 							TrianglesTestInstance	(Context& context, VkSampleCountFlagBits sampleCount)
2067 								: BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, sampleCount)
2068 							{}
2069 
2070 	void					generateTriangles		(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
2071 };
2072 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2073 void TrianglesTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2074 {
2075 	outData.resize(6);
2076 
2077 	switch (iteration)
2078 	{
2079 		case 0:
2080 			// \note: these values are chosen arbitrarily
2081 			outData[0] = tcu::Vec4( 0.2f,  0.8f, 0.0f, 1.0f);
2082 			outData[1] = tcu::Vec4( 0.5f,  0.2f, 0.0f, 1.0f);
2083 			outData[2] = tcu::Vec4( 0.5f,  0.3f, 0.0f, 1.0f);
2084 			outData[3] = tcu::Vec4(-0.5f,  0.2f, 0.0f, 1.0f);
2085 			outData[4] = tcu::Vec4(-1.5f, -0.4f, 0.0f, 1.0f);
2086 			outData[5] = tcu::Vec4(-0.4f,  0.2f, 0.0f, 1.0f);
2087 			break;
2088 
2089 		case 1:
2090 			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
2091 			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
2092 			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
2093 			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
2094 			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
2095 			outData[5] = tcu::Vec4(   0.4f,   1.2f, 0.0f, 1.0f);
2096 			break;
2097 
2098 		case 2:
2099 			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
2100 			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
2101 			outData[2] = tcu::Vec4( -1.1f, -0.1f, 0.0f, 1.0f);
2102 			outData[3] = tcu::Vec4(-0.11f,  0.2f, 0.0f, 1.0f);
2103 			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
2104 			outData[5] = tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f);
2105 			break;
2106 	}
2107 
2108 	outTriangles.resize(2);
2109 	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
2110 	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = false;
2111 	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = false;
2112 
2113 	outTriangles[1].positions[0] = outData[3];	outTriangles[1].sharedEdge[0] = false;
2114 	outTriangles[1].positions[1] = outData[4];	outTriangles[1].sharedEdge[1] = false;
2115 	outTriangles[1].positions[2] = outData[5];	outTriangles[1].sharedEdge[2] = false;
2116 
2117 	// log
2118 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outTriangles.size() << " triangle(s):" << tcu::TestLog::EndMessage;
2119 	for (int triangleNdx = 0; triangleNdx < (int)outTriangles.size(); ++triangleNdx)
2120 	{
2121 		m_context.getTestContext().getLog()
2122 			<< tcu::TestLog::Message
2123 			<< "Triangle " << (triangleNdx+1) << ":"
2124 			<< "\n\t" << outTriangles[triangleNdx].positions[0]
2125 			<< "\n\t" << outTriangles[triangleNdx].positions[1]
2126 			<< "\n\t" << outTriangles[triangleNdx].positions[2]
2127 			<< tcu::TestLog::EndMessage;
2128 	}
2129 }
2130 
2131 class TriangleStripTestInstance : public BaseTriangleTestInstance
2132 {
2133 public:
TriangleStripTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2134 				TriangleStripTestInstance		(Context& context, VkSampleCountFlagBits sampleCount)
2135 					: BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, sampleCount)
2136 				{}
2137 
2138 	void		generateTriangles				(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
2139 };
2140 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2141 void TriangleStripTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2142 {
2143 	outData.resize(5);
2144 
2145 	switch (iteration)
2146 	{
2147 		case 0:
2148 			// \note: these values are chosen arbitrarily
2149 			outData[0] = tcu::Vec4(-0.504f,  0.8f,   0.0f, 1.0f);
2150 			outData[1] = tcu::Vec4(-0.2f,   -0.2f,   0.0f, 1.0f);
2151 			outData[2] = tcu::Vec4(-0.2f,    0.199f, 0.0f, 1.0f);
2152 			outData[3] = tcu::Vec4( 0.5f,    0.201f, 0.0f, 1.0f);
2153 			outData[4] = tcu::Vec4( 1.5f,    0.4f,   0.0f, 1.0f);
2154 			break;
2155 
2156 		case 1:
2157 			outData[0] = tcu::Vec4(-0.499f, 0.129f,  0.0f, 1.0f);
2158 			outData[1] = tcu::Vec4(-0.501f,  -0.3f,  0.0f, 1.0f);
2159 			outData[2] = tcu::Vec4(  0.11f,  -0.2f,  0.0f, 1.0f);
2160 			outData[3] = tcu::Vec4(  0.11f,  -0.31f, 0.0f, 1.0f);
2161 			outData[4] = tcu::Vec4(  0.88f,   0.9f,  0.0f, 1.0f);
2162 			break;
2163 
2164 		case 2:
2165 			outData[0] = tcu::Vec4( -0.9f, -0.3f,  0.0f, 1.0f);
2166 			outData[1] = tcu::Vec4(  1.1f, -0.9f,  0.0f, 1.0f);
2167 			outData[2] = tcu::Vec4(-0.87f, -0.1f,  0.0f, 1.0f);
2168 			outData[3] = tcu::Vec4(-0.11f,  0.19f, 0.0f, 1.0f);
2169 			outData[4] = tcu::Vec4( 0.88f,  0.7f,  0.0f, 1.0f);
2170 			break;
2171 	}
2172 
2173 	outTriangles.resize(3);
2174 	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
2175 	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = true;
2176 	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = false;
2177 
2178 	outTriangles[1].positions[0] = outData[2];	outTriangles[1].sharedEdge[0] = true;
2179 	outTriangles[1].positions[1] = outData[1];	outTriangles[1].sharedEdge[1] = false;
2180 	outTriangles[1].positions[2] = outData[3];	outTriangles[1].sharedEdge[2] = true;
2181 
2182 	outTriangles[2].positions[0] = outData[2];	outTriangles[2].sharedEdge[0] = true;
2183 	outTriangles[2].positions[1] = outData[3];	outTriangles[2].sharedEdge[1] = false;
2184 	outTriangles[2].positions[2] = outData[4];	outTriangles[2].sharedEdge[2] = false;
2185 
2186 	// log
2187 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle strip, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
2188 	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
2189 	{
2190 		m_context.getTestContext().getLog()
2191 			<< tcu::TestLog::Message
2192 			<< "\t" << outData[vtxNdx]
2193 			<< tcu::TestLog::EndMessage;
2194 	}
2195 }
2196 
2197 class TriangleFanTestInstance : public BaseTriangleTestInstance
2198 {
2199 public:
TriangleFanTestInstance(Context & context,VkSampleCountFlagBits sampleCount)2200 				TriangleFanTestInstance			(Context& context, VkSampleCountFlagBits sampleCount)
2201 					: BaseTriangleTestInstance(context, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, sampleCount)
2202 				{}
2203 
2204 	void		generateTriangles				(int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles);
2205 };
2206 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2207 void TriangleFanTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2208 {
2209 	outData.resize(5);
2210 
2211 	switch (iteration)
2212 	{
2213 		case 0:
2214 			// \note: these values are chosen arbitrarily
2215 			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
2216 			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
2217 			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
2218 			outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
2219 			outData[4] = tcu::Vec4(-1.5f,  -0.4f, 0.0f, 1.0f);
2220 			break;
2221 
2222 		case 1:
2223 			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
2224 			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
2225 			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
2226 			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
2227 			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
2228 			break;
2229 
2230 		case 2:
2231 			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
2232 			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
2233 			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
2234 			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
2235 			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
2236 			break;
2237 	}
2238 
2239 	outTriangles.resize(3);
2240 	outTriangles[0].positions[0] = outData[0];	outTriangles[0].sharedEdge[0] = false;
2241 	outTriangles[0].positions[1] = outData[1];	outTriangles[0].sharedEdge[1] = false;
2242 	outTriangles[0].positions[2] = outData[2];	outTriangles[0].sharedEdge[2] = true;
2243 
2244 	outTriangles[1].positions[0] = outData[0];	outTriangles[1].sharedEdge[0] = true;
2245 	outTriangles[1].positions[1] = outData[2];	outTriangles[1].sharedEdge[1] = false;
2246 	outTriangles[1].positions[2] = outData[3];	outTriangles[1].sharedEdge[2] = true;
2247 
2248 	outTriangles[2].positions[0] = outData[0];	outTriangles[2].sharedEdge[0] = true;
2249 	outTriangles[2].positions[1] = outData[3];	outTriangles[2].sharedEdge[1] = false;
2250 	outTriangles[2].positions[2] = outData[4];	outTriangles[2].sharedEdge[2] = false;
2251 
2252 	// log
2253 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering triangle fan, " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
2254 	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
2255 	{
2256 		m_context.getTestContext().getLog()
2257 			<< tcu::TestLog::Message
2258 			<< "\t" << outData[vtxNdx]
2259 			<< tcu::TestLog::EndMessage;
2260 	}
2261 }
2262 
2263 struct ConservativeTestConfig
2264 {
2265 	VkConservativeRasterizationModeEXT	conservativeRasterizationMode;
2266 	float								extraOverestimationSize;
2267 	VkPrimitiveTopology					primitiveTopology;
2268 	bool								degeneratePrimitives;
2269 	float								lineWidth;
2270 	deUint32							resolution;
2271 };
2272 
getExtraOverestimationSize(const float overestimationSizeDesired,const VkPhysicalDeviceConservativeRasterizationPropertiesEXT & conservativeRasterizationProperties)2273 float getExtraOverestimationSize (const float overestimationSizeDesired, const VkPhysicalDeviceConservativeRasterizationPropertiesEXT& conservativeRasterizationProperties)
2274 {
2275 	const float extraOverestimationSize	= overestimationSizeDesired == TCU_INFINITY ? conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize
2276 										: overestimationSizeDesired == -TCU_INFINITY ? conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity
2277 										: overestimationSizeDesired;
2278 
2279 	return extraOverestimationSize;
2280 }
2281 
2282 template <typename ConcreteTestInstance>
2283 class ConservativeTestCase : public BaseRenderingTestCase
2284 {
2285 public:
ConservativeTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,const ConservativeTestConfig & conservativeTestConfig,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)2286 									ConservativeTestCase		(tcu::TestContext&					context,
2287 																 const std::string&					name,
2288 																 const std::string&					description,
2289 																 const ConservativeTestConfig&		conservativeTestConfig,
2290 																 VkSampleCountFlagBits				sampleCount = VK_SAMPLE_COUNT_1_BIT)
2291 										: BaseRenderingTestCase		(context, name, description, sampleCount)
2292 										, m_conservativeTestConfig	(conservativeTestConfig)
2293 									{}
2294 
2295 	virtual void					checkSupport				(Context& context) const;
2296 
createInstance(Context & context) const2297 	virtual TestInstance*			createInstance				(Context& context) const
2298 									{
2299 										return new ConcreteTestInstance(context, m_conservativeTestConfig, m_sampleCount);
2300 									}
2301 
2302 protected:
2303 	bool							isUseLineSubPixel			(Context& context) const;
2304 	deUint32						getSubPixelResolution		(Context& context) const;
2305 
2306 	const ConservativeTestConfig	m_conservativeTestConfig;
2307 };
2308 
2309 template <typename ConcreteTestInstance>
isUseLineSubPixel(Context & context) const2310 bool ConservativeTestCase<ConcreteTestInstance>::isUseLineSubPixel (Context& context) const
2311 {
2312 	return (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) && context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"));
2313 }
2314 
2315 template <typename ConcreteTestInstance>
getSubPixelResolution(Context & context) const2316 deUint32 ConservativeTestCase<ConcreteTestInstance>::getSubPixelResolution (Context& context) const
2317 {
2318 	if (isUseLineSubPixel(context))
2319 	{
2320 		const VkPhysicalDeviceLineRasterizationPropertiesEXT	lineRasterizationPropertiesEXT	= context.getLineRasterizationPropertiesEXT();
2321 
2322 		return lineRasterizationPropertiesEXT.lineSubPixelPrecisionBits;
2323 	}
2324 	else
2325 	{
2326 		return context.getDeviceProperties().limits.subPixelPrecisionBits;
2327 	}
2328 }
2329 
2330 template <typename ConcreteTestInstance>
checkSupport(Context & context) const2331 void ConservativeTestCase<ConcreteTestInstance>::checkSupport (Context& context) const
2332 {
2333 	context.requireDeviceFunctionality("VK_EXT_conservative_rasterization");
2334 
2335 	const VkPhysicalDeviceConservativeRasterizationPropertiesEXT	conservativeRasterizationProperties	= context.getConservativeRasterizationPropertiesEXT();
2336 	const deUint32													subPixelPrecisionBits				= getSubPixelResolution(context);
2337 	const deUint32													subPixelPrecision					= 1<<subPixelPrecisionBits;
2338 	const bool														linesPrecision						= isUseLineSubPixel(context);
2339 	const float														primitiveOverestimationSizeMult		= float(subPixelPrecision) * conservativeRasterizationProperties.primitiveOverestimationSize;
2340 	const bool														topologyLineOrPoint					= isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology) || isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology);
2341 
2342 	DE_ASSERT(subPixelPrecisionBits < sizeof(deUint32) * 8);
2343 
2344 	context.getTestContext().getLog()
2345 		<< tcu::TestLog::Message
2346 		<< "maxExtraPrimitiveOverestimationSize="			<< conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize << '\n'
2347 		<< "extraPrimitiveOverestimationSizeGranularity="	<< conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity << '\n'
2348 		<< "degenerateLinesRasterized="						<< conservativeRasterizationProperties.degenerateLinesRasterized << '\n'
2349 		<< "degenerateTrianglesRasterized="					<< conservativeRasterizationProperties.degenerateTrianglesRasterized << '\n'
2350 		<< "primitiveOverestimationSize="					<< conservativeRasterizationProperties.primitiveOverestimationSize << " (==" << primitiveOverestimationSizeMult << '/' << subPixelPrecision << ")\n"
2351 		<< "subPixelPrecisionBits="							<< subPixelPrecisionBits << (linesPrecision ? " (using VK_EXT_line_rasterization)" : " (using limits)") << '\n'
2352 		<< tcu::TestLog::EndMessage;
2353 
2354 	if (conservativeRasterizationProperties.extraPrimitiveOverestimationSizeGranularity > conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
2355 		TCU_FAIL("Granularity cannot be greater than maximum extra size");
2356 
2357 	if (topologyLineOrPoint)
2358 	{
2359 		if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
2360 			TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
2361 	}
2362 
2363 	if (m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT)
2364 	{
2365 		if (conservativeRasterizationProperties.primitiveUnderestimation == DE_FALSE)
2366 			TCU_THROW(NotSupportedError, "Underestimation is not supported");
2367 
2368 		if (isPrimitiveTopologyLine(m_conservativeTestConfig.primitiveTopology))
2369 		{
2370 			const float	testLineWidth	= m_conservativeTestConfig.lineWidth;
2371 
2372 			if (testLineWidth != 1.0f)
2373 			{
2374 				const VkPhysicalDeviceLimits&	limits					= context.getDeviceProperties().limits;
2375 				const float						lineWidthRange[2]		= { limits.lineWidthRange[0], limits.lineWidthRange[1] };
2376 				const float						lineWidthGranularity	= limits.lineWidthGranularity;
2377 
2378 				context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
2379 
2380 				if (lineWidthGranularity == 0.0f)
2381 					TCU_THROW(NotSupportedError, "Wide lines required for test, but are not supported");
2382 
2383 				DE_ASSERT(lineWidthGranularity > 0.0f && lineWidthRange[0] > 0.0f && lineWidthRange[1] >= lineWidthRange[0]);
2384 
2385 				if (!de::inBounds(testLineWidth, lineWidthRange[0], lineWidthRange[1]))
2386 					TCU_THROW(NotSupportedError, "Tested line width is not supported");
2387 
2388 				const float	n	= (testLineWidth - lineWidthRange[0]) / lineWidthGranularity;
2389 
2390 				if (deFloatFrac(n) != 0.0f || n * lineWidthGranularity + lineWidthRange[0] != testLineWidth)
2391 					TCU_THROW(NotSupportedError, "Exact match of line width is required for the test");
2392 			}
2393 		}
2394 		else if (isPrimitiveTopologyPoint(m_conservativeTestConfig.primitiveTopology))
2395 		{
2396 			const float	testPointSize	= m_conservativeTestConfig.lineWidth;
2397 
2398 			if (testPointSize != 1.0f)
2399 			{
2400 				const VkPhysicalDeviceLimits&	limits					= context.getDeviceProperties().limits;
2401 				const float						pointSizeRange[2]		= { limits.pointSizeRange[0], limits.pointSizeRange[1] };
2402 				const float						pointSizeGranularity	= limits.pointSizeGranularity;
2403 
2404 				context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
2405 
2406 				if (pointSizeGranularity == 0.0f)
2407 					TCU_THROW(NotSupportedError, "Large points required for test, but are not supported");
2408 
2409 				DE_ASSERT(pointSizeGranularity > 0.0f && pointSizeRange[0] > 0.0f && pointSizeRange[1] >= pointSizeRange[0]);
2410 
2411 				if (!de::inBounds(testPointSize, pointSizeRange[0], pointSizeRange[1]))
2412 					TCU_THROW(NotSupportedError, "Tested point size is not supported");
2413 
2414 				const float	n	= (testPointSize - pointSizeRange[0]) / pointSizeGranularity;
2415 
2416 				if (deFloatFrac(n) != 0.0f || n * pointSizeGranularity + pointSizeRange[0] != testPointSize)
2417 					TCU_THROW(NotSupportedError, "Exact match of point size is required for the test");
2418 			}
2419 		}
2420 	}
2421 	else if (m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT)
2422 	{
2423 		const float extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, conservativeRasterizationProperties);
2424 
2425 		if (extraOverestimationSize > conservativeRasterizationProperties.maxExtraPrimitiveOverestimationSize)
2426 			TCU_THROW(NotSupportedError, "Specified overestimation size is not supported");
2427 
2428 		if (topologyLineOrPoint)
2429 		{
2430 			if (!conservativeRasterizationProperties.conservativePointAndLineRasterization)
2431 				TCU_THROW(NotSupportedError, "Conservative line and point rasterization is not supported");
2432 		}
2433 
2434 		if (isPrimitiveTopologyTriangle(m_conservativeTestConfig.primitiveTopology))
2435 		{
2436 			if (m_conservativeTestConfig.degeneratePrimitives)
2437 			{
2438 				// Enforce specification minimum required limit to avoid division by zero
2439 				DE_ASSERT(subPixelPrecisionBits >= 4);
2440 
2441 				// Make sure float precision of 22 bits is enough, i.e. resoultion in subpixel quarters less than float precision
2442 				if (m_conservativeTestConfig.resolution * (1<<(subPixelPrecisionBits + 2)) > (1<<21))
2443 					TCU_THROW(NotSupportedError, "Subpixel resolution is too high to generate degenerate primitives");
2444 			}
2445 		}
2446 	}
2447 	else
2448 		TCU_THROW(InternalError, "Non-conservative mode tests are not supported by this class");
2449 }
2450 
2451 class ConservativeTraingleTestInstance : public BaseTriangleTestInstance
2452 {
2453 public:
ConservativeTraingleTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)2454 																				ConservativeTraingleTestInstance				(Context&				context,
2455 																																 ConservativeTestConfig	conservativeTestConfig,
2456 																																 VkSampleCountFlagBits	sampleCount)
2457 																					: BaseTriangleTestInstance						(context,
2458 																																	 conservativeTestConfig.primitiveTopology,
2459 																																	 sampleCount,
2460 																																	 conservativeTestConfig.resolution)
2461 																					, m_conservativeTestConfig						(conservativeTestConfig)
2462 																					, m_conservativeRasterizationProperties			(context.getConservativeRasterizationPropertiesEXT())
2463 																					, m_rasterizationConservativeStateCreateInfo	(initRasterizationConservativeStateCreateInfo())
2464 																					, m_rasterizationStateCreateInfo				(initRasterizationStateCreateInfo())
2465 																				{}
2466 
2467 	void																		generateTriangles								(int											iteration,
2468 																																 std::vector<tcu::Vec4>&						outData,
2469 																																 std::vector<TriangleSceneSpec::SceneTriangle>&	outTriangles);
2470 	const VkPipelineRasterizationStateCreateInfo*								getRasterizationStateCreateInfo					(void) const;
2471 
2472 protected:
2473 	virtual const VkPipelineRasterizationLineStateCreateInfoEXT*				getLineRasterizationStateCreateInfo				(void) const;
2474 
2475 	virtual bool																compareAndVerify								(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
2476 																																 tcu::Surface&									resultImage,
2477 																																 std::vector<tcu::Vec4>&						drawBuffer);
2478 	virtual bool																compareAndVerifyOverestimatedNormal				(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
2479 																																 tcu::Surface&									resultImage);
2480 	virtual bool																compareAndVerifyOverestimatedDegenerate			(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
2481 																																 tcu::Surface&									resultImage);
2482 	virtual bool																compareAndVerifyUnderestimatedNormal			(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
2483 																																 tcu::Surface&									resultImage);
2484 	virtual bool																compareAndVerifyUnderestimatedDegenerate		(std::vector<TriangleSceneSpec::SceneTriangle>&	triangles,
2485 																																 tcu::Surface&									resultImage);
2486 	void																		generateNormalTriangles							(int											iteration,
2487 																																 std::vector<tcu::Vec4>&						outData,
2488 																																 std::vector<TriangleSceneSpec::SceneTriangle>&	outTriangles);
2489 	void																		generateDegenerateTriangles					(int											iteration,
2490 																																 std::vector<tcu::Vec4>&						outData,
2491 																																 std::vector<TriangleSceneSpec::SceneTriangle>&	outTriangles);
2492 	void																		drawPrimitives									(tcu::Surface&									result,
2493 																																 const std::vector<tcu::Vec4>&					vertexData,
2494 																																 VkPrimitiveTopology							primitiveTopology);
2495 
2496 private:
2497 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	initRasterizationConservativeStateCreateInfo	(void);
2498 	const std::vector<VkPipelineRasterizationStateCreateInfo>					initRasterizationStateCreateInfo				(void);
2499 
2500 	const ConservativeTestConfig												m_conservativeTestConfig;
2501 	const VkPhysicalDeviceConservativeRasterizationPropertiesEXT				m_conservativeRasterizationProperties;
2502 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	m_rasterizationConservativeStateCreateInfo;
2503 	const std::vector<VkPipelineRasterizationStateCreateInfo>					m_rasterizationStateCreateInfo;
2504 };
2505 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2506 void ConservativeTraingleTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2507 {
2508 	if (m_conservativeTestConfig.degeneratePrimitives)
2509 		generateDegenerateTriangles(iteration, outData, outTriangles);
2510 	else
2511 		generateNormalTriangles(iteration, outData, outTriangles);
2512 }
2513 
generateNormalTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2514 void ConservativeTraingleTestInstance::generateNormalTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2515 {
2516 	const float	halfPixel						= 1.0f / float(m_renderSize);
2517 	const float extraOverestimationSize			= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
2518 	const float	overestimate					= 2.0f * halfPixel * (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
2519 	const float	overestimateMargin				= overestimate;
2520 	const float	underestimateMargin				= 0.0f;
2521 	const bool	isOverestimate					= m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
2522 	const float	margin							= isOverestimate ? overestimateMargin : underestimateMargin;
2523 	const char*	overestimateIterationComments[]	= { "Corner touch", "Any portion pixel coverage", "Edge touch" };
2524 
2525 	outData.resize(6);
2526 
2527 	switch (iteration)
2528 	{
2529 		case 0:
2530 		{
2531 			// Corner touch
2532 			const float edge	= 2 * halfPixel + margin;
2533 			const float left	= -1.0f + edge;
2534 			const float right	= +1.0f - edge;
2535 			const float up		= -1.0f + edge;
2536 			const float down	= +1.0f - edge;
2537 
2538 			outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
2539 			outData[1] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2540 			outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
2541 
2542 			outData[3] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2543 			outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
2544 			outData[5] = tcu::Vec4(right,   up, 0.0f, 1.0f);
2545 
2546 			break;
2547 		}
2548 
2549 		case 1:
2550 		{
2551 			// Partial coverage
2552 			const float eps		= halfPixel / 32.0f;
2553 			const float edge	= 4.0f * halfPixel  + margin - eps;
2554 			const float left	= -1.0f + edge;
2555 			const float right	= +1.0f - edge;
2556 			const float up		= -1.0f + edge;
2557 			const float down	= +1.0f - edge;
2558 
2559 			outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
2560 			outData[1] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2561 			outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
2562 
2563 			outData[3] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2564 			outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
2565 			outData[5] = tcu::Vec4(right,   up, 0.0f, 1.0f);
2566 
2567 			break;
2568 		}
2569 
2570 		case 2:
2571 		{
2572 			// Edge touch
2573 			const float edge	= 6.0f * halfPixel + margin;
2574 			const float left	= -1.0f + edge;
2575 			const float right	= +1.0f - edge;
2576 			const float up		= -1.0f + edge;
2577 			const float down	= +1.0f - edge;
2578 
2579 			outData[0] = tcu::Vec4( left, down, 0.0f, 1.0f);
2580 			outData[1] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2581 			outData[2] = tcu::Vec4(right, down, 0.0f, 1.0f);
2582 
2583 			outData[3] = tcu::Vec4( left,   up, 0.0f, 1.0f);
2584 			outData[4] = tcu::Vec4(right, down, 0.0f, 1.0f);
2585 			outData[5] = tcu::Vec4(right,   up, 0.0f, 1.0f);
2586 
2587 			break;
2588 		}
2589 
2590 		default:
2591 			TCU_THROW(InternalError, "Unexpected iteration");
2592 	}
2593 
2594 	outTriangles.resize(outData.size() / 3);
2595 
2596 	for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
2597 	{
2598 		outTriangles[ndx].positions[0] = outData[3 * ndx + 0];	outTriangles[ndx].sharedEdge[0] = false;
2599 		outTriangles[ndx].positions[1] = outData[3 * ndx + 1];	outTriangles[ndx].sharedEdge[1] = false;
2600 		outTriangles[ndx].positions[2] = outData[3 * ndx + 2];	outTriangles[ndx].sharedEdge[2] = false;
2601 	}
2602 
2603 	// log
2604 	if (isOverestimate)
2605 	{
2606 		m_context.getTestContext().getLog()
2607 			<< tcu::TestLog::Message
2608 			<< "Testing " << overestimateIterationComments[iteration] << " "
2609 			<< "with rendering " << outTriangles.size() << " triangle(s):"
2610 			<< tcu::TestLog::EndMessage;
2611 	}
2612 	else
2613 	{
2614 		m_context.getTestContext().getLog()
2615 			<< tcu::TestLog::Message
2616 			<< "Rendering " << outTriangles.size() << " triangle(s):"
2617 			<< tcu::TestLog::EndMessage;
2618 	}
2619 
2620 	for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
2621 	{
2622 		const deUint32	 multiplier	= m_renderSize / 2;
2623 
2624 		m_context.getTestContext().getLog()
2625 			<< tcu::TestLog::Message
2626 			<< "Triangle " << (ndx + 1) << ":"
2627 			<< "\n\t" << outTriangles[ndx].positions[0] << " == " << (float(multiplier) * outTriangles[ndx].positions[0]) << "/" << multiplier
2628 			<< "\n\t" << outTriangles[ndx].positions[1] << " == " << (float(multiplier) * outTriangles[ndx].positions[1]) << "/" << multiplier
2629 			<< "\n\t" << outTriangles[ndx].positions[2] << " == " << (float(multiplier) * outTriangles[ndx].positions[2]) << "/" << multiplier
2630 			<< tcu::TestLog::EndMessage;
2631 	}
2632 }
2633 
generateDegenerateTriangles(int iteration,std::vector<tcu::Vec4> & outData,std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles)2634 void ConservativeTraingleTestInstance::generateDegenerateTriangles (int iteration, std::vector<tcu::Vec4>& outData, std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles)
2635 {
2636 	tcu::TestLog&	log								= m_context.getTestContext().getLog();
2637 	const float		pixelSize						= 2.0f / float(m_renderSize);
2638 	const deUint32	subPixels						= 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
2639 	const float		subPixelSize					= pixelSize / float(subPixels);
2640 	const float		extraOverestimationSize			= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
2641 	const float		totalOverestimate				= m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
2642 	const float		totalOverestimateInSubPixels	= deFloatCeil(totalOverestimate * float(subPixels));
2643 	const float		overestimate					= subPixelSize * totalOverestimateInSubPixels;
2644 	const float		overestimateSafetyMargin		= subPixelSize * 0.125f;
2645 	const float		overestimateMargin				= overestimate + overestimateSafetyMargin;
2646 	const float		underestimateMargin				= 0.0f;
2647 	const bool		isOverestimate					= m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
2648 	const float		margin							= isOverestimate ? overestimateMargin : underestimateMargin;
2649 	const char*		overestimateIterationComments[]	= { "Backfacing", "Generate pixels", "Use provoking vertex" };
2650 
2651 	if (pixelSize < 2 * overestimateMargin)
2652 		TCU_THROW(NotSupportedError, "Could not generate degenerate triangle for such overestimate parameters");
2653 
2654 	outData.clear();
2655 
2656 	switch (iteration)
2657 	{
2658 		case 0:
2659 		case 1:
2660 		case 2:
2661 		{
2662 			for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
2663 			for (int colNdx = 0; colNdx < 4; ++colNdx)
2664 			{
2665 				const float	offsetX		= -1.0f + float(4 * (colNdx + 1)) * pixelSize;
2666 				const float	offsetY		= -1.0f + float(4 * (rowNdx + 1)) * pixelSize;
2667 				const float	left		= offsetX + margin;
2668 				const float	right		= offsetX + margin + 0.25f * subPixelSize;
2669 				const float	up			= offsetY + margin;
2670 				const float	down		= offsetY + margin + 0.25f * subPixelSize;
2671 				const bool	luPresent	= (rowNdx & 1) == 0;
2672 				const bool	rdPresent	= (rowNdx & 2) == 0;
2673 				const bool	luCW		= (colNdx & 1) == 0;
2674 				const bool	rdCW		= (colNdx & 2) == 0;
2675 
2676 				DE_ASSERT(left < right);
2677 				DE_ASSERT(up < down);
2678 
2679 				if (luPresent)
2680 				{
2681 					if (luCW)
2682 					{
2683 						// CW triangle left up
2684 						outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
2685 						outData.push_back(tcu::Vec4( left,   up, 0.0f, 1.0f));
2686 						outData.push_back(tcu::Vec4(right,   up, 0.0f, 1.0f));
2687 					}
2688 					else
2689 					{
2690 						// CCW triangle left up
2691 						outData.push_back(tcu::Vec4(right,   up, 0.0f, 1.0f));
2692 						outData.push_back(tcu::Vec4( left,   up, 0.0f, 1.0f));
2693 						outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
2694 					}
2695 				}
2696 
2697 				if (rdPresent)
2698 				{
2699 					if (rdCW)
2700 					{
2701 						// CW triangle right down
2702 						outData.push_back(tcu::Vec4(right,   up, 0.0f, 1.0f));
2703 						outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
2704 						outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
2705 					}
2706 					else
2707 					{
2708 						// CCW triangle right down
2709 						outData.push_back(tcu::Vec4( left, down, 0.0f, 1.0f));
2710 						outData.push_back(tcu::Vec4(right, down, 0.0f, 1.0f));
2711 						outData.push_back(tcu::Vec4(right,   up, 0.0f, 1.0f));
2712 					}
2713 				}
2714 			}
2715 
2716 			break;
2717 		}
2718 
2719 		default:
2720 			TCU_THROW(InternalError, "Unexpected iteration");
2721 	}
2722 
2723 	outTriangles.resize(outData.size() / 3);
2724 
2725 	for (size_t ndx = 0; ndx < outTriangles.size(); ++ndx)
2726 	{
2727 		outTriangles[ndx].positions[0] = outData[3 * ndx + 0];	outTriangles[ndx].sharedEdge[0] = false;
2728 		outTriangles[ndx].positions[1] = outData[3 * ndx + 1];	outTriangles[ndx].sharedEdge[1] = false;
2729 		outTriangles[ndx].positions[2] = outData[3 * ndx + 2];	outTriangles[ndx].sharedEdge[2] = false;
2730 	}
2731 
2732 	// log
2733 	if (isOverestimate)
2734 	{
2735 		m_context.getTestContext().getLog()
2736 			<< tcu::TestLog::Message
2737 			<< "Testing " << overestimateIterationComments[iteration] << " "
2738 			<< "with rendering " << outTriangles.size() << " triangle(s):"
2739 			<< tcu::TestLog::EndMessage;
2740 	}
2741 	else
2742 	{
2743 		m_context.getTestContext().getLog()
2744 			<< tcu::TestLog::Message
2745 			<< "Rendering " << outTriangles.size() << " triangle(s):"
2746 			<< tcu::TestLog::EndMessage;
2747 	}
2748 
2749 	for (int ndx = 0; ndx < (int)outTriangles.size(); ++ndx)
2750 	{
2751 		const deUint32	multiplierInt	= m_renderSize / 2;
2752 		const deUint32	multiplierFrac	= subPixels;
2753 		std::string		coordsString;
2754 
2755 		for (size_t vertexNdx = 0; vertexNdx < 3; ++vertexNdx)
2756 		{
2757 			const tcu::Vec4&	pos				= outTriangles[ndx].positions[vertexNdx];
2758 			std::ostringstream	coordsFloat;
2759 			std::ostringstream	coordsNatural;
2760 
2761 			for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
2762 			{
2763 				const char*	sep		= (coordNdx < 1) ? "," : "";
2764 				const float	coord	= pos[coordNdx];
2765 				const char	sign	= deSign(coord) < 0 ? '-' : '+';
2766 				const float	m		= deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
2767 				const float	r		= deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
2768 
2769 				coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
2770 				coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
2771 			}
2772 
2773 			coordsString += "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
2774 		}
2775 
2776 		log << tcu::TestLog::Message
2777 			<< "Triangle " << (ndx + 1) << ':'
2778 			<< coordsString
2779 			<< tcu::TestLog::EndMessage;
2780 	}
2781 }
2782 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)2783 void ConservativeTraingleTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
2784 {
2785 	if (m_conservativeTestConfig.degeneratePrimitives && getIteration() == 2)
2786 	{
2787 		// Set provoking vertex color to white
2788 		tcu::Vec4				colorProvoking	(1.0f, 1.0f, 1.0f, 1.0f);
2789 		tcu::Vec4				colorOther		(0.0f, 1.0f, 1.0f, 1.0f);
2790 		std::vector<tcu::Vec4>	colorData;
2791 
2792 		colorData.reserve(vertexData.size());
2793 
2794 		for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
2795 			if (vertexNdx % 3 == 0)
2796 				colorData.push_back(colorProvoking);
2797 			else
2798 				colorData.push_back(colorOther);
2799 
2800 		BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
2801 	}
2802 	else
2803 		BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
2804 }
2805 
compareAndVerify(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)2806 bool ConservativeTraingleTestInstance::compareAndVerify (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
2807 {
2808 	DE_UNREF(drawBuffer);
2809 
2810 	switch (m_conservativeTestConfig.conservativeRasterizationMode)
2811 	{
2812 		case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
2813 		{
2814 			if (m_conservativeTestConfig.degeneratePrimitives)
2815 				return compareAndVerifyOverestimatedDegenerate(triangles, resultImage);
2816 			else
2817 				return compareAndVerifyOverestimatedNormal(triangles, resultImage);
2818 
2819 			break;
2820 		}
2821 
2822 		case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
2823 		{
2824 			if (m_conservativeTestConfig.degeneratePrimitives)
2825 				return compareAndVerifyUnderestimatedDegenerate(triangles, resultImage);
2826 			else
2827 				return compareAndVerifyUnderestimatedNormal(triangles, resultImage);
2828 
2829 			break;
2830 		}
2831 
2832 		default:
2833 			TCU_THROW(InternalError, "Unknown conservative rasterization mode");
2834 	}
2835 }
2836 
compareAndVerifyOverestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)2837 bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
2838 {
2839 	DE_UNREF(triangles);
2840 
2841 	const int			start					= getIteration() + 1;
2842 	const int			end						= resultImage.getHeight() - start;
2843 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
2844 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
2845 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
2846 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
2847 	int					errX					= 0;
2848 	int					errY					= 0;
2849 	deUint32			errValue				= 0;
2850 	bool				result					= true;
2851 
2852 	DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
2853 
2854 	for (int y = start; result && y < end; ++y)
2855 	for (int x = start; result && x < end; ++x)
2856 	{
2857 		if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
2858 		{
2859 			result		= false;
2860 			errX		= x;
2861 			errY		= y;
2862 			errValue	= resultImage.getPixel(x,y).getPacked();
2863 
2864 			break;
2865 		}
2866 	}
2867 
2868 	if (!result)
2869 	{
2870 		tcu::Surface	errorMask		(resultImage.getWidth(), resultImage.getHeight());
2871 		tcu::Surface	expectedImage	(resultImage.getWidth(), resultImage.getHeight());
2872 
2873 		for (int y = 0; y < errorMask.getHeight(); ++y)
2874 		for (int x = 0; x < errorMask.getWidth(); ++x)
2875 		{
2876 			errorMask.setPixel(x, y, backgroundColor);
2877 			expectedImage.setPixel(x, y, backgroundColor);
2878 		}
2879 
2880 		for (int y = start; y < end; ++y)
2881 		for (int x = start; x < end; ++x)
2882 		{
2883 			expectedImage.setPixel(x, y, foregroundColor);
2884 
2885 			if (resultImage.getPixel(x, y).getPacked() != foregroundColor.getPacked())
2886 				errorMask.setPixel(x, y, unexpectedPixelColor);
2887 		}
2888 
2889 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
2890 			<< tcu::TestLog::EndMessage;
2891 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2892 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
2893 			<< tcu::TestLog::Image("Expected",	"Expected",		expectedImage)
2894 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
2895 			<< tcu::TestLog::EndImageSet;
2896 	}
2897 	else
2898 	{
2899 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
2900 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2901 			<< tcu::TestLog::Image("Result", "Result", resultImage)
2902 			<< tcu::TestLog::EndImageSet;
2903 	}
2904 
2905 	return result;
2906 }
2907 
compareAndVerifyOverestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)2908 bool ConservativeTraingleTestInstance::compareAndVerifyOverestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
2909 {
2910 	DE_UNREF(triangles);
2911 
2912 	const char*			iterationComments[]		= { "Cull back face triangles", "Cull front face triangles", "Cull none" };
2913 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
2914 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
2915 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
2916 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
2917 	bool				result					= true;
2918 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
2919 
2920 	for (int y = 0; y < resultImage.getHeight(); ++y)
2921 	for (int x = 0; x < resultImage.getWidth(); ++x)
2922 		referenceImage.setPixel(x, y, backgroundColor);
2923 
2924 	if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
2925 	{
2926 		if (getIteration() != 0)
2927 		{
2928 			log << tcu::TestLog::Message << "Triangles expected to be rasterized with at least one pixel of white color each" << tcu::TestLog::EndMessage;
2929 
2930 			for (int rowNdx = 0; rowNdx < 3; ++rowNdx)
2931 			for (int colNdx = 0; colNdx < 4; ++colNdx)
2932 			{
2933 				referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1), foregroundColor);
2934 
2935 				// Allow implementations that need to be extra conservative with degenerate triangles,
2936 				// which may cause extra coverage.
2937 				if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1) == foregroundColor)
2938 					referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1) - 1, foregroundColor);
2939 				if (resultImage.getPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1)) == foregroundColor)
2940 					referenceImage.setPixel(4 * (colNdx + 1) - 1, 4 * (rowNdx + 1), foregroundColor);
2941 				if (resultImage.getPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1) == foregroundColor)
2942 					referenceImage.setPixel(4 * (colNdx + 1), 4 * (rowNdx + 1) - 1, foregroundColor);
2943 			}
2944 		}
2945 		else
2946 			log << tcu::TestLog::Message << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to be backfacing" << tcu::TestLog::EndMessage;
2947 	}
2948 	else
2949 		log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false" << tcu::TestLog::EndMessage;
2950 
2951 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
2952 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
2953 	{
2954 		if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
2955 		{
2956 			result = false;
2957 
2958 			break;
2959 		}
2960 	}
2961 
2962 	if (!result)
2963 	{
2964 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
2965 
2966 		for (int y = 0; y < errorMask.getHeight(); ++y)
2967 		for (int x = 0; x < errorMask.getWidth(); ++x)
2968 		{
2969 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
2970 				errorMask.setPixel(x, y, unexpectedPixelColor);
2971 			else
2972 				errorMask.setPixel(x, y, backgroundColor);
2973 		}
2974 
2975 		log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()] << "'"
2976 			<< tcu::TestLog::EndMessage;
2977 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2978 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
2979 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
2980 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
2981 			<< tcu::TestLog::EndImageSet;
2982 	}
2983 	else
2984 	{
2985 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
2986 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
2987 			<< tcu::TestLog::Image("Result", "Result", resultImage)
2988 			<< tcu::TestLog::EndImageSet;
2989 	}
2990 
2991 	return result;
2992 }
2993 
compareAndVerifyUnderestimatedNormal(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)2994 bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedNormal (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
2995 {
2996 	DE_UNREF(triangles);
2997 
2998 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
2999 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
3000 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3001 	const tcu::IVec2	viewportSize			= tcu::IVec2(resultImage.getWidth(), resultImage.getHeight());
3002 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3003 	int					errX					= -1;
3004 	int					errY					= -1;
3005 	deUint32			errValue				= 0;
3006 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
3007 	bool				result					= true;
3008 
3009 	DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
3010 
3011 	for (int y = 0; y < resultImage.getHeight(); ++y)
3012 	for (int x = 0; x < resultImage.getWidth(); ++x)
3013 		referenceImage.setPixel(x, y, backgroundColor);
3014 
3015 	for (size_t triangleNdx = 0; triangleNdx < triangles.size(); ++triangleNdx)
3016 	{
3017 		const tcu::Vec4&	p0	= triangles[triangleNdx].positions[0];
3018 		const tcu::Vec4&	p1	= triangles[triangleNdx].positions[1];
3019 		const tcu::Vec4&	p2	= triangles[triangleNdx].positions[2];
3020 
3021 		for (int y = 0; y < resultImage.getHeight(); ++y)
3022 		for (int x = 0; x < resultImage.getWidth(); ++x)
3023 		{
3024 			if (calculateUnderestimateTriangleCoverage(p0, p1, p2, tcu::IVec2(x,y), m_subpixelBits, viewportSize) == tcu::COVERAGE_FULL)
3025 				referenceImage.setPixel(x, y, foregroundColor);
3026 		}
3027 	}
3028 
3029 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
3030 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
3031 		if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3032 		{
3033 			result		= false;
3034 			errX		= x;
3035 			errY		= y;
3036 			errValue	= resultImage.getPixel(x,y).getPacked();
3037 		}
3038 
3039 	if (!result)
3040 	{
3041 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
3042 
3043 		for (int y = 0; y < errorMask.getHeight(); ++y)
3044 		for (int x = 0; x < errorMask.getWidth(); ++x)
3045 		{
3046 			if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
3047 				errorMask.setPixel(x, y, unexpectedPixelColor);
3048 			else
3049 				errorMask.setPixel(x, y, backgroundColor);
3050 		}
3051 
3052 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
3053 			<< tcu::TestLog::EndMessage;
3054 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3055 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3056 			<< tcu::TestLog::Image("Refernce",	"Refernce",		referenceImage)
3057 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3058 			<< tcu::TestLog::EndImageSet;
3059 	}
3060 	else
3061 	{
3062 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3063 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3064 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3065 			<< tcu::TestLog::EndImageSet;
3066 	}
3067 
3068 	return result;
3069 }
3070 
compareAndVerifyUnderestimatedDegenerate(std::vector<TriangleSceneSpec::SceneTriangle> & triangles,tcu::Surface & resultImage)3071 bool ConservativeTraingleTestInstance::compareAndVerifyUnderestimatedDegenerate (std::vector<TriangleSceneSpec::SceneTriangle>& triangles, tcu::Surface& resultImage)
3072 {
3073 	DE_UNREF(triangles);
3074 
3075 	const char*			iterationComments[]		= { "Cull back face triangles", "Cull front face triangles", "Cull none" };
3076 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
3077 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3078 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3079 	int					errX					= 0;
3080 	int					errY					= 0;
3081 	deUint32			errValue				= 0;
3082 	bool				result					= true;
3083 
3084 	if (m_conservativeRasterizationProperties.degenerateTrianglesRasterized)
3085 	{
3086 		if (getIteration() != 0)
3087 			log << tcu::TestLog::Message << "Triangles expected to be not rendered due to no one triangle can fully cover fragment" << tcu::TestLog::EndMessage;
3088 		else
3089 			log << tcu::TestLog::Message << "Triangles expected to be culled due to backfacing culling and all degenerate triangles assumed to be backfacing" << tcu::TestLog::EndMessage;
3090 	}
3091 	else
3092 		log << tcu::TestLog::Message << "Triangles expected to be culled due to degenerateTrianglesRasterized=false" << tcu::TestLog::EndMessage;
3093 
3094 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
3095 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
3096 	{
3097 		if (resultImage.getPixel(x, y).getPacked() != backgroundColor.getPacked())
3098 		{
3099 			result		= false;
3100 			errX		= x;
3101 			errY		= y;
3102 			errValue	= resultImage.getPixel(x,y).getPacked();
3103 
3104 			break;
3105 		}
3106 	}
3107 
3108 	if (!result)
3109 	{
3110 		tcu::Surface	referenceImage	(resultImage.getWidth(), resultImage.getHeight());
3111 		tcu::Surface	errorMask		(resultImage.getWidth(), resultImage.getHeight());
3112 
3113 		for (int y = 0; y < resultImage.getHeight(); ++y)
3114 		for (int x = 0; x < resultImage.getWidth(); ++x)
3115 			referenceImage.setPixel(x, y, backgroundColor);
3116 
3117 		for (int y = 0; y < errorMask.getHeight(); ++y)
3118 		for (int x = 0; x < errorMask.getWidth(); ++x)
3119 		{
3120 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3121 				errorMask.setPixel(x, y, unexpectedPixelColor);
3122 			else
3123 				errorMask.setPixel(x, y, backgroundColor);
3124 		}
3125 
3126 		log << tcu::TestLog::Message << "Invalid pixels found for mode '" << iterationComments[getIteration()] << "' starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
3127 			<< tcu::TestLog::EndMessage;
3128 
3129 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3130 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3131 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
3132 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3133 			<< tcu::TestLog::EndImageSet;
3134 	}
3135 	else
3136 	{
3137 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3138 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3139 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3140 			<< tcu::TestLog::EndImageSet;
3141 	}
3142 
3143 	return result;
3144 }
3145 
initRasterizationConservativeStateCreateInfo(void)3146 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeTraingleTestInstance::initRasterizationConservativeStateCreateInfo (void)
3147 {
3148 	const float															extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3149 	std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	result;
3150 
3151 	result.reserve(getIterationCount());
3152 
3153 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3154 	{
3155 		const VkPipelineRasterizationConservativeStateCreateInfoEXT	rasterizationConservativeStateCreateInfo	=
3156 		{
3157 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT,	//  VkStructureType											sType;
3158 			DE_NULL,																		//  const void*												pNext;
3159 			(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0,						//  VkPipelineRasterizationConservativeStateCreateFlagsEXT	flags;
3160 			m_conservativeTestConfig.conservativeRasterizationMode,							//  VkConservativeRasterizationModeEXT						conservativeRasterizationMode;
3161 			extraOverestimationSize															//  float													extraPrimitiveOverestimationSize;
3162 		};
3163 
3164 		result.push_back(rasterizationConservativeStateCreateInfo);
3165 	}
3166 
3167 	return result;
3168 }
3169 
initRasterizationStateCreateInfo(void)3170 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeTraingleTestInstance::initRasterizationStateCreateInfo (void)
3171 {
3172 	std::vector<VkPipelineRasterizationStateCreateInfo>	result;
3173 
3174 	result.reserve(getIterationCount());
3175 
3176 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3177 	{
3178 		const VkCullModeFlags							cullModeFlags					= (!m_conservativeTestConfig.degeneratePrimitives) ? VK_CULL_MODE_NONE
3179 																						: (iteration == 0) ? VK_CULL_MODE_BACK_BIT
3180 																						: (iteration == 1) ? VK_CULL_MODE_FRONT_BIT
3181 																						: VK_CULL_MODE_NONE;
3182 
3183 		const VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
3184 		{
3185 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		//  VkStructureType							sType;
3186 			&m_rasterizationConservativeStateCreateInfo[iteration],			//  const void*								pNext;
3187 			0,																//  VkPipelineRasterizationStateCreateFlags	flags;
3188 			false,															//  VkBool32								depthClampEnable;
3189 			false,															//  VkBool32								rasterizerDiscardEnable;
3190 			VK_POLYGON_MODE_FILL,											//  VkPolygonMode							polygonMode;
3191 			cullModeFlags,													//  VkCullModeFlags							cullMode;
3192 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								//  VkFrontFace								frontFace;
3193 			VK_FALSE,														//  VkBool32								depthBiasEnable;
3194 			0.0f,															//  float									depthBiasConstantFactor;
3195 			0.0f,															//  float									depthBiasClamp;
3196 			0.0f,															//  float									depthBiasSlopeFactor;
3197 			getLineWidth(),													//  float									lineWidth;
3198 		};
3199 
3200 		result.push_back(rasterizationStateCreateInfo);
3201 	}
3202 
3203 	return result;
3204 }
3205 
getRasterizationStateCreateInfo(void) const3206 const VkPipelineRasterizationStateCreateInfo* ConservativeTraingleTestInstance::getRasterizationStateCreateInfo	(void) const
3207 {
3208 	return &m_rasterizationStateCreateInfo[getIteration()];
3209 }
3210 
getLineRasterizationStateCreateInfo(void) const3211 const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativeTraingleTestInstance::getLineRasterizationStateCreateInfo	(void) const
3212 {
3213 	return DE_NULL;
3214 }
3215 
3216 
3217 class ConservativeLineTestInstance : public BaseLineTestInstance
3218 {
3219 public:
3220 																				ConservativeLineTestInstance					(Context&								context,
3221 																																 ConservativeTestConfig					conservativeTestConfig,
3222 																																 VkSampleCountFlagBits					sampleCount);
3223 
3224 	void																		generateLines									(int									iteration,
3225 																																 std::vector<tcu::Vec4>&				outData,
3226 																																 std::vector<LineSceneSpec::SceneLine>&	outLines);
3227 	const VkPipelineRasterizationStateCreateInfo*								getRasterizationStateCreateInfo					(void) const;
3228 
3229 protected:
3230 	virtual const VkPipelineRasterizationLineStateCreateInfoEXT*				getLineRasterizationStateCreateInfo				(void) const;
3231 
3232 	virtual bool																compareAndVerify								(std::vector<LineSceneSpec::SceneLine>&	lines,
3233 																																 tcu::Surface&							resultImage,
3234 																																 std::vector<tcu::Vec4>&				drawBuffer);
3235 	virtual bool																compareAndVerifyOverestimatedNormal				(std::vector<LineSceneSpec::SceneLine>&	lines,
3236 																																 tcu::Surface&							resultImage);
3237 	virtual bool																compareAndVerifyOverestimatedDegenerate			(std::vector<LineSceneSpec::SceneLine>&	lines,
3238 																																 tcu::Surface&							resultImage);
3239 	virtual bool																compareAndVerifyUnderestimatedNormal			(std::vector<LineSceneSpec::SceneLine>&	lines,
3240 																																 tcu::Surface&							resultImage);
3241 	virtual bool																compareAndVerifyUnderestimatedDegenerate		(std::vector<LineSceneSpec::SceneLine>&	lines,
3242 																																 tcu::Surface&							resultImage);
3243 	void																		generateNormalLines								(int									iteration,
3244 																																 std::vector<tcu::Vec4>&				outData,
3245 																																 std::vector<LineSceneSpec::SceneLine>&	outLines);
3246 	void																		generateDegenerateLines							(int									iteration,
3247 																																 std::vector<tcu::Vec4>&				outData,
3248 																																 std::vector<LineSceneSpec::SceneLine>&	outLines);
3249 	void																		drawPrimitives									(tcu::Surface&							result,
3250 																																 const std::vector<tcu::Vec4>&			vertexData,
3251 																																 VkPrimitiveTopology					primitiveTopology);
3252 
3253 private:
3254 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	initRasterizationConservativeStateCreateInfo	(void);
3255 	const std::vector<VkPipelineRasterizationStateCreateInfo>					initRasterizationStateCreateInfo				(void);
3256 
3257 	const ConservativeTestConfig												m_conservativeTestConfig;
3258 	const VkPhysicalDeviceConservativeRasterizationPropertiesEXT				m_conservativeRasterizationProperties;
3259 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	m_rasterizationConservativeStateCreateInfo;
3260 	const std::vector<VkPipelineRasterizationStateCreateInfo>					m_rasterizationStateCreateInfo;
3261 };
3262 
ConservativeLineTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)3263 ConservativeLineTestInstance::ConservativeLineTestInstance (Context&				context,
3264 															ConservativeTestConfig	conservativeTestConfig,
3265 															VkSampleCountFlagBits	sampleCount)
3266 	: BaseLineTestInstance							(
3267 														context,
3268 														conservativeTestConfig.primitiveTopology,
3269 														PRIMITIVEWIDENESS_NARROW,
3270 														PRIMITIVESTRICTNESS_IGNORE,
3271 														sampleCount,
3272 														LINESTIPPLE_DISABLED,
3273 														VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
3274 														0,
3275 														conservativeTestConfig.resolution,
3276 														conservativeTestConfig.lineWidth
3277 													)
3278 	, m_conservativeTestConfig						(conservativeTestConfig)
3279 	, m_conservativeRasterizationProperties			(context.getConservativeRasterizationPropertiesEXT())
3280 	, m_rasterizationConservativeStateCreateInfo	(initRasterizationConservativeStateCreateInfo())
3281 	, m_rasterizationStateCreateInfo				(initRasterizationStateCreateInfo())
3282 {
3283 }
3284 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3285 void ConservativeLineTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
3286 {
3287 	if (m_conservativeTestConfig.degeneratePrimitives)
3288 		generateDegenerateLines(iteration, outData, outLines);
3289 	else
3290 		generateNormalLines(iteration, outData, outLines);
3291 }
3292 
generateNormalLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3293 void ConservativeLineTestInstance::generateNormalLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
3294 {
3295 	const char*		iterationComment		= "";
3296 	const float		halfPixel				= 1.0f / float(m_renderSize);
3297 	const float		extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3298 	const float		overestimate			= 2.0f * halfPixel * (m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize);
3299 	const float		overestimateMargin		= overestimate;
3300 	const float		underestimateMargin		= 0.0f;
3301 	const bool		isOverestimate			= m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
3302 	const float		margin					= isOverestimate ? overestimateMargin : underestimateMargin;
3303 	const float		edge					= 4 * halfPixel + margin;
3304 	const float		left					= -1.0f + edge;
3305 	const float		right					= +1.0f - edge;
3306 	const float		up						= -1.0f + edge;
3307 	const float		down					= +1.0f - edge;
3308 
3309 	outData.reserve(2);
3310 
3311 	if (isOverestimate)
3312 	{
3313 		const char*		iterationComments[]		= { "Horizontal up line", "Vertical line", "Horizontal down line" };
3314 
3315 		iterationComment = iterationComments[iteration];
3316 
3317 		switch (iteration)
3318 		{
3319 			case 0:
3320 			{
3321 				outData.push_back(tcu::Vec4(              left,   up + halfPixel, 0.0f, 1.0f));
3322 				outData.push_back(tcu::Vec4(             right,   up + halfPixel, 0.0f, 1.0f));
3323 
3324 				break;
3325 			}
3326 
3327 			case 1:
3328 			{
3329 				outData.push_back(tcu::Vec4(  left + halfPixel,               up, 0.0f, 1.0f));
3330 				outData.push_back(tcu::Vec4(  left + halfPixel,             down, 0.0f, 1.0f));
3331 
3332 				break;
3333 			}
3334 
3335 			case 2:
3336 			{
3337 				outData.push_back(tcu::Vec4(              left, down - halfPixel, 0.0f, 1.0f));
3338 				outData.push_back(tcu::Vec4(             right, down - halfPixel, 0.0f, 1.0f));
3339 
3340 				break;
3341 			}
3342 
3343 			default:
3344 				TCU_THROW(InternalError, "Unexpected iteration");
3345 		}
3346 	}
3347 	else
3348 	{
3349 		const char*		iterationComments[]	= { "Horizontal lines", "Vertical lines", "Diagonal lines" };
3350 		const deUint32	subPixels			= 1u << m_subpixelBits;
3351 		const float		subPixelSize		= 2.0f * halfPixel / float(subPixels);
3352 		const float		blockStep			= 16.0f * 2.0f * halfPixel;
3353 		const float		lineWidth			= 2.0f * halfPixel * getLineWidth();
3354 		const float		offsets[]			=
3355 		{
3356 			float(1) * blockStep,
3357 			float(2) * blockStep + halfPixel,
3358 			float(3) * blockStep + 0.5f * lineWidth + 2.0f * subPixelSize,
3359 			float(4) * blockStep + 0.5f * lineWidth - 2.0f * subPixelSize,
3360 		};
3361 
3362 		iterationComment = iterationComments[iteration];
3363 
3364 		outData.reserve(DE_LENGTH_OF_ARRAY(offsets));
3365 
3366 		switch (iteration)
3367 		{
3368 			case 0:
3369 			{
3370 				for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3371 				{
3372 					outData.push_back(tcu::Vec4( left + halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
3373 					outData.push_back(tcu::Vec4(right - halfPixel, up + offsets[lineNdx], 0.0f, 1.0f));
3374 				}
3375 
3376 				break;
3377 			}
3378 
3379 			case 1:
3380 			{
3381 				for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3382 				{
3383 					outData.push_back(tcu::Vec4(left + offsets[lineNdx],   up + halfPixel, 0.0f, 1.0f));
3384 					outData.push_back(tcu::Vec4(left + offsets[lineNdx], down - halfPixel, 0.0f, 1.0f));
3385 				}
3386 
3387 				break;
3388 			}
3389 
3390 			case 2:
3391 			{
3392 				for (size_t lineNdx = 0; lineNdx < DE_LENGTH_OF_ARRAY(offsets); ++lineNdx)
3393 				{
3394 					outData.push_back(tcu::Vec4(left + offsets[lineNdx],          up + halfPixel, 0.0f, 1.0f));
3395 					outData.push_back(tcu::Vec4(      right - halfPixel, down - offsets[lineNdx], 0.0f, 1.0f));
3396 				}
3397 
3398 				break;
3399 			}
3400 
3401 			default:
3402 				TCU_THROW(InternalError, "Unexpected iteration");
3403 		}
3404 	}
3405 
3406 	DE_ASSERT(outData.size() % 2 == 0);
3407 	outLines.resize(outData.size() / 2);
3408 	for(size_t lineNdx = 0; lineNdx < outLines.size(); ++lineNdx)
3409 	{
3410 		outLines[lineNdx].positions[0] = outData[2 * lineNdx + 0];
3411 		outLines[lineNdx].positions[1] = outData[2 * lineNdx + 1];
3412 	}
3413 
3414 	// log
3415 	m_context.getTestContext().getLog()
3416 		<< tcu::TestLog::Message
3417 		<< "Testing " << iterationComment << " "
3418 		<< "with rendering " << outLines.size() << " line(s):"
3419 		<< tcu::TestLog::EndMessage;
3420 
3421 	for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
3422 	{
3423 		const deUint32	 multiplier	= m_renderSize / 2;
3424 
3425 		m_context.getTestContext().getLog()
3426 			<< tcu::TestLog::Message
3427 			<< "Line " << (ndx+1) << ":"
3428 			<< "\n\t" << outLines[ndx].positions[0] << " == " << (float(multiplier) * outLines[ndx].positions[0]) << "/" << multiplier
3429 			<< "\n\t" << outLines[ndx].positions[1] << " == " << (float(multiplier) * outLines[ndx].positions[1]) << "/" << multiplier
3430 			<< tcu::TestLog::EndMessage;
3431 	}
3432 }
3433 
generateDegenerateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)3434 void ConservativeLineTestInstance::generateDegenerateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
3435 {
3436 	const bool		isOverestimate		= m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
3437 	const float		pixelSize			= 2.0f / float(m_renderSize);
3438 	const deUint32	subPixels			= 1u << m_context.getDeviceProperties().limits.subPixelPrecisionBits;
3439 	const float		subPixelSize		= pixelSize / float(subPixels);
3440 	const char*		iterationComments[]	= { "Horizontal line", "Vertical line", "Diagonal line" };
3441 
3442 	outData.clear();
3443 
3444 	if (isOverestimate)
3445 	{
3446 		const float		extraOverestimationSize			= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3447 		const float		totalOverestimate				= m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
3448 		const float		totalOverestimateInSubPixels	= deFloatCeil(totalOverestimate * float(subPixels));
3449 		const float		overestimate					= subPixelSize * totalOverestimateInSubPixels;
3450 		const float		overestimateSafetyMargin		= subPixelSize * 0.125f;
3451 		const float		margin							= overestimate + overestimateSafetyMargin;
3452 		const float		originOffset					= -1.0f + 1 * pixelSize;
3453 		const float		originLeft						= originOffset + margin;
3454 		const float		originRight						= originOffset + margin + 0.25f * subPixelSize;
3455 		const float		originUp						= originOffset + margin;
3456 		const float		originDown						= originOffset + margin + 0.25f * subPixelSize;
3457 
3458 		switch (iteration)
3459 		{
3460 			case 0:
3461 			{
3462 				outData.push_back(tcu::Vec4( originLeft,   originUp, 0.0f, 1.0f));
3463 				outData.push_back(tcu::Vec4(originRight,   originUp, 0.0f, 1.0f));
3464 
3465 				break;
3466 			}
3467 
3468 			case 1:
3469 			{
3470 				outData.push_back(tcu::Vec4( originLeft,   originUp, 0.0f, 1.0f));
3471 				outData.push_back(tcu::Vec4( originLeft, originDown, 0.0f, 1.0f));
3472 
3473 				break;
3474 			}
3475 
3476 			case 2:
3477 			{
3478 				outData.push_back(tcu::Vec4( originLeft,   originUp, 0.0f, 1.0f));
3479 				outData.push_back(tcu::Vec4(originRight, originDown, 0.0f, 1.0f));
3480 
3481 				break;
3482 			}
3483 
3484 			default:
3485 				TCU_THROW(InternalError, "Unexpected iteration");
3486 		}
3487 	}
3488 	else
3489 	{
3490 		size_t rowStart	= 3 * getIteration();
3491 		size_t rowEnd	= 3 * (getIteration() + 1);
3492 
3493 		for (size_t rowNdx = rowStart; rowNdx < rowEnd; ++rowNdx)
3494 		for (size_t colNdx = 0; colNdx < 3 * 3; ++colNdx)
3495 		{
3496 			const float		originOffsetY	= -1.0f + float(4 * (1 + rowNdx)) * pixelSize;
3497 			const float		originOffsetX	= -1.0f + float(4 * (1 + colNdx)) * pixelSize;
3498 			const float		x0				= float(rowNdx % 3);
3499 			const float		y0				= float(rowNdx / 3);
3500 			const float		x1				= float(colNdx % 3);
3501 			const float		y1				= float(colNdx / 3);
3502 			const tcu::Vec4	p0				= tcu::Vec4(originOffsetX + x0 * pixelSize / 2.0f, originOffsetY + y0 * pixelSize / 2.0f, 0.0f, 1.0f);
3503 			const tcu::Vec4	p1				= tcu::Vec4(originOffsetX + x1 * pixelSize / 2.0f, originOffsetY + y1 * pixelSize / 2.0f, 0.0f, 1.0f);
3504 
3505 			if (x0 == x1 && y0 == y1)
3506 				continue;
3507 
3508 			outData.push_back(p0);
3509 			outData.push_back(p1);
3510 		}
3511 	}
3512 
3513 	outLines.resize(outData.size() / 2);
3514 
3515 	for (size_t ndx = 0; ndx < outLines.size(); ++ndx)
3516 	{
3517 		outLines[ndx].positions[0] = outData[2 * ndx + 0];
3518 		outLines[ndx].positions[1] = outData[2 * ndx + 1];
3519 	}
3520 
3521 	// log
3522 	m_context.getTestContext().getLog()
3523 		<< tcu::TestLog::Message
3524 		<< "Testing " << iterationComments[iteration] << " "
3525 		<< "with rendering " << outLines.size() << " line(s):"
3526 		<< tcu::TestLog::EndMessage;
3527 
3528 	for (int ndx = 0; ndx < (int)outLines.size(); ++ndx)
3529 	{
3530 		const deUint32	multiplierInt	= m_renderSize / 2;
3531 		const deUint32	multiplierFrac	= subPixels;
3532 		std::string		coordsString;
3533 
3534 		for (size_t vertexNdx = 0; vertexNdx < 2; ++vertexNdx)
3535 		{
3536 			const tcu::Vec4&	pos				= outLines[ndx].positions[vertexNdx];
3537 			std::ostringstream	coordsFloat;
3538 			std::ostringstream	coordsNatural;
3539 
3540 			for (int coordNdx = 0; coordNdx < 2; ++coordNdx)
3541 			{
3542 				const char*	sep		= (coordNdx < 1) ? "," : "";
3543 				const float	coord	= pos[coordNdx];
3544 				const char	sign	= deSign(coord) < 0 ? '-' : '+';
3545 				const float	m		= deFloatFloor(float(multiplierInt) * deFloatAbs(coord));
3546 				const float	r		= deFloatFrac(float(multiplierInt) * deFloatAbs(coord)) * float(multiplierFrac);
3547 
3548 				coordsFloat << std::fixed << std::setw(13) << std::setprecision(10) << coord << sep;
3549 				coordsNatural << sign << '(' << m << '+' << r << '/' << multiplierFrac << ')' << sep;
3550 			}
3551 
3552 			coordsString += "\n\t[" + coordsFloat.str() + "] == [" + coordsNatural.str() + "] / " + de::toString(multiplierInt);
3553 		}
3554 
3555 		m_context.getTestContext().getLog()
3556 			<< tcu::TestLog::Message
3557 			<< "Line " << (ndx + 1) << ':'
3558 			<< coordsString
3559 			<< tcu::TestLog::EndMessage;
3560 	}
3561 }
3562 
drawPrimitives(tcu::Surface & result,const std::vector<tcu::Vec4> & vertexData,VkPrimitiveTopology primitiveTopology)3563 void ConservativeLineTestInstance::drawPrimitives (tcu::Surface& result, const std::vector<tcu::Vec4>& vertexData, VkPrimitiveTopology primitiveTopology)
3564 {
3565 	if (m_conservativeTestConfig.degeneratePrimitives)
3566 	{
3567 		// Set provoking vertex color to white
3568 		tcu::Vec4				colorProvoking	(1.0f, 1.0f, 1.0f, 1.0f);
3569 		tcu::Vec4				colorOther		(0.0f, 1.0f, 1.0f, 1.0f);
3570 		std::vector<tcu::Vec4>	colorData;
3571 
3572 		colorData.reserve(vertexData.size());
3573 
3574 		for (size_t vertexNdx = 0; vertexNdx < vertexData.size(); ++vertexNdx)
3575 			if (vertexNdx % 2 == 0)
3576 				colorData.push_back(colorProvoking);
3577 			else
3578 				colorData.push_back(colorOther);
3579 
3580 		BaseRenderingTestInstance::drawPrimitives(result, vertexData, colorData, primitiveTopology);
3581 	}
3582 	else
3583 		BaseRenderingTestInstance::drawPrimitives(result, vertexData, primitiveTopology);
3584 }
3585 
compareAndVerify(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)3586 bool ConservativeLineTestInstance::compareAndVerify (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
3587 {
3588 	DE_UNREF(drawBuffer);
3589 
3590 	switch (m_conservativeTestConfig.conservativeRasterizationMode)
3591 	{
3592 		case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
3593 		{
3594 			if (m_conservativeTestConfig.degeneratePrimitives)
3595 				return compareAndVerifyOverestimatedDegenerate(lines, resultImage);
3596 			else
3597 				return compareAndVerifyOverestimatedNormal(lines, resultImage);
3598 
3599 			break;
3600 		}
3601 		case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
3602 		{
3603 			if (m_conservativeTestConfig.degeneratePrimitives)
3604 				return compareAndVerifyUnderestimatedDegenerate(lines, resultImage);
3605 			else
3606 				return compareAndVerifyUnderestimatedNormal(lines, resultImage);
3607 
3608 			break;
3609 		}
3610 
3611 		default:
3612 			TCU_THROW(InternalError, "Unknown conservative rasterization mode");
3613 	}
3614 }
3615 
compareAndVerifyOverestimatedNormal(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)3616 bool ConservativeLineTestInstance::compareAndVerifyOverestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
3617 {
3618 	DE_UNREF(lines);
3619 
3620 	const int			b						= 3; // bar width
3621 	const int			w						= resultImage.getWidth() - 1;
3622 	const int			h						= resultImage.getHeight() - 1;
3623 	const int			xStarts[]				= {     1,     1,     1 };
3624 	const int			xEnds[]					= { w - 1,     b, w - 1 };
3625 	const int			yStarts[]				= {     1,     1, h - b };
3626 	const int			yEnds[]					= {     b, h - 1, h - 1 };
3627 	const int			xStart					= xStarts[getIteration()];
3628 	const int			xEnd					= xEnds[getIteration()];
3629 	const int			yStart					= yStarts[getIteration()];
3630 	const int			yEnd					= yEnds[getIteration()];
3631 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
3632 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
3633 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3634 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3635 	int					errX					= 0;
3636 	int					errY					= 0;
3637 	deUint32			errValue				= 0;
3638 	bool				result					= true;
3639 
3640 	DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
3641 
3642 	for (int y = yStart; result && y < yEnd; ++y)
3643 	for (int x = xStart; result && x < xEnd; ++x)
3644 	{
3645 		if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
3646 		{
3647 			result		= false;
3648 			errX		= x;
3649 			errY		= y;
3650 			errValue	= resultImage.getPixel(x,y).getPacked();
3651 
3652 			break;
3653 		}
3654 	}
3655 
3656 	if (!result)
3657 	{
3658 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
3659 
3660 		for (int y = 0; y < errorMask.getHeight(); ++y)
3661 		for (int x = 0; x < errorMask.getWidth(); ++x)
3662 			errorMask.setPixel(x, y, backgroundColor);
3663 
3664 		for (int y = yStart; y < yEnd; ++y)
3665 		for (int x = xStart; x < xEnd; ++x)
3666 		{
3667 			if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
3668 				errorMask.setPixel(x,y, unexpectedPixelColor);
3669 		}
3670 
3671 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
3672 			<< tcu::TestLog::EndMessage;
3673 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3674 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3675 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3676 			<< tcu::TestLog::EndImageSet;
3677 	}
3678 	else
3679 	{
3680 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3681 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3682 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3683 			<< tcu::TestLog::EndImageSet;
3684 	}
3685 
3686 	return result;
3687 }
3688 
compareAndVerifyOverestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)3689 bool ConservativeLineTestInstance::compareAndVerifyOverestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
3690 {
3691 	DE_UNREF(lines);
3692 
3693 	const char*			iterationComments[]		= { "Horizontal line", "Vertical line", "Diagonal line" };
3694 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
3695 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
3696 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3697 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3698 	bool				result					= true;
3699 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
3700 
3701 	for (int y = 0; y < resultImage.getHeight(); ++y)
3702 	for (int x = 0; x < resultImage.getWidth(); ++x)
3703 		referenceImage.setPixel(x, y, backgroundColor);
3704 
3705 	if (m_conservativeRasterizationProperties.degenerateLinesRasterized)
3706 	{
3707 		log << tcu::TestLog::Message << "Lines expected to be rasterized with white color" << tcu::TestLog::EndMessage;
3708 
3709 		// This pixel will alway be covered due to the placement of the line.
3710 		referenceImage.setPixel(1, 1, foregroundColor);
3711 
3712 		// Additional pixels will be covered based on the extra bloat added to the primitive.
3713 		const float extraOverestimation = getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3714 		const int xExtent = 1 + int((extraOverestimation * 2.0f) + 0.5f);
3715 		const int yExtent = xExtent;
3716 
3717 		for (int y = 0; y <= yExtent; ++y)
3718 		for (int x = 0; x <= xExtent; ++x)
3719 			referenceImage.setPixel(x, y, foregroundColor);
3720 	}
3721 	else
3722 		log << tcu::TestLog::Message << "Lines expected to be culled" << tcu::TestLog::EndMessage;
3723 
3724 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
3725 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
3726 	{
3727 		if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3728 		{
3729 			result = false;
3730 
3731 			break;
3732 		}
3733 	}
3734 
3735 	if (!result)
3736 	{
3737 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
3738 
3739 		for (int y = 0; y < errorMask.getHeight(); ++y)
3740 		for (int x = 0; x < errorMask.getWidth(); ++x)
3741 		{
3742 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3743 				errorMask.setPixel(x, y, unexpectedPixelColor);
3744 			else
3745 				errorMask.setPixel(x, y, backgroundColor);
3746 		}
3747 
3748 		log << tcu::TestLog::Message << "Invalid pixels found for mode " << iterationComments[getIteration()]
3749 			<< tcu::TestLog::EndMessage;
3750 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3751 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3752 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
3753 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3754 			<< tcu::TestLog::EndImageSet;
3755 	}
3756 	else
3757 	{
3758 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3759 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3760 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3761 			<< tcu::TestLog::EndImageSet;
3762 	}
3763 
3764 	return result;
3765 }
3766 
compareAndVerifyUnderestimatedNormal(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)3767 bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedNormal (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
3768 {
3769 	DE_UNREF(lines);
3770 
3771 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
3772 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
3773 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3774 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3775 	int					errX					= -1;
3776 	int					errY					= -1;
3777 	tcu::RGBA			errValue;
3778 	bool				result					= true;
3779 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
3780 
3781 	DE_ASSERT(resultImage.getHeight() == resultImage.getWidth());
3782 
3783 	for (int y = 0; y < referenceImage.getHeight(); ++y)
3784 	for (int x = 0; x < referenceImage.getWidth(); ++x)
3785 		referenceImage.setPixel(x, y, backgroundColor);
3786 
3787 	if (getLineWidth() > 1.0f)
3788 	{
3789 		const tcu::IVec2	viewportSize(resultImage.getWidth(), resultImage.getHeight());
3790 
3791 		for (size_t lineNdx = 0; lineNdx < lines.size(); ++lineNdx)
3792 		for (int y = 0; y < resultImage.getHeight(); ++y)
3793 		for (int x = 0; x < resultImage.getWidth(); ++x)
3794 		{
3795 			if (calculateUnderestimateLineCoverage(lines[lineNdx].positions[0], lines[lineNdx].positions[1], getLineWidth(), tcu::IVec2(x,y), viewportSize) == tcu::COVERAGE_FULL)
3796 				referenceImage.setPixel(x, y, foregroundColor);
3797 		}
3798 	}
3799 
3800 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
3801 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
3802 	{
3803 		if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
3804 		{
3805 			result		= false;
3806 			errX		= x;
3807 			errY		= y;
3808 			errValue	= resultImage.getPixel(x,y);
3809 
3810 			break;
3811 		}
3812 	}
3813 
3814 	if (!result)
3815 	{
3816 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
3817 
3818 		for (int y = 0; y < errorMask.getHeight(); ++y)
3819 		for (int x = 0; x < errorMask.getWidth(); ++x)
3820 			errorMask.setPixel(x, y, backgroundColor);
3821 
3822 		for (int y = 0; y < errorMask.getHeight(); ++y)
3823 		for (int x = 0; x < errorMask.getWidth();  ++x)
3824 		{
3825 			if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
3826 				errorMask.setPixel(x, y, unexpectedPixelColor);
3827 		}
3828 
3829 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " errValue=" << errValue
3830 			<< tcu::TestLog::EndMessage;
3831 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3832 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3833 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
3834 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3835 			<< tcu::TestLog::EndImageSet;
3836 	}
3837 	else
3838 	{
3839 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3840 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3841 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3842 			<< tcu::TestLog::EndImageSet;
3843 	}
3844 
3845 	return result;
3846 }
3847 
compareAndVerifyUnderestimatedDegenerate(std::vector<LineSceneSpec::SceneLine> & lines,tcu::Surface & resultImage)3848 bool ConservativeLineTestInstance::compareAndVerifyUnderestimatedDegenerate (std::vector<LineSceneSpec::SceneLine>& lines, tcu::Surface& resultImage)
3849 {
3850 	DE_UNREF(lines);
3851 
3852 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
3853 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
3854 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
3855 	bool				result					= true;
3856 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
3857 
3858 	for (int y = 0; y < resultImage.getHeight(); ++y)
3859 	for (int x = 0; x < resultImage.getWidth(); ++x)
3860 		referenceImage.setPixel(x, y, backgroundColor);
3861 
3862 	log << tcu::TestLog::Message << "No lines expected to be rasterized" << tcu::TestLog::EndMessage;
3863 
3864 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
3865 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
3866 	{
3867 		if (resultImage.getPixel(x,y).getPacked() != referenceImage.getPixel(x,y).getPacked())
3868 		{
3869 			result = false;
3870 
3871 			break;
3872 		}
3873 	}
3874 
3875 	if (!result)
3876 	{
3877 		tcu::Surface	errorMask	(resultImage.getWidth(), resultImage.getHeight());
3878 
3879 		for (int y = 0; y < errorMask.getHeight(); ++y)
3880 		for (int x = 0; x < errorMask.getWidth(); ++x)
3881 		{
3882 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
3883 				errorMask.setPixel(x, y, unexpectedPixelColor);
3884 			else
3885 				errorMask.setPixel(x, y, backgroundColor);
3886 		}
3887 
3888 		log << tcu::TestLog::Message << "Invalid pixels found" << tcu::TestLog::EndMessage;
3889 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3890 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
3891 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
3892 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
3893 			<< tcu::TestLog::EndImageSet;
3894 	}
3895 	else
3896 	{
3897 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
3898 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
3899 			<< tcu::TestLog::Image("Result", "Result", resultImage)
3900 			<< tcu::TestLog::EndImageSet;
3901 	}
3902 
3903 	return result;
3904 }
3905 
initRasterizationConservativeStateCreateInfo(void)3906 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativeLineTestInstance::initRasterizationConservativeStateCreateInfo (void)
3907 {
3908 	const float															extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
3909 	std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	result;
3910 
3911 	result.reserve(getIterationCount());
3912 
3913 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3914 	{
3915 		const VkPipelineRasterizationConservativeStateCreateInfoEXT	rasterizationConservativeStateCreateInfo	=
3916 		{
3917 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT,	//  VkStructureType											sType;
3918 			DE_NULL,																		//  const void*												pNext;
3919 			(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0,						//  VkPipelineRasterizationConservativeStateCreateFlagsEXT	flags;
3920 			m_conservativeTestConfig.conservativeRasterizationMode,							//  VkConservativeRasterizationModeEXT						conservativeRasterizationMode;
3921 			extraOverestimationSize															//  float													extraPrimitiveOverestimationSize;
3922 		};
3923 
3924 		result.push_back(rasterizationConservativeStateCreateInfo);
3925 	}
3926 
3927 	return result;
3928 }
3929 
initRasterizationStateCreateInfo(void)3930 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativeLineTestInstance::initRasterizationStateCreateInfo (void)
3931 {
3932 	std::vector<VkPipelineRasterizationStateCreateInfo>	result;
3933 
3934 	result.reserve(getIterationCount());
3935 
3936 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
3937 	{
3938 		const VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
3939 		{
3940 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		//  VkStructureType							sType;
3941 			&m_rasterizationConservativeStateCreateInfo[iteration],			//  const void*								pNext;
3942 			0,																//  VkPipelineRasterizationStateCreateFlags	flags;
3943 			false,															//  VkBool32								depthClampEnable;
3944 			false,															//  VkBool32								rasterizerDiscardEnable;
3945 			VK_POLYGON_MODE_FILL,											//  VkPolygonMode							polygonMode;
3946 			VK_CULL_MODE_NONE,												//  VkCullModeFlags							cullMode;
3947 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								//  VkFrontFace								frontFace;
3948 			VK_FALSE,														//  VkBool32								depthBiasEnable;
3949 			0.0f,															//  float									depthBiasConstantFactor;
3950 			0.0f,															//  float									depthBiasClamp;
3951 			0.0f,															//  float									depthBiasSlopeFactor;
3952 			getLineWidth(),													//  float									lineWidth;
3953 		};
3954 
3955 		result.push_back(rasterizationStateCreateInfo);
3956 	}
3957 
3958 	return result;
3959 }
3960 
getRasterizationStateCreateInfo(void) const3961 const VkPipelineRasterizationStateCreateInfo* ConservativeLineTestInstance::getRasterizationStateCreateInfo	(void) const
3962 {
3963 	return &m_rasterizationStateCreateInfo[getIteration()];
3964 }
3965 
getLineRasterizationStateCreateInfo(void) const3966 const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativeLineTestInstance::getLineRasterizationStateCreateInfo	(void) const
3967 {
3968 	return DE_NULL;
3969 }
3970 
3971 
3972 class ConservativePointTestInstance : public PointTestInstance
3973 {
3974 public:
ConservativePointTestInstance(Context & context,ConservativeTestConfig conservativeTestConfig,VkSampleCountFlagBits sampleCount)3975 																				ConservativePointTestInstance					(Context&				context,
3976 																																 ConservativeTestConfig	conservativeTestConfig,
3977 																																 VkSampleCountFlagBits	sampleCount)
3978 																					: PointTestInstance								(
3979 																																		context,
3980 																																		PRIMITIVEWIDENESS_NARROW,
3981 																																		PRIMITIVESTRICTNESS_IGNORE,
3982 																																		sampleCount,
3983 																																		LINESTIPPLE_DISABLED,
3984 																																		VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT,
3985 																																		0,
3986 																																		conservativeTestConfig.resolution,
3987 																																		conservativeTestConfig.lineWidth
3988 																																	)
3989 																					, m_conservativeTestConfig						(conservativeTestConfig)
3990 																					, m_conservativeRasterizationProperties			(context.getConservativeRasterizationPropertiesEXT())
3991 																					, m_rasterizationConservativeStateCreateInfo	(initRasterizationConservativeStateCreateInfo())
3992 																					, m_rasterizationStateCreateInfo				(initRasterizationStateCreateInfo())
3993 																					, m_renderStart									()
3994 																					, m_renderEnd									()
3995 																				{}
3996 
3997 	void																		generatePoints									(int										iteration,
3998 																																 std::vector<tcu::Vec4>&					outData,
3999 																																 std::vector<PointSceneSpec::ScenePoint>&	outPoints);
4000 	const VkPipelineRasterizationStateCreateInfo*								getRasterizationStateCreateInfo					(void) const;
4001 
4002 protected:
4003 	virtual const VkPipelineRasterizationLineStateCreateInfoEXT*				getLineRasterizationStateCreateInfo				(void) const;
4004 
4005 	virtual bool																compareAndVerify								(std::vector<PointSceneSpec::ScenePoint>&	points,
4006 																																 tcu::Surface&								resultImage,
4007 																																 std::vector<tcu::Vec4>&					drawBuffer);
4008 	virtual bool																compareAndVerifyOverestimated					(std::vector<PointSceneSpec::ScenePoint>&	points,
4009 																																 tcu::Surface&								resultImage);
4010 	virtual bool																compareAndVerifyUnderestimated					(std::vector<PointSceneSpec::ScenePoint>&	points,
4011 																																 tcu::Surface&								resultImage);
4012 
4013 private:
4014 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	initRasterizationConservativeStateCreateInfo	(void);
4015 	const std::vector<VkPipelineRasterizationStateCreateInfo>					initRasterizationStateCreateInfo				(void);
4016 
4017 	const ConservativeTestConfig												m_conservativeTestConfig;
4018 	const VkPhysicalDeviceConservativeRasterizationPropertiesEXT				m_conservativeRasterizationProperties;
4019 	const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	m_rasterizationConservativeStateCreateInfo;
4020 	const std::vector<VkPipelineRasterizationStateCreateInfo>					m_rasterizationStateCreateInfo;
4021 	std::vector<int>															m_renderStart;
4022 	std::vector<int>															m_renderEnd;
4023 };
4024 
generatePoints(int iteration,std::vector<tcu::Vec4> & outData,std::vector<PointSceneSpec::ScenePoint> & outPoints)4025 void ConservativePointTestInstance::generatePoints (int iteration, std::vector<tcu::Vec4>& outData, std::vector<PointSceneSpec::ScenePoint>& outPoints)
4026 {
4027 	const float	pixelSize		= 2.0f / float(m_renderSize);
4028 	const bool	isOverestimate	= m_conservativeTestConfig.conservativeRasterizationMode == VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
4029 
4030 	m_renderStart.clear();
4031 	m_renderEnd.clear();
4032 
4033 	if (isOverestimate)
4034 	{
4035 		const float	extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
4036 		const float	overestimate			= m_conservativeRasterizationProperties.primitiveOverestimationSize + extraOverestimationSize;
4037 		const float	halfRenderAreaSize		= overestimate + 0.5f;
4038 		const float	pointCenterOffset		= 2.0f + 0.5f * float(iteration) + halfRenderAreaSize;
4039 		const float	pointEdgeStart			= pointCenterOffset - halfRenderAreaSize;
4040 		const float	pointEdgeEnd			= pointEdgeStart + 2 * halfRenderAreaSize;
4041 		const int	renderStart				= int(deFloatFloor(pointEdgeStart)) + int((deFloatFrac(pointEdgeStart) > 0.0f) ? 0 : -1);
4042 		const int	renderEnd				= int(deFloatCeil(pointEdgeEnd)) + int((deFloatFrac(pointEdgeEnd) > 0.0f) ? 0 : 1);
4043 
4044 		outData.push_back(tcu::Vec4(-1.0f + pixelSize * pointCenterOffset, -1.0f + pixelSize * pointCenterOffset, 0.0f, 1.0f));
4045 
4046 		m_renderStart.push_back(renderStart);
4047 		m_renderEnd.push_back(renderEnd);
4048 	}
4049 	else
4050 	{
4051 		const float	pointSize			= m_conservativeTestConfig.lineWidth;
4052 		const float	halfRenderAreaSize	= pointSize / 2.0f;
4053 
4054 		switch (iteration)
4055 		{
4056 			case 0:
4057 			{
4058 				const float	pointCenterOffset	= (pointSize + 1.0f + deFloatFrac(pointSize)) / 2.0f;
4059 				const float	pointEdgeStart		= pointCenterOffset - halfRenderAreaSize;
4060 				const float	pointEdgeEnd		= pointEdgeStart + 2.0f * halfRenderAreaSize;
4061 				const int	renderStart			= (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
4062 				const int	renderEnd			= (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
4063 
4064 				outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4065 
4066 				m_renderStart.push_back(renderStart);
4067 				m_renderEnd.push_back(renderEnd);
4068 
4069 				break;
4070 			}
4071 
4072 			case 1:
4073 			{
4074 				const float subPixelSize		= 1.0f / float(1u<<(m_subpixelBits - 1));
4075 				const float	pointBottomLeft		= 1.0f - subPixelSize;
4076 				const float	pointCenterOffset	= pointBottomLeft + pointSize / 2.0f;
4077 				const float	pointEdgeStart		= pointCenterOffset - halfRenderAreaSize;
4078 				const float	pointEdgeEnd		= pointEdgeStart + 2.0f * halfRenderAreaSize;
4079 				const int	renderStart			= (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart));
4080 				const int	renderEnd			= (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd));
4081 
4082 				outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4083 
4084 				m_renderStart.push_back(renderStart);
4085 				m_renderEnd.push_back(renderEnd);
4086 
4087 				break;
4088 			}
4089 
4090 			case 2:
4091 			{
4092 				// Edges of a point are considered not covered. Top-left coverage rule is not applicable for underestimate rasterization.
4093 				const float	pointCenterOffset	= (pointSize + deFloatFrac(pointSize)) / 2.0f;
4094 				const float	pointEdgeStart		= pointCenterOffset - halfRenderAreaSize;
4095 				const float	pointEdgeEnd		= pointEdgeStart + 2.0f * halfRenderAreaSize;
4096 				const int	renderStart			= (m_renderSize / 2) + int(deFloatCeil(pointEdgeStart)) + 1;
4097 				const int	renderEnd			= (m_renderSize / 2) + int(deFloatFloor(pointEdgeEnd)) - 1;
4098 
4099 				outData.push_back(tcu::Vec4(pixelSize * pointCenterOffset, pixelSize * pointCenterOffset, 0.0f, 1.0f));
4100 
4101 				m_renderStart.push_back(renderStart);
4102 				m_renderEnd.push_back(renderEnd);
4103 
4104 				break;
4105 			}
4106 
4107 			default:
4108 				TCU_THROW(InternalError, "Unexpected iteration");
4109 		}
4110 	}
4111 
4112 	outPoints.resize(outData.size());
4113 	for (size_t ndx = 0; ndx < outPoints.size(); ++ndx)
4114 	{
4115 		outPoints[ndx].position = outData[ndx];
4116 		outPoints[ndx].pointSize = getPointSize();
4117 	}
4118 
4119 	// log
4120 	m_context.getTestContext().getLog()
4121 		<< tcu::TestLog::Message
4122 		<< "Testing conservative point rendering "
4123 		<< "with rendering " << outPoints.size() << " points(s):"
4124 		<< tcu::TestLog::EndMessage;
4125 	for (int ndx = 0; ndx < (int)outPoints.size(); ++ndx)
4126 	{
4127 		const deUint32	 multiplier	= m_renderSize / 2;
4128 
4129 		m_context.getTestContext().getLog()
4130 			<< tcu::TestLog::Message
4131 			<< "Point " << (ndx+1) << ":"
4132 			<< "\n\t" << outPoints[ndx].position << " == " << (float(multiplier) * outPoints[ndx].position) << "/" << multiplier
4133 			<< tcu::TestLog::EndMessage;
4134 	}
4135 }
4136 
compareAndVerify(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage,std::vector<tcu::Vec4> & drawBuffer)4137 bool ConservativePointTestInstance::compareAndVerify (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage, std::vector<tcu::Vec4>& drawBuffer)
4138 {
4139 	DE_UNREF(drawBuffer);
4140 
4141 	switch (m_conservativeTestConfig.conservativeRasterizationMode)
4142 	{
4143 		case VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT:
4144 		{
4145 			return compareAndVerifyOverestimated(points, resultImage);
4146 		}
4147 		case VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT:
4148 		{
4149 			return compareAndVerifyUnderestimated(points, resultImage);
4150 		}
4151 
4152 		default:
4153 			TCU_THROW(InternalError, "Unknown conservative rasterization mode");
4154 	}
4155 }
4156 
compareAndVerifyOverestimated(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage)4157 bool ConservativePointTestInstance::compareAndVerifyOverestimated (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage)
4158 {
4159 	DE_UNREF(points);
4160 
4161 	const char*			iterationComments[]		= { "Edges and corners", "Partial coverage", "Edges and corners" };
4162 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
4163 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
4164 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
4165 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
4166 	int					errX					= 0;
4167 	int					errY					= 0;
4168 	deUint32			errValue				= 0;
4169 	bool				result					= true;
4170 
4171 	log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
4172 	log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
4173 
4174 	for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4175 	{
4176 		const int renderStart	= m_renderStart[renderAreaNdx];
4177 		const int renderEnd		= m_renderEnd[renderAreaNdx];
4178 
4179 		for (int y = renderStart; result && y < renderEnd; ++y)
4180 		for (int x = renderStart; result && x < renderEnd; ++x)
4181 		{
4182 			if (resultImage.getPixel(x,y).getPacked() != foregroundColor.getPacked())
4183 			{
4184 				result		= false;
4185 				errX		= x;
4186 				errY		= y;
4187 				errValue	= resultImage.getPixel(x, y).getPacked();
4188 
4189 				break;
4190 			}
4191 		}
4192 	}
4193 
4194 	if (!result)
4195 	{
4196 		tcu::Surface		referenceImage	(resultImage.getWidth(), resultImage.getHeight());
4197 		tcu::Surface		errorMask		(resultImage.getWidth(), resultImage.getHeight());
4198 		std::ostringstream	css;
4199 
4200 		for (int y = 0; y < resultImage.getHeight(); ++y)
4201 		for (int x = 0; x < resultImage.getWidth(); ++x)
4202 			referenceImage.setPixel(x, y, backgroundColor);
4203 
4204 		for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4205 		{
4206 			const int renderStart	= m_renderStart[renderAreaNdx];
4207 			const int renderEnd		= m_renderEnd[renderAreaNdx];
4208 
4209 			for (int y = renderStart; y < renderEnd; ++y)
4210 			for (int x = renderStart; x < renderEnd; ++x)
4211 				referenceImage.setPixel(x, y, foregroundColor);
4212 		}
4213 
4214 		for (int y = 0; y < errorMask.getHeight(); ++y)
4215 		for (int x = 0; x < errorMask.getWidth(); ++x)
4216 		{
4217 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4218 				errorMask.setPixel(x, y, unexpectedPixelColor);
4219 			else
4220 				errorMask.setPixel(x, y, backgroundColor);
4221 		}
4222 
4223 		css << std::endl;
4224 		for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4225 		{
4226 			const int renderStart	= m_renderStart[renderAreaNdx];
4227 			const int renderEnd		= m_renderEnd[renderAreaNdx];
4228 
4229 			css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")" << std::endl;
4230 		}
4231 
4232 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
4233 			<< tcu::TestLog::EndMessage;
4234 		log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str()
4235 			<< tcu::TestLog::EndMessage;
4236 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4237 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
4238 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
4239 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
4240 			<< tcu::TestLog::EndImageSet;
4241 	}
4242 	else
4243 	{
4244 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4245 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4246 			<< tcu::TestLog::Image("Result", "Result", resultImage)
4247 			<< tcu::TestLog::EndImageSet;
4248 	}
4249 
4250 	return result;
4251 }
4252 
compareAndVerifyUnderestimated(std::vector<PointSceneSpec::ScenePoint> & points,tcu::Surface & resultImage)4253 bool ConservativePointTestInstance::compareAndVerifyUnderestimated (std::vector<PointSceneSpec::ScenePoint>& points, tcu::Surface& resultImage)
4254 {
4255 	DE_UNREF(points);
4256 
4257 	const char*			iterationComments[]		= { "Full coverage", "Full coverage with subpixel", "Exact coverage" };
4258 	const tcu::RGBA		backgroundColor			= tcu::RGBA(0, 0, 0, 255);
4259 	const tcu::RGBA		foregroundColor			= tcu::RGBA(255, 255, 255, 255);
4260 	const tcu::RGBA		unexpectedPixelColor	= tcu::RGBA(255, 0, 0, 255);
4261 	tcu::TestLog&		log						= m_context.getTestContext().getLog();
4262 	int					errX					= 0;
4263 	int					errY					= 0;
4264 	deUint32			errValue				= 0;
4265 	bool				result					= true;
4266 	tcu::Surface		referenceImage			(resultImage.getWidth(), resultImage.getHeight());
4267 
4268 	log << tcu::TestLog::Message << "Points expected to be rasterized with white color" << tcu::TestLog::EndMessage;
4269 	log << tcu::TestLog::Message << "Testing " << iterationComments[getIteration()] << tcu::TestLog::EndMessage;
4270 
4271 	for (int y = 0; y < resultImage.getHeight(); ++y)
4272 	for (int x = 0; x < resultImage.getWidth(); ++x)
4273 		referenceImage.setPixel(x, y, backgroundColor);
4274 
4275 	for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4276 	{
4277 		const int renderStart	= m_renderStart[renderAreaNdx];
4278 		const int renderEnd		= m_renderEnd[renderAreaNdx];
4279 
4280 		for (int y = renderStart; y < renderEnd; ++y)
4281 		for (int x = renderStart; x < renderEnd; ++x)
4282 			referenceImage.setPixel(x, y, foregroundColor);
4283 	}
4284 
4285 	for (int y = 0; result && y < resultImage.getHeight(); ++y)
4286 	for (int x = 0; result && x < resultImage.getWidth(); ++x)
4287 	{
4288 		if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4289 		{
4290 			result		= false;
4291 			errX		= x;
4292 			errY		= y;
4293 			errValue	= resultImage.getPixel(x, y).getPacked();
4294 
4295 			break;
4296 		}
4297 	}
4298 
4299 	if (!result)
4300 	{
4301 		tcu::Surface		errorMask	(resultImage.getWidth(), resultImage.getHeight());
4302 		std::ostringstream	css;
4303 
4304 		for (int y = 0; y < errorMask.getHeight(); ++y)
4305 		for (int x = 0; x < errorMask.getWidth(); ++x)
4306 		{
4307 			if (resultImage.getPixel(x, y).getPacked() != referenceImage.getPixel(x, y).getPacked())
4308 				errorMask.setPixel(x, y, unexpectedPixelColor);
4309 			else
4310 				errorMask.setPixel(x, y, backgroundColor);
4311 		}
4312 
4313 		css << std::endl;
4314 		for (size_t renderAreaNdx = 0; result && renderAreaNdx < m_renderStart.size(); ++renderAreaNdx)
4315 		{
4316 			const int renderStart	= m_renderStart[renderAreaNdx];
4317 			const int renderEnd		= m_renderEnd[renderAreaNdx];
4318 
4319 			css << "[" << renderStart << "," << renderEnd << ") x [" << renderStart << "," << renderEnd << ")" << std::endl;
4320 		}
4321 
4322 		log << tcu::TestLog::Message << "Invalid pixels found starting at " << errX << "," << errY << " value=0x" << std::hex << errValue
4323 			<< tcu::TestLog::EndMessage;
4324 		log << tcu::TestLog::Message << "Expected area(s) to be filled:" << css.str()
4325 			<< tcu::TestLog::EndMessage;
4326 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4327 			<< tcu::TestLog::Image("Result",	"Result",		resultImage)
4328 			<< tcu::TestLog::Image("Reference",	"Reference",	referenceImage)
4329 			<< tcu::TestLog::Image("ErrorMask", "ErrorMask",	errorMask)
4330 			<< tcu::TestLog::EndImageSet;
4331 	}
4332 	else
4333 	{
4334 		log << tcu::TestLog::Message << "No invalid pixels found." << tcu::TestLog::EndMessage;
4335 		log << tcu::TestLog::ImageSet("Verification result", "Result of rendering")
4336 			<< tcu::TestLog::Image("Result", "Result", resultImage)
4337 			<< tcu::TestLog::EndImageSet;
4338 	}
4339 
4340 	return result;
4341 }
4342 
initRasterizationConservativeStateCreateInfo(void)4343 const std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT> ConservativePointTestInstance::initRasterizationConservativeStateCreateInfo (void)
4344 {
4345 	const float															extraOverestimationSize	= getExtraOverestimationSize(m_conservativeTestConfig.extraOverestimationSize, m_conservativeRasterizationProperties);
4346 	std::vector<VkPipelineRasterizationConservativeStateCreateInfoEXT>	result;
4347 
4348 	result.reserve(getIterationCount());
4349 
4350 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4351 	{
4352 		const VkPipelineRasterizationConservativeStateCreateInfoEXT	rasterizationConservativeStateCreateInfo	=
4353 		{
4354 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT,	//  VkStructureType											sType;
4355 			DE_NULL,																		//  const void*												pNext;
4356 			(VkPipelineRasterizationConservativeStateCreateFlagsEXT)0,						//  VkPipelineRasterizationConservativeStateCreateFlagsEXT	flags;
4357 			m_conservativeTestConfig.conservativeRasterizationMode,							//  VkConservativeRasterizationModeEXT						conservativeRasterizationMode;
4358 			extraOverestimationSize															//  float													extraPrimitiveOverestimationSize;
4359 		};
4360 
4361 		result.push_back(rasterizationConservativeStateCreateInfo);
4362 	}
4363 
4364 	return result;
4365 }
4366 
initRasterizationStateCreateInfo(void)4367 const std::vector<VkPipelineRasterizationStateCreateInfo> ConservativePointTestInstance::initRasterizationStateCreateInfo (void)
4368 {
4369 	std::vector<VkPipelineRasterizationStateCreateInfo>	result;
4370 
4371 	result.reserve(getIterationCount());
4372 
4373 	for (int iteration = 0; iteration < getIterationCount(); ++iteration)
4374 	{
4375 		const VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
4376 		{
4377 			VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		//  VkStructureType							sType;
4378 			&m_rasterizationConservativeStateCreateInfo[iteration],			//  const void*								pNext;
4379 			0,																//  VkPipelineRasterizationStateCreateFlags	flags;
4380 			false,															//  VkBool32								depthClampEnable;
4381 			false,															//  VkBool32								rasterizerDiscardEnable;
4382 			VK_POLYGON_MODE_FILL,											//  VkPolygonMode							polygonMode;
4383 			VK_CULL_MODE_NONE,												//  VkCullModeFlags							cullMode;
4384 			VK_FRONT_FACE_COUNTER_CLOCKWISE,								//  VkFrontFace								frontFace;
4385 			VK_FALSE,														//  VkBool32								depthBiasEnable;
4386 			0.0f,															//  float									depthBiasConstantFactor;
4387 			0.0f,															//  float									depthBiasClamp;
4388 			0.0f,															//  float									depthBiasSlopeFactor;
4389 			0.0f,															//  float									lineWidth;
4390 		};
4391 
4392 		result.push_back(rasterizationStateCreateInfo);
4393 	}
4394 
4395 	return result;
4396 }
4397 
getRasterizationStateCreateInfo(void) const4398 const VkPipelineRasterizationStateCreateInfo* ConservativePointTestInstance::getRasterizationStateCreateInfo	(void) const
4399 {
4400 	return &m_rasterizationStateCreateInfo[getIteration()];
4401 }
4402 
getLineRasterizationStateCreateInfo(void) const4403 const VkPipelineRasterizationLineStateCreateInfoEXT* ConservativePointTestInstance::getLineRasterizationStateCreateInfo	(void) const
4404 {
4405 	return DE_NULL;
4406 }
4407 
4408 
4409 template <typename ConcreteTestInstance>
4410 class WidenessTestCase : public BaseRenderingTestCase
4411 {
4412 public:
WidenessTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,PrimitiveWideness wideness,PrimitiveStrictness strictness,bool isLineTest,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,deUint32 additionalRenderSize=0)4413 								WidenessTestCase	(tcu::TestContext&			context,
4414 													 const std::string&			name,
4415 													 const std::string&			description,
4416 													 PrimitiveWideness			wideness,
4417 													 PrimitiveStrictness		strictness,
4418 													 bool						isLineTest,
4419 													 VkSampleCountFlagBits		sampleCount,
4420 													 LineStipple				stipple,
4421 													 VkLineRasterizationModeEXT	lineRasterizationMode,
4422 													 deUint32					additionalRenderSize	= 0)
4423 									: BaseRenderingTestCase		(context, name, description, sampleCount)
4424 									, m_wideness(wideness)
4425 									, m_strictness				(strictness)
4426 									, m_isLineTest				(isLineTest)
4427 									, m_stipple					(stipple)
4428 									, m_lineRasterizationMode	(lineRasterizationMode)
4429 									, m_additionalRenderSize	(additionalRenderSize)
4430 								{}
4431 
createInstance(Context & context) const4432 	virtual TestInstance*		createInstance		(Context& context) const
4433 								{
4434 									return new ConcreteTestInstance(context, m_wideness, m_strictness, m_sampleCount, m_stipple, m_lineRasterizationMode, m_additionalRenderSize);
4435 								}
4436 
checkSupport(Context & context) const4437 	virtual	void				checkSupport		(Context& context) const
4438 								{
4439 									if (m_isLineTest)
4440 									{
4441 										if (m_wideness == PRIMITIVEWIDENESS_WIDE)
4442 											context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
4443 
4444 										switch (m_lineRasterizationMode)
4445 										{
4446 											default:
4447 												TCU_THROW(InternalError, "Unknown line rasterization mode");
4448 
4449 											case VK_LINE_RASTERIZATION_MODE_EXT_LAST:
4450 											{
4451 												if (m_strictness == PRIMITIVESTRICTNESS_STRICT)
4452 													if (!context.getDeviceProperties().limits.strictLines)
4453 														TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
4454 
4455 												if (m_strictness == PRIMITIVESTRICTNESS_NONSTRICT)
4456 													if (context.getDeviceProperties().limits.strictLines)
4457 														TCU_THROW(NotSupportedError, "Nonstrict rasterization is not supported");
4458 
4459 												break;
4460 											}
4461 
4462 											case VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT:
4463 											{
4464 												if (!context.getDeviceProperties().limits.strictLines)
4465 													TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
4466 
4467 												if (getLineStippleEnable() &&
4468 													!context.getLineRasterizationFeaturesEXT().stippledRectangularLines)
4469 													TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
4470 												break;
4471 											}
4472 
4473 											case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT:
4474 											{
4475 												if (!context.getLineRasterizationFeaturesEXT().rectangularLines)
4476 													TCU_THROW(NotSupportedError, "Rectangular lines not supported");
4477 
4478 												if (getLineStippleEnable() &&
4479 													!context.getLineRasterizationFeaturesEXT().stippledRectangularLines)
4480 													TCU_THROW(NotSupportedError, "Stippled rectangular lines not supported");
4481 												break;
4482 											}
4483 
4484 											case VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT:
4485 											{
4486 												if (!context.getLineRasterizationFeaturesEXT().bresenhamLines)
4487 													TCU_THROW(NotSupportedError, "Bresenham lines not supported");
4488 
4489 												if (getLineStippleEnable() &&
4490 													!context.getLineRasterizationFeaturesEXT().stippledBresenhamLines)
4491 													TCU_THROW(NotSupportedError, "Stippled Bresenham lines not supported");
4492 												break;
4493 											}
4494 
4495 											case VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT:
4496 											{
4497 												if (!context.getLineRasterizationFeaturesEXT().smoothLines)
4498 													TCU_THROW(NotSupportedError, "Smooth lines not supported");
4499 
4500 												if (getLineStippleEnable() &&
4501 													!context.getLineRasterizationFeaturesEXT().stippledSmoothLines)
4502 													TCU_THROW(NotSupportedError, "Stippled smooth lines not supported");
4503 												break;
4504 											}
4505 										}
4506 									}
4507 									else
4508 									{
4509 										if (m_wideness == PRIMITIVEWIDENESS_WIDE)
4510 											context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_LARGE_POINTS);
4511 									}
4512 								}
4513 
getLineStippleEnable(void) const4514 	bool					getLineStippleEnable	(void) const { return m_stipple != LINESTIPPLE_DISABLED; }
getLineStippleDynamic(void) const4515 	virtual bool			getLineStippleDynamic	(void) const { return m_stipple == LINESTIPPLE_DYNAMIC; };
4516 
4517 protected:
4518 	const PrimitiveWideness				m_wideness;
4519 	const PrimitiveStrictness			m_strictness;
4520 	const bool							m_isLineTest;
4521 	const LineStipple					m_stipple;
4522 	const VkLineRasterizationModeEXT	m_lineRasterizationMode;
4523 	const deUint32						m_additionalRenderSize;
4524 };
4525 
4526 class LinesTestInstance : public BaseLineTestInstance
4527 {
4528 public:
LinesTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,deUint32 additionalRenderSize=0)4529 								LinesTestInstance	(Context& context, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode, deUint32 additionalRenderSize = 0)
4530 									: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, wideness, strictness, sampleCount, stipple, lineRasterizationMode, additionalRenderSize)
4531 								{}
4532 
4533 	virtual void				generateLines		(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
4534 };
4535 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)4536 void LinesTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
4537 {
4538 	outData.resize(8);
4539 
4540 	switch (iteration)
4541 	{
4542 		case 0:
4543 			// \note: these values are chosen arbitrarily
4544 			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
4545 			outData[1] = tcu::Vec4(  0.5f,  0.2f, 0.0f, 1.0f);
4546 			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
4547 			outData[3] = tcu::Vec4( -0.3f,  0.2f, 0.0f, 1.0f);
4548 			outData[4] = tcu::Vec4( -1.5f, -0.4f, 0.0f, 1.0f);
4549 			outData[5] = tcu::Vec4(  0.1f,  0.5f, 0.0f, 1.0f);
4550 			outData[6] = tcu::Vec4( 0.75f, -0.4f, 0.0f, 1.0f);
4551 			outData[7] = tcu::Vec4(  0.3f,  0.8f, 0.0f, 1.0f);
4552 			break;
4553 
4554 		case 1:
4555 			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
4556 			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
4557 			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
4558 			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
4559 			outData[4] = tcu::Vec4(  0.88f,   0.9f, 0.0f, 1.0f);
4560 			outData[5] = tcu::Vec4(  0.18f,  -0.2f, 0.0f, 1.0f);
4561 			outData[6] = tcu::Vec4(   0.0f,   1.0f, 0.0f, 1.0f);
4562 			outData[7] = tcu::Vec4(   0.0f,  -1.0f, 0.0f, 1.0f);
4563 			break;
4564 
4565 		case 2:
4566 			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
4567 			outData[1] = tcu::Vec4(  1.1f, -0.9f, 0.0f, 1.0f);
4568 			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
4569 			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
4570 			outData[4] = tcu::Vec4( 0.88f,  0.7f, 0.0f, 1.0f);
4571 			outData[5] = tcu::Vec4(  0.8f, -0.7f, 0.0f, 1.0f);
4572 			outData[6] = tcu::Vec4(  0.9f,  0.7f, 0.0f, 1.0f);
4573 			outData[7] = tcu::Vec4( -0.9f,  0.7f, 0.0f, 1.0f);
4574 			break;
4575 	}
4576 
4577 	outLines.resize(4);
4578 	outLines[0].positions[0] = outData[0];
4579 	outLines[0].positions[1] = outData[1];
4580 	outLines[1].positions[0] = outData[2];
4581 	outLines[1].positions[1] = outData[3];
4582 	outLines[2].positions[0] = outData[4];
4583 	outLines[2].positions[1] = outData[5];
4584 	outLines[3].positions[0] = outData[6];
4585 	outLines[3].positions[1] = outData[7];
4586 
4587 	// log
4588 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering " << outLines.size() << " lines(s): (width = " << getLineWidth() << ")" << tcu::TestLog::EndMessage;
4589 	for (int lineNdx = 0; lineNdx < (int)outLines.size(); ++lineNdx)
4590 	{
4591 		m_context.getTestContext().getLog()
4592 			<< tcu::TestLog::Message
4593 			<< "Line " << (lineNdx+1) << ":"
4594 			<< "\n\t" << outLines[lineNdx].positions[0]
4595 			<< "\n\t" << outLines[lineNdx].positions[1]
4596 			<< tcu::TestLog::EndMessage;
4597 	}
4598 }
4599 
4600 class LineStripTestInstance : public BaseLineTestInstance
4601 {
4602 public:
LineStripTestInstance(Context & context,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount,LineStipple stipple,VkLineRasterizationModeEXT lineRasterizationMode,deUint32)4603 					LineStripTestInstance	(Context& context, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount, LineStipple stipple, VkLineRasterizationModeEXT lineRasterizationMode, deUint32)
4604 						: BaseLineTestInstance(context, VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, wideness, strictness, sampleCount, stipple, lineRasterizationMode)
4605 					{}
4606 
4607 	virtual void	generateLines			(int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines);
4608 };
4609 
generateLines(int iteration,std::vector<tcu::Vec4> & outData,std::vector<LineSceneSpec::SceneLine> & outLines)4610 void LineStripTestInstance::generateLines (int iteration, std::vector<tcu::Vec4>& outData, std::vector<LineSceneSpec::SceneLine>& outLines)
4611 {
4612 	outData.resize(4);
4613 
4614 	switch (iteration)
4615 	{
4616 		case 0:
4617 			// \note: these values are chosen arbitrarily
4618 			outData[0] = tcu::Vec4( 0.01f,  0.0f, 0.0f, 1.0f);
4619 			outData[1] = tcu::Vec4( 0.5f,   0.2f, 0.0f, 1.0f);
4620 			outData[2] = tcu::Vec4( 0.46f,  0.3f, 0.0f, 1.0f);
4621 			outData[3] = tcu::Vec4(-0.5f,   0.2f, 0.0f, 1.0f);
4622 			break;
4623 
4624 		case 1:
4625 			outData[0] = tcu::Vec4(-0.499f, 0.128f, 0.0f, 1.0f);
4626 			outData[1] = tcu::Vec4(-0.501f,  -0.3f, 0.0f, 1.0f);
4627 			outData[2] = tcu::Vec4(  0.11f,  -0.2f, 0.0f, 1.0f);
4628 			outData[3] = tcu::Vec4(  0.11f,   0.2f, 0.0f, 1.0f);
4629 			break;
4630 
4631 		case 2:
4632 			outData[0] = tcu::Vec4( -0.9f, -0.3f, 0.0f, 1.0f);
4633 			outData[1] = tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f);
4634 			outData[2] = tcu::Vec4(  0.7f, -0.1f, 0.0f, 1.0f);
4635 			outData[3] = tcu::Vec4( 0.11f,  0.2f, 0.0f, 1.0f);
4636 			break;
4637 	}
4638 
4639 	outLines.resize(3);
4640 	outLines[0].positions[0] = outData[0];
4641 	outLines[0].positions[1] = outData[1];
4642 	outLines[1].positions[0] = outData[1];
4643 	outLines[1].positions[1] = outData[2];
4644 	outLines[2].positions[0] = outData[2];
4645 	outLines[2].positions[1] = outData[3];
4646 
4647 	// log
4648 	m_context.getTestContext().getLog() << tcu::TestLog::Message << "Rendering line strip, width = " << getLineWidth() << ", " << outData.size() << " vertices." << tcu::TestLog::EndMessage;
4649 	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
4650 	{
4651 		m_context.getTestContext().getLog()
4652 			<< tcu::TestLog::Message
4653 			<< "\t" << outData[vtxNdx]
4654 			<< tcu::TestLog::EndMessage;
4655 	}
4656 }
4657 
4658 class FillRuleTestInstance : public BaseRenderingTestInstance
4659 {
4660 public:
4661 	enum FillRuleCaseType
4662 	{
4663 		FILLRULECASE_BASIC = 0,
4664 		FILLRULECASE_REVERSED,
4665 		FILLRULECASE_CLIPPED_FULL,
4666 		FILLRULECASE_CLIPPED_PARTIAL,
4667 		FILLRULECASE_PROJECTED,
4668 
4669 		FILLRULECASE_LAST
4670 	};
4671 														FillRuleTestInstance			(Context& context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount);
4672 	virtual tcu::TestStatus								iterate							(void);
4673 
4674 private:
4675 
4676 	virtual const VkPipelineColorBlendStateCreateInfo*	getColorBlendStateCreateInfo	(void) const;
4677 	int													getRenderSize					(FillRuleCaseType type) const;
4678 	int													getNumIterations				(FillRuleCaseType type) const;
4679 	void												generateTriangles				(int iteration, std::vector<tcu::Vec4>& outData) const;
4680 
4681 	const FillRuleCaseType								m_caseType;
4682 	int													m_iteration;
4683 	const int											m_iterationCount;
4684 	bool												m_allIterationsPassed;
4685 
4686 };
4687 
FillRuleTestInstance(Context & context,FillRuleCaseType type,VkSampleCountFlagBits sampleCount)4688 FillRuleTestInstance::FillRuleTestInstance (Context& context, FillRuleCaseType type, VkSampleCountFlagBits sampleCount)
4689 	: BaseRenderingTestInstance		(context, sampleCount, getRenderSize(type))
4690 	, m_caseType					(type)
4691 	, m_iteration					(0)
4692 	, m_iterationCount				(getNumIterations(type))
4693 	, m_allIterationsPassed			(true)
4694 {
4695 	DE_ASSERT(type < FILLRULECASE_LAST);
4696 }
4697 
iterate(void)4698 tcu::TestStatus FillRuleTestInstance::iterate (void)
4699 {
4700 	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
4701 	const tcu::ScopedLogSection				section					(m_context.getTestContext().getLog(), iterationDescription, iterationDescription);
4702 	tcu::IVec4								colorBits				= tcu::getTextureFormatBitDepth(getTextureFormat());
4703 	const int								thresholdRed			= 1 << (8 - colorBits[0]);
4704 	const int								thresholdGreen			= 1 << (8 - colorBits[1]);
4705 	const int								thresholdBlue			= 1 << (8 - colorBits[2]);
4706 	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
4707 	std::vector<tcu::Vec4>					drawBuffer;
4708 
4709 	generateTriangles(m_iteration, drawBuffer);
4710 
4711 	// draw image
4712 	{
4713 		const std::vector<tcu::Vec4>	colorBuffer		(drawBuffer.size(), tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f));
4714 
4715 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing gray triangles with shared edges.\nEnabling additive blending to detect overlapping fragments." << tcu::TestLog::EndMessage;
4716 
4717 		drawPrimitives(resultImage, drawBuffer, colorBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
4718 	}
4719 
4720 	// verify no overdraw
4721 	{
4722 		const tcu::RGBA	triangleColor	= tcu::RGBA(127, 127, 127, 255);
4723 		bool			overdraw		= false;
4724 
4725 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Verifying result." << tcu::TestLog::EndMessage;
4726 
4727 		for (int y = 0; y < resultImage.getHeight(); ++y)
4728 		for (int x = 0; x < resultImage.getWidth();  ++x)
4729 		{
4730 			const tcu::RGBA color = resultImage.getPixel(x, y);
4731 
4732 			// color values are greater than triangle color? Allow lower values for multisampled edges and background.
4733 			if ((color.getRed()   - triangleColor.getRed())   > thresholdRed   ||
4734 				(color.getGreen() - triangleColor.getGreen()) > thresholdGreen ||
4735 				(color.getBlue()  - triangleColor.getBlue())  > thresholdBlue)
4736 				overdraw = true;
4737 		}
4738 
4739 		// results
4740 		if (!overdraw)
4741 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "No overlapping fragments detected." << tcu::TestLog::EndMessage;
4742 		else
4743 		{
4744 			m_context.getTestContext().getLog()	<< tcu::TestLog::Message << "Overlapping fragments detected, image is not valid." << tcu::TestLog::EndMessage;
4745 			m_allIterationsPassed = false;
4746 		}
4747 	}
4748 
4749 	// verify no missing fragments in the full viewport case
4750 	if (m_caseType == FILLRULECASE_CLIPPED_FULL)
4751 	{
4752 		bool missingFragments = false;
4753 
4754 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Searching missing fragments." << tcu::TestLog::EndMessage;
4755 
4756 		for (int y = 0; y < resultImage.getHeight(); ++y)
4757 		for (int x = 0; x < resultImage.getWidth();  ++x)
4758 		{
4759 			const tcu::RGBA color = resultImage.getPixel(x, y);
4760 
4761 			// black? (background)
4762 			if (color.getRed()   <= thresholdRed   ||
4763 				color.getGreen() <= thresholdGreen ||
4764 				color.getBlue()  <= thresholdBlue)
4765 				missingFragments = true;
4766 		}
4767 
4768 		// results
4769 		if (!missingFragments)
4770 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "No missing fragments detected." << tcu::TestLog::EndMessage;
4771 		else
4772 		{
4773 			m_context.getTestContext().getLog()	<< tcu::TestLog::Message << "Missing fragments detected, image is not valid." << tcu::TestLog::EndMessage;
4774 
4775 			m_allIterationsPassed = false;
4776 		}
4777 	}
4778 
4779 	m_context.getTestContext().getLog()	<< tcu::TestLog::ImageSet("Result of rendering", "Result of rendering")
4780 										<< tcu::TestLog::Image("Result", "Result", resultImage)
4781 										<< tcu::TestLog::EndImageSet;
4782 
4783 	// result
4784 	if (++m_iteration == m_iterationCount)
4785 	{
4786 		if (m_allIterationsPassed)
4787 			return tcu::TestStatus::pass("Pass");
4788 		else
4789 			return tcu::TestStatus::fail("Found invalid pixels");
4790 	}
4791 	else
4792 		return tcu::TestStatus::incomplete();
4793 }
4794 
getRenderSize(FillRuleCaseType type) const4795 int FillRuleTestInstance::getRenderSize (FillRuleCaseType type) const
4796 {
4797 	if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
4798 		return RESOLUTION_POT / 4;
4799 	else
4800 		return RESOLUTION_POT;
4801 }
4802 
getNumIterations(FillRuleCaseType type) const4803 int FillRuleTestInstance::getNumIterations (FillRuleCaseType type) const
4804 {
4805 	if (type == FILLRULECASE_CLIPPED_FULL || type == FILLRULECASE_CLIPPED_PARTIAL)
4806 		return 15;
4807 	else
4808 		return 2;
4809 }
4810 
generateTriangles(int iteration,std::vector<tcu::Vec4> & outData) const4811 void FillRuleTestInstance::generateTriangles (int iteration, std::vector<tcu::Vec4>& outData) const
4812 {
4813 	switch (m_caseType)
4814 	{
4815 		case FILLRULECASE_BASIC:
4816 		case FILLRULECASE_REVERSED:
4817 		case FILLRULECASE_PROJECTED:
4818 		{
4819 			const int	numRows		= 4;
4820 			const int	numColumns	= 4;
4821 			const float	quadSide	= 0.15f;
4822 			de::Random	rnd			(0xabcd);
4823 
4824 			outData.resize(6 * numRows * numColumns);
4825 
4826 			for (int col = 0; col < numColumns; ++col)
4827 			for (int row = 0; row < numRows;    ++row)
4828 			{
4829 				const tcu::Vec2 center		= tcu::Vec2(((float)row + 0.5f) / (float)numRows * 2.0f - 1.0f, ((float)col + 0.5f) / (float)numColumns * 2.0f - 1.0f);
4830 				const float		rotation	= (float)(iteration * numColumns * numRows + col * numRows + row) / (float)(m_iterationCount * numColumns * numRows) * DE_PI / 2.0f;
4831 				const tcu::Vec2 sideH		= quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
4832 				const tcu::Vec2 sideV		= tcu::Vec2(sideH.y(), -sideH.x());
4833 				const tcu::Vec2 quad[4]		=
4834 				{
4835 					center + sideH + sideV,
4836 					center + sideH - sideV,
4837 					center - sideH - sideV,
4838 					center - sideH + sideV,
4839 				};
4840 
4841 				if (m_caseType == FILLRULECASE_BASIC)
4842 				{
4843 					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4844 					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
4845 					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4846 					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4847 					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4848 					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
4849 				}
4850 				else if (m_caseType == FILLRULECASE_REVERSED)
4851 				{
4852 					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4853 					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
4854 					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4855 					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4856 					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4857 					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
4858 				}
4859 				else if (m_caseType == FILLRULECASE_PROJECTED)
4860 				{
4861 					const float w0 = rnd.getFloat(0.1f, 4.0f);
4862 					const float w1 = rnd.getFloat(0.1f, 4.0f);
4863 					const float w2 = rnd.getFloat(0.1f, 4.0f);
4864 					const float w3 = rnd.getFloat(0.1f, 4.0f);
4865 
4866 					outData[6 * (col * numRows + row) + 0] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
4867 					outData[6 * (col * numRows + row) + 1] = tcu::Vec4(quad[1].x() * w1, quad[1].y() * w1, 0.0f, w1);
4868 					outData[6 * (col * numRows + row) + 2] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
4869 					outData[6 * (col * numRows + row) + 3] = tcu::Vec4(quad[2].x() * w2, quad[2].y() * w2, 0.0f, w2);
4870 					outData[6 * (col * numRows + row) + 4] = tcu::Vec4(quad[0].x() * w0, quad[0].y() * w0, 0.0f, w0);
4871 					outData[6 * (col * numRows + row) + 5] = tcu::Vec4(quad[3].x() * w3, quad[3].y() * w3, 0.0f, w3);
4872 				}
4873 				else
4874 					DE_ASSERT(DE_FALSE);
4875 			}
4876 
4877 			break;
4878 		}
4879 
4880 		case FILLRULECASE_CLIPPED_PARTIAL:
4881 		case FILLRULECASE_CLIPPED_FULL:
4882 		{
4883 			const float		quadSide	= (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (1.0f) : (2.0f);
4884 			const tcu::Vec2 center		= (m_caseType == FILLRULECASE_CLIPPED_PARTIAL) ? (tcu::Vec2(0.5f, 0.5f)) : (tcu::Vec2(0.0f, 0.0f));
4885 			const float		rotation	= (float)(iteration) / (float)(m_iterationCount - 1) * DE_PI / 2.0f;
4886 			const tcu::Vec2 sideH		= quadSide * tcu::Vec2(deFloatCos(rotation), deFloatSin(rotation));
4887 			const tcu::Vec2 sideV		= tcu::Vec2(sideH.y(), -sideH.x());
4888 			const tcu::Vec2 quad[4]		=
4889 			{
4890 				center + sideH + sideV,
4891 				center + sideH - sideV,
4892 				center - sideH - sideV,
4893 				center - sideH + sideV,
4894 			};
4895 
4896 			outData.resize(6);
4897 			outData[0] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4898 			outData[1] = tcu::Vec4(quad[1].x(), quad[1].y(), 0.0f, 1.0f);
4899 			outData[2] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4900 			outData[3] = tcu::Vec4(quad[2].x(), quad[2].y(), 0.0f, 1.0f);
4901 			outData[4] = tcu::Vec4(quad[0].x(), quad[0].y(), 0.0f, 1.0f);
4902 			outData[5] = tcu::Vec4(quad[3].x(), quad[3].y(), 0.0f, 1.0f);
4903 			break;
4904 		}
4905 
4906 		default:
4907 			DE_ASSERT(DE_FALSE);
4908 	}
4909 }
4910 
getColorBlendStateCreateInfo(void) const4911 const VkPipelineColorBlendStateCreateInfo* FillRuleTestInstance::getColorBlendStateCreateInfo (void) const
4912 {
4913 	static const VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
4914 	{
4915 		true,														// VkBool32			blendEnable;
4916 		VK_BLEND_FACTOR_ONE,										// VkBlend			srcBlendColor;
4917 		VK_BLEND_FACTOR_ONE,										// VkBlend			destBlendColor;
4918 		VK_BLEND_OP_ADD,											// VkBlendOp		blendOpColor;
4919 		VK_BLEND_FACTOR_ONE,										// VkBlend			srcBlendAlpha;
4920 		VK_BLEND_FACTOR_ONE,										// VkBlend			destBlendAlpha;
4921 		VK_BLEND_OP_ADD,											// VkBlendOp		blendOpAlpha;
4922 		(VK_COLOR_COMPONENT_R_BIT |
4923 		 VK_COLOR_COMPONENT_G_BIT |
4924 		 VK_COLOR_COMPONENT_B_BIT |
4925 		 VK_COLOR_COMPONENT_A_BIT)									// VkChannelFlags	channelWriteMask;
4926 	};
4927 
4928 	static const VkPipelineColorBlendStateCreateInfo colorBlendStateParams =
4929 	{
4930 		VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType								sType;
4931 		DE_NULL,													// const void*									pNext;
4932 		0,															// VkPipelineColorBlendStateCreateFlags			flags;
4933 		false,														// VkBool32										logicOpEnable;
4934 		VK_LOGIC_OP_COPY,											// VkLogicOp									logicOp;
4935 		1u,															// deUint32										attachmentCount;
4936 		&colorBlendAttachmentState,									// const VkPipelineColorBlendAttachmentState*	pAttachments;
4937 		{ 0.0f, 0.0f, 0.0f, 0.0f },									// float										blendConst[4];
4938 	};
4939 
4940 	return &colorBlendStateParams;
4941 }
4942 
4943 
4944 class FillRuleTestCase : public BaseRenderingTestCase
4945 {
4946 public:
FillRuleTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,FillRuleTestInstance::FillRuleCaseType type,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)4947 								FillRuleTestCase	(tcu::TestContext& context, const std::string& name, const std::string& description, FillRuleTestInstance::FillRuleCaseType type, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
4948 									: BaseRenderingTestCase	(context, name, description, sampleCount)
4949 									, m_type				(type)
4950 								{}
4951 
createInstance(Context & context) const4952 	virtual TestInstance*		createInstance		(Context& context) const
4953 								{
4954 									return new FillRuleTestInstance(context, m_type, m_sampleCount);
4955 								}
4956 protected:
4957 	const FillRuleTestInstance::FillRuleCaseType m_type;
4958 };
4959 
4960 class CullingTestInstance : public BaseRenderingTestInstance
4961 {
4962 public:
CullingTestInstance(Context & context,VkCullModeFlags cullMode,VkPrimitiveTopology primitiveTopology,VkFrontFace frontFace,VkPolygonMode polygonMode)4963 													CullingTestInstance				(Context& context, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkPolygonMode polygonMode)
4964 														: BaseRenderingTestInstance		(context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
4965 														, m_cullMode					(cullMode)
4966 														, m_primitiveTopology			(primitiveTopology)
4967 														, m_frontFace					(frontFace)
4968 														, m_polygonMode					(polygonMode)
4969 														, m_multisampling				(true)
4970 													{}
4971 	virtual
4972 	const VkPipelineRasterizationStateCreateInfo*	getRasterizationStateCreateInfo (void) const;
4973 
4974 	tcu::TestStatus									iterate							(void);
4975 
4976 private:
4977 	void											generateVertices				(std::vector<tcu::Vec4>& outData) const;
4978 	void											extractTriangles				(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
4979 	void											extractLines					(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<LineSceneSpec::SceneLine>& outLines) const;
4980 	void											extractPoints					(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, std::vector<PointSceneSpec::ScenePoint>& outPoints) const;
4981 	bool											triangleOrder					(const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const;
4982 
4983 	const VkCullModeFlags							m_cullMode;
4984 	const VkPrimitiveTopology						m_primitiveTopology;
4985 	const VkFrontFace								m_frontFace;
4986 	const VkPolygonMode								m_polygonMode;
4987 	const bool										m_multisampling;
4988 };
4989 
4990 
iterate(void)4991 tcu::TestStatus CullingTestInstance::iterate (void)
4992 {
4993 	DE_ASSERT(m_polygonMode <= VK_POLYGON_MODE_POINT);
4994 
4995 	tcu::Surface									resultImage						(m_renderSize, m_renderSize);
4996 	std::vector<tcu::Vec4>							drawBuffer;
4997 	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
4998 	std::vector<PointSceneSpec::ScenePoint>			points;
4999 	std::vector<LineSceneSpec::SceneLine>			lines;
5000 
5001 	const InstanceInterface&						vk				= m_context.getInstanceInterface();
5002 	const VkPhysicalDevice							physicalDevice	= m_context.getPhysicalDevice();
5003 	const VkPhysicalDeviceFeatures					deviceFeatures	= getPhysicalDeviceFeatures(vk, physicalDevice);
5004 
5005 	if (!(deviceFeatures.fillModeNonSolid) && (m_polygonMode == VK_POLYGON_MODE_LINE || m_polygonMode == VK_POLYGON_MODE_POINT))
5006 		TCU_THROW(NotSupportedError, "Wireframe fill modes are not supported");
5007 
5008 	// generate scene
5009 	generateVertices(drawBuffer);
5010 	extractTriangles(triangles, drawBuffer);
5011 
5012 	if (m_polygonMode == VK_POLYGON_MODE_LINE)
5013 		extractLines(triangles ,lines);
5014 	else if (m_polygonMode == VK_POLYGON_MODE_POINT)
5015 		extractPoints(triangles, points);
5016 
5017 	// draw image
5018 	{
5019 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting front face to " << m_frontFace << tcu::TestLog::EndMessage;
5020 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Setting cull face to " << m_cullMode << tcu::TestLog::EndMessage;
5021 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Drawing test pattern (" << m_primitiveTopology << ")" << tcu::TestLog::EndMessage;
5022 
5023 		drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
5024 	}
5025 
5026 	// compare
5027 	{
5028 		RasterizationArguments	args;
5029 		tcu::IVec4				colorBits	= tcu::getTextureFormatBitDepth(getTextureFormat());
5030 		bool					isCompareOk	= false;
5031 
5032 		args.numSamples		= m_multisampling ? 1 : 0;
5033 		args.subpixelBits	= m_subpixelBits;
5034 		args.redBits		= colorBits[0];
5035 		args.greenBits		= colorBits[1];
5036 		args.blueBits		= colorBits[2];
5037 
5038 		switch (m_polygonMode)
5039 		{
5040 			case VK_POLYGON_MODE_LINE:
5041 			{
5042 				LineSceneSpec scene;
5043 				scene.lineWidth = 0;
5044 				scene.lines.swap(lines);
5045 				isCompareOk = verifyLineGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
5046 				break;
5047 			}
5048 			case VK_POLYGON_MODE_POINT:
5049 			{
5050 				PointSceneSpec scene;
5051 				scene.points.swap(points);
5052 				isCompareOk = verifyPointGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog());
5053 				break;
5054 			}
5055 			default:
5056 			{
5057 				TriangleSceneSpec scene;
5058 				scene.triangles.swap(triangles);
5059 				isCompareOk = verifyTriangleGroupRasterization(resultImage, scene, args, m_context.getTestContext().getLog(), tcu::VERIFICATIONMODE_WEAK);
5060 				break;
5061 			}
5062 		}
5063 
5064 		if (isCompareOk)
5065 			return tcu::TestStatus::pass("Pass");
5066 		else
5067 			return tcu::TestStatus::fail("Incorrect rendering");
5068 	}
5069 }
5070 
generateVertices(std::vector<tcu::Vec4> & outData) const5071 void CullingTestInstance::generateVertices (std::vector<tcu::Vec4>& outData) const
5072 {
5073 	de::Random rnd(543210);
5074 
5075 	outData.resize(6);
5076 	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
5077 	{
5078 		outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
5079 		outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
5080 		outData[vtxNdx].z() = 0.0f;
5081 		outData[vtxNdx].w() = 1.0f;
5082 	}
5083 }
5084 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const5085 void CullingTestInstance::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
5086 {
5087 	const bool cullDirection = (m_cullMode == VK_CULL_MODE_FRONT_BIT) ^ (m_frontFace == VK_FRONT_FACE_COUNTER_CLOCKWISE);
5088 
5089 	// No triangles
5090 	if (m_cullMode == VK_CULL_MODE_FRONT_AND_BACK)
5091 		return;
5092 
5093 	switch (m_primitiveTopology)
5094 	{
5095 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5096 		{
5097 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
5098 			{
5099 				const tcu::Vec4& v0 = vertices[vtxNdx + 0];
5100 				const tcu::Vec4& v1 = vertices[vtxNdx + 1];
5101 				const tcu::Vec4& v2 = vertices[vtxNdx + 2];
5102 
5103 				if (triangleOrder(v0, v1, v2) != cullDirection)
5104 				{
5105 					TriangleSceneSpec::SceneTriangle tri;
5106 					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
5107 					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
5108 					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
5109 
5110 					outTriangles.push_back(tri);
5111 				}
5112 			}
5113 			break;
5114 		}
5115 
5116 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5117 		{
5118 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
5119 			{
5120 				const tcu::Vec4& v0 = vertices[vtxNdx + 0];
5121 				const tcu::Vec4& v1 = vertices[vtxNdx + 1];
5122 				const tcu::Vec4& v2 = vertices[vtxNdx + 2];
5123 
5124 				if (triangleOrder(v0, v1, v2) != (cullDirection ^ (vtxNdx % 2 != 0)))
5125 				{
5126 					TriangleSceneSpec::SceneTriangle tri;
5127 					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
5128 					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
5129 					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
5130 
5131 					outTriangles.push_back(tri);
5132 				}
5133 			}
5134 			break;
5135 		}
5136 
5137 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5138 		{
5139 			for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5140 			{
5141 				const tcu::Vec4& v0 = vertices[0];
5142 				const tcu::Vec4& v1 = vertices[vtxNdx + 0];
5143 				const tcu::Vec4& v2 = vertices[vtxNdx + 1];
5144 
5145 				if (triangleOrder(v0, v1, v2) != cullDirection)
5146 				{
5147 					TriangleSceneSpec::SceneTriangle tri;
5148 					tri.positions[0] = v0;	tri.sharedEdge[0] = false;
5149 					tri.positions[1] = v1;	tri.sharedEdge[1] = false;
5150 					tri.positions[2] = v2;	tri.sharedEdge[2] = false;
5151 
5152 					outTriangles.push_back(tri);
5153 				}
5154 			}
5155 			break;
5156 		}
5157 
5158 		default:
5159 			DE_ASSERT(false);
5160 	}
5161 }
5162 
extractLines(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,std::vector<LineSceneSpec::SceneLine> & outLines) const5163 void CullingTestInstance::extractLines (std::vector<TriangleSceneSpec::SceneTriangle>&	outTriangles,
5164 										std::vector<LineSceneSpec::SceneLine>&			outLines) const
5165 {
5166 	for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
5167 	{
5168 		for (int vrtxNdx = 0; vrtxNdx < 2; ++vrtxNdx)
5169 		{
5170 			LineSceneSpec::SceneLine line;
5171 			line.positions[0] = outTriangles.at(triNdx).positions[vrtxNdx];
5172 			line.positions[1] = outTriangles.at(triNdx).positions[vrtxNdx + 1];
5173 
5174 			outLines.push_back(line);
5175 		}
5176 		LineSceneSpec::SceneLine line;
5177 		line.positions[0] = outTriangles.at(triNdx).positions[2];
5178 		line.positions[1] = outTriangles.at(triNdx).positions[0];
5179 		outLines.push_back(line);
5180 	}
5181 }
5182 
extractPoints(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,std::vector<PointSceneSpec::ScenePoint> & outPoints) const5183 void CullingTestInstance::extractPoints (std::vector<TriangleSceneSpec::SceneTriangle>	&outTriangles,
5184 										std::vector<PointSceneSpec::ScenePoint>			&outPoints) const
5185 {
5186 	for (int triNdx = 0; triNdx < (int)outTriangles.size(); ++triNdx)
5187 	{
5188 		for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
5189 		{
5190 			PointSceneSpec::ScenePoint point;
5191 			point.position = outTriangles.at(triNdx).positions[vrtxNdx];
5192 			point.pointSize = 1.0f;
5193 
5194 			outPoints.push_back(point);
5195 		}
5196 	}
5197 }
5198 
triangleOrder(const tcu::Vec4 & v0,const tcu::Vec4 & v1,const tcu::Vec4 & v2) const5199 bool CullingTestInstance::triangleOrder (const tcu::Vec4& v0, const tcu::Vec4& v1, const tcu::Vec4& v2) const
5200 {
5201 	const tcu::Vec2 s0 = v0.swizzle(0, 1) / v0.w();
5202 	const tcu::Vec2 s1 = v1.swizzle(0, 1) / v1.w();
5203 	const tcu::Vec2 s2 = v2.swizzle(0, 1) / v2.w();
5204 
5205 	// cross
5206 	return ((s1.x() - s0.x()) * (s2.y() - s0.y()) - (s2.x() - s0.x()) * (s1.y() - s0.y())) > 0;
5207 }
5208 
5209 
getRasterizationStateCreateInfo(void) const5210 const VkPipelineRasterizationStateCreateInfo* CullingTestInstance::getRasterizationStateCreateInfo (void) const
5211 {
5212 	static VkPipelineRasterizationStateCreateInfo	rasterizationStateCreateInfo	=
5213 	{
5214 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,		// VkStructureType							sType;
5215 		DE_NULL,														// const void*								pNext;
5216 		0,																// VkPipelineRasterizationStateCreateFlags	flags;
5217 		false,															// VkBool32									depthClipEnable;
5218 		false,															// VkBool32									rasterizerDiscardEnable;
5219 		VK_POLYGON_MODE_FILL,											// VkFillMode								fillMode;
5220 		VK_CULL_MODE_NONE,												// VkCullMode								cullMode;
5221 		VK_FRONT_FACE_COUNTER_CLOCKWISE,								// VkFrontFace								frontFace;
5222 		VK_FALSE,														// VkBool32									depthBiasEnable;
5223 		0.0f,															// float									depthBias;
5224 		0.0f,															// float									depthBiasClamp;
5225 		0.0f,															// float									slopeScaledDepthBias;
5226 		getLineWidth(),													// float									lineWidth;
5227 	};
5228 
5229 	rasterizationStateCreateInfo.lineWidth		= getLineWidth();
5230 	rasterizationStateCreateInfo.cullMode		= m_cullMode;
5231 	rasterizationStateCreateInfo.frontFace		= m_frontFace;
5232 	rasterizationStateCreateInfo.polygonMode	= m_polygonMode;
5233 
5234 	return &rasterizationStateCreateInfo;
5235 }
5236 
5237 class CullingTestCase : public BaseRenderingTestCase
5238 {
5239 public:
CullingTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkCullModeFlags cullMode,VkPrimitiveTopology primitiveTopology,VkFrontFace frontFace,VkPolygonMode polygonMode,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)5240 								CullingTestCase		(tcu::TestContext& context, const std::string& name, const std::string& description, VkCullModeFlags cullMode, VkPrimitiveTopology primitiveTopology, VkFrontFace frontFace, VkPolygonMode polygonMode, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
5241 									: BaseRenderingTestCase	(context, name, description, sampleCount)
5242 									, m_cullMode			(cullMode)
5243 									, m_primitiveTopology	(primitiveTopology)
5244 									, m_frontFace			(frontFace)
5245 									, m_polygonMode			(polygonMode)
5246 								{}
5247 
createInstance(Context & context) const5248 	virtual TestInstance*		createInstance		(Context& context) const
5249 								{
5250 									return new CullingTestInstance(context, m_cullMode, m_primitiveTopology, m_frontFace, m_polygonMode);
5251 								}
5252 	void						checkSupport		(Context& context) const;
5253 protected:
5254 	const VkCullModeFlags		m_cullMode;
5255 	const VkPrimitiveTopology	m_primitiveTopology;
5256 	const VkFrontFace			m_frontFace;
5257 	const VkPolygonMode			m_polygonMode;
5258 };
5259 
checkSupport(Context & context) const5260 void CullingTestCase::checkSupport (Context& context) const
5261 {
5262 	if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
5263 	{
5264 		const VkPhysicalDevicePortabilitySubsetFeaturesKHR& subsetFeatures = context.getPortabilitySubsetFeatures();
5265 		if (m_polygonMode == VK_POLYGON_MODE_POINT && !subsetFeatures.pointPolygons)
5266 			TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Point polygons are not supported by this implementation");
5267 		if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && !subsetFeatures.triangleFans)
5268 			TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
5269 	}
5270 }
5271 
5272 class DiscardTestInstance : public BaseRenderingTestInstance
5273 {
5274 public:
DiscardTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,deBool queryFragmentShaderInvocations)5275 															DiscardTestInstance					(Context& context, VkPrimitiveTopology primitiveTopology, deBool queryFragmentShaderInvocations)
5276 																: BaseRenderingTestInstance			(context, VK_SAMPLE_COUNT_1_BIT, RESOLUTION_POT)
5277 																, m_primitiveTopology				(primitiveTopology)
5278 																, m_queryFragmentShaderInvocations	(queryFragmentShaderInvocations)
5279 															{}
5280 
5281 	virtual const VkPipelineRasterizationStateCreateInfo*	getRasterizationStateCreateInfo		(void) const;
5282 	tcu::TestStatus											iterate								(void);
5283 
5284 private:
5285 	void													generateVertices					(std::vector<tcu::Vec4>& outData) const;
5286 	void													extractTriangles					(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const;
5287 	void													extractLines						(std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices) const;
5288 	void													extractPoints						(std::vector<PointSceneSpec::ScenePoint>& outPoints, const std::vector<tcu::Vec4>& vertices) const;
5289 	void													drawPrimitivesDiscard				(tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, VkPrimitiveTopology primitiveTopology, Move<VkQueryPool>& queryPool);
5290 
5291 	const VkPrimitiveTopology								m_primitiveTopology;
5292 	const deBool											m_queryFragmentShaderInvocations;
5293 };
5294 
iterate(void)5295 tcu::TestStatus DiscardTestInstance::iterate (void)
5296 {
5297 	const DeviceInterface&							vkd			= m_context.getDeviceInterface();
5298 	const VkDevice									vkDevice	= m_context.getDevice();
5299 	deUint64										queryResult	= 0u;
5300 	tcu::Surface									resultImage	(m_renderSize, m_renderSize);
5301 	std::vector<tcu::Vec4>							drawBuffer;
5302 	std::vector<PointSceneSpec::ScenePoint>			points;
5303 	std::vector<LineSceneSpec::SceneLine>			lines;
5304 	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
5305 
5306 	generateVertices(drawBuffer);
5307 
5308 	switch (m_primitiveTopology)
5309 	{
5310 		case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
5311 			extractPoints(points, drawBuffer);
5312 			break;
5313 
5314 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
5315 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
5316 			extractLines(lines, drawBuffer);
5317 			break;
5318 
5319 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5320 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5321 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5322 			extractTriangles(triangles, drawBuffer);
5323 			break;
5324 
5325 		default:
5326 			DE_ASSERT(false);
5327 	}
5328 
5329 	const VkQueryPoolCreateInfo queryPoolCreateInfo =
5330 	{
5331 		VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO,						// VkStructureType					sType
5332 		DE_NULL,														// const void*						pNext
5333 		(VkQueryPoolCreateFlags)0,										// VkQueryPoolCreateFlags			flags
5334 		VK_QUERY_TYPE_PIPELINE_STATISTICS ,								// VkQueryType						queryType
5335 		1u,																// deUint32							entryCount
5336 		VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT,	// VkQueryPipelineStatisticFlags	pipelineStatistics
5337 	};
5338 
5339 	if (m_queryFragmentShaderInvocations)
5340 	{
5341 		Move<VkQueryPool> queryPool	= createQueryPool(vkd, vkDevice, &queryPoolCreateInfo);
5342 
5343 		drawPrimitivesDiscard(resultImage, drawBuffer, m_primitiveTopology, queryPool);
5344 		vkd.getQueryPoolResults(vkDevice, *queryPool, 0u, 1u, sizeof(deUint64), &queryResult, 0u, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT);
5345 	}
5346 	else
5347 		BaseRenderingTestInstance::drawPrimitives(resultImage, drawBuffer, m_primitiveTopology);
5348 
5349 	// compare
5350 	{
5351 		tcu::IVec4						colorBits	= tcu::getTextureFormatBitDepth(getTextureFormat());
5352 
5353 		const RasterizationArguments	args		=
5354 		{
5355 			0,							// int	numSamples;
5356 			(int)m_subpixelBits,		// int	subpixelBits;
5357 			colorBits[0],				// int	redBits;
5358 			colorBits[1],				// int	greenBits;
5359 			colorBits[2]				// int	blueBits;
5360 		};
5361 
5362 		// Empty scene to compare to, primitives should be discarded before rasterization
5363 		TriangleSceneSpec				scene;
5364 
5365 		const bool						isCompareOk	= verifyTriangleGroupRasterization(resultImage,
5366 																					   scene,
5367 																					   args,
5368 																					   m_context.getTestContext().getLog(),
5369 																					   tcu::VERIFICATIONMODE_STRICT);
5370 
5371 		if (isCompareOk)
5372 		{
5373 			if (m_queryFragmentShaderInvocations && queryResult > 0u)
5374 				return tcu::TestStatus::fail("Fragment shader invocations occured");
5375 			else
5376 				return tcu::TestStatus::pass("Pass");
5377 		}
5378 		else
5379 			return tcu::TestStatus::fail("Incorrect rendering");
5380 	}
5381 }
5382 
generateVertices(std::vector<tcu::Vec4> & outData) const5383 void DiscardTestInstance::generateVertices (std::vector<tcu::Vec4>& outData) const
5384 {
5385 	de::Random rnd(12345);
5386 
5387 	outData.resize(6);
5388 
5389 	for (int vtxNdx = 0; vtxNdx < (int)outData.size(); ++vtxNdx)
5390 	{
5391 		outData[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
5392 		outData[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
5393 		outData[vtxNdx].z() = 0.0f;
5394 		outData[vtxNdx].w() = 1.0f;
5395 	}
5396 }
5397 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices) const5398 void DiscardTestInstance::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices) const
5399 {
5400 	switch (m_primitiveTopology)
5401 	{
5402 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5403 		{
5404 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
5405 			{
5406 				TriangleSceneSpec::SceneTriangle	tri;
5407 				const tcu::Vec4&					v0	= vertices[vtxNdx + 0];
5408 				const tcu::Vec4&					v1	= vertices[vtxNdx + 1];
5409 				const tcu::Vec4&					v2	= vertices[vtxNdx + 2];
5410 
5411 				tri.positions[0] = v0;
5412 				tri.positions[1] = v1;
5413 				tri.positions[2] = v2;
5414 
5415 				outTriangles.push_back(tri);
5416 			}
5417 
5418 			break;
5419 		}
5420 
5421 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5422 		{
5423 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
5424 			{
5425 				TriangleSceneSpec::SceneTriangle	tri;
5426 				const tcu::Vec4&					v0	= vertices[vtxNdx + 0];
5427 				const tcu::Vec4&					v1	= vertices[vtxNdx + 1];
5428 				const tcu::Vec4&					v2	= vertices[vtxNdx + 2];
5429 
5430 				tri.positions[0] = v0;
5431 				tri.positions[1] = v1;
5432 				tri.positions[2] = v2;
5433 
5434 				outTriangles.push_back(tri);
5435 			}
5436 
5437 			break;
5438 		}
5439 
5440 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5441 		{
5442 			for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5443 			{
5444 				TriangleSceneSpec::SceneTriangle	tri;
5445 				const tcu::Vec4&					v0	= vertices[0];
5446 				const tcu::Vec4&					v1	= vertices[vtxNdx + 0];
5447 				const tcu::Vec4&					v2	= vertices[vtxNdx + 1];
5448 
5449 				tri.positions[0] = v0;
5450 				tri.positions[1] = v1;
5451 				tri.positions[2] = v2;
5452 
5453 				outTriangles.push_back(tri);
5454 			}
5455 
5456 			break;
5457 		}
5458 
5459 		default:
5460 			DE_ASSERT(false);
5461 	}
5462 }
5463 
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices) const5464 void DiscardTestInstance::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices) const
5465 {
5466 	switch (m_primitiveTopology)
5467 	{
5468 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
5469 		{
5470 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
5471 			{
5472 				LineSceneSpec::SceneLine line;
5473 
5474 				line.positions[0] = vertices[vtxNdx + 0];
5475 				line.positions[1] = vertices[vtxNdx + 1];
5476 
5477 				outLines.push_back(line);
5478 			}
5479 
5480 			break;
5481 		}
5482 
5483 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
5484 		{
5485 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5486 			{
5487 				LineSceneSpec::SceneLine line;
5488 
5489 				line.positions[0] = vertices[vtxNdx + 0];
5490 				line.positions[1] = vertices[vtxNdx + 1];
5491 
5492 				outLines.push_back(line);
5493 			}
5494 
5495 			break;
5496 		}
5497 
5498 		default:
5499 			DE_ASSERT(false);
5500 		}
5501 }
5502 
extractPoints(std::vector<PointSceneSpec::ScenePoint> & outPoints,const std::vector<tcu::Vec4> & vertices) const5503 void DiscardTestInstance::extractPoints (std::vector<PointSceneSpec::ScenePoint>& outPoints, const std::vector<tcu::Vec4>& vertices) const
5504 {
5505 	for (int pointNdx = 0; pointNdx < (int)outPoints.size(); ++pointNdx)
5506 	{
5507 		for (int vrtxNdx = 0; vrtxNdx < 3; ++vrtxNdx)
5508 		{
5509 			PointSceneSpec::ScenePoint point;
5510 
5511 			point.position	= vertices[vrtxNdx];
5512 			point.pointSize	= 1.0f;
5513 
5514 			outPoints.push_back(point);
5515 		}
5516 	}
5517 }
5518 
getRasterizationStateCreateInfo(void) const5519 const VkPipelineRasterizationStateCreateInfo* DiscardTestInstance::getRasterizationStateCreateInfo (void) const
5520 {
5521 	static const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
5522 	{
5523 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	// VkStructureType							sType;
5524 		NULL,														// const void*								pNext;
5525 		0,															// VkPipelineRasterizationStateCreateFlags	flags;
5526 		VK_FALSE,													// VkBool32									depthClipEnable;
5527 		VK_TRUE,													// VkBool32									rasterizerDiscardEnable;
5528 		VK_POLYGON_MODE_FILL,										// VkFillMode								fillMode;
5529 		VK_CULL_MODE_NONE,											// VkCullMode								cullMode;
5530 		VK_FRONT_FACE_COUNTER_CLOCKWISE,							// VkFrontFace								frontFace;
5531 		VK_FALSE,													// VkBool32									depthBiasEnable;
5532 		0.0f,														// float									depthBias;
5533 		0.0f,														// float									depthBiasClamp;
5534 		0.0f,														// float									slopeScaledDepthBias;
5535 		getLineWidth(),												// float									lineWidth;
5536 	};
5537 
5538 	return &rasterizationStateCreateInfo;
5539 }
5540 
drawPrimitivesDiscard(tcu::Surface & result,const std::vector<tcu::Vec4> & positionData,VkPrimitiveTopology primitiveTopology,Move<VkQueryPool> & queryPool)5541 void DiscardTestInstance::drawPrimitivesDiscard (tcu::Surface& result, const std::vector<tcu::Vec4>& positionData, VkPrimitiveTopology primitiveTopology, Move<VkQueryPool>& queryPool)
5542 {
5543 	const DeviceInterface&				vkd					= m_context.getDeviceInterface();
5544 	const VkDevice						vkDevice			= m_context.getDevice();
5545 	const VkPhysicalDeviceProperties	properties			= m_context.getDeviceProperties();
5546 	const VkQueue						queue				= m_context.getUniversalQueue();
5547 	const deUint32						queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
5548 	Allocator&							allocator			= m_context.getDefaultAllocator();
5549 
5550 	const size_t						attributeBatchSize	= positionData.size() * sizeof(tcu::Vec4);
5551 	const VkDeviceSize					vertexBufferOffset	= 0;
5552 	de::MovePtr<Allocation>				vertexBufferMemory;
5553 	Move<VkBuffer>						vertexBuffer;
5554 	Move<VkCommandBuffer>				commandBuffer;
5555 	Move<VkPipeline>					graphicsPipeline;
5556 
5557 	if (attributeBatchSize > properties.limits.maxVertexInputAttributeOffset)
5558 	{
5559 		std::stringstream message;
5560 		message << "Larger vertex input attribute offset is needed (" << attributeBatchSize << ") than the available maximum (" << properties.limits.maxVertexInputAttributeOffset << ").";
5561 		TCU_THROW(NotSupportedError, message.str().c_str());
5562 	}
5563 
5564 	// Create Graphics Pipeline
5565 	{
5566 		const VkVertexInputBindingDescription		vertexInputBindingDescription		=
5567 		{
5568 			0u,										// deUint32					binding;
5569 			sizeof(tcu::Vec4),						// deUint32					strideInBytes;
5570 			VK_VERTEX_INPUT_RATE_VERTEX				// VkVertexInputStepRate	stepRate;
5571 		};
5572 
5573 		const VkVertexInputAttributeDescription		vertexInputAttributeDescriptions[2]	=
5574 		{
5575 			{
5576 				0u,									// deUint32	location;
5577 				0u,									// deUint32	binding;
5578 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
5579 				0u									// deUint32	offsetInBytes;
5580 			},
5581 			{
5582 				1u,									// deUint32	location;
5583 				0u,									// deUint32	binding;
5584 				VK_FORMAT_R32G32B32A32_SFLOAT,		// VkFormat	format;
5585 				(deUint32)attributeBatchSize		// deUint32	offsetInBytes;
5586 			}
5587 		};
5588 
5589 		const VkPipelineVertexInputStateCreateInfo	vertexInputStateParams				=
5590 		{
5591 			VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	// VkStructureType							sType;
5592 			DE_NULL,													// const void*								pNext;
5593 			0,															// VkPipelineVertexInputStateCreateFlags	flags;
5594 			1u,															// deUint32									bindingCount;
5595 			&vertexInputBindingDescription,								// const VkVertexInputBindingDescription*	pVertexBindingDescriptions;
5596 			2u,															// deUint32									attributeCount;
5597 			vertexInputAttributeDescriptions							// const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
5598 		};
5599 
5600 		const std::vector<VkViewport>				viewports							(1, makeViewport(tcu::UVec2(m_renderSize)));
5601 		const std::vector<VkRect2D>					scissors							(1, makeRect2D(tcu::UVec2(m_renderSize)));
5602 
5603 		const VkPipelineMultisampleStateCreateInfo	multisampleStateParams				=
5604 		{
5605 			VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	// VkStructureType							sType;
5606 			DE_NULL,													// const void*								pNext;
5607 			0u,															// VkPipelineMultisampleStateCreateFlags	flags;
5608 			m_sampleCount,												// VkSampleCountFlagBits					rasterizationSamples;
5609 			VK_FALSE,													// VkBool32									sampleShadingEnable;
5610 			0.0f,														// float									minSampleShading;
5611 			DE_NULL,													// const VkSampleMask*						pSampleMask;
5612 			VK_FALSE,													// VkBool32									alphaToCoverageEnable;
5613 			VK_FALSE													// VkBool32									alphaToOneEnable;
5614 		};
5615 
5616 		graphicsPipeline = makeGraphicsPipeline(vkd,								// const DeviceInterface&							vk
5617 												vkDevice,							// const VkDevice									device
5618 												*m_pipelineLayout,					// const VkPipelineLayout							pipelineLayout
5619 												*m_vertexShaderModule,				// const VkShaderModule								vertexShaderModule
5620 												DE_NULL,							// const VkShaderModule								tessellationControlShaderModule
5621 												DE_NULL,							// const VkShaderModule								tessellationEvalShaderModule
5622 												DE_NULL,							// const VkShaderModule								geometryShaderModule
5623 												*m_fragmentShaderModule,			// const VkShaderModule								fragmentShaderModule
5624 												*m_renderPass,						// const VkRenderPass								renderPass
5625 												viewports,							// const std::vector<VkViewport>&					viewports
5626 												scissors,							// const std::vector<VkRect2D>&						scissors
5627 												primitiveTopology,					// const VkPrimitiveTopology						topology
5628 												0u,									// const deUint32									subpass
5629 												0u,									// const deUint32									patchControlPoints
5630 												&vertexInputStateParams,			// const VkPipelineVertexInputStateCreateInfo*		vertexInputStateCreateInfo
5631 												getRasterizationStateCreateInfo(),	// const VkPipelineRasterizationStateCreateInfo*	rasterizationStateCreateInfo
5632 												&multisampleStateParams,			// const VkPipelineMultisampleStateCreateInfo*		multisampleStateCreateInfo
5633 												DE_NULL,							// const VkPipelineDepthStencilStateCreateInfo*		depthStencilStateCreateInfo,
5634 												getColorBlendStateCreateInfo());	// const VkPipelineColorBlendStateCreateInfo*		colorBlendStateCreateInfo
5635 	}
5636 
5637 	// Create Vertex Buffer
5638 	{
5639 		const VkBufferCreateInfo					vertexBufferParams		=
5640 		{
5641 			VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,	// VkStructureType		sType;
5642 			DE_NULL,								// const void*			pNext;
5643 			0u,										// VkBufferCreateFlags	flags;
5644 			attributeBatchSize * 2,					// VkDeviceSize			size;
5645 			VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,		// VkBufferUsageFlags	usage;
5646 			VK_SHARING_MODE_EXCLUSIVE,				// VkSharingMode		sharingMode;
5647 			1u,										// deUint32				queueFamilyCount;
5648 			&queueFamilyIndex						// const deUint32*		pQueueFamilyIndices;
5649 		};
5650 
5651 		const std::vector<tcu::Vec4>				colorData				(positionData.size(), tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
5652 
5653 		vertexBuffer		= createBuffer(vkd, vkDevice, &vertexBufferParams);
5654 		vertexBufferMemory	= allocator.allocate(getBufferMemoryRequirements(vkd, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
5655 
5656 		VK_CHECK(vkd.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferMemory->getMemory(), vertexBufferMemory->getOffset()));
5657 
5658 		// Load vertices into vertex buffer
5659 		deMemcpy(vertexBufferMemory->getHostPtr(), positionData.data(), attributeBatchSize);
5660 		deMemcpy(reinterpret_cast<deUint8*>(vertexBufferMemory->getHostPtr()) + attributeBatchSize, colorData.data(), attributeBatchSize);
5661 		flushAlloc(vkd, vkDevice, *vertexBufferMemory);
5662 	}
5663 
5664 	// Create Command Buffer
5665 	commandBuffer = allocateCommandBuffer(vkd, vkDevice, *m_commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
5666 
5667 	// Begin Command Buffer
5668 	beginCommandBuffer(vkd, *commandBuffer);
5669 
5670 	addImageTransitionBarrier(*commandBuffer,									// VkCommandBuffer			commandBuffer
5671 							  *m_image,											// VkImage					image
5672 							  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,				// VkPipelineStageFlags		srcStageMask
5673 							  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,				// VkPipelineStageFlags		dstStageMask
5674 							  0,												// VkAccessFlags			srcAccessMask
5675 							  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,				// VkAccessFlags			dstAccessMask
5676 							  VK_IMAGE_LAYOUT_UNDEFINED,						// VkImageLayout			oldLayout;
5677 							  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);		// VkImageLayout			newLayout;
5678 
5679 	if (m_multisampling)
5680 	{
5681 		addImageTransitionBarrier(*commandBuffer,								// VkCommandBuffer			commandBuffer
5682 								  *m_resolvedImage,								// VkImage					image
5683 								  VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,			// VkPipelineStageFlags		srcStageMask
5684 								  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,			// VkPipelineStageFlags		dstStageMask
5685 								  0,											// VkAccessFlags			srcAccessMask
5686 								  VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,			// VkAccessFlags			dstAccessMask
5687 								  VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout			oldLayout;
5688 								  VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);	// VkImageLayout			newLayout;
5689 	}
5690 
5691 	// Reset query pool
5692 	vkd.cmdResetQueryPool(*commandBuffer, *queryPool, 0u, 1u);
5693 
5694 	// Begin render pass and start query
5695 	beginRenderPass(vkd, *commandBuffer, *m_renderPass, *m_frameBuffer, vk::makeRect2D(0, 0, m_renderSize, m_renderSize), tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
5696 	vkd.cmdBeginQuery(*commandBuffer, *queryPool, 0u, (VkQueryControlFlags)0u);
5697 	vkd.cmdBindPipeline(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
5698 	vkd.cmdBindDescriptorSets(*commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_pipelineLayout, 0u, 1, &m_descriptorSet.get(), 0u, DE_NULL);
5699 	vkd.cmdBindVertexBuffers(*commandBuffer, 0, 1, &vertexBuffer.get(), &vertexBufferOffset);
5700 	vkd.cmdDraw(*commandBuffer, (deUint32)positionData.size(), 1, 0, 0);
5701 	endRenderPass(vkd, *commandBuffer);
5702 	vkd.cmdEndQuery(*commandBuffer, *queryPool, 0u);
5703 
5704 	// Copy Image
5705 	copyImageToBuffer(vkd, *commandBuffer, m_multisampling ? *m_resolvedImage : *m_image, *m_resultBuffer, tcu::IVec2(m_renderSize, m_renderSize));
5706 
5707 	endCommandBuffer(vkd, *commandBuffer);
5708 
5709 	// Set Point Size
5710 	{
5711 		float pointSize = getPointSize();
5712 
5713 		deMemcpy(m_uniformBufferMemory->getHostPtr(), &pointSize, (size_t)m_uniformBufferSize);
5714 		flushAlloc(vkd, vkDevice, *m_uniformBufferMemory);
5715 	}
5716 
5717 	// Submit
5718 	submitCommandsAndWait(vkd, vkDevice, queue, commandBuffer.get());
5719 
5720 	invalidateAlloc(vkd, vkDevice, *m_resultBufferMemory);
5721 	tcu::copy(result.getAccess(), tcu::ConstPixelBufferAccess(m_textureFormat, tcu::IVec3(m_renderSize, m_renderSize, 1), m_resultBufferMemory->getHostPtr()));
5722 }
5723 
5724 class DiscardTestCase : public BaseRenderingTestCase
5725 {
5726 public:
DiscardTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkPrimitiveTopology primitiveTopology,deBool queryFragmentShaderInvocations,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)5727 								DiscardTestCase					(tcu::TestContext& context, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, deBool queryFragmentShaderInvocations, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
5728 									: BaseRenderingTestCase				(context, name, description, sampleCount)
5729 									, m_primitiveTopology				(primitiveTopology)
5730 									, m_queryFragmentShaderInvocations	(queryFragmentShaderInvocations)
5731 								{}
5732 
createInstance(Context & context) const5733 	virtual TestInstance*		createInstance		(Context& context) const
5734 								{
5735 									return new DiscardTestInstance (context, m_primitiveTopology, m_queryFragmentShaderInvocations);
5736 								}
5737 
checkSupport(Context & context) const5738 	virtual	void				checkSupport		(Context& context) const
5739 								{
5740 									if (m_queryFragmentShaderInvocations)
5741 										context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_PIPELINE_STATISTICS_QUERY);
5742 
5743 									if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
5744 											context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
5745 											!context.getPortabilitySubsetFeatures().triangleFans)
5746 										TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
5747 								}
5748 
5749 protected:
5750 	const VkPrimitiveTopology	m_primitiveTopology;
5751 	const deBool				m_queryFragmentShaderInvocations;
5752 };
5753 
5754 class TriangleInterpolationTestInstance : public BaseRenderingTestInstance
5755 {
5756 public:
5757 
TriangleInterpolationTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,int flags,VkSampleCountFlagBits sampleCount)5758 								TriangleInterpolationTestInstance	(Context& context, VkPrimitiveTopology primitiveTopology, int flags, VkSampleCountFlagBits sampleCount)
5759 									: BaseRenderingTestInstance	(context, sampleCount, RESOLUTION_POT)
5760 									, m_primitiveTopology		(primitiveTopology)
5761 									, m_projective				((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
5762 									, m_iterationCount			(3)
5763 									, m_iteration				(0)
5764 									, m_allIterationsPassed		(true)
5765 									, m_flatshade				((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
5766 								{}
5767 
5768 	tcu::TestStatus				iterate								(void);
5769 
5770 
5771 private:
5772 	void						generateVertices					(int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
5773 	void						extractTriangles					(std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
5774 
5775 
5776 	VkPrimitiveTopology			m_primitiveTopology;
5777 	const bool					m_projective;
5778 	const int					m_iterationCount;
5779 	int							m_iteration;
5780 	bool						m_allIterationsPassed;
5781 	const deBool				m_flatshade;
5782 };
5783 
iterate(void)5784 tcu::TestStatus TriangleInterpolationTestInstance::iterate (void)
5785 {
5786 	const std::string								iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
5787 	const tcu::ScopedLogSection						section					(m_context.getTestContext().getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
5788 	tcu::Surface									resultImage				(m_renderSize, m_renderSize);
5789 	std::vector<tcu::Vec4>							drawBuffer;
5790 	std::vector<tcu::Vec4>							colorBuffer;
5791 	std::vector<TriangleSceneSpec::SceneTriangle>	triangles;
5792 
5793 	// generate scene
5794 	generateVertices(m_iteration, drawBuffer, colorBuffer);
5795 	extractTriangles(triangles, drawBuffer, colorBuffer);
5796 
5797 	// log
5798 	{
5799 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
5800 		for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
5801 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
5802 	}
5803 
5804 	// draw image
5805 	drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology);
5806 
5807 	// compare
5808 	{
5809 		RasterizationArguments	args;
5810 		TriangleSceneSpec		scene;
5811 		tcu::IVec4				colorBits	= tcu::getTextureFormatBitDepth(getTextureFormat());
5812 
5813 		args.numSamples		= m_multisampling ? 1 : 0;
5814 		args.subpixelBits	= m_subpixelBits;
5815 		args.redBits		= colorBits[0];
5816 		args.greenBits		= colorBits[1];
5817 		args.blueBits		= colorBits[2];
5818 
5819 		scene.triangles.swap(triangles);
5820 
5821 		if (!verifyTriangleGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog()))
5822 			m_allIterationsPassed = false;
5823 	}
5824 
5825 	// result
5826 	if (++m_iteration == m_iterationCount)
5827 	{
5828 		if (m_allIterationsPassed)
5829 			return tcu::TestStatus::pass("Pass");
5830 		else
5831 			return tcu::TestStatus::fail("Found invalid pixel values");
5832 	}
5833 	else
5834 		return tcu::TestStatus::incomplete();
5835 }
5836 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const5837 void TriangleInterpolationTestInstance::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
5838 {
5839 	// use only red, green and blue
5840 	const tcu::Vec4 colors[] =
5841 	{
5842 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
5843 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
5844 		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
5845 	};
5846 
5847 	de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology);
5848 
5849 	outVertices.resize(6);
5850 	outColors.resize(6);
5851 
5852 	for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
5853 	{
5854 		outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
5855 		outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
5856 		outVertices[vtxNdx].z() = 0.0f;
5857 
5858 		if (!m_projective)
5859 			outVertices[vtxNdx].w() = 1.0f;
5860 		else
5861 		{
5862 			const float w = rnd.getFloat(0.2f, 4.0f);
5863 
5864 			outVertices[vtxNdx].x() *= w;
5865 			outVertices[vtxNdx].y() *= w;
5866 			outVertices[vtxNdx].z() *= w;
5867 			outVertices[vtxNdx].w() = w;
5868 		}
5869 
5870 		outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
5871 	}
5872 }
5873 
extractTriangles(std::vector<TriangleSceneSpec::SceneTriangle> & outTriangles,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const5874 void TriangleInterpolationTestInstance::extractTriangles (std::vector<TriangleSceneSpec::SceneTriangle>& outTriangles, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
5875 {
5876 	switch (m_primitiveTopology)
5877 	{
5878 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
5879 		{
5880 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; vtxNdx += 3)
5881 			{
5882 				TriangleSceneSpec::SceneTriangle tri;
5883 				tri.positions[0]	= vertices[vtxNdx + 0];
5884 				tri.positions[1]	= vertices[vtxNdx + 1];
5885 				tri.positions[2]	= vertices[vtxNdx + 2];
5886 				tri.sharedEdge[0]	= false;
5887 				tri.sharedEdge[1]	= false;
5888 				tri.sharedEdge[2]	= false;
5889 
5890 				if (m_flatshade)
5891 				{
5892 					tri.colors[0] = colors[vtxNdx];
5893 					tri.colors[1] = colors[vtxNdx];
5894 					tri.colors[2] = colors[vtxNdx];
5895 				}
5896 				else
5897 				{
5898 					tri.colors[0] = colors[vtxNdx + 0];
5899 					tri.colors[1] = colors[vtxNdx + 1];
5900 					tri.colors[2] = colors[vtxNdx + 2];
5901 				}
5902 
5903 				outTriangles.push_back(tri);
5904 			}
5905 			break;
5906 		}
5907 
5908 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
5909 		{
5910 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 2; ++vtxNdx)
5911 			{
5912 				TriangleSceneSpec::SceneTriangle tri;
5913 				tri.positions[0]	= vertices[vtxNdx + 0];
5914 				tri.positions[1]	= vertices[vtxNdx + 1];
5915 				tri.positions[2]	= vertices[vtxNdx + 2];
5916 				tri.sharedEdge[0]	= false;
5917 				tri.sharedEdge[1]	= false;
5918 				tri.sharedEdge[2]	= false;
5919 
5920 				if (m_flatshade)
5921 				{
5922 					tri.colors[0] = colors[vtxNdx];
5923 					tri.colors[1] = colors[vtxNdx];
5924 					tri.colors[2] = colors[vtxNdx];
5925 				}
5926 				else
5927 				{
5928 					tri.colors[0] = colors[vtxNdx + 0];
5929 					tri.colors[1] = colors[vtxNdx + 1];
5930 					tri.colors[2] = colors[vtxNdx + 2];
5931 				}
5932 
5933 				outTriangles.push_back(tri);
5934 			}
5935 			break;
5936 		}
5937 
5938 		case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
5939 		{
5940 			for (int vtxNdx = 1; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
5941 			{
5942 				TriangleSceneSpec::SceneTriangle tri;
5943 				tri.positions[0]	= vertices[0];
5944 				tri.positions[1]	= vertices[vtxNdx + 0];
5945 				tri.positions[2]	= vertices[vtxNdx + 1];
5946 				tri.sharedEdge[0]	= false;
5947 				tri.sharedEdge[1]	= false;
5948 				tri.sharedEdge[2]	= false;
5949 
5950 				if (m_flatshade)
5951 				{
5952 					tri.colors[0] = colors[vtxNdx];
5953 					tri.colors[1] = colors[vtxNdx];
5954 					tri.colors[2] = colors[vtxNdx];
5955 				}
5956 				else
5957 				{
5958 					tri.colors[0] = colors[0];
5959 					tri.colors[1] = colors[vtxNdx + 0];
5960 					tri.colors[2] = colors[vtxNdx + 1];
5961 				}
5962 
5963 				outTriangles.push_back(tri);
5964 			}
5965 			break;
5966 		}
5967 
5968 		default:
5969 			DE_ASSERT(false);
5970 	}
5971 }
5972 
5973 class TriangleInterpolationTestCase : public BaseRenderingTestCase
5974 {
5975 public:
TriangleInterpolationTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkPrimitiveTopology primitiveTopology,int flags,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)5976 								TriangleInterpolationTestCase	(tcu::TestContext& context, const std::string& name, const std::string& description, VkPrimitiveTopology primitiveTopology, int flags, VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT)
5977 									: BaseRenderingTestCase		(context, name, description, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
5978 									, m_primitiveTopology		(primitiveTopology)
5979 									, m_flags					(flags)
5980 								{}
5981 
createInstance(Context & context) const5982 	virtual TestInstance*		createInstance					(Context& context) const
5983 								{
5984 									return new TriangleInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_sampleCount);
5985 								}
5986 
checkSupport(Context & context) const5987 	virtual	void				checkSupport		(Context& context) const
5988 								{
5989 									if (m_primitiveTopology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN &&
5990 										context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
5991 										!context.getPortabilitySubsetFeatures().triangleFans)
5992 									{
5993 										TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: Triangle fans are not supported by this implementation");
5994 									}
5995 								}
5996 protected:
5997 	const VkPrimitiveTopology	m_primitiveTopology;
5998 	const int					m_flags;
5999 };
6000 
6001 class LineInterpolationTestInstance : public BaseRenderingTestInstance
6002 {
6003 public:
6004 							LineInterpolationTestInstance	(Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount);
6005 
6006 	virtual tcu::TestStatus	iterate							(void);
6007 
6008 private:
6009 	void					generateVertices				(int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const;
6010 	void					extractLines					(std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const;
6011 	virtual float			getLineWidth					(void) const;
6012 
6013 	VkPrimitiveTopology		m_primitiveTopology;
6014 	const bool				m_projective;
6015 	const int				m_iterationCount;
6016 	const PrimitiveWideness	m_primitiveWideness;
6017 
6018 	int						m_iteration;
6019 	bool					m_allIterationsPassed;
6020 	float					m_maxLineWidth;
6021 	std::vector<float>		m_lineWidths;
6022 	bool					m_flatshade;
6023 	PrimitiveStrictness		m_strictness;
6024 };
6025 
LineInterpolationTestInstance(Context & context,VkPrimitiveTopology primitiveTopology,int flags,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount)6026 LineInterpolationTestInstance::LineInterpolationTestInstance (Context& context, VkPrimitiveTopology primitiveTopology, int flags, PrimitiveWideness wideness, PrimitiveStrictness strictness, VkSampleCountFlagBits sampleCount)
6027 	: BaseRenderingTestInstance			(context, sampleCount)
6028 	, m_primitiveTopology				(primitiveTopology)
6029 	, m_projective						((flags & INTERPOLATIONFLAGS_PROJECTED) != 0)
6030 	, m_iterationCount					(3)
6031 	, m_primitiveWideness				(wideness)
6032 	, m_iteration						(0)
6033 	, m_allIterationsPassed				(true)
6034 	, m_maxLineWidth					(1.0f)
6035 	, m_flatshade						((flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6036 	, m_strictness						(strictness)
6037 {
6038 	DE_ASSERT(m_primitiveWideness < PRIMITIVEWIDENESS_LAST);
6039 
6040 	// create line widths
6041 	if (m_primitiveWideness == PRIMITIVEWIDENESS_NARROW)
6042 	{
6043 		m_lineWidths.resize(m_iterationCount, 1.0f);
6044 	}
6045 	else if (m_primitiveWideness == PRIMITIVEWIDENESS_WIDE)
6046 	{
6047 		const float*	range = context.getDeviceProperties().limits.lineWidthRange;
6048 
6049 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "ALIASED_LINE_WIDTH_RANGE = [" << range[0] << ", " << range[1] << "]" << tcu::TestLog::EndMessage;
6050 
6051 		DE_ASSERT(range[1] > 1.0f);
6052 
6053 		// set hand picked sizes
6054 		m_lineWidths.push_back(5.0f);
6055 		m_lineWidths.push_back(10.0f);
6056 		m_lineWidths.push_back(range[1]);
6057 		DE_ASSERT((int)m_lineWidths.size() == m_iterationCount);
6058 
6059 		m_maxLineWidth = range[1];
6060 	}
6061 	else
6062 		DE_ASSERT(false);
6063 }
6064 
iterate(void)6065 tcu::TestStatus LineInterpolationTestInstance::iterate (void)
6066 {
6067 	const std::string						iterationDescription	= "Test iteration " + de::toString(m_iteration+1) + " / " + de::toString(m_iterationCount);
6068 	const tcu::ScopedLogSection				section					(m_context.getTestContext().getLog(), "Iteration" + de::toString(m_iteration+1), iterationDescription);
6069 	const float								lineWidth				= getLineWidth();
6070 	tcu::Surface							resultImage				(m_renderSize, m_renderSize);
6071 	std::vector<tcu::Vec4>					drawBuffer;
6072 	std::vector<tcu::Vec4>					colorBuffer;
6073 	std::vector<LineSceneSpec::SceneLine>	lines;
6074 
6075 	// supported?
6076 	if (lineWidth <= m_maxLineWidth)
6077 	{
6078 		// generate scene
6079 		generateVertices(m_iteration, drawBuffer, colorBuffer);
6080 		extractLines(lines, drawBuffer, colorBuffer);
6081 
6082 		// log
6083 		{
6084 			m_context.getTestContext().getLog() << tcu::TestLog::Message << "Generated vertices:" << tcu::TestLog::EndMessage;
6085 			for (int vtxNdx = 0; vtxNdx < (int)drawBuffer.size(); ++vtxNdx)
6086 				m_context.getTestContext().getLog() << tcu::TestLog::Message << "\t" << drawBuffer[vtxNdx] << ",\tcolor= " << colorBuffer[vtxNdx] << tcu::TestLog::EndMessage;
6087 		}
6088 
6089 		// draw image
6090 		drawPrimitives(resultImage, drawBuffer, colorBuffer, m_primitiveTopology);
6091 
6092 		// compare
6093 		{
6094 			RasterizationArguments	args;
6095 			LineSceneSpec			scene;
6096 
6097 			tcu::IVec4				colorBits = tcu::getTextureFormatBitDepth(getTextureFormat());
6098 
6099 			args.numSamples		= m_multisampling ? 1 : 0;
6100 			args.subpixelBits	= m_subpixelBits;
6101 			args.redBits		= colorBits[0];
6102 			args.greenBits		= colorBits[1];
6103 			args.blueBits		= colorBits[2];
6104 
6105 			scene.lines.swap(lines);
6106 			scene.lineWidth = getLineWidth();
6107 
6108 			switch (m_strictness)
6109 			{
6110 				case PRIMITIVESTRICTNESS_STRICT:
6111 				{
6112 					if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog(), true))
6113 						m_allIterationsPassed = false;
6114 
6115 					break;
6116 				}
6117 
6118 				case PRIMITIVESTRICTNESS_NONSTRICT:
6119 				case PRIMITIVESTRICTNESS_IGNORE:
6120 				{
6121 					if (!verifyTriangulatedLineGroupInterpolation(resultImage, scene, args, m_context.getTestContext().getLog(), false, true))
6122 						m_allIterationsPassed = false;
6123 
6124 					break;
6125 				}
6126 
6127 				default:
6128 					TCU_THROW(InternalError, "Not implemented");
6129 			}
6130 		}
6131 	}
6132 	else
6133 		m_context.getTestContext().getLog() << tcu::TestLog::Message << "Line width " << lineWidth << " not supported, skipping iteration." << tcu::TestLog::EndMessage;
6134 
6135 	// result
6136 	if (++m_iteration == m_iterationCount)
6137 	{
6138 		if (m_allIterationsPassed)
6139 			return tcu::TestStatus::pass("Pass");
6140 		else
6141 			return tcu::TestStatus::fail("Incorrect rasterization");
6142 	}
6143 	else
6144 		return tcu::TestStatus::incomplete();
6145 }
6146 
generateVertices(int iteration,std::vector<tcu::Vec4> & outVertices,std::vector<tcu::Vec4> & outColors) const6147 void LineInterpolationTestInstance::generateVertices (int iteration, std::vector<tcu::Vec4>& outVertices, std::vector<tcu::Vec4>& outColors) const
6148 {
6149 	// use only red, green and blue
6150 	const tcu::Vec4 colors[] =
6151 	{
6152 		tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
6153 		tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f),
6154 		tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f),
6155 	};
6156 
6157 	de::Random rnd(123 + iteration * 1000 + (int)m_primitiveTopology);
6158 
6159 	outVertices.resize(6);
6160 	outColors.resize(6);
6161 
6162 	for (int vtxNdx = 0; vtxNdx < (int)outVertices.size(); ++vtxNdx)
6163 	{
6164 		outVertices[vtxNdx].x() = rnd.getFloat(-0.9f, 0.9f);
6165 		outVertices[vtxNdx].y() = rnd.getFloat(-0.9f, 0.9f);
6166 		outVertices[vtxNdx].z() = 0.0f;
6167 
6168 		if (!m_projective)
6169 			outVertices[vtxNdx].w() = 1.0f;
6170 		else
6171 		{
6172 			const float w = rnd.getFloat(0.2f, 4.0f);
6173 
6174 			outVertices[vtxNdx].x() *= w;
6175 			outVertices[vtxNdx].y() *= w;
6176 			outVertices[vtxNdx].z() *= w;
6177 			outVertices[vtxNdx].w() = w;
6178 		}
6179 
6180 		outColors[vtxNdx] = colors[vtxNdx % DE_LENGTH_OF_ARRAY(colors)];
6181 	}
6182 }
6183 
extractLines(std::vector<LineSceneSpec::SceneLine> & outLines,const std::vector<tcu::Vec4> & vertices,const std::vector<tcu::Vec4> & colors) const6184 void LineInterpolationTestInstance::extractLines (std::vector<LineSceneSpec::SceneLine>& outLines, const std::vector<tcu::Vec4>& vertices, const std::vector<tcu::Vec4>& colors) const
6185 {
6186 	switch (m_primitiveTopology)
6187 	{
6188 		case VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
6189 		{
6190 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; vtxNdx += 2)
6191 			{
6192 				LineSceneSpec::SceneLine line;
6193 				line.positions[0] = vertices[vtxNdx + 0];
6194 				line.positions[1] = vertices[vtxNdx + 1];
6195 
6196 				if (m_flatshade)
6197 				{
6198 					line.colors[0] = colors[vtxNdx];
6199 					line.colors[1] = colors[vtxNdx];
6200 				}
6201 				else
6202 				{
6203 					line.colors[0] = colors[vtxNdx + 0];
6204 					line.colors[1] = colors[vtxNdx + 1];
6205 				}
6206 
6207 				outLines.push_back(line);
6208 			}
6209 			break;
6210 		}
6211 
6212 		case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
6213 		{
6214 			for (int vtxNdx = 0; vtxNdx < (int)vertices.size() - 1; ++vtxNdx)
6215 			{
6216 				LineSceneSpec::SceneLine line;
6217 				line.positions[0] = vertices[vtxNdx + 0];
6218 				line.positions[1] = vertices[vtxNdx + 1];
6219 
6220 				if (m_flatshade)
6221 				{
6222 					line.colors[0] = colors[vtxNdx];
6223 					line.colors[1] = colors[vtxNdx];
6224 				}
6225 				else
6226 				{
6227 					line.colors[0] = colors[vtxNdx + 0];
6228 					line.colors[1] = colors[vtxNdx + 1];
6229 				}
6230 
6231 				outLines.push_back(line);
6232 			}
6233 			break;
6234 		}
6235 
6236 		default:
6237 			DE_ASSERT(false);
6238 	}
6239 }
6240 
getLineWidth(void) const6241 float LineInterpolationTestInstance::getLineWidth (void) const
6242 {
6243 	return m_lineWidths[m_iteration];
6244 }
6245 
6246 class LineInterpolationTestCase : public BaseRenderingTestCase
6247 {
6248 public:
LineInterpolationTestCase(tcu::TestContext & context,const std::string & name,const std::string & description,VkPrimitiveTopology primitiveTopology,int flags,PrimitiveWideness wideness,PrimitiveStrictness strictness,VkSampleCountFlagBits sampleCount=VK_SAMPLE_COUNT_1_BIT)6249 								LineInterpolationTestCase		(tcu::TestContext&		context,
6250 																 const std::string&		name,
6251 																 const std::string&		description,
6252 																 VkPrimitiveTopology	primitiveTopology,
6253 																 int					flags,
6254 																 PrimitiveWideness		wideness,
6255 																 PrimitiveStrictness	strictness,
6256 																 VkSampleCountFlagBits	sampleCount = VK_SAMPLE_COUNT_1_BIT)
6257 									: BaseRenderingTestCase		(context, name, description, sampleCount, (flags & INTERPOLATIONFLAGS_FLATSHADE) != 0)
6258 									, m_primitiveTopology		(primitiveTopology)
6259 									, m_flags					(flags)
6260 									, m_wideness				(wideness)
6261 									, m_strictness				(strictness)
6262 								{}
6263 
createInstance(Context & context) const6264 	virtual TestInstance*		createInstance					(Context& context) const
6265 								{
6266 									return new LineInterpolationTestInstance(context, m_primitiveTopology, m_flags, m_wideness, m_strictness, m_sampleCount);
6267 								}
6268 
checkSupport(Context & context) const6269 	virtual	void				checkSupport		(Context& context) const
6270 								{
6271 									if (m_strictness == PRIMITIVESTRICTNESS_STRICT &&
6272 										!context.getDeviceProperties().limits.strictLines)
6273 										TCU_THROW(NotSupportedError, "Strict rasterization is not supported");
6274 
6275 									if (m_wideness == PRIMITIVEWIDENESS_WIDE)
6276 										context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
6277 								}
6278 protected:
6279 	const VkPrimitiveTopology	m_primitiveTopology;
6280 	const int					m_flags;
6281 	const PrimitiveWideness		m_wideness;
6282 	const PrimitiveStrictness	m_strictness;
6283 };
6284 
6285 class StrideZeroCase : public vkt::TestCase
6286 {
6287 public:
6288 	struct Params
6289 	{
6290 		std::vector<tcu::Vec2>	bufferData;
6291 		deUint32				drawVertexCount;
6292 	};
6293 
StrideZeroCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const Params & params)6294 							StrideZeroCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const Params& params)
6295 								: vkt::TestCase	(testCtx, name, description)
6296 								, m_params		(params)
6297 								{}
6298 
~StrideZeroCase(void)6299 	virtual					~StrideZeroCase		(void) {}
6300 
6301 	virtual void			initPrograms		(vk::SourceCollections& programCollection) const;
6302 	virtual TestInstance*	createInstance		(Context& context) const;
6303 	virtual void			checkSupport		(Context& context) const;
6304 
6305 	static constexpr vk::VkFormat				kColorFormat	= vk::VK_FORMAT_R8G8B8A8_UNORM;
6306 	static constexpr vk::VkFormatFeatureFlags	kColorFeatures	= (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
6307 	static constexpr vk::VkImageUsageFlags		kColorUsage		= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
6308 
6309 	//	(-1,-1)
6310 	//		+-----+-----+
6311 	//		|     |     |
6312 	//		|  a  |  b  |	a = (-0.5, -0.5)
6313 	//		|     |     |	b = ( 0.5, -0.5)
6314 	//		+-----------+	c = (-0.5,  0.5)
6315 	//		|     |     |	d = ( 0.5,  0.5)
6316 	//		|  c  |  d  |
6317 	//		|     |     |
6318 	//		+-----+-----+
6319 	//					(1,1)
6320 	static constexpr deUint32					kImageDim		= 2u;
6321 	static const float							kCornerDelta;	// 0.5f;
6322 
6323 	static const tcu::Vec4						kClearColor;
6324 	static const tcu::Vec4						kDrawColor;
6325 
6326 private:
6327 	Params m_params;
6328 };
6329 
6330 const float		StrideZeroCase::kCornerDelta	= 0.5f;
6331 const tcu::Vec4	StrideZeroCase::kClearColor		(0.0f, 0.0f, 0.0f, 1.0f);
6332 const tcu::Vec4	StrideZeroCase::kDrawColor		(1.0f, 1.0f, 1.0f, 1.0f);
6333 
6334 class StrideZeroInstance : public vkt::TestInstance
6335 {
6336 public:
StrideZeroInstance(Context & context,const StrideZeroCase::Params & params)6337 								StrideZeroInstance	(Context& context, const StrideZeroCase::Params& params)
6338 									: vkt::TestInstance	(context)
6339 									, m_params			(params)
6340 									{}
6341 
~StrideZeroInstance(void)6342 	virtual						~StrideZeroInstance	(void) {}
6343 
6344 	virtual tcu::TestStatus		iterate				(void);
6345 
6346 private:
6347 	StrideZeroCase::Params m_params;
6348 };
6349 
initPrograms(vk::SourceCollections & programCollection) const6350 void StrideZeroCase::initPrograms (vk::SourceCollections& programCollection) const
6351 {
6352 	std::ostringstream vert;
6353 	std::ostringstream frag;
6354 
6355 	std::ostringstream drawColor;
6356 	drawColor
6357 		<< std::setprecision(2) << std::fixed
6358 		<< "vec4(" << kDrawColor.x() << ", " << kDrawColor.y() << ", " << kDrawColor.z() << ", " << kDrawColor.w() << ")";
6359 
6360 	vert
6361 		<< "#version 450\n"
6362 		<< "layout (location=0) in vec2 inPos;\n"
6363 		<< "void main() {\n"
6364 		<< "    gl_Position = vec4(inPos, 0.0, 1.0);\n"
6365 		<< "    gl_PointSize = 1.0;\n"
6366 		<< "}\n"
6367 		;
6368 
6369 	frag
6370 		<< "#version 450\n"
6371 		<< "layout (location=0) out vec4 outColor;\n"
6372 		<< "void main() {\n"
6373 		<< "    outColor = " << drawColor.str() << ";\n"
6374 		<< "}\n"
6375 		;
6376 
6377 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
6378 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
6379 }
6380 
createInstance(Context & context) const6381 TestInstance* StrideZeroCase::createInstance (Context& context) const
6382 {
6383 	return new StrideZeroInstance(context, m_params);
6384 }
6385 
checkSupport(Context & context) const6386 void StrideZeroCase::checkSupport (Context& context) const
6387 {
6388 	const auto properties = vk::getPhysicalDeviceFormatProperties(context.getInstanceInterface(), context.getPhysicalDevice(), kColorFormat);
6389 	if ((properties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
6390 		TCU_THROW(NotSupportedError, "Required image format not supported");
6391 }
6392 
6393 // Creates a vertex buffer with the given data but uses zero as the binding stride.
6394 // Then, tries to draw the requested number of points. Only the first point should ever be used.
iterate(void)6395 tcu::TestStatus StrideZeroInstance::iterate (void)
6396 {
6397 	const auto&		vkd			= m_context.getDeviceInterface();
6398 	const auto		device		= m_context.getDevice();
6399 	auto&			alloc		= m_context.getDefaultAllocator();
6400 	const auto		queue		= m_context.getUniversalQueue();
6401 	const auto		queueIndex	= m_context.getUniversalQueueFamilyIndex();
6402 	constexpr auto	kImageDim	= StrideZeroCase::kImageDim;
6403 	const auto		colorExtent	= vk::makeExtent3D(kImageDim, kImageDim, 1u);
6404 
6405 	// Prepare vertex buffer.
6406 	const auto					vertexBufferSize	= static_cast<vk::VkDeviceSize>(m_params.bufferData.size() * sizeof(decltype(m_params.bufferData)::value_type));
6407 	const auto					vertexBufferInfo	= vk::makeBufferCreateInfo(vertexBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
6408 	const vk::BufferWithMemory	vertexBuffer(		vkd, device, alloc, vertexBufferInfo, vk::MemoryRequirement::HostVisible);
6409 	auto&						vertexBufferAlloc	= vertexBuffer.getAllocation();
6410 	const vk::VkDeviceSize		vertexBufferOffset	= 0ull;
6411 	deMemcpy(vertexBufferAlloc.getHostPtr(), m_params.bufferData.data(), static_cast<size_t>(vertexBufferSize));
6412 	flushAlloc(vkd, device, vertexBufferAlloc);
6413 
6414 	// Prepare render image.
6415 	const vk::VkImageCreateInfo colorAttachmentInfo =
6416 	{
6417 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
6418 		nullptr,									//	const void*				pNext;
6419 		0u,											//	VkImageCreateFlags		flags;
6420 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
6421 		StrideZeroCase::kColorFormat,				//	VkFormat				format;
6422 		colorExtent,								//	VkExtent3D				extent;
6423 		1u,											//	deUint32				mipLevels;
6424 		1u,											//	deUint32				arrayLayers;
6425 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
6426 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
6427 		StrideZeroCase::kColorUsage,				//	VkImageUsageFlags		usage;
6428 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
6429 		1u,											//	deUint32				queueFamilyIndexCount;
6430 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
6431 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
6432 	};
6433 	const vk::ImageWithMemory colorAttachment(vkd, device, alloc, colorAttachmentInfo, vk::MemoryRequirement::Any);
6434 
6435 	const auto colorSubresourceRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
6436 	const auto colorAttachmentView		= vk::makeImageView(vkd, device, colorAttachment.get(), vk::VK_IMAGE_VIEW_TYPE_2D, StrideZeroCase::kColorFormat, colorSubresourceRange);
6437 
6438 	const vk::VkVertexInputBindingDescription vertexBinding =
6439 	{
6440 		0u,									//	deUint32			binding;
6441 		0u,									//	deUint32			stride;		[IMPORTANT]
6442 		vk::VK_VERTEX_INPUT_RATE_VERTEX,	//	VkVertexInputRate	inputRate;
6443 	};
6444 
6445 	const vk::VkVertexInputAttributeDescription vertexAttribute =
6446 	{
6447 		0u,								//	deUint32	location;
6448 		0u,								//	deUint32	binding;
6449 		vk::VK_FORMAT_R32G32_SFLOAT,	//	VkFormat	format;
6450 		0u,								//	deUint32	offset;
6451 	};
6452 
6453 	const vk::VkPipelineVertexInputStateCreateInfo vertexInput =
6454 	{
6455 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
6456 		nullptr,														//	const void*									pNext;
6457 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
6458 		1u,																//	deUint32									vertexBindingDescriptionCount;
6459 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
6460 		1u,																//	deUint32									vertexAttributeDescriptionCount;
6461 		&vertexAttribute,												//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
6462 	};
6463 
6464 	const auto renderArea		= vk::makeRect2D(kImageDim, kImageDim);
6465 	const auto viewports		= std::vector<vk::VkViewport>(1, vk::makeViewport(kImageDim, kImageDim));
6466 	const auto scissors			= std::vector<vk::VkRect2D>(1, renderArea);
6467 	const auto pipelineLayout	= vk::makePipelineLayout(vkd, device);
6468 	const auto vertexShader		= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
6469 	const auto fragmentShader	= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
6470 	const auto renderPass		= vk::makeRenderPass(vkd, device, StrideZeroCase::kColorFormat);
6471 	const auto graphicsPipeline	= vk::makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
6472 		vertexShader.get(), DE_NULL, DE_NULL, DE_NULL, fragmentShader.get(),					// Shaders.
6473 		renderPass.get(), viewports, scissors, vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST, 0u, 0u,	// Render pass, viewports, scissors, topology.
6474 		&vertexInput);																			// Vertex input state.
6475 	const auto framebuffer		= vk::makeFramebuffer(vkd, device, renderPass.get(), colorAttachmentView.get(), kImageDim, kImageDim);
6476 
6477 	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
6478 	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
6479 	const auto cmdBuffer	= cmdBufferPtr.get();
6480 
6481 	// Buffer used to verify results.
6482 	const auto					tcuFormat			= vk::mapVkFormat(StrideZeroCase::kColorFormat);
6483 	const auto					colorBufferSize		= static_cast<vk::VkDeviceSize>(tcu::getPixelSize(tcuFormat)) * kImageDim * kImageDim;
6484 	const auto					colorBufferInfo		= vk::makeBufferCreateInfo(colorBufferSize, vk::VK_BUFFER_USAGE_TRANSFER_DST_BIT);
6485 	const vk::BufferWithMemory	colorBuffer			(vkd, device, alloc, colorBufferInfo, vk::MemoryRequirement::HostVisible);
6486 	auto&						colorBufferAlloc	= colorBuffer.getAllocation();
6487 	void*						colorBufferPtr		= colorBufferAlloc.getHostPtr();
6488 	const auto					colorLayers			= vk::makeImageSubresourceLayers(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
6489 	const auto					copyRegion			= vk::makeBufferImageCopy(colorExtent, colorLayers);
6490 
6491 	// Barriers from attachment to buffer and buffer to host.
6492 	const auto colorAttachmentBarrier	= vk::makeImageMemoryBarrier	(vk::VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, vk::VK_ACCESS_TRANSFER_READ_BIT, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorAttachment.get(), colorSubresourceRange);
6493 	const auto colorBufferBarrier		= vk::makeBufferMemoryBarrier	(vk::VK_ACCESS_TRANSFER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT, colorBuffer.get(), 0ull, colorBufferSize);
6494 
6495 	vk::beginCommandBuffer(vkd, cmdBuffer);
6496 	vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), renderArea, StrideZeroCase::kClearColor);
6497 	vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
6498 	vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
6499 	vkd.cmdDraw(cmdBuffer, m_params.drawVertexCount, 1u, 0u, 0u);
6500 	vk::endRenderPass(vkd, cmdBuffer);
6501 	vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorAttachmentBarrier);
6502 	vkd.cmdCopyImageToBuffer(cmdBuffer, colorAttachment.get(), vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer.get(), 1u, &copyRegion);
6503 	vkd.cmdPipelineBarrier(cmdBuffer, vk::VK_PIPELINE_STAGE_TRANSFER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, nullptr, 1u, &colorBufferBarrier, 0u, nullptr);
6504 	vk::endCommandBuffer(vkd, cmdBuffer);
6505 
6506 	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
6507 
6508 	// Invalidate color buffer alloc.
6509 	vk::invalidateAlloc(vkd, device, colorBufferAlloc);
6510 
6511 	// Check buffer.
6512 	const int							imageDimI	= static_cast<int>(kImageDim);
6513 	const tcu::ConstPixelBufferAccess	colorPixels	(tcuFormat, imageDimI, imageDimI, 1, colorBufferPtr);
6514 	tcu::TestStatus						testStatus	= tcu::TestStatus::pass("Pass");
6515 	auto&								log			= m_context.getTestContext().getLog();
6516 
6517 	for (int x = 0; x < imageDimI; ++x)
6518 	for (int y = 0; y < imageDimI; ++y)
6519 	{
6520 		// Only the top-left corner should have draw data.
6521 		const auto expectedColor	= ((x == 0 && y == 0) ? StrideZeroCase::kDrawColor : StrideZeroCase::kClearColor);
6522 		const auto imageColor		= colorPixels.getPixel(x, y);
6523 
6524 		if (expectedColor != imageColor)
6525 		{
6526 			log
6527 				<< tcu::TestLog::Message
6528 				<< "Unexpected color found in pixel (" << x << ", " << y << "): "
6529 				<< "expected (" << expectedColor.x() << ", " << expectedColor.y() << ", " << expectedColor.z() << ", " << expectedColor.w() << ") "
6530 				<< "and found (" << imageColor.x() << ", " << imageColor.y() << ", " << imageColor.z() << ", " << imageColor.w() << ")"
6531 				<< tcu::TestLog::EndMessage;
6532 
6533 			testStatus = tcu::TestStatus::fail("Failed; Check log for details");
6534 		}
6535 	}
6536 
6537 	return testStatus;
6538 }
6539 
createRasterizationTests(tcu::TestCaseGroup * rasterizationTests)6540 void createRasterizationTests (tcu::TestCaseGroup* rasterizationTests)
6541 {
6542 	tcu::TestContext&	testCtx		=	rasterizationTests->getTestContext();
6543 
6544 	// .primitives
6545 	{
6546 		tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(testCtx, "primitives", "Primitive rasterization");
6547 
6548 		rasterizationTests->addChild(primitives);
6549 
6550 		tcu::TestCaseGroup* const nostippleTests = new tcu::TestCaseGroup(testCtx, "no_stipple", "No stipple");
6551 		tcu::TestCaseGroup* const stippleStaticTests = new tcu::TestCaseGroup(testCtx, "static_stipple", "Line stipple static");
6552 		tcu::TestCaseGroup* const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple", "Line stipple dynamic");
6553 		tcu::TestCaseGroup* const strideZeroTests = new tcu::TestCaseGroup(testCtx, "stride_zero", "Test input assembly with stride zero");
6554 
6555 		primitives->addChild(nostippleTests);
6556 		primitives->addChild(stippleStaticTests);
6557 		primitives->addChild(stippleDynamicTests);
6558 		primitives->addChild(strideZeroTests);
6559 
6560 		// .stride_zero
6561 		{
6562 			{
6563 				StrideZeroCase::Params params;
6564 				params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
6565 				params.drawVertexCount = 1u;
6566 				strideZeroTests->addChild(new StrideZeroCase(testCtx, "single_point", "Attempt to draw 1 point with stride 0", params));
6567 			}
6568 			{
6569 				StrideZeroCase::Params params;
6570 				params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
6571 				params.bufferData.emplace_back( StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
6572 				params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta,  StrideZeroCase::kCornerDelta);
6573 				params.bufferData.emplace_back( StrideZeroCase::kCornerDelta,  StrideZeroCase::kCornerDelta);
6574 				params.drawVertexCount = static_cast<deUint32>(params.bufferData.size());
6575 				strideZeroTests->addChild(new StrideZeroCase(testCtx, "four_points", "Attempt to draw 4 points with stride 0 and 4 points in the buffer", params));
6576 			}
6577 			{
6578 				StrideZeroCase::Params params;
6579 				params.bufferData.emplace_back(-StrideZeroCase::kCornerDelta, -StrideZeroCase::kCornerDelta);
6580 				params.drawVertexCount = 100000u;
6581 				strideZeroTests->addChild(new StrideZeroCase(testCtx, "many_points", "Attempt to draw many points with stride 0 with one point in the buffer", params));
6582 			}
6583 		}
6584 
6585 		nostippleTests->addChild(new BaseTestCase<TrianglesTestInstance>		(testCtx, "triangles",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result"));
6586 		nostippleTests->addChild(new BaseTestCase<TriangleStripTestInstance>	(testCtx, "triangle_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, verify rasterization result"));
6587 		nostippleTests->addChild(new BaseTestCase<TriangleFanTestInstance>		(testCtx, "triangle_fan",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN, verify rasterization result"));
6588 		nostippleTests->addChild(new WidenessTestCase<PointTestInstance>		(testCtx, "points",				"Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result",					PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, false, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
6589 
6590 		nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "strict_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6591 		nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "strict_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode, verify rasterization result",					PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6592 		nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "strict_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6593 		nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "strict_line_strip_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in strict mode with wide lines, verify rasterization result",	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6594 
6595 		nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "non_strict_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result",					PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6596 		nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "non_strict_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode, verify rasterization result",					PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6597 		nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "non_strict_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result",	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6598 		nostippleTests->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "non_strict_line_strip_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP in nonstrict mode with wide lines, verify rasterization result",	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT, true, VK_SAMPLE_COUNT_1_BIT, LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
6599 
6600 		for (int i = 0; i < 3; ++i) {
6601 
6602 			tcu::TestCaseGroup *g = i == 2 ? stippleDynamicTests : i == 1 ? stippleStaticTests : nostippleTests;
6603 
6604 			LineStipple stipple = (LineStipple)i;
6605 
6606 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "lines",						"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, i == 0 ? RESOLUTION_NPOT : 0));
6607 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "line_strip",					"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
6608 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "lines_wide",					"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
6609 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "line_strip_wide",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
6610 
6611 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "rectangular_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
6612 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "rectangular_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
6613 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "rectangular_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
6614 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "rectangular_line_strip_wide","Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
6615 
6616 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "bresenham_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
6617 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "bresenham_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
6618 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "bresenham_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
6619 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "bresenham_line_strip_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
6620 
6621 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "smooth_lines",				"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
6622 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "smooth_line_strip",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
6623 			g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "smooth_lines_wide",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
6624 			g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "smooth_line_strip_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, VK_SAMPLE_COUNT_1_BIT, stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
6625 		}
6626 	}
6627 
6628 	// .primitive_size
6629 	{
6630 		tcu::TestCaseGroup* const primitiveSize = new tcu::TestCaseGroup(testCtx, "primitive_size", "Primitive size");
6631 		rasterizationTests->addChild(primitiveSize);
6632 
6633 		// .points
6634 		{
6635 			tcu::TestCaseGroup* const points = new tcu::TestCaseGroup(testCtx, "points", "Point size");
6636 
6637 			static const struct TestCombinations
6638 			{
6639 				const deUint32	renderSize;
6640 				const float		pointSize;
6641 			} testCombinations[] =
6642 			{
6643 				{ 1024,		128.0f		},
6644 				{ 1024,		256.0f		},
6645 				{ 1024,		512.0f		},
6646 				{ 2048,		1024.0f		},
6647 				{ 4096,		2048.0f		},
6648 				{ 8192,		4096.0f		},
6649 				{ 9216,		8192.0f		},
6650 				{ 10240,	10000.0f	}
6651 			};
6652 
6653 			for (size_t testCombNdx = 0; testCombNdx < DE_LENGTH_OF_ARRAY(testCombinations); testCombNdx++)
6654 			{
6655 				std::string	testCaseName	= "point_size_" + de::toString(testCombinations[testCombNdx].pointSize);
6656 				deUint32	renderSize		= testCombinations[testCombNdx].renderSize;
6657 				float		pointSize		= testCombinations[testCombNdx].pointSize;
6658 
6659 				points->addChild(new PointSizeTestCase<PointSizeTestInstance>	(testCtx, testCaseName,	testCaseName, renderSize, pointSize));
6660 			}
6661 
6662 			primitiveSize->addChild(points);
6663 		}
6664 	}
6665 
6666 	// .fill_rules
6667 	{
6668 		tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(testCtx, "fill_rules", "Primitive fill rules");
6669 
6670 		rasterizationTests->addChild(fillRules);
6671 
6672 		fillRules->addChild(new FillRuleTestCase(testCtx,	"basic_quad",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_BASIC));
6673 		fillRules->addChild(new FillRuleTestCase(testCtx,	"basic_quad_reverse",	"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_REVERSED));
6674 		fillRules->addChild(new FillRuleTestCase(testCtx,	"clipped_full",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL));
6675 		fillRules->addChild(new FillRuleTestCase(testCtx,	"clipped_partly",		"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL));
6676 		fillRules->addChild(new FillRuleTestCase(testCtx,	"projected",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_PROJECTED));
6677 	}
6678 
6679 	// .culling
6680 	{
6681 		static const struct CullMode
6682 		{
6683 			VkCullModeFlags	mode;
6684 			const char*		prefix;
6685 		} cullModes[] =
6686 		{
6687 			{ VK_CULL_MODE_FRONT_BIT,				"front_"	},
6688 			{ VK_CULL_MODE_BACK_BIT,				"back_"		},
6689 			{ VK_CULL_MODE_FRONT_AND_BACK,			"both_"		},
6690 		};
6691 		static const struct PrimitiveType
6692 		{
6693 			VkPrimitiveTopology	type;
6694 			const char*			name;
6695 		} primitiveTypes[] =
6696 		{
6697 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,			"triangles"			},
6698 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,			"triangle_strip"	},
6699 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,			"triangle_fan"		},
6700 		};
6701 		static const struct FrontFaceOrder
6702 		{
6703 			VkFrontFace	mode;
6704 			const char*	postfix;
6705 		} frontOrders[] =
6706 		{
6707 			{ VK_FRONT_FACE_COUNTER_CLOCKWISE,	""			},
6708 			{ VK_FRONT_FACE_CLOCKWISE,			"_reverse"	},
6709 		};
6710 
6711 		static const struct PolygonMode
6712 		{
6713 			VkPolygonMode	mode;
6714 			const char*		name;
6715 		} polygonModes[] =
6716 		{
6717 			{ VK_POLYGON_MODE_FILL,		""		},
6718 			{ VK_POLYGON_MODE_LINE,		"_line"		},
6719 			{ VK_POLYGON_MODE_POINT,	"_point"	}
6720 		};
6721 
6722 		tcu::TestCaseGroup* const culling = new tcu::TestCaseGroup(testCtx, "culling", "Culling");
6723 
6724 		rasterizationTests->addChild(culling);
6725 
6726 		for (int cullModeNdx	= 0; cullModeNdx	< DE_LENGTH_OF_ARRAY(cullModes);		++cullModeNdx)
6727 		for (int primitiveNdx	= 0; primitiveNdx	< DE_LENGTH_OF_ARRAY(primitiveTypes);	++primitiveNdx)
6728 		for (int frontOrderNdx	= 0; frontOrderNdx	< DE_LENGTH_OF_ARRAY(frontOrders);		++frontOrderNdx)
6729 		for (int polygonModeNdx = 0; polygonModeNdx	< DE_LENGTH_OF_ARRAY(polygonModes);		++polygonModeNdx)
6730 		{
6731 			if (!(cullModes[cullModeNdx].mode == VK_CULL_MODE_FRONT_AND_BACK && polygonModes[polygonModeNdx].mode != VK_POLYGON_MODE_FILL))
6732 			{
6733 				const std::string name = std::string(cullModes[cullModeNdx].prefix) + primitiveTypes[primitiveNdx].name + frontOrders[frontOrderNdx].postfix + polygonModes[polygonModeNdx].name;
6734 				culling->addChild(new CullingTestCase(testCtx, name, "Test primitive culling.", cullModes[cullModeNdx].mode, primitiveTypes[primitiveNdx].type, frontOrders[frontOrderNdx].mode, polygonModes[polygonModeNdx].mode));
6735 			}
6736 		}
6737 	}
6738 
6739 	// .discard
6740 	{
6741 		static const struct PrimitiveType
6742 		{
6743 			VkPrimitiveTopology	type;
6744 			const char*			name;
6745 		} primitiveTypes[] =
6746 		{
6747 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	"triangle_list"		},
6748 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	"triangle_strip"	},
6749 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,	"triangle_fan"		},
6750 			{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		"line_list"			},
6751 			{ VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		"line_strip"		},
6752 			{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST,		"point_list"		}
6753 		};
6754 
6755 		static const struct queryPipeline
6756 		{
6757 			deBool			useQuery;
6758 			const char*		name;
6759 		} queryPipeline[] =
6760 		{
6761 			{ DE_FALSE,	"query_pipeline_false"	},
6762 			{ DE_TRUE,	"query_pipeline_true"	},
6763 		};
6764 
6765 		tcu::TestCaseGroup* const discard = new tcu::TestCaseGroup(testCtx, "discard", "Rasterizer discard");
6766 
6767 		for (int primitiveNdx = 0; primitiveNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveNdx)
6768 		{
6769 			tcu::TestCaseGroup* const primitive = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveNdx].name, "Rasterizer discard");
6770 
6771 			for (int useQueryNdx = 0; useQueryNdx < DE_LENGTH_OF_ARRAY(queryPipeline); useQueryNdx++)
6772 			{
6773 				const std::string name = std::string(queryPipeline[useQueryNdx].name);
6774 
6775 				primitive->addChild(new DiscardTestCase(testCtx, name, "Test primitive discarding.", primitiveTypes[primitiveNdx].type, queryPipeline[useQueryNdx].useQuery));
6776 			}
6777 
6778 			discard->addChild(primitive);
6779 		}
6780 
6781 		rasterizationTests->addChild(discard);
6782 	}
6783 
6784 	// .conservative
6785 	{
6786 		typedef struct
6787 		{
6788 			float			size;
6789 			const char*		name;
6790 		} overestimateSizes;
6791 
6792 		const overestimateSizes overestimateNormalSizes[]	=
6793 		{
6794 			{ 0.00f,			"0_00" },
6795 			{ 0.25f,			"0_25" },
6796 			{ 0.50f,			"0_50" },
6797 			{ 0.75f,			"0_75" },
6798 			{ 1.00f,			"1_00" },
6799 			{ 2.00f,			"2_00" },
6800 			{ 4.00f,			"4_00" },
6801 			{ -TCU_INFINITY,	"min" },
6802 			{ TCU_INFINITY,		"max" },
6803 		};
6804 		const overestimateSizes overestimateDegenerate[]	=
6805 		{
6806 			{ 0.00f,			"0_00" },
6807 			{ 0.25f,			"0_25" },
6808 			{ -TCU_INFINITY,	"min" },
6809 			{ TCU_INFINITY,		"max" },
6810 		};
6811 		const overestimateSizes underestimateLineWidths[]	=
6812 		{
6813 			{ 0.50f,			"0_50" },
6814 			{ 1.00f,			"1_00" },
6815 			{ 1.50f,			"1_50" },
6816 		};
6817 		const overestimateSizes underestimatePointSizes[]	=
6818 		{
6819 			{ 1.00f,			"1_00" },
6820 			{ 1.50f,			"1_50" },
6821 			{ 2.00f,			"2_00" },
6822 			{ 3.00f,			"3_00" },
6823 			{ 4.00f,			"4_00" },
6824 			{ 8.00f,			"8_00" },
6825 		};
6826 		const struct PrimitiveType
6827 		{
6828 			VkPrimitiveTopology	type;
6829 			const char*			name;
6830 		}
6831 		primitiveTypes[] =
6832 		{
6833 			{ VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	"triangles"		},
6834 			{ VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		"lines"			},
6835 			{ VK_PRIMITIVE_TOPOLOGY_POINT_LIST,		"points"		}
6836 		};
6837 		const VkSampleCountFlagBits samples[] =
6838 		{
6839 			VK_SAMPLE_COUNT_1_BIT,
6840 			VK_SAMPLE_COUNT_2_BIT,
6841 			VK_SAMPLE_COUNT_4_BIT,
6842 			VK_SAMPLE_COUNT_8_BIT,
6843 			VK_SAMPLE_COUNT_16_BIT,
6844 			VK_SAMPLE_COUNT_32_BIT,
6845 			VK_SAMPLE_COUNT_64_BIT
6846 		};
6847 
6848 		tcu::TestCaseGroup* const conservative = new tcu::TestCaseGroup(testCtx, "conservative", "Conservative rasterization tests");
6849 
6850 		rasterizationTests->addChild(conservative);
6851 
6852 		{
6853 			tcu::TestCaseGroup* const overestimate = new tcu::TestCaseGroup(testCtx, "overestimate", "Overestimate tests");
6854 
6855 			conservative->addChild(overestimate);
6856 
6857 			for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
6858 			{
6859 				const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
6860 
6861 				tcu::TestCaseGroup* const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str(), "Samples tests");
6862 
6863 				overestimate->addChild(samplesGroup);
6864 
6865 				for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
6866 				{
6867 					tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name, "Primitive tests");
6868 
6869 					samplesGroup->addChild(primitiveGroup);
6870 
6871 					{
6872 						tcu::TestCaseGroup* const normal = new tcu::TestCaseGroup(testCtx, "normal", "Normal conservative rasterization tests");
6873 
6874 						primitiveGroup->addChild(normal);
6875 
6876 						for (int overestimateSizesNdx = 0; overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateNormalSizes); ++overestimateSizesNdx)
6877 						{
6878 							const ConservativeTestConfig	config	=
6879 							{
6880 								VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT,	//  VkConservativeRasterizationModeEXT	conservativeRasterizationMode;
6881 								overestimateNormalSizes[overestimateSizesNdx].size,		//  float								extraOverestimationSize;
6882 								primitiveTypes[primitiveTypeNdx].type,					//  VkPrimitiveTopology					primitiveTopology;
6883 								false,													//  bool								degeneratePrimitives;
6884 								1.0f,													//  float								lineWidth;
6885 								RESOLUTION_POT,											//  deUint32							resolution;
6886 							};
6887 
6888 							if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
6889 								normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>	(testCtx,
6890 																											 overestimateNormalSizes[overestimateSizesNdx].name,
6891 																											 "Overestimate test, verify rasterization result",
6892 																											 config,
6893 																											 samples[samplesNdx]));
6894 
6895 							if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
6896 								normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance>		(testCtx,
6897 																											 overestimateNormalSizes[overestimateSizesNdx].name,
6898 																											 "Overestimate test, verify rasterization result",
6899 																											 config,
6900 																											 samples[samplesNdx]));
6901 
6902 							if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
6903 								normal->addChild(new ConservativeTestCase<ConservativePointTestInstance>	(testCtx,
6904 																											 overestimateNormalSizes[overestimateSizesNdx].name,
6905 																											 "Overestimate test, verify rasterization result",
6906 																											 config,
6907 																											 samples[samplesNdx]));
6908 						}
6909 					}
6910 
6911 					{
6912 						tcu::TestCaseGroup* const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate", "Degenerate primitives conservative rasterization tests");
6913 
6914 						primitiveGroup->addChild(degenerate);
6915 
6916 						for (int overestimateSizesNdx = 0; overestimateSizesNdx < DE_LENGTH_OF_ARRAY(overestimateDegenerate); ++overestimateSizesNdx)
6917 						{
6918 							const ConservativeTestConfig	config	=
6919 							{
6920 								VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT,	//  VkConservativeRasterizationModeEXT	conservativeRasterizationMode;
6921 								overestimateDegenerate[overestimateSizesNdx].size,		//  float								extraOverestimationSize;
6922 								primitiveTypes[primitiveTypeNdx].type,					//  VkPrimitiveTopology					primitiveTopology;
6923 								true,													//  bool								degeneratePrimitives;
6924 								1.0f,													//  float								lineWidth;
6925 								64u,													//  deUint32							resolution;
6926 							};
6927 
6928 							if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
6929 								degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>	(testCtx,
6930 																												 overestimateDegenerate[overestimateSizesNdx].name,
6931 																												 "Overestimate triangle test, verify rasterization result",
6932 																												 config,
6933 																												 samples[samplesNdx]));
6934 
6935 							if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
6936 								degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance>		(testCtx,
6937 																												 overestimateDegenerate[overestimateSizesNdx].name,
6938 																												 "Overestimate line test, verify rasterization result",
6939 																												 config,
6940 																												 samples[samplesNdx]));
6941 						}
6942 					}
6943 				}
6944 			}
6945 		}
6946 
6947 		{
6948 			tcu::TestCaseGroup* const underestimate = new tcu::TestCaseGroup(testCtx, "underestimate", "Underestimate tests");
6949 
6950 			conservative->addChild(underestimate);
6951 
6952 			for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); ++samplesNdx)
6953 			{
6954 				const std::string samplesGroupName = "samples_" + de::toString(samples[samplesNdx]);
6955 
6956 				tcu::TestCaseGroup* const samplesGroup = new tcu::TestCaseGroup(testCtx, samplesGroupName.c_str(), "Samples tests");
6957 
6958 				underestimate->addChild(samplesGroup);
6959 
6960 				for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
6961 				{
6962 					tcu::TestCaseGroup* const primitiveGroup = new tcu::TestCaseGroup(testCtx, primitiveTypes[primitiveTypeNdx].name, "Primitive tests");
6963 
6964 					samplesGroup->addChild(primitiveGroup);
6965 
6966 					{
6967 						tcu::TestCaseGroup* const normal = new tcu::TestCaseGroup(testCtx, "normal", "Normal conservative rasterization tests");
6968 
6969 						primitiveGroup->addChild(normal);
6970 
6971 						ConservativeTestConfig	config	=
6972 						{
6973 							VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT,	//  VkConservativeRasterizationModeEXT	conservativeRasterizationMode;
6974 							0.0f,													//  float								extraOverestimationSize;
6975 							primitiveTypes[primitiveTypeNdx].type,					//  VkPrimitiveTopology					primitiveTopology;
6976 							false,													//  bool								degeneratePrimitives;
6977 							1.0f,													//  float								lineWidth;
6978 							64u,													//  deUint32							resolution;
6979 						};
6980 
6981 						if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
6982 							normal->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>	(testCtx,
6983 																										 "test",
6984 																										 "Underestimate test, verify rasterization result",
6985 																										 config,
6986 																										 samples[samplesNdx]));
6987 
6988 						if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
6989 						{
6990 							for (int underestimateWidthNdx = 0; underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths); ++underestimateWidthNdx)
6991 							{
6992 								config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
6993 								normal->addChild(new ConservativeTestCase<ConservativeLineTestInstance>		(testCtx,
6994 																											 underestimateLineWidths[underestimateWidthNdx].name,
6995 																											 "Underestimate test, verify rasterization result",
6996 																											 config,
6997 																											 samples[samplesNdx]));
6998 							}
6999 						}
7000 
7001 						if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
7002 						{
7003 							for (int underestimatePointSizeNdx = 0; underestimatePointSizeNdx < DE_LENGTH_OF_ARRAY(underestimatePointSizes); ++underestimatePointSizeNdx)
7004 							{
7005 								config.lineWidth = underestimatePointSizes[underestimatePointSizeNdx].size;
7006 								normal->addChild(new ConservativeTestCase<ConservativePointTestInstance>	(testCtx,
7007 																											 underestimatePointSizes[underestimatePointSizeNdx].name,
7008 																											 "Underestimate test, verify rasterization result",
7009 																											 config,
7010 																											 samples[samplesNdx]));
7011 							}
7012 						}
7013 					}
7014 
7015 					{
7016 						tcu::TestCaseGroup* const degenerate = new tcu::TestCaseGroup(testCtx, "degenerate", "Degenerate primitives conservative rasterization tests");
7017 
7018 						primitiveGroup->addChild(degenerate);
7019 
7020 						ConservativeTestConfig	config	=
7021 						{
7022 							VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT,	//  VkConservativeRasterizationModeEXT	conservativeRasterizationMode;
7023 							0.0f,													//  float								extraOverestimationSize;
7024 							primitiveTypes[primitiveTypeNdx].type,					//  VkPrimitiveTopology					primitiveTopology;
7025 							true,													//  bool								degeneratePrimitives;
7026 							1.0f,													//  float								lineWidth;
7027 							64u,													//  deUint32							resolution;
7028 						};
7029 
7030 						if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
7031 							degenerate->addChild(new ConservativeTestCase<ConservativeTraingleTestInstance>	(testCtx,
7032 																											 "test",
7033 																											 "Underestimate triangle test, verify rasterization result",
7034 																											 config,
7035 																											 samples[samplesNdx]));
7036 
7037 						if (primitiveTypes[primitiveTypeNdx].type == VK_PRIMITIVE_TOPOLOGY_LINE_LIST)
7038 						{
7039 							for (int underestimateWidthNdx = 0; underestimateWidthNdx < DE_LENGTH_OF_ARRAY(underestimateLineWidths); ++underestimateWidthNdx)
7040 							{
7041 								config.lineWidth = underestimateLineWidths[underestimateWidthNdx].size;
7042 								degenerate->addChild(new ConservativeTestCase<ConservativeLineTestInstance>		(testCtx,
7043 																												 underestimateLineWidths[underestimateWidthNdx].name,
7044 																												 "Underestimate line test, verify rasterization result",
7045 																												 config,
7046 																												 samples[samplesNdx]));
7047 							}
7048 						}
7049 					}
7050 				}
7051 			}
7052 		}
7053 	}
7054 
7055 	// .interpolation
7056 	{
7057 		tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(testCtx, "interpolation", "Test interpolation");
7058 
7059 		rasterizationTests->addChild(interpolation);
7060 
7061 		// .basic
7062 		{
7063 			tcu::TestCaseGroup* const basic = new tcu::TestCaseGroup(testCtx, "basic", "Non-projective interpolation");
7064 
7065 			interpolation->addChild(basic);
7066 
7067 			basic->addChild(new TriangleInterpolationTestCase		(testCtx, "triangles",		"Verify triangle interpolation",		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	INTERPOLATIONFLAGS_NONE));
7068 			basic->addChild(new TriangleInterpolationTestCase		(testCtx, "triangle_strip",	"Verify triangle strip interpolation",	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_NONE));
7069 			basic->addChild(new TriangleInterpolationTestCase		(testCtx, "triangle_fan",	"Verify triangle fan interpolation",	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,		INTERPOLATIONFLAGS_NONE));
7070 			basic->addChild(new LineInterpolationTestCase			(testCtx, "lines",			"Verify line interpolation",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7071 			basic->addChild(new LineInterpolationTestCase			(testCtx, "line_strip",		"Verify line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7072 			basic->addChild(new LineInterpolationTestCase			(testCtx, "lines_wide",		"Verify wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7073 			basic->addChild(new LineInterpolationTestCase			(testCtx, "line_strip_wide","Verify wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7074 
7075 			basic->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines",			"Verify strict line interpolation",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7076 			basic->addChild(new LineInterpolationTestCase			(testCtx, "strict_line_strip",		"Verify strict line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7077 			basic->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines_wide",		"Verify strict wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7078 			basic->addChild(new LineInterpolationTestCase			(testCtx, "strict_line_strip_wide",	"Verify strict wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7079 
7080 			basic->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines",			"Verify non-strict line interpolation",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7081 			basic->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_line_strip",		"Verify non-strict line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7082 			basic->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines_wide",		"Verify non-strict wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7083 			basic->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_line_strip_wide",	"Verify non-strict wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,	INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7084 		}
7085 
7086 		// .projected
7087 		{
7088 			tcu::TestCaseGroup* const projected = new tcu::TestCaseGroup(testCtx, "projected", "Projective interpolation");
7089 
7090 			interpolation->addChild(projected);
7091 
7092 			projected->addChild(new TriangleInterpolationTestCase	(testCtx, "triangles",		"Verify triangle interpolation",		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	INTERPOLATIONFLAGS_PROJECTED));
7093 			projected->addChild(new TriangleInterpolationTestCase	(testCtx, "triangle_strip",	"Verify triangle strip interpolation",	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_PROJECTED));
7094 			projected->addChild(new TriangleInterpolationTestCase	(testCtx, "triangle_fan",	"Verify triangle fan interpolation",	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,		INTERPOLATIONFLAGS_PROJECTED));
7095 			projected->addChild(new LineInterpolationTestCase		(testCtx, "lines",			"Verify line interpolation",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7096 			projected->addChild(new LineInterpolationTestCase		(testCtx, "line_strip",		"Verify line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7097 			projected->addChild(new LineInterpolationTestCase		(testCtx, "lines_wide",		"Verify wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7098 			projected->addChild(new LineInterpolationTestCase		(testCtx, "line_strip_wide","Verify wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7099 
7100 			projected->addChild(new LineInterpolationTestCase		(testCtx, "strict_lines",			"Verify strict line interpolation",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7101 			projected->addChild(new LineInterpolationTestCase		(testCtx, "strict_line_strip",		"Verify strict line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7102 			projected->addChild(new LineInterpolationTestCase		(testCtx, "strict_lines_wide",		"Verify strict wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7103 			projected->addChild(new LineInterpolationTestCase		(testCtx, "strict_line_strip_wide",	"Verify strict wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7104 
7105 			projected->addChild(new LineInterpolationTestCase		(testCtx, "non_strict_lines",			"Verify non-strict line interpolation",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7106 			projected->addChild(new LineInterpolationTestCase		(testCtx, "non_strict_line_strip",		"Verify non-strict line strip interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7107 			projected->addChild(new LineInterpolationTestCase		(testCtx, "non_strict_lines_wide",		"Verify non-strict wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7108 			projected->addChild(new LineInterpolationTestCase		(testCtx, "non_strict_line_strip_wide",	"Verify non-strict wide line strip interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_PROJECTED,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7109 		}
7110 	}
7111 
7112 	// .flatshading
7113 	{
7114 		tcu::TestCaseGroup* const flatshading = new tcu::TestCaseGroup(testCtx, "flatshading", "Test flatshading");
7115 
7116 		rasterizationTests->addChild(flatshading);
7117 
7118 		flatshading->addChild(new TriangleInterpolationTestCase		(testCtx, "triangles",		"Verify triangle flatshading",			VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	INTERPOLATIONFLAGS_FLATSHADE));
7119 		flatshading->addChild(new TriangleInterpolationTestCase		(testCtx, "triangle_strip",	"Verify triangle strip flatshading",	VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,	INTERPOLATIONFLAGS_FLATSHADE));
7120 		flatshading->addChild(new TriangleInterpolationTestCase		(testCtx, "triangle_fan",	"Verify triangle fan flatshading",		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,		INTERPOLATIONFLAGS_FLATSHADE));
7121 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "lines",			"Verify line flatshading",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7122 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "line_strip",		"Verify line strip flatshading",		VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE));
7123 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "lines_wide",		"Verify wide line flatshading",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7124 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "line_strip_wide","Verify wide line strip flatshading",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE));
7125 
7126 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines",			"Verify strict line flatshading",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7127 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "strict_line_strip",		"Verify strict line strip flatshading",			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT));
7128 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines_wide",		"Verify strict wide line flatshading",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7129 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "strict_line_strip_wide",	"Verify strict wide line strip flatshading",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT));
7130 
7131 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines",			"Verify non-strict line flatshading",				VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7132 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_line_strip",		"Verify non-strict line strip flatshading",			VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT));
7133 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines_wide",		"Verify non-strict wide line flatshading",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7134 		flatshading->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_line_strip_wide",	"Verify non-strict wide line strip flatshading",	VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,		INTERPOLATIONFLAGS_FLATSHADE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT));
7135 	}
7136 
7137 	const VkSampleCountFlagBits samples[] =
7138 	{
7139 		VK_SAMPLE_COUNT_2_BIT,
7140 		VK_SAMPLE_COUNT_4_BIT,
7141 		VK_SAMPLE_COUNT_8_BIT,
7142 		VK_SAMPLE_COUNT_16_BIT,
7143 		VK_SAMPLE_COUNT_32_BIT,
7144 		VK_SAMPLE_COUNT_64_BIT
7145 	};
7146 
7147 	for (int samplesNdx = 0; samplesNdx < DE_LENGTH_OF_ARRAY(samples); samplesNdx++)
7148 	{
7149 		std::ostringstream caseName;
7150 
7151 		caseName << "_multisample_" << (2 << samplesNdx) << "_bit";
7152 
7153 		// .primitives
7154 		{
7155 			tcu::TestCaseGroup* const primitives = new tcu::TestCaseGroup(testCtx, ("primitives" + caseName.str()).c_str(), "Primitive rasterization");
7156 
7157 			rasterizationTests->addChild(primitives);
7158 
7159 			tcu::TestCaseGroup* const nostippleTests = new tcu::TestCaseGroup(testCtx, "no_stipple", "No stipple");
7160 			tcu::TestCaseGroup* const stippleStaticTests = new tcu::TestCaseGroup(testCtx, "static_stipple", "Line stipple static");
7161 			tcu::TestCaseGroup* const stippleDynamicTests = new tcu::TestCaseGroup(testCtx, "dynamic_stipple", "Line stipple dynamic");
7162 
7163 			primitives->addChild(nostippleTests);
7164 			primitives->addChild(stippleStaticTests);
7165 			primitives->addChild(stippleDynamicTests);
7166 
7167 			nostippleTests->addChild(new BaseTestCase<TrianglesTestInstance>		(testCtx, "triangles",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, verify rasterization result",					samples[samplesNdx]));
7168 			nostippleTests->addChild(new WidenessTestCase<PointTestInstance>		(testCtx, "points",				"Render primitives as VK_PRIMITIVE_TOPOLOGY_POINT_LIST, verify rasterization result",						PRIMITIVEWIDENESS_WIDE,	PRIMITIVESTRICTNESS_IGNORE,	false, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
7169 
7170 			nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "strict_lines",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT,	true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
7171 			nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "strict_lines_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in strict mode with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT,	true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
7172 
7173 			nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "non_strict_lines",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT,	true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
7174 			nostippleTests->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "non_strict_lines_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST in nonstrict mode with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT,	true, samples[samplesNdx], LINESTIPPLE_DISABLED, VK_LINE_RASTERIZATION_MODE_EXT_LAST));
7175 
7176 			for (int i = 0; i < 3; ++i) {
7177 
7178 				tcu::TestCaseGroup *g = i == 2 ? stippleDynamicTests : i == 1 ? stippleStaticTests : nostippleTests;
7179 
7180 				LineStipple stipple = (LineStipple)i;
7181 
7182 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "lines",						"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT, i == 0 ? RESOLUTION_NPOT : 0));
7183 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "line_strip",					"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
7184 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "lines_wide",					"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
7185 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "line_strip_wide",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT));
7186 
7187 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "rectangular_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
7188 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "rectangular_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
7189 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "rectangular_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
7190 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "rectangular_line_strip_wide","Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT));
7191 
7192 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "bresenham_lines",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
7193 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "bresenham_line_strip",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
7194 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "bresenham_lines_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
7195 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "bresenham_line_strip_wide",	"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT));
7196 
7197 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "smooth_lines",				"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
7198 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "smooth_line_strip",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP, verify rasterization result",						PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
7199 				g->addChild(new WidenessTestCase<LinesTestInstance>		(testCtx, "smooth_lines_wide",			"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_LIST with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
7200 				g->addChild(new WidenessTestCase<LineStripTestInstance>	(testCtx, "smooth_line_strip_wide",		"Render primitives as VK_PRIMITIVE_TOPOLOGY_LINE_STRIP with wide lines, verify rasterization result",		PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE, true, samples[samplesNdx], stipple, VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT));
7201 			}
7202 		}
7203 
7204 		// .fill_rules
7205 		{
7206 			tcu::TestCaseGroup* const fillRules = new tcu::TestCaseGroup(testCtx, ("fill_rules" + caseName.str()).c_str(), "Primitive fill rules");
7207 
7208 			rasterizationTests->addChild(fillRules);
7209 
7210 			fillRules->addChild(new FillRuleTestCase(testCtx,	"basic_quad",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_BASIC,			samples[samplesNdx]));
7211 			fillRules->addChild(new FillRuleTestCase(testCtx,	"basic_quad_reverse",	"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_REVERSED,		samples[samplesNdx]));
7212 			fillRules->addChild(new FillRuleTestCase(testCtx,	"clipped_full",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_CLIPPED_FULL,	samples[samplesNdx]));
7213 			fillRules->addChild(new FillRuleTestCase(testCtx,	"clipped_partly",		"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_CLIPPED_PARTIAL,	samples[samplesNdx]));
7214 			fillRules->addChild(new FillRuleTestCase(testCtx,	"projected",			"Verify fill rules",	FillRuleTestInstance::FILLRULECASE_PROJECTED,		samples[samplesNdx]));
7215 		}
7216 
7217 		// .interpolation
7218 		{
7219 			tcu::TestCaseGroup* const interpolation = new tcu::TestCaseGroup(testCtx, ("interpolation" + caseName.str()).c_str(), "Test interpolation");
7220 
7221 			rasterizationTests->addChild(interpolation);
7222 
7223 			interpolation->addChild(new TriangleInterpolationTestCase		(testCtx, "triangles",		"Verify triangle interpolation",		VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	INTERPOLATIONFLAGS_NONE,															samples[samplesNdx]));
7224 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "lines",			"Verify line interpolation",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_IGNORE,	samples[samplesNdx]));
7225 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "lines_wide",		"Verify wide line interpolation",		VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_IGNORE,	samples[samplesNdx]));
7226 
7227 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines",			"Verify strict line interpolation",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_STRICT,	samples[samplesNdx]));
7228 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "strict_lines_wide",		"Verify strict wide line interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_STRICT,	samples[samplesNdx]));
7229 
7230 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines",			"Verify non-strict line interpolation",			VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_NARROW,	PRIMITIVESTRICTNESS_NONSTRICT,	samples[samplesNdx]));
7231 			interpolation->addChild(new LineInterpolationTestCase			(testCtx, "non_strict_lines_wide",		"Verify non-strict wide line interpolation",	VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		INTERPOLATIONFLAGS_NONE,	PRIMITIVEWIDENESS_WIDE,		PRIMITIVESTRICTNESS_NONSTRICT,	samples[samplesNdx]));
7232 		}
7233 	}
7234 
7235 	// .provoking_vertex
7236 	{
7237 		tcu::TestCaseGroup* const	provokingVertex		= new tcu::TestCaseGroup(testCtx, "provoking_vertex", "Test provoking vertex");
7238 
7239 		struct Params { const char *type; bool requireGeometryShader; };
7240 		Params	primitiveTypes[]	=
7241 		{
7242 			{ "triangle_list", false },
7243 			{ "triangle_list_with_adjacency", true },
7244 			{ "triangle_strip", false },
7245 			{ "triangle_strip_with_adjacency", true },
7246 			{ "triangle_fan", false },
7247 			{ "line_list", false },
7248 			{ "line_list_with_adjacency", true },
7249 			{ "line_strip", false },
7250 			{ "line_strip_with_adjacency", true },
7251 		};
7252 
7253 		rasterizationTests->addChild(provokingVertex);
7254 
7255 		for (deUint32 primitiveTypeIdx = 0; primitiveTypeIdx < DE_LENGTH_OF_ARRAY(primitiveTypes); primitiveTypeIdx++)
7256 		{
7257 			Params &					params		= primitiveTypes[primitiveTypeIdx];
7258 			const std::string			file		= std::string(params.type) + ".amber";
7259 
7260 			cts_amber::AmberTestCase*	testCase	= cts_amber::createAmberTestCase(testCtx, params.type, "", "provoking_vertex", file);
7261 			if (params.requireGeometryShader)
7262 			{
7263 				testCase->addRequirement("Features.geometryShader");
7264 			}
7265 			provokingVertex->addChild(testCase);
7266 		}
7267 	}
7268 
7269 	// .line_continuity
7270 	{
7271 		tcu::TestCaseGroup* const	lineContinuity	= new tcu::TestCaseGroup(testCtx, "line_continuity", "Test line continuity");
7272 		static const char			dataDir[]		= "rasterization/line_continuity";
7273 
7274 		struct Case
7275 		{
7276 			std::string	name;
7277 			std::string	desc;
7278 			bool		requireFillModeNonSolid;
7279 		};
7280 
7281 		static const Case cases[] =
7282 		{
7283 			{	"line-strip",			"Test line strip drawing produces continuous lines",	false	},
7284 			{	"polygon-mode-lines",	"Test triangles drawn with lines are continuous",		true	}
7285 		};
7286 
7287 		rasterizationTests->addChild(lineContinuity);
7288 
7289 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
7290 		{
7291 			const std::string			fileName	= cases[i].name + ".amber";
7292 			cts_amber::AmberTestCase*	testCase	= cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), cases[i].desc.c_str(), dataDir, fileName);
7293 
7294 			if (cases[i].requireFillModeNonSolid)
7295 			{
7296 				testCase->addRequirement("Features.fillModeNonSolid");
7297 			}
7298 
7299 			lineContinuity->addChild(testCase);
7300 		}
7301 	}
7302 
7303 	// .depth bias
7304 	{
7305 		tcu::TestCaseGroup* const	depthBias	= new tcu::TestCaseGroup(testCtx, "depth_bias", "Test depth bias");
7306 		static const char			dataDir[]	= "rasterization/depth_bias";
7307 
7308 		static const struct
7309 		{
7310 			std::string name;
7311 			vk::VkFormat format;
7312 			std::string description;
7313 		} cases [] =
7314 		{
7315 			{"d16_unorm",	vk::VK_FORMAT_D16_UNORM,			"Test depth bias with format D16_UNORM"},
7316 			{"d32_sfloat",	vk::VK_FORMAT_D32_SFLOAT,			"Test depth bias with format D32_SFLOAT"},
7317 			{"d24_unorm",	vk::VK_FORMAT_D24_UNORM_S8_UINT,	"Test depth bias with format D24_UNORM_S8_UINT"}
7318 		};
7319 
7320 		for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
7321 		{
7322 			const VkImageCreateInfo vkImageCreateInfo = {
7323 				VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,			// sType
7324 				nullptr,										// pNext
7325 				0,												// flags
7326 				VK_IMAGE_TYPE_2D,								// imageType
7327 				cases[i].format,								// format
7328 				{250, 250, 1},									// extent
7329 				1,												// mipLevels
7330 				1,												// arrayLayers
7331 				VK_SAMPLE_COUNT_1_BIT,							// samples
7332 				VK_IMAGE_TILING_OPTIMAL,						// tiling
7333 				VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,	// usage
7334 				VK_SHARING_MODE_EXCLUSIVE,						// sharingMode
7335 				0,												// queueFamilyIndexCount
7336 				nullptr,										// pQueueFamilyIndices
7337 				VK_IMAGE_LAYOUT_UNDEFINED,						// initialLayout
7338 			};
7339 
7340 			std::vector<std::string>		requirements = std::vector<std::string>(0);
7341 			std::vector<VkImageCreateInfo>	imageRequirements;
7342 			imageRequirements.push_back(vkImageCreateInfo);
7343 			const std::string			fileName	= cases[i].name + ".amber";
7344 			cts_amber::AmberTestCase*	testCase	= cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), cases[i].description.c_str(), dataDir, fileName, requirements, imageRequirements);
7345 
7346 			depthBias->addChild(testCase);
7347 		}
7348 
7349 		rasterizationTests->addChild(depthBias);
7350 	}
7351 
7352 	// Fragment shader side effects.
7353 	{
7354 		rasterizationTests->addChild(createFragSideEffectsTests(testCtx));
7355 	}
7356 }
7357 
7358 } // anonymous
7359 
createTests(tcu::TestContext & testCtx)7360 tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
7361 {
7362 	return createTestGroup(testCtx, "rasterization", "Rasterization Tests", createRasterizationTests);
7363 }
7364 
7365 } // rasterization
7366 } // vkt
7367