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