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