• 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 Miscellaneous Draw Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationMiscDrawTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuImageIO.hpp"
31 #include "tcuTexture.hpp"
32 #include "tcuImageCompare.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 #include "deStringUtil.hpp"
48 
49 #include <string>
50 #include <vector>
51 #include <utility>
52 
53 namespace vkt
54 {
55 namespace tessellation
56 {
57 
58 using namespace vk;
59 
60 namespace
61 {
62 
63 struct CaseDefinition
64 {
65 	TessPrimitiveType	primitiveType;
66 	SpacingMode			spacingMode;
67 	std::string			referenceImagePathPrefix;	//!< without case suffix and extension (e.g. "_1.png")
68 };
69 
makeCaseDefinition(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const std::string & referenceImagePathPrefix)70 inline CaseDefinition makeCaseDefinition (const TessPrimitiveType	primitiveType,
71 										  const SpacingMode			spacingMode,
72 										  const std::string&		referenceImagePathPrefix)
73 {
74 	CaseDefinition caseDef;
75 	caseDef.primitiveType = primitiveType;
76 	caseDef.spacingMode = spacingMode;
77 	caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
78 	return caseDef;
79 }
80 
genTessLevelCases(const SpacingMode spacingMode)81 std::vector<TessLevels> genTessLevelCases (const SpacingMode spacingMode)
82 {
83 	static const TessLevels tessLevelCases[] =
84 	{
85 		{ { 9.0f,	9.0f	},	{ 9.0f,		9.0f,	9.0f,	9.0f	} },
86 		{ { 8.0f,	11.0f	},	{ 13.0f,	15.0f,	18.0f,	21.0f	} },
87 		{ { 17.0f,	14.0f	},	{ 3.0f,		6.0f,	9.0f,	12.0f	} },
88 	};
89 
90 	std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
91 
92 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
93 	{
94 		TessLevels& tessLevels = resultTessLevels[tessLevelCaseNdx];
95 
96 		for (int i = 0; i < 2; ++i)
97 			tessLevels.inner[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
98 
99 		for (int i = 0; i < 4; ++i)
100 			tessLevels.outer[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
101 	}
102 
103 	return resultTessLevels;
104 }
105 
genVertexPositions(const TessPrimitiveType primitiveType)106 std::vector<tcu::Vec2> genVertexPositions (const TessPrimitiveType primitiveType)
107 {
108 	std::vector<tcu::Vec2> positions;
109 	positions.reserve(4);
110 
111 	if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
112 	{
113 		positions.push_back(tcu::Vec2( 0.8f,    0.6f));
114 		positions.push_back(tcu::Vec2( 0.0f, -0.786f));
115 		positions.push_back(tcu::Vec2(-0.8f,    0.6f));
116 	}
117 	else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
118 	{
119 		positions.push_back(tcu::Vec2(-0.8f, -0.8f));
120 		positions.push_back(tcu::Vec2( 0.8f, -0.8f));
121 		positions.push_back(tcu::Vec2(-0.8f,  0.8f));
122 		positions.push_back(tcu::Vec2( 0.8f,  0.8f));
123 	}
124 	else
125 		DE_ASSERT(false);
126 
127 	return positions;
128 }
129 
130 //! Common test function used by all test cases.
runTest(Context & context,const CaseDefinition caseDef)131 tcu::TestStatus runTest (Context& context, const CaseDefinition caseDef)
132 {
133 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
134 
135 	const DeviceInterface&	vk					= context.getDeviceInterface();
136 	const VkDevice			device				= context.getDevice();
137 	const VkQueue			queue				= context.getUniversalQueue();
138 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
139 	Allocator&				allocator			= context.getDefaultAllocator();
140 
141 	const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
142 	const std::vector<tcu::Vec2>  vertexData	 = genVertexPositions(caseDef.primitiveType);
143 	const deUint32				  inPatchSize	 = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
144 
145 	// Vertex input: positions
146 
147 	const VkFormat	   vertexFormat		   = VK_FORMAT_R32G32_SFLOAT;
148 	const deUint32	   vertexStride		   = tcu::getPixelSize(mapVkFormat(vertexFormat));
149 	const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
150 
151 	const BufferWithMemory vertexBuffer(vk, device, allocator,
152 		makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
153 
154 	DE_ASSERT(inPatchSize == vertexData.size());
155 	DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
156 
157 	{
158 		const Allocation& alloc = vertexBuffer.getAllocation();
159 
160 		deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
161 		flushAlloc(vk, device, alloc);
162 		// No barrier needed, flushed memory is automatically visible
163 	}
164 
165 	// Color attachment
166 
167 	const tcu::IVec2			  renderSize				 = tcu::IVec2(256, 256);
168 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
169 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
170 	const ImageWithMemory		  colorAttachmentImage		 (vk, device, allocator,
171 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
172 															 MemoryRequirement::Any);
173 
174 	// Color output buffer: image will be copied here for verification
175 
176 	const VkDeviceSize		colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
177 	const BufferWithMemory	colorBuffer			(vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
178 
179 	// Input buffer: tessellation levels. Data is filled in later.
180 
181 	const BufferWithMemory tessLevelsBuffer(vk, device, allocator,
182 		makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
183 
184 	// Descriptors
185 
186 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
187 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
188 		.build(vk, device));
189 
190 	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
191 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
192 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
193 
194 	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
195 
196 	const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
197 
198 	DescriptorSetUpdateBuilder()
199 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
200 		.update(vk, device);
201 
202 	// Pipeline
203 
204 	const Unique<VkImageView>		colorAttachmentView	(makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
205 	const Unique<VkRenderPass>		renderPass			(makeRenderPass(vk, device, colorFormat));
206 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
207 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
208 	const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
209 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
210 
211 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
212 		.setRenderSize				  (renderSize)
213 		.setVertexInputSingleAttribute(vertexFormat, vertexStride)
214 		.setPatchControlPoints		  (inPatchSize)
215 		.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
216 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
217 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
218 		.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL)
219 		.build						  (vk, device, *pipelineLayout, *renderPass));
220 
221 	// Draw commands
222 
223 	deUint32 numPassedCases = 0;
224 
225 	for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
226 	{
227 		context.getTestContext().getLog()
228 			<< tcu::TestLog::Message
229 			<< "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
230 			<< tcu::TestLog::EndMessage;
231 
232 		// Upload tessellation levels data to the input buffer
233 		{
234 			const Allocation& alloc				= tessLevelsBuffer.getAllocation();
235 			TessLevels* const bufferTessLevels	= static_cast<TessLevels*>(alloc.getHostPtr());
236 
237 			*bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
238 			flushAlloc(vk, device, alloc);
239 		}
240 
241 		// Reset the command buffer and begin recording.
242 		beginCommandBuffer(vk, *cmdBuffer);
243 
244 		// Change color attachment image layout
245 		{
246 			// State is slightly different on the first iteration.
247 			const VkImageLayout currentLayout = (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
248 			const VkAccessFlags srcFlags	  = (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
249 
250 			const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
251 				srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
252 				currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
253 				*colorAttachmentImage, colorImageSubresourceRange);
254 
255 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
256 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
257 		}
258 
259 		// Begin render pass
260 		{
261 			const VkRect2D	renderArea	= makeRect2D(renderSize);
262 			const tcu::Vec4	clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
263 
264 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
265 		}
266 
267 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
268 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
269 		{
270 			const VkDeviceSize vertexBufferOffset = 0ull;
271 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
272 		}
273 
274 		// Process enough vertices to make a patch.
275 		vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
276 		endRenderPass(vk, *cmdBuffer);
277 
278 		// Copy render result to a host-visible buffer
279 		copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
280 
281 		endCommandBuffer(vk, *cmdBuffer);
282 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
283 
284 		{
285 			const Allocation&	colorBufferAlloc	= colorBuffer.getAllocation();
286 
287 			invalidateAlloc(vk, device, colorBufferAlloc);
288 
289 			// Verify case result
290 			const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
291 
292 			// Load reference image
293 			const std::string	referenceImagePath	= caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
294 
295 			tcu::TextureLevel	referenceImage;
296 			tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
297 
298 			if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
299 								  referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
300 				++numPassedCases;
301 		}
302 	} // tessLevelCaseNdx
303 
304 	return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
305 }
306 
getTessLevelsSSBODeclaration(void)307 inline const char* getTessLevelsSSBODeclaration (void)
308 {
309 	return	"layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
310 			"    float inner0;\n"
311 			"    float inner1;\n"
312 			"    float outer0;\n"
313 			"    float outer1;\n"
314 			"    float outer2;\n"
315 			"    float outer3;\n"
316 			"} sb_levels;\n";
317 }
318 
319 //! Add vertex, fragment, and tessellation control shaders.
initCommonPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)320 void initCommonPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
321 {
322 	DE_ASSERT(!programCollection.glslSources.contains("vert"));
323 	DE_ASSERT(!programCollection.glslSources.contains("tesc"));
324 	DE_ASSERT(!programCollection.glslSources.contains("frag"));
325 
326 	// Vertex shader
327 	{
328 		std::ostringstream src;
329 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
330 			<< "\n"
331 			<< "layout(location = 0) in  highp vec2 in_v_position;\n"
332 			<< "layout(location = 0) out highp vec2 in_tc_position;\n"
333 			<< "\n"
334 			<< "void main (void)\n"
335 			<< "{\n"
336 			<< "    in_tc_position = in_v_position;\n"
337 			<< "}\n";
338 
339 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
340 	}
341 
342 	// Tessellation control shader
343 	{
344 		const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
345 
346 		std::ostringstream src;
347 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
348 			<< "#extension GL_EXT_tessellation_shader : require\n"
349 			<< "\n"
350 			<< "layout(vertices = " << numVertices << ") out;\n"
351 			<< "\n"
352 			<< getTessLevelsSSBODeclaration()
353 			<< "\n"
354 			<< "layout(location = 0) in  highp vec2 in_tc_position[];\n"
355 			<< "layout(location = 0) out highp vec2 in_te_position[];\n"
356 			<< "\n"
357 			<< "void main (void)\n"
358 			<< "{\n"
359 			<< "    in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
360 			<< "\n"
361 			<< "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
362 			<< "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
363 			<< "\n"
364 			<< "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
365 			<< "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
366 			<< "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
367 			<< "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
368 			<< "}\n";
369 
370 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
371 	}
372 
373 	// Fragment shader
374 	{
375 		std::ostringstream src;
376 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
377 			<< "\n"
378 			<< "layout(location = 0) in  highp   vec4 in_f_color;\n"
379 			<< "layout(location = 0) out mediump vec4 o_color;\n"
380 			<< "\n"
381 			<< "void main (void)\n"
382 			<< "{\n"
383 			<< "    o_color = in_f_color;\n"
384 			<< "}\n";
385 
386 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
387 	}
388 }
389 
initProgramsFillCoverCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)390 void initProgramsFillCoverCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
391 {
392 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
393 
394 	initCommonPrograms(programCollection, caseDef);
395 
396 	// Tessellation evaluation shader
397 	{
398 		std::ostringstream src;
399 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
400 			<< "#extension GL_EXT_tessellation_shader : require\n"
401 			<< "\n"
402 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
403 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
404 			<< "\n"
405 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
406 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
407 			<< "\n"
408 			<< "void main (void)\n"
409 			<< "{\n"
410 			<<	(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
411 					"    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
412 					"    highp vec2 corner0 = in_te_position[0];\n"
413 					"    highp vec2 corner1 = in_te_position[1];\n"
414 					"    highp vec2 corner2 = in_te_position[2];\n"
415 					"    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
416 					"    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
417 					"    highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
418 					"    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
419 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
420 				: caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
421 					"    highp vec2 corner0 = in_te_position[0];\n"
422 					"    highp vec2 corner1 = in_te_position[1];\n"
423 					"    highp vec2 corner2 = in_te_position[2];\n"
424 					"    highp vec2 corner3 = in_te_position[3];\n"
425 					"    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
426 					"                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
427 					"                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
428 					"                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
429 					"    highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
430 					"    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
431 					"    highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
432 					"    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
433 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
434 				: "")
435 			<< "    in_f_color = vec4(1.0);\n"
436 			<< "}\n";
437 
438 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
439 	}
440 }
441 
initProgramsFillNonOverlapCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)442 void initProgramsFillNonOverlapCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
443 {
444 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
445 
446 	initCommonPrograms(programCollection, caseDef);
447 
448 	// Tessellation evaluation shader
449 	{
450 		std::ostringstream src;
451 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
452 			<< "#extension GL_EXT_tessellation_shader : require\n"
453 			<< "\n"
454 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
455 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
456 			<< "\n"
457 			<< getTessLevelsSSBODeclaration()
458 			<< "\n"
459 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
460 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
461 			<< "\n"
462 			<< "void main (void)\n"
463 			<< "{\n"
464 			<<	(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
465 					"    highp vec2 corner0 = in_te_position[0];\n"
466 					"    highp vec2 corner1 = in_te_position[1];\n"
467 					"    highp vec2 corner2 = in_te_position[2];\n"
468 					"    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
469 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
470 					"    highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
471 					"    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
472 					"    highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
473 					"    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
474 					"               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
475 					"               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
476 				: caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
477 					"    highp vec2 corner0 = in_te_position[0];\n"
478 					"    highp vec2 corner1 = in_te_position[1];\n"
479 					"    highp vec2 corner2 = in_te_position[2];\n"
480 					"    highp vec2 corner3 = in_te_position[3];\n"
481 					"    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
482 					"                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
483 					"                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
484 					"                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
485 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
486 					"    highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
487 					"    highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
488 					"    highp int phase = min(phaseX, phaseY) % 3;\n"
489 					"    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
490 					"               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
491 					"               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
492 					: "")
493 			<< "}\n";
494 
495 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
496 	}
497 }
498 
initProgramsIsolinesCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)499 void initProgramsIsolinesCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
500 {
501 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
502 
503 	initCommonPrograms(programCollection, caseDef);
504 
505 	// Tessellation evaluation shader
506 	{
507 		std::ostringstream src;
508 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
509 			<< "#extension GL_EXT_tessellation_shader : require\n"
510 			<< "\n"
511 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
512 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
513 			<< "\n"
514 			<< getTessLevelsSSBODeclaration()
515 			<< "\n"
516 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
517 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
518 			<< "\n"
519 			<< "void main (void)\n"
520 			<< "{\n"
521 			<< "    highp vec2 corner0 = in_te_position[0];\n"
522 			<< "    highp vec2 corner1 = in_te_position[1];\n"
523 			<< "    highp vec2 corner2 = in_te_position[2];\n"
524 			<< "    highp vec2 corner3 = in_te_position[3];\n"
525 			<< "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
526 			<< "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
527 			<< "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
528 			<< "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
529 			<< "    pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
530 			<< "    gl_Position = vec4(pos, 0.0, 1.0);\n"
531 			<< "    highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
532 			<< "    highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
533 			<< "    highp int phase = (phaseX + phaseY) % 3;\n"
534 			<< "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
535 			<< "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
536 			<< "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
537 			<< "}\n";
538 
539 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
540 	}
541 }
542 
getReferenceImagePathPrefix(const std::string & caseName)543 inline std::string getReferenceImagePathPrefix (const std::string& caseName)
544 {
545 	return "vulkan/data/tessellation/" + caseName + "_ref";
546 }
547 
548 struct TessStateSwitchParams
549 {
550 	const std::pair<TessPrimitiveType, TessPrimitiveType>					patchTypes;
551 	const std::pair<SpacingMode, SpacingMode>								spacing;
552 	const std::pair<VkTessellationDomainOrigin, VkTessellationDomainOrigin>	domainOrigin;
553 	const bool																geometryShader;
554 
nonDefaultDomainOriginvkt::tessellation::__anonae63b47f0111::TessStateSwitchParams555 	bool nonDefaultDomainOrigin (void) const
556 	{
557 		return (domainOrigin.first != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT ||
558 				domainOrigin.second != VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT);
559 	}
560 };
561 
562 class TessStateSwitchInstance : public vkt::TestInstance
563 {
564 public:
TessStateSwitchInstance(Context & context,const TessStateSwitchParams & params)565 						TessStateSwitchInstance		(Context& context, const TessStateSwitchParams& params)
566 							: vkt::TestInstance	(context)
567 							, m_params			(params)
568 							{}
569 
~TessStateSwitchInstance(void)570 	virtual				~TessStateSwitchInstance	(void) {}
571 
572 	tcu::TestStatus		iterate						(void);
573 
574 protected:
575 	const TessStateSwitchParams m_params;
576 };
577 
578 class TessStateSwitchCase : public vkt::TestCase
579 {
580 public:
TessStateSwitchCase(tcu::TestContext & testCtx,const std::string & name,const TessStateSwitchParams & params)581 					TessStateSwitchCase		(tcu::TestContext& testCtx, const std::string& name, const TessStateSwitchParams& params)
582 						: vkt::TestCase	(testCtx, name)
583 						, m_params		(params)
584 						{}
585 
~TessStateSwitchCase(void)586 	virtual			~TessStateSwitchCase	(void) {}
587 
588 	void			checkSupport			(Context& context) const;
589 	void			initPrograms			(vk::SourceCollections& programCollection) const;
createInstance(Context & context) const590 	TestInstance*	createInstance			(Context& context) const { return new TessStateSwitchInstance(context, m_params); }
591 
592 protected:
593 	const TessStateSwitchParams m_params;
594 };
595 
checkSupport(Context & context) const596 void TessStateSwitchCase::checkSupport (Context& context) const
597 {
598 	context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
599 
600 	if (m_params.geometryShader)
601 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
602 
603 	if (m_params.nonDefaultDomainOrigin())
604 		context.requireDeviceFunctionality("VK_KHR_maintenance2");
605 }
606 
initPrograms(vk::SourceCollections & programCollection) const607 void TessStateSwitchCase::initPrograms (vk::SourceCollections& programCollection) const
608 {
609 	std::ostringstream vert;
610 	vert
611 		<< "#version 460\n"
612 		<< "layout (location=0) in vec4 inPos;\n"
613 		<< "layout (push_constant, std430) uniform PushConstantBlock { vec2 offset; } pc;\n"
614 		<< "out gl_PerVertex\n"
615 		<< "{\n"
616 		<< "  vec4 gl_Position;\n"
617 		<< "};\n"
618 		<< "void main() {\n"
619 		<< "    gl_Position = inPos + vec4(pc.offset, 0.0, 0.0);\n"
620 		<< "}\n"
621 		;
622 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
623 
624 	if (m_params.geometryShader)
625 	{
626 		std::ostringstream geom;
627 		geom
628 			<< "#version 460\n"
629 			<< "layout (triangles) in;\n"
630 			<< "layout (triangle_strip, max_vertices=3) out;\n"
631 			<< "in gl_PerVertex\n"
632 			<< "{\n"
633 			<< "    vec4 gl_Position;\n"
634 			<< "} gl_in[3];\n"
635 			<< "out gl_PerVertex\n"
636 			<< "{\n"
637 			<< "    vec4 gl_Position;\n"
638 			<< "};\n"
639 			<< "void main() {\n"
640 			<< "    gl_Position    = gl_in[0].gl_Position; EmitVertex();\n"
641 			<< "    gl_Position    = gl_in[1].gl_Position; EmitVertex();\n"
642 			<< "    gl_Position    = gl_in[2].gl_Position; EmitVertex();\n"
643 			<< "    gl_PrimitiveID = gl_PrimitiveIDIn;     EndPrimitive();\n"
644 			<< "}\n"
645 			;
646 		programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
647 	}
648 
649 	const auto even			= (m_params.spacing.second == SPACINGMODE_FRACTIONAL_EVEN);
650 	const auto extraLevel	= (even ? "1.0" : "0.0");
651 
652 	std::ostringstream tesc;
653 	tesc
654 		<< "#version 460\n"
655 		<< "layout (vertices=4) out;\n"
656 		<< "in gl_PerVertex\n"
657 		<< "{\n"
658 		<< "  vec4 gl_Position;\n"
659 		<< "} gl_in[gl_MaxPatchVertices];\n"
660 		<< "out gl_PerVertex\n"
661 		<< "{\n"
662 		<< "  vec4 gl_Position;\n"
663 		<< "} gl_out[];\n"
664 		<< "void main() {\n"
665 		<< "    const float extraLevel = " << extraLevel << ";\n"
666 		<< "    gl_TessLevelInner[0] = 10.0 + extraLevel;\n"
667 		<< "    gl_TessLevelInner[1] = 10.0 + extraLevel;\n"
668 		<< "    gl_TessLevelOuter[0] = 50.0 + extraLevel;\n"
669 		<< "    gl_TessLevelOuter[1] = 40.0 + extraLevel;\n"
670 		<< "    gl_TessLevelOuter[2] = 30.0 + extraLevel;\n"
671 		<< "    gl_TessLevelOuter[3] = 20.0 + extraLevel;\n"
672 		<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
673 		<< "}\n"
674 		;
675 	programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
676 
677 	for (uint32_t i = 0u; i < 2u; ++i)
678 	{
679 		const auto& primType	= ((i == 0u) ? m_params.patchTypes.first : m_params.patchTypes.second);
680 		const auto& spacing		= ((i == 0u) ? m_params.spacing.first : m_params.spacing.second);
681 
682 		std::ostringstream tese;
683 		tese
684 			<< "#version 460\n"
685 			<< "layout (" << getTessPrimitiveTypeShaderName(primType) << ", " << getSpacingModeShaderName(spacing) << ", ccw) in;\n"
686 			<< "in gl_PerVertex\n"
687 			<< "{\n"
688 			<< "  vec4 gl_Position;\n"
689 			<< "} gl_in[gl_MaxPatchVertices];\n"
690 			<< "out gl_PerVertex\n"
691 			<< "{\n"
692 			<< "  vec4 gl_Position;\n"
693 			<< "};\n"
694 			<< "\n"
695 			<< "// This assumes 2D, calculates barycentrics for point p inside triangle (a, b, c)\n"
696 			<< "vec3 calcBaryCoords(vec2 p, vec2 a, vec2 b, vec2 c)\n"
697 			<< "{\n"
698 			<< "    const vec2 v0 = b - a;\n"
699 			<< "    const vec2 v1 = c - a;\n"
700 			<< "    const vec2 v2 = p - a;\n"
701 			<< "\n"
702 			<< "    const float den = v0.x * v1.y - v1.x * v0.y;\n"
703 			<< "    const float v   = (v2.x * v1.y - v1.x * v2.y) / den;\n"
704 			<< "    const float w   = (v0.x * v2.y - v2.x * v0.y) / den;\n"
705 			<< "    const float u   = 1.0 - v - w;\n"
706 			<< "\n"
707 			<< "    return vec3(u, v, w);\n"
708 			<< "}\n"
709 			<< "\n"
710 			<< "void main() {\n"
711 			<< ((primType == TESSPRIMITIVETYPE_QUADS)
712 				// For quads.
713 				?	"    const float u = gl_TessCoord.x;\n"
714 					"    const float v = gl_TessCoord.y;\n"
715 					"    gl_Position = (1 - u) * (1 - v) * gl_in[0].gl_Position + (1 - u) * v * gl_in[1].gl_Position + u * (1 - v) * gl_in[2].gl_Position + u * v * gl_in[3].gl_Position;\n"
716 				// For triangles.
717 				:	"    // We have a patch with 4 corners (v0,v1,v2,v3), but triangle-based tessellation.\n"
718 					"    // Lets suppose the triangle covers half the patch (triangle v0,v2,v1).\n"
719 					"    // Expand the triangle by virtually grabbing it from the midpoint between v1 and v2 (which should fall in the middle of the patch) and stretching that point to the fourth corner (v3).\n"
720 					"    const vec4 origpoint = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
721 					"                           (gl_TessCoord.y * gl_in[2].gl_Position) +\n"
722 					"                           (gl_TessCoord.z * gl_in[1].gl_Position);\n"
723 					"    const vec4 midpoint = 0.5 * gl_in[1].gl_Position + 0.5 * gl_in[2].gl_Position;\n"
724 					"\n"
725 					"    // Find out if it falls on left or right side of the triangle.\n"
726 					"    vec4 halfTriangle[3];\n"
727 					"    vec4 stretchedHalf[3];\n"
728 					"\n"
729 					"    if (gl_TessCoord.z >= gl_TessCoord.y)\n"
730 					"    {\n"
731 					"        halfTriangle[0] = gl_in[0].gl_Position;\n"
732 					"        halfTriangle[1] = midpoint;\n"
733 					"        halfTriangle[2] = gl_in[1].gl_Position;\n"
734 					"\n"
735 					"        stretchedHalf[0] = gl_in[0].gl_Position;\n"
736 					"        stretchedHalf[1] = gl_in[3].gl_Position;\n"
737 					"        stretchedHalf[2] = gl_in[1].gl_Position;\n"
738 					"    }\n"
739 					"    else\n"
740 					"    {\n"
741 					"        halfTriangle[0] = gl_in[0].gl_Position;\n"
742 					"        halfTriangle[1] = gl_in[2].gl_Position;\n"
743 					"        halfTriangle[2] = midpoint;\n"
744 					"\n"
745 					"        stretchedHalf[0] = gl_in[0].gl_Position;\n"
746 					"        stretchedHalf[1] = gl_in[2].gl_Position;\n"
747 					"        stretchedHalf[2] = gl_in[3].gl_Position;\n"
748 					"    }\n"
749 					"\n"
750 					"    // Calculate the barycentric coordinates for the left or right sides.\n"
751 					"    vec3 sideBaryCoord = calcBaryCoords(origpoint.xy, halfTriangle[0].xy, halfTriangle[1].xy, halfTriangle[2].xy);\n"
752 					"\n"
753 					"    // Move the point by stretching the half triangle and dragging the midpoint vertex to v3.\n"
754 					"    gl_Position = sideBaryCoord.x * stretchedHalf[0] + sideBaryCoord.y * stretchedHalf[1] + sideBaryCoord.z * stretchedHalf[2];\n"
755 				)
756 			<< "}\n"
757 			;
758 		programCollection.glslSources.add("tese" + std::to_string(i)) << glu::TessellationEvaluationSource(tese.str());
759 	}
760 
761 	std::ostringstream frag;
762 	frag
763 		<< "#version 460\n"
764 		<< "layout (location=0) out vec4 outColor;\n"
765 		<< "void main() {\n"
766 		<< "    outColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
767 		<< "}\n"
768 		;
769 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
770 }
771 
iterate(void)772 tcu::TestStatus TessStateSwitchInstance::iterate (void)
773 {
774 	const auto&			ctx				= m_context.getContextCommonData();
775 	const tcu::IVec3	fbExtent		(128, 128, 1);
776 	const auto			vkExtent		= makeExtent3D(fbExtent);
777 	const auto			colorFormat		= VK_FORMAT_R8G8B8A8_UNORM;
778 	const auto			tcuFormat		= mapVkFormat(colorFormat);
779 	const auto			colorUsage		= (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
780 	const auto			imageType		= VK_IMAGE_TYPE_2D;
781 	const auto			colorSRR		= makeDefaultImageSubresourceRange();
782 	const auto			bindPoint		= VK_PIPELINE_BIND_POINT_GRAPHICS;
783 
784 	ImageWithBuffer referenceBuffer	(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType, colorSRR);
785 	ImageWithBuffer resultBuffer	(ctx.vkd, ctx.device, ctx.allocator, vkExtent, colorFormat, colorUsage, imageType, colorSRR);
786 
787 	// Vertex buffer containing a single full-screen patch.
788 	const std::vector<tcu::Vec4> vertices
789 	{
790 		tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f),
791 		tcu::Vec4(-1.0f,  1.0f, 0.0f, 1.0f),
792 		tcu::Vec4( 1.0f, -1.0f, 0.0f, 1.0f),
793 		tcu::Vec4( 1.0f,  1.0f, 0.0f, 1.0f),
794 	};
795 	const auto vertexCount			= de::sizeU32(vertices);
796 	const auto patchControlPoints	= vertexCount;
797 
798 	const auto			vertexBufferSize	= static_cast<VkDeviceSize>(de::dataSize(vertices));
799 	const auto			vertexBufferInfo	= makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
800 	BufferWithMemory	vertexBuffer		(ctx.vkd, ctx.device, ctx.allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
801 	auto&				vertexBufferAlloc	= vertexBuffer.getAllocation();
802 	void*				vertexBufferData	= vertexBufferAlloc.getHostPtr();
803 	const auto			vertexBufferOffset	= static_cast<VkDeviceSize>(0);
804 
805 	deMemcpy(vertexBufferData, de::dataOrNull(vertices), de::dataSize(vertices));
806 	flushAlloc(ctx.vkd, ctx.device, vertexBufferAlloc);
807 
808 	const auto pcSize	= static_cast<uint32_t>(sizeof(tcu::Vec2));
809 	const auto pcStages	= static_cast<VkShaderStageFlags>(VK_SHADER_STAGE_VERTEX_BIT);
810 	const auto pcRange	= makePushConstantRange(pcStages, 0u, pcSize);
811 
812 	const auto pipelineLayout = makePipelineLayout(ctx.vkd, ctx.device, VK_NULL_HANDLE, &pcRange);
813 
814 	const auto renderPass = makeRenderPass(ctx.vkd, ctx.device, colorFormat);
815 
816 	// Framebuffers.
817 	const auto framebuffer0 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, referenceBuffer.getImageView(), vkExtent.width, vkExtent.height);
818 	const auto framebuffer1 = makeFramebuffer(ctx.vkd, ctx.device, *renderPass, resultBuffer.getImageView(), vkExtent.width, vkExtent.height);
819 
820 	// Viewport and scissor.
821 	const std::vector<VkViewport>	viewports	(1u, makeViewport(fbExtent));
822 	const std::vector<VkRect2D>		scissors	(1u, makeRect2D(fbExtent));
823 
824 	// Shaders.
825 	const auto&		binaries	= m_context.getBinaryCollection();
826 	const auto		vertModule	= createShaderModule(ctx.vkd, ctx.device, binaries.get("vert"));
827 	const auto		tescModule	= createShaderModule(ctx.vkd, ctx.device, binaries.get("tesc"));
828 	const auto		teseModule0	= createShaderModule(ctx.vkd, ctx.device, binaries.get("tese0"));
829 	const auto		teseModule1	= createShaderModule(ctx.vkd, ctx.device, binaries.get("tese1"));
830 	const auto		geomModule	= (m_params.geometryShader ? createShaderModule(ctx.vkd, ctx.device, binaries.get("geom")) : Move<VkShaderModule>());
831 	const auto		fragModule	= createShaderModule(ctx.vkd, ctx.device, binaries.get("frag"));
832 
833 	const VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
834 	{
835 		VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
836 		nullptr,														//	const void*								pNext;
837 		0u,																//	VkPipelineInputAssemblyStateCreateFlags	flags;
838 		VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,								//	VkPrimitiveTopology						topology;
839 		VK_FALSE,														//	VkBool32								primitiveRestartEnable;
840 	};
841 
842 	VkPipelineTessellationDomainOriginStateCreateInfo domainOriginStateCreateInfo =
843 	{
844 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO,	//	VkStructureType				sType;
845 		nullptr,																	//	const void*					pNext;
846 		m_params.domainOrigin.first,													//	VkTessellationDomainOrigin	domainOrigin;
847 	};
848 
849 	const auto tessPNext = (m_params.nonDefaultDomainOrigin() ? &domainOriginStateCreateInfo : nullptr);
850 	const VkPipelineTessellationStateCreateInfo tessellationStateCreateInfo =
851 	{
852 		VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
853 		tessPNext,													//	const void*								pNext;
854 		0u,															//	VkPipelineTessellationStateCreateFlags	flags;
855 		patchControlPoints,											//	uint32_t								patchControlPoints;
856 	};
857 
858 	const VkPipelineViewportStateCreateInfo viewportStateCreateInfo =
859 	{
860 		VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,	//	VkStructureType						sType;
861 		nullptr,												//	const void*							pNext;
862 		0u,														//	VkPipelineViewportStateCreateFlags	flags;
863 		de::sizeU32(viewports),									//	uint32_t							viewportCount;
864 		de::dataOrNull(viewports),								//	const VkViewport*					pViewports;
865 		de::sizeU32(scissors),									//	uint32_t							scissorCount;
866 		de::dataOrNull(scissors),								//	const VkRect2D*						pScissors;
867 	};
868 
869 	// In the rasterization parameters, use wireframe mode to see each triangle if possible.
870 	// This makes the test harder to pass by mistake.
871 	// We also cull back faces, which will help test domain origin.
872 	// The front face changes with the domain origin.
873 	const auto frontFace	= ((m_params.domainOrigin.second == VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
874 							? VK_FRONT_FACE_COUNTER_CLOCKWISE	// With the default value it's as specified in the shader.
875 							: VK_FRONT_FACE_CLOCKWISE);			// Otherwise the winding order changes.
876 	const auto polygonMode	= ((m_context.getDeviceFeatures().fillModeNonSolid)
877 							? VK_POLYGON_MODE_LINE
878 							: VK_POLYGON_MODE_FILL);
879 	const VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
880 	{
881 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
882 		nullptr,													//	const void*								pNext;
883 		0u,															//	VkPipelineRasterizationStateCreateFlags	flags;
884 		VK_FALSE,													//	VkBool32								depthClampEnable;
885 		VK_FALSE,													//	VkBool32								rasterizerDiscardEnable;
886 		polygonMode,												//	VkPolygonMode							polygonMode;
887 		VK_CULL_MODE_BACK_BIT,										//	VkCullModeFlags							cullMode;
888 		frontFace,													//	VkFrontFace								frontFace;
889 		VK_FALSE,													//	VkBool32								depthBiasEnable;
890 		0.0f,														//	float									depthBiasConstantFactor;
891 		0.0f,														//	float									depthBiasClamp;
892 		0.0f,														//	float									depthBiasSlopeFactor;
893 		1.0f,														//	float									lineWidth;
894 	};
895 
896 	// Create two pipelines varying the tessellation evaluation module.
897 	const auto pipeline0 = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout,
898 		*vertModule, *tescModule, *teseModule0, *geomModule, *fragModule,
899 		*renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo, &tessellationStateCreateInfo, &viewportStateCreateInfo,
900 		&rasterizationStateCreateInfo);
901 
902 	domainOriginStateCreateInfo.domainOrigin = m_params.domainOrigin.second;
903 
904 	const auto pipeline1 = makeGraphicsPipeline(ctx.vkd, ctx.device, *pipelineLayout,
905 		*vertModule, *tescModule, *teseModule1, *geomModule, *fragModule,
906 		*renderPass, 0u, nullptr, &inputAssemblyStateCreateInfo, &tessellationStateCreateInfo, &viewportStateCreateInfo,
907 		&rasterizationStateCreateInfo);
908 
909 	const auto cmdPool = makeCommandPool(ctx.vkd, ctx.device, ctx.qfIndex);
910 	const auto cmdBufferRef = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
911 	const auto cmdBufferRes = allocateCommandBuffer(ctx.vkd, ctx.device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
912 
913 	const tcu::Vec2 noOffset		(0.0f, 0.0f);
914 	const tcu::Vec2 offscreenOffset	(50.0f, 50.0f);
915 	const tcu::Vec4 clearColor		(0.0f, 0.0f, 0.0f, 1.0f);
916 
917 	// Reference image.
918 	beginCommandBuffer(ctx.vkd, *cmdBufferRef);
919 	beginRenderPass(ctx.vkd, *cmdBufferRef, *renderPass, *framebuffer0, scissors.at(0u), clearColor);
920 	ctx.vkd.cmdBindVertexBuffers(*cmdBufferRef, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
921 	ctx.vkd.cmdBindPipeline(*cmdBufferRef, bindPoint, *pipeline1);
922 	ctx.vkd.cmdPushConstants(*cmdBufferRef, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
923 	ctx.vkd.cmdDraw(*cmdBufferRef, vertexCount, 1u, 0u, 0u);
924 	endRenderPass(ctx.vkd, *cmdBufferRef);
925 	copyImageToBuffer(ctx.vkd, *cmdBufferRef, referenceBuffer.getImage(), referenceBuffer.getBuffer(), fbExtent.swizzle(0, 1),
926 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
927 		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
928 	endCommandBuffer(ctx.vkd, *cmdBufferRef);
929 	submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRef);
930 
931 	// Result image.
932 	beginCommandBuffer(ctx.vkd, *cmdBufferRes);
933 	beginRenderPass(ctx.vkd, *cmdBufferRes, *renderPass, *framebuffer1, scissors.at(0u), clearColor);
934 	ctx.vkd.cmdBindVertexBuffers(*cmdBufferRes, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
935 	// Draw offscreen first to force tessellation state emission.
936 	ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline0);
937 	ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &offscreenOffset);
938 	ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
939 	// Draw on screen second changing some tessellation state.
940 	ctx.vkd.cmdBindPipeline(*cmdBufferRes, bindPoint, *pipeline1);
941 	ctx.vkd.cmdPushConstants(*cmdBufferRes, *pipelineLayout, pcStages, 0u, pcSize, &noOffset);
942 	ctx.vkd.cmdDraw(*cmdBufferRes, vertexCount, 1u, 0u, 0u);
943 	endRenderPass(ctx.vkd, *cmdBufferRes);
944 	copyImageToBuffer(ctx.vkd, *cmdBufferRes, resultBuffer.getImage(), resultBuffer.getBuffer(), fbExtent.swizzle(0, 1),
945 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
946 		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
947 	endCommandBuffer(ctx.vkd, *cmdBufferRes);
948 	submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, *cmdBufferRes);
949 
950 	invalidateAlloc(ctx.vkd, ctx.device, referenceBuffer.getBufferAllocation());
951 	invalidateAlloc(ctx.vkd, ctx.device, resultBuffer.getBufferAllocation());
952 
953 	tcu::ConstPixelBufferAccess referenceAccess	(tcuFormat, fbExtent, referenceBuffer.getBufferAllocation().getHostPtr());
954 	tcu::ConstPixelBufferAccess resultAccess	(tcuFormat, fbExtent, resultBuffer.getBufferAllocation().getHostPtr());
955 
956 	auto&			log				= m_context.getTestContext().getLog();
957 	const float		threshold		= 0.005f; // 1/255 < 0.005 < 2/255
958 	const tcu::Vec4	thresholdVec	(threshold, threshold, threshold, 0.0f);
959 
960 	if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, thresholdVec, tcu::COMPARE_LOG_ON_ERROR))
961 		return tcu::TestStatus::fail("Color result does not match reference image -- check log for details");
962 
963 	// Render pass and framebuffers.const DeviceCoreFeature requiredDeviceCoreFeature
964 	return tcu::TestStatus::pass("Pass");
965 }
966 
getDomainOriginName(VkTessellationDomainOrigin value)967 std::string getDomainOriginName(VkTessellationDomainOrigin value)
968 {
969 	static const size_t	prefixLen	= strlen("VK_TESSELLATION_DOMAIN_ORIGIN_");
970 	std::string			nameStr		= getTessellationDomainOriginName(value);
971 
972 	return de::toLower(nameStr.substr(prefixLen));
973 }
974 
975 } // anonymous
976 
977 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
createMiscDrawTests(tcu::TestContext & testCtx)978 tcu::TestCaseGroup* createMiscDrawTests (tcu::TestContext& testCtx)
979 {
980 	// Miscellaneous draw-result-verifying cases
981 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc_draw"));
982 
983 	static const TessPrimitiveType primitivesNoIsolines[] =
984 	{
985 		TESSPRIMITIVETYPE_TRIANGLES,
986 		TESSPRIMITIVETYPE_QUADS,
987 	};
988 
989 	// Triangle fill case
990 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
991 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
992 	{
993 		const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
994 		const SpacingMode		spacingMode	  = static_cast<SpacingMode>(spacingModeNdx);
995 		const std::string		caseName	  = std::string() + "fill_cover_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
996 
997 		// Check that there are no obvious gaps in the triangle-filled area of a tessellated shape
998 		addFunctionCaseWithPrograms(group.get(), caseName,
999 									initProgramsFillCoverCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1000 	}
1001 
1002 	// Triangle non-overlap case
1003 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
1004 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1005 	{
1006 		const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
1007 		const SpacingMode		spacingMode	  = static_cast<SpacingMode>(spacingModeNdx);
1008 		const std::string		caseName	  = std::string() + "fill_overlap_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
1009 
1010 		// Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape
1011 		addFunctionCaseWithPrograms(group.get(), caseName,
1012 									initProgramsFillNonOverlapCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
1013 	}
1014 
1015 	// Isolines
1016 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
1017 	{
1018 		const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
1019 		const std::string caseName    = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
1020 
1021 		// Basic isolines render test
1022 		addFunctionCaseWithPrograms(group.get(), caseName, checkSupportCase,
1023 									initProgramsIsolinesCase, runTest, makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, getReferenceImagePathPrefix(caseName)));
1024 	}
1025 
1026 	// Test switching tessellation parameters on the fly.
1027 	for (const auto& geometryShader : { false, true })
1028 	{
1029 		const auto nameSuffix = (geometryShader ? "_with_geom_shader" : "");
1030 
1031 		static const VkTessellationDomainOrigin domainOrigins[] =
1032 		{
1033 			VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT,
1034 			VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT,
1035 		};
1036 
1037 		for (const auto& firstPrimitiveType : primitivesNoIsolines)
1038 			for (const auto& secondPrimitiveType : primitivesNoIsolines)
1039 			{
1040 				if (firstPrimitiveType == secondPrimitiveType)
1041 					continue;
1042 
1043 				const TessStateSwitchParams params
1044 				{
1045 					std::make_pair(firstPrimitiveType, secondPrimitiveType),
1046 					std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1047 					std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1048 					geometryShader,
1049 				};
1050 
1051 				const auto testName = std::string("switch_primitive_") + getTessPrimitiveTypeShaderName(params.patchTypes.first) + "_to_" + getTessPrimitiveTypeShaderName(params.patchTypes.second) + nameSuffix;
1052 				group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1053 			}
1054 
1055 		for (const auto& firstDomainOrigin : domainOrigins)
1056 			for (const auto& secondDomainOrigin : domainOrigins)
1057 			{
1058 				if (firstDomainOrigin == secondDomainOrigin)
1059 					continue;
1060 
1061 				const TessStateSwitchParams params
1062 				{
1063 					std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1064 					std::make_pair(SPACINGMODE_EQUAL, SPACINGMODE_EQUAL),
1065 					std::make_pair(firstDomainOrigin, secondDomainOrigin),
1066 					geometryShader,
1067 				};
1068 
1069 				const auto testName = std::string("switch_domain_origin_") + getDomainOriginName(params.domainOrigin.first) + "_to_" + getDomainOriginName(params.domainOrigin.second) + nameSuffix;
1070 				group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1071 			}
1072 
1073 		for (int firstSpacingModeNdx = 0; firstSpacingModeNdx < SPACINGMODE_LAST; ++firstSpacingModeNdx)
1074 			for (int secondSpacingModeNdx = 0; secondSpacingModeNdx < SPACINGMODE_LAST; ++secondSpacingModeNdx)
1075 			{
1076 				if (firstSpacingModeNdx == secondSpacingModeNdx)
1077 					continue;
1078 
1079 				const SpacingMode firstSpacingMode	= static_cast<SpacingMode>(firstSpacingModeNdx);
1080 				const SpacingMode secondSpacingMode	= static_cast<SpacingMode>(secondSpacingModeNdx);
1081 
1082 				const TessStateSwitchParams params
1083 				{
1084 					std::make_pair(TESSPRIMITIVETYPE_QUADS, TESSPRIMITIVETYPE_QUADS),
1085 					std::make_pair(firstSpacingMode, secondSpacingMode),
1086 					std::make_pair(VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT, VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT),
1087 					geometryShader,
1088 				};
1089 
1090 				const auto testName = std::string("switch_spacing_mode_") + getSpacingModeShaderName(params.spacing.first) + "_to_" + getSpacingModeShaderName(params.spacing.second) + nameSuffix;
1091 				group->addChild(new TessStateSwitchCase(testCtx, testName, params));
1092 			}
1093 	}
1094 
1095 	return group.release();
1096 }
1097 
1098 } // tessellation
1099 } // vkt
1100