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