• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2014 The Android Open Source Project
6  * Copyright (c) 2016 The Khronos Group Inc.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Tessellation Winding Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationWindingTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 #include "vktTestGroupUtil.hpp"
29 
30 #include "tcuTestLog.hpp"
31 #include "tcuRGBA.hpp"
32 #include "tcuMaybe.hpp"
33 
34 #include "vkDefs.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkQueryUtil.hpp"
37 #include "vkBuilderUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkTypeUtil.hpp"
40 #include "vkStrUtil.hpp"
41 #include "vkCmdUtil.hpp"
42 #include "vkObjUtil.hpp"
43 #include "vkBufferWithMemory.hpp"
44 #include "vkImageWithMemory.hpp"
45 
46 #include "deUniquePtr.hpp"
47 
48 namespace vkt
49 {
50 namespace tessellation
51 {
52 
53 using namespace vk;
54 
55 namespace
56 {
57 
getCaseName(const TessPrimitiveType primitiveType,const ShaderLanguage shaderLanguage,const Winding winding,bool yFlip)58 std::string getCaseName (const TessPrimitiveType primitiveType, const ShaderLanguage shaderLanguage, const Winding winding, bool yFlip)
59 {
60 	std::ostringstream str;
61 	str << getShaderLanguageName(shaderLanguage) << "_" << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getWindingShaderName(winding);
62 	if (yFlip)
63 		str << "_yflip";
64 	return str.str();
65 }
66 
mapFrontFace(const Winding winding)67 inline VkFrontFace mapFrontFace (const Winding winding)
68 {
69 	switch (winding)
70 	{
71 		case WINDING_CCW:	return VK_FRONT_FACE_COUNTER_CLOCKWISE;
72 		case WINDING_CW:	return VK_FRONT_FACE_CLOCKWISE;
73 		default:
74 			DE_ASSERT(false);
75 			return VK_FRONT_FACE_LAST;
76 	}
77 }
78 
79 //! Returns true when the image passes the verification.
verifyResultImage(tcu::TestLog & log,const tcu::ConstPixelBufferAccess image,const TessPrimitiveType primitiveType,const VkTessellationDomainOrigin domainOrigin,const Winding winding,bool yFlip,const Winding frontFaceWinding)80 bool verifyResultImage (tcu::TestLog&						log,
81 						const tcu::ConstPixelBufferAccess	image,
82 						const TessPrimitiveType				primitiveType,
83 						const VkTessellationDomainOrigin	domainOrigin,
84 						const Winding						winding,
85 						bool								yFlip,
86 						const Winding						frontFaceWinding)
87 {
88 	const bool			expectVisiblePrimitive	= ((frontFaceWinding == winding) == (domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)) != yFlip;
89 
90 	const int			totalNumPixels			= image.getWidth()*image.getHeight();
91 
92 	const tcu::Vec4		white					 = tcu::RGBA::white().toVec();
93 	const tcu::Vec4		red						 = tcu::RGBA::red().toVec();
94 
95 	int					numWhitePixels			= 0;
96 	int					numRedPixels			= 0;
97 
98 	// Count red and white pixels
99 	for (int y = 0; y < image.getHeight();	y++)
100 	for (int x = 0; x < image.getWidth();	x++)
101 	{
102 		numWhitePixels += image.getPixel(x, y) == white ? 1 : 0;
103 		numRedPixels   += image.getPixel(x, y) == red   ? 1 : 0;
104 	}
105 
106 	DE_ASSERT(numWhitePixels + numRedPixels <= totalNumPixels);
107 
108 	log << tcu::TestLog::Message << "Note: got " << numWhitePixels << " white and " << numRedPixels << " red pixels" << tcu::TestLog::EndMessage;
109 
110 	{
111 		const int otherPixels = totalNumPixels - numWhitePixels - numRedPixels;
112 		if (otherPixels > 0)
113 		{
114 			log << tcu::TestLog::Message
115 				<< "Failure: Got " << otherPixels << " other than white or red pixels"
116 				<< tcu::TestLog::EndMessage;
117 			return false;
118 		}
119 	}
120 
121 	if (expectVisiblePrimitive)
122 	{
123 		if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
124 		{
125 			const int	badPixelTolerance	= (primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 5*de::max(image.getWidth(), image.getHeight()) : 0);
126 
127 			if (de::abs(numWhitePixels - totalNumPixels/2) > badPixelTolerance)
128 			{
129 				log << tcu::TestLog::Message << "Failure: wrong number of white pixels; expected approximately " << totalNumPixels/2 << tcu::TestLog::EndMessage;
130 				return false;
131 			}
132 
133 			// Check number of filled pixels (from left) in top and bottom rows to
134 			// determine if triangle is in right orientation.
135 			{
136 				const tcu::IVec2	expectedStart	(0, 1);
137 				const tcu::IVec2	expectedEnd		(image.getWidth()-1, image.getWidth());
138 				const tcu::IVec2	expectedTop		= yFlip ? expectedStart : expectedEnd;
139 				const tcu::IVec2	expectedBottom	= yFlip ? expectedEnd : expectedStart;
140 				int					numTopFilled	= 0;
141 				int					numBottomFilled	= 0;
142 
143 				for (int x = 0; x < image.getWidth(); ++x)
144 				{
145 					if (image.getPixel(x, 0) == white)
146 						numTopFilled += 1;
147 					else
148 						break;
149 				}
150 
151 				for (int x = 0; x < image.getWidth(); ++x)
152 				{
153 					if (image.getPixel(x, image.getHeight()-1) == white)
154 						numBottomFilled += 1;
155 					else
156 						break;
157 				}
158 
159 				if (!de::inBounds(numTopFilled, expectedTop[0], expectedTop[1]) ||
160 					!de::inBounds(numBottomFilled, expectedBottom[0], expectedBottom[1]))
161 				{
162 					log << tcu::TestLog::Message << "Failure: triangle orientation is incorrect" << tcu::TestLog::EndMessage;
163 					return false;
164 				}
165 			}
166 
167 		}
168 		else if (primitiveType == TESSPRIMITIVETYPE_QUADS)
169 		{
170 			if (numWhitePixels != totalNumPixels)
171 			{
172 				log << tcu::TestLog::Message << "Failure: expected only white pixels (full-viewport quad)" << tcu::TestLog::EndMessage;
173 				return false;
174 			}
175 		}
176 		else
177 			DE_ASSERT(false);
178 	}
179 	else
180 	{
181 		if (numWhitePixels != 0)
182 		{
183 			log << tcu::TestLog::Message << "Failure: expected only red pixels (everything culled)" << tcu::TestLog::EndMessage;
184 			return false;
185 		}
186 	}
187 
188 	return true;
189 }
190 
191 typedef tcu::Maybe<VkTessellationDomainOrigin> MaybeDomainOrigin;
192 
193 class WindingTest : public TestCase
194 {
195 public:
196 								WindingTest		(tcu::TestContext&			testCtx,
197 												 const TessPrimitiveType	primitiveType,
198 												 const MaybeDomainOrigin&	domainOrigin,
199 												 const ShaderLanguage		shaderLanguage,
200 												 const Winding				winding,
201 												 bool						yFlip);
202 
203 	void						initPrograms	(SourceCollections&			programCollection) const;
204 	TestInstance*				createInstance	(Context&					context) const;
205 
206 private:
207 	const TessPrimitiveType		m_primitiveType;
208 	const MaybeDomainOrigin		m_domainOrigin;
209 	const ShaderLanguage		m_shaderLanguage;
210 	const Winding				m_winding;
211 	const bool					m_yFlip;
212 };
213 
WindingTest(tcu::TestContext & testCtx,const TessPrimitiveType primitiveType,const MaybeDomainOrigin & domainOrigin,const ShaderLanguage shaderLanguage,const Winding winding,bool yFlip)214 WindingTest::WindingTest (tcu::TestContext&			testCtx,
215 						  const TessPrimitiveType	primitiveType,
216 						  const MaybeDomainOrigin&	domainOrigin,
217 						  const ShaderLanguage		shaderLanguage,
218 						  const Winding				winding,
219 						  bool						yFlip)
220 	: TestCase			(testCtx, getCaseName(primitiveType, shaderLanguage, winding, yFlip), "")
221 	, m_primitiveType	(primitiveType)
222 	, m_domainOrigin	(domainOrigin)
223 	, m_shaderLanguage	(shaderLanguage)
224 	, m_winding			(winding)
225 	, m_yFlip			(yFlip)
226 {
227 }
228 
initPrograms(SourceCollections & programCollection) const229 void WindingTest::initPrograms (SourceCollections& programCollection) const
230 {
231 	if (m_shaderLanguage == SHADER_LANGUAGE_GLSL)
232 	{
233 		// Vertex shader - no inputs
234 		{
235 			std::ostringstream src;
236 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
237 				<< "\n"
238 				<< "void main (void)\n"
239 				<< "{\n"
240 				<< "}\n";
241 
242 			programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
243 		}
244 
245 		// Tessellation control shader
246 		{
247 			std::ostringstream src;
248 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
249 				<< "#extension GL_EXT_tessellation_shader : require\n"
250 				<< "\n"
251 				<< "layout(vertices = 1) out;\n"
252 				<< "\n"
253 				<< "void main (void)\n"
254 				<< "{\n"
255 				<< "    gl_TessLevelInner[0] = 5.0;\n"
256 				<< "    gl_TessLevelInner[1] = 5.0;\n"
257 				<< "\n"
258 				<< "    gl_TessLevelOuter[0] = 5.0;\n"
259 				<< "    gl_TessLevelOuter[1] = 5.0;\n"
260 				<< "    gl_TessLevelOuter[2] = 5.0;\n"
261 				<< "    gl_TessLevelOuter[3] = 5.0;\n"
262 				<< "}\n";
263 
264 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
265 		}
266 
267 		// Tessellation evaluation shader
268 		{
269 			std::ostringstream src;
270 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
271 				<< "#extension GL_EXT_tessellation_shader : require\n"
272 				<< "\n"
273 				<< "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ", "
274 							 << getWindingShaderName(m_winding) << ") in;\n"
275 				<< "\n"
276 				<< "void main (void)\n"
277 				<< "{\n"
278 				<< "    gl_Position = vec4(gl_TessCoord.xy*2.0 - 1.0, 0.0, 1.0);\n"
279 				<< "}\n";
280 
281 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
282 		}
283 
284 		// Fragment shader
285 		{
286 			std::ostringstream src;
287 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
288 				<< "\n"
289 				<< "layout(location = 0) out mediump vec4 o_color;\n"
290 				<< "\n"
291 				<< "void main (void)\n"
292 				<< "{\n"
293 				<< "    o_color = vec4(1.0);\n"
294 				<< "}\n";
295 
296 			programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
297 		}
298 	}
299 	else
300 	{
301 		// Vertex shader - no inputs
302 		{
303 			std::ostringstream src;
304 			src << "void main (void)\n"
305 				<< "{\n"
306 				<< "}\n";
307 
308 			programCollection.hlslSources.add("vert") << glu::VertexSource(src.str());
309 		}
310 
311 		// Tessellation control shader
312 		{
313 			std::ostringstream src;
314 			src << "struct HS_CONSTANT_OUT\n"
315 				<< "{\n"
316 				<< "    float tessLevelsOuter[4] : SV_TessFactor;\n"
317 				<< "    float tessLevelsInner[2] : SV_InsideTessFactor;\n"
318 				<< "};\n"
319 				<< "\n"
320 				<< "[domain(\"" << getDomainName(m_primitiveType) << "\")]\n"
321 				<< "[partitioning(\"integer\")]\n"
322 				<< "[outputtopology(\"" << getOutputTopologyName (m_primitiveType, m_winding, false) << "\")]\n"
323 				<< "[outputcontrolpoints(1)]\n"
324 				<< "[patchconstantfunc(\"PCF\")]\n"
325 				<< "void main()\n"
326 				<< "{\n"
327 				<< "}\n"
328 				<< "\n"
329 				<< "HS_CONSTANT_OUT PCF()\n"
330 				<< "{\n"
331 				<< "    HS_CONSTANT_OUT output;\n"
332 				<< "    output.tessLevelsInner[0] = 5.0;\n"
333 				<< "    output.tessLevelsInner[1] = 5.0;\n"
334 				<< "    output.tessLevelsOuter[0] = 5.0;\n"
335 				<< "    output.tessLevelsOuter[1] = 5.0;\n"
336 				<< "    output.tessLevelsOuter[2] = 5.0;\n"
337 				<< "    output.tessLevelsOuter[3] = 5.0;\n"
338 				<< "    return output;\n"
339 				<< "}\n";
340 
341 			programCollection.hlslSources.add("tesc") << glu::TessellationControlSource(src.str());
342 		}
343 
344 		// Tessellation evaluation shader
345 		{
346 			std::ostringstream src;
347 
348 			src	<< "float4 main(" << (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "float3" : "float2") << " tessCoords : SV_DOMAINLOCATION) : SV_POSITION\n"
349 				<< "{\n"
350 				<< "    return float4(tessCoords.xy*2.0 - 1, 0.0, 1.0);\n"
351 				<< "}\n";
352 
353 			programCollection.hlslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
354 		}
355 
356 		// Fragment shader
357 		{
358 			std::ostringstream src;
359 			src << "float4 main (void) : COLOR0\n"
360 				<< "{\n"
361 				<< "    return float4(1.0);\n"
362 				<< "}\n";
363 
364 			programCollection.hlslSources.add("frag") << glu::FragmentSource(src.str());
365 		}
366 	}
367 }
368 
369 class WindingTestInstance : public TestInstance
370 {
371 public:
372 								WindingTestInstance (Context&					context,
373 													 const TessPrimitiveType	primitiveType,
374 													 const MaybeDomainOrigin&	domainOrigin,
375 													 const Winding				winding,
376 													 bool						yFlip);
377 
378 	tcu::TestStatus				iterate				(void);
379 
380 private:
381 	void						requireExtension	(const char* name) const;
382 
383 	const TessPrimitiveType		m_primitiveType;
384 	const MaybeDomainOrigin		m_domainOrigin;
385 	const Winding				m_winding;
386 	const bool					m_yFlip;
387 };
388 
WindingTestInstance(Context & context,const TessPrimitiveType primitiveType,const MaybeDomainOrigin & domainOrigin,const Winding winding,bool yFlip)389 WindingTestInstance::WindingTestInstance (Context&					context,
390 										  const TessPrimitiveType	primitiveType,
391 										  const MaybeDomainOrigin&	domainOrigin,
392 										  const Winding				winding,
393 										  bool						yFlip)
394 	: TestInstance		(context)
395 	, m_primitiveType	(primitiveType)
396 	, m_domainOrigin	(domainOrigin)
397 	, m_winding			(winding)
398 	, m_yFlip			(yFlip)
399 {
400 	if (m_yFlip)
401 		requireExtension("VK_KHR_maintenance1");
402 
403 	if ((bool)m_domainOrigin)
404 		requireExtension("VK_KHR_maintenance2");
405 }
406 
requireExtension(const char * name) const407 void WindingTestInstance::requireExtension (const char* name) const
408 {
409 	if(!m_context.isDeviceFunctionalitySupported(name))
410 		TCU_THROW(NotSupportedError, (std::string(name) + " is not supported").c_str());
411 }
412 
iterate(void)413 tcu::TestStatus WindingTestInstance::iterate (void)
414 {
415 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
416 	const VkDevice			device				= m_context.getDevice();
417 	const VkQueue			queue				= m_context.getUniversalQueue();
418 	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
419 	Allocator&				allocator			= m_context.getDefaultAllocator();
420 
421 	// Color attachment
422 
423 	const tcu::IVec2			  renderSize				 = tcu::IVec2(64, 64);
424 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
425 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
426 	const ImageWithMemory		  colorAttachmentImage		 (vk, device, allocator,
427 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
428 															 MemoryRequirement::Any);
429 
430 	// Color output buffer: image will be copied here for verification
431 
432 	const VkDeviceSize		colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
433 	const BufferWithMemory	colorBuffer			 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
434 
435 	// Pipeline
436 
437 	const Unique<VkImageView>		colorAttachmentView	(makeImageView		(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
438 	const Unique<VkRenderPass>		renderPass			(makeRenderPass		(vk, device, colorFormat));
439 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer	(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
440 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout	(vk, device));
441 
442 	const VkCullModeFlags cullMode = VK_CULL_MODE_BACK_BIT;
443 
444 	// Front face is static state, so we have to create two pipelines.
445 
446 	const Unique<VkPipeline> pipelineCounterClockwise(GraphicsPipelineBuilder()
447 		.setCullModeFlags				(cullMode)
448 		.setFrontFace					(VK_FRONT_FACE_COUNTER_CLOCKWISE)
449 		.setShader						(vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
450 		.setShader						(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,		m_context.getBinaryCollection().get("tesc"), DE_NULL)
451 		.setShader						(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,	m_context.getBinaryCollection().get("tese"), DE_NULL)
452 		.setShader						(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,					m_context.getBinaryCollection().get("frag"), DE_NULL)
453 		.setTessellationDomainOrigin	(m_domainOrigin)
454 		.build							(vk, device, *pipelineLayout, *renderPass));
455 
456 	const Unique<VkPipeline> pipelineClockwise(GraphicsPipelineBuilder()
457 		.setCullModeFlags				(cullMode)
458 		.setFrontFace					(VK_FRONT_FACE_CLOCKWISE)
459 		.setShader						(vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
460 		.setShader						(vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,		m_context.getBinaryCollection().get("tesc"), DE_NULL)
461 		.setShader						(vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT,	m_context.getBinaryCollection().get("tese"), DE_NULL)
462 		.setShader						(vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,					m_context.getBinaryCollection().get("frag"), DE_NULL)
463 		.setTessellationDomainOrigin	(m_domainOrigin)
464 		.build							(vk, device, *pipelineLayout, *renderPass));
465 
466 	const struct // not static
467 	{
468 		Winding		frontFaceWinding;
469 		VkPipeline	pipeline;
470 	} testCases[] =
471 	{
472 		{ WINDING_CCW,	*pipelineCounterClockwise },
473 		{ WINDING_CW,	*pipelineClockwise		  },
474 	};
475 
476 	tcu::TestLog& log = m_context.getTestContext().getLog();
477 	log << tcu::TestLog::Message << "Pipeline uses " << getCullModeFlagsStr(cullMode) << tcu::TestLog::EndMessage;
478 
479 	bool success = true;
480 
481 	// Draw commands
482 
483 	const Unique<VkCommandPool>   cmdPool  (makeCommandPool  (vk, device, queueFamilyIndex));
484 	const Unique<VkCommandBuffer> cmdBuffer(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
485 
486 	for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(testCases); ++caseNdx)
487 	{
488 		const Winding frontFaceWinding = testCases[caseNdx].frontFaceWinding;
489 
490 		log << tcu::TestLog::Message << "Setting " << getFrontFaceName(mapFrontFace(frontFaceWinding)) << tcu::TestLog::EndMessage;
491 
492 		// Reset the command buffer and begin.
493 		beginCommandBuffer(vk, *cmdBuffer);
494 
495 		// Change color attachment image layout
496 		{
497 			// State is slightly different on the first iteration.
498 			const VkImageLayout currentLayout = (caseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
499 			const VkAccessFlags srcFlags	  = (caseNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
500 
501 			const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
502 				srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
503 				currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
504 				*colorAttachmentImage, colorImageSubresourceRange);
505 
506 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
507 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
508 		}
509 
510 		// Begin render pass
511 		{
512 			const VkRect2D	renderArea	= makeRect2D(renderSize);
513 			const tcu::Vec4	clearColor	= tcu::RGBA::red().toVec();
514 
515 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
516 		}
517 
518 		const VkViewport viewport =
519 		{
520 			0.0f,															// float	x;
521 			m_yFlip ? static_cast<float>(renderSize.y()) : 0.0f,			// float	y;
522 			static_cast<float>(renderSize.x()),								// float	width;
523 			static_cast<float>(m_yFlip ? -renderSize.y() : renderSize.y()),	// float	height;
524 			0.0f,															// float	minDepth;
525 			1.0f,															// float	maxDepth;
526 		};
527 		vk.cmdSetViewport(*cmdBuffer, 0, 1, &viewport);
528 
529 		const VkRect2D scissor = makeRect2D(renderSize);
530 		vk.cmdSetScissor(*cmdBuffer, 0, 1, &scissor);
531 
532 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, testCases[caseNdx].pipeline);
533 
534 		// Process a single abstract vertex.
535 		vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
536 		endRenderPass(vk, *cmdBuffer);
537 
538 		// Copy render result to a host-visible buffer
539 		copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
540 
541 		endCommandBuffer(vk, *cmdBuffer);
542 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
543 
544 		{
545 			// Log rendered image
546 			const Allocation&					colorBufferAlloc	= colorBuffer.getAllocation();
547 
548 			invalidateAlloc(vk, device, colorBufferAlloc);
549 
550 			const tcu::ConstPixelBufferAccess	imagePixelAccess	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
551 
552 			log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess);
553 
554 			// Verify case result
555 			success = verifyResultImage(log,
556 										imagePixelAccess,
557 										m_primitiveType,
558 										!m_domainOrigin ? VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT : *m_domainOrigin,
559 										m_winding,
560 										m_yFlip,
561 										frontFaceWinding) && success;
562 		}
563 	}  // for windingNdx
564 
565 	return (success ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
566 }
567 
createInstance(Context & context) const568 TestInstance* WindingTest::createInstance (Context& context) const
569 {
570 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
571 
572 	return new WindingTestInstance(context, m_primitiveType, m_domainOrigin, m_winding, m_yFlip);
573 }
574 
populateWindingGroup(tcu::TestCaseGroup * group,tcu::Maybe<VkTessellationDomainOrigin> domainOrigin)575 void populateWindingGroup (tcu::TestCaseGroup* group, tcu::Maybe<VkTessellationDomainOrigin> domainOrigin)
576 {
577 	static const TessPrimitiveType primitivesNoIsolines[] =
578 	{
579 		TESSPRIMITIVETYPE_TRIANGLES,
580 		TESSPRIMITIVETYPE_QUADS,
581 	};
582 
583 	static const ShaderLanguage shaderLanguage[] =
584 	{
585 		SHADER_LANGUAGE_GLSL,
586 		SHADER_LANGUAGE_HLSL,
587 	};
588 
589 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
590 	for (int shaderLanguageNdx = 0; shaderLanguageNdx < DE_LENGTH_OF_ARRAY(shaderLanguage); ++shaderLanguageNdx)
591 	for (int windingNdx = 0; windingNdx < WINDING_LAST; ++windingNdx)
592 	{
593 		group->addChild(new WindingTest(group->getTestContext(), primitivesNoIsolines[primitiveTypeNdx], domainOrigin, shaderLanguage[shaderLanguageNdx], (Winding)windingNdx, false));
594 		group->addChild(new WindingTest(group->getTestContext(), primitivesNoIsolines[primitiveTypeNdx], domainOrigin, shaderLanguage[shaderLanguageNdx], (Winding)windingNdx, true));
595 	}
596 }
597 
598 } // anonymous
599 
600 //! These tests correspond to dEQP-GLES31.functional.tessellation.winding.*
createWindingTests(tcu::TestContext & testCtx)601 tcu::TestCaseGroup* createWindingTests (tcu::TestContext& testCtx)
602 {
603 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "winding", "Test the cw and ccw input layout qualifiers"));
604 
605 	addTestGroup(group.get(), "default_domain",		"No tessellation domain specified",	populateWindingGroup,	tcu::nothing<VkTessellationDomainOrigin>());
606 	addTestGroup(group.get(), "lower_left_domain",	"Lower left tessellation domain",	populateWindingGroup,	tcu::just(VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT));
607 	addTestGroup(group.get(), "upper_left_domain",	"Upper left tessellation domain",	populateWindingGroup,	tcu::just(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT));
608 
609 	return group.release();
610 }
611 
612 } // tessellation
613 } // vkt
614