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