• 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 "vkQueryUtil.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkImageUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkStrUtil.hpp"
40 
41 #include "deUniquePtr.hpp"
42 #include "deStringUtil.hpp"
43 
44 #include <string>
45 #include <vector>
46 
47 namespace vkt
48 {
49 namespace tessellation
50 {
51 
52 using namespace vk;
53 
54 namespace
55 {
56 
57 struct CaseDefinition
58 {
59 	TessPrimitiveType	primitiveType;
60 	SpacingMode			spacingMode;
61 	std::string			referenceImagePathPrefix;	//!< without case suffix and extension (e.g. "_1.png")
62 };
63 
makeCaseDefinition(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const std::string & referenceImagePathPrefix)64 inline CaseDefinition makeCaseDefinition (const TessPrimitiveType	primitiveType,
65 										  const SpacingMode			spacingMode,
66 										  const std::string&		referenceImagePathPrefix)
67 {
68 	CaseDefinition caseDef;
69 	caseDef.primitiveType = primitiveType;
70 	caseDef.spacingMode = spacingMode;
71 	caseDef.referenceImagePathPrefix = referenceImagePathPrefix;
72 	return caseDef;
73 }
74 
genTessLevelCases(const SpacingMode spacingMode)75 std::vector<TessLevels> genTessLevelCases (const SpacingMode spacingMode)
76 {
77 	static const TessLevels tessLevelCases[] =
78 	{
79 		{ { 9.0f,	9.0f	},	{ 9.0f,		9.0f,	9.0f,	9.0f	} },
80 		{ { 8.0f,	11.0f	},	{ 13.0f,	15.0f,	18.0f,	21.0f	} },
81 		{ { 17.0f,	14.0f	},	{ 3.0f,		6.0f,	9.0f,	12.0f	} },
82 	};
83 
84 	std::vector<TessLevels> resultTessLevels(DE_LENGTH_OF_ARRAY(tessLevelCases));
85 
86 	for (int tessLevelCaseNdx = 0; tessLevelCaseNdx < DE_LENGTH_OF_ARRAY(tessLevelCases); ++tessLevelCaseNdx)
87 	{
88 		TessLevels& tessLevels = resultTessLevels[tessLevelCaseNdx];
89 
90 		for (int i = 0; i < 2; ++i)
91 			tessLevels.inner[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].inner[i]));
92 
93 		for (int i = 0; i < 4; ++i)
94 			tessLevels.outer[i] = static_cast<float>(getClampedRoundedTessLevel(spacingMode, tessLevelCases[tessLevelCaseNdx].outer[i]));
95 	}
96 
97 	return resultTessLevels;
98 }
99 
genVertexPositions(const TessPrimitiveType primitiveType)100 std::vector<tcu::Vec2> genVertexPositions (const TessPrimitiveType primitiveType)
101 {
102 	std::vector<tcu::Vec2> positions;
103 	positions.reserve(4);
104 
105 	if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
106 	{
107 		positions.push_back(tcu::Vec2( 0.8f,    0.6f));
108 		positions.push_back(tcu::Vec2( 0.0f, -0.786f));
109 		positions.push_back(tcu::Vec2(-0.8f,    0.6f));
110 	}
111 	else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
112 	{
113 		positions.push_back(tcu::Vec2(-0.8f, -0.8f));
114 		positions.push_back(tcu::Vec2( 0.8f, -0.8f));
115 		positions.push_back(tcu::Vec2(-0.8f,  0.8f));
116 		positions.push_back(tcu::Vec2( 0.8f,  0.8f));
117 	}
118 	else
119 		DE_ASSERT(false);
120 
121 	return positions;
122 }
123 
124 //! Common test function used by all test cases.
runTest(Context & context,const CaseDefinition caseDef)125 tcu::TestStatus runTest (Context& context, const CaseDefinition caseDef)
126 {
127 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
128 
129 	const DeviceInterface&	vk					= context.getDeviceInterface();
130 	const VkDevice			device				= context.getDevice();
131 	const VkQueue			queue				= context.getUniversalQueue();
132 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
133 	Allocator&				allocator			= context.getDefaultAllocator();
134 
135 	const std::vector<TessLevels> tessLevelCases = genTessLevelCases(caseDef.spacingMode);
136 	const std::vector<tcu::Vec2>  vertexData	 = genVertexPositions(caseDef.primitiveType);
137 	const deUint32				  inPatchSize	 = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
138 
139 	// Vertex input: positions
140 
141 	const VkFormat	   vertexFormat		   = VK_FORMAT_R32G32_SFLOAT;
142 	const deUint32	   vertexStride		   = tcu::getPixelSize(mapVkFormat(vertexFormat));
143 	const VkDeviceSize vertexDataSizeBytes = sizeInBytes(vertexData);
144 
145 	const Buffer vertexBuffer(vk, device, allocator,
146 		makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
147 
148 	DE_ASSERT(inPatchSize == vertexData.size());
149 	DE_ASSERT(sizeof(vertexData[0]) == vertexStride);
150 
151 	{
152 		const Allocation& alloc = vertexBuffer.getAllocation();
153 		deMemcpy(alloc.getHostPtr(), &vertexData[0], static_cast<std::size_t>(vertexDataSizeBytes));
154 
155 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
156 		// No barrier needed, flushed memory is automatically visible
157 	}
158 
159 	// Color attachment
160 
161 	const tcu::IVec2			  renderSize				 = tcu::IVec2(256, 256);
162 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
163 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
164 	const Image					  colorAttachmentImage		 (vk, device, allocator,
165 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
166 															 MemoryRequirement::Any);
167 
168 	// Color output buffer: image will be copied here for verification
169 
170 	const VkDeviceSize colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
171 	const Buffer	   colorBuffer			(vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
172 
173 	// Input buffer: tessellation levels. Data is filled in later.
174 
175 	const Buffer tessLevelsBuffer(vk, device, allocator,
176 		makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
177 
178 	// Descriptors
179 
180 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
181 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
182 		.build(vk, device));
183 
184 	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
185 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
186 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
187 
188 	const Unique<VkDescriptorSet> descriptorSet(makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
189 
190 	const VkDescriptorBufferInfo tessLevelsBufferInfo = makeDescriptorBufferInfo(tessLevelsBuffer.get(), 0ull, sizeof(TessLevels));
191 
192 	DescriptorSetUpdateBuilder()
193 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
194 		.update(vk, device);
195 
196 	// Pipeline
197 
198 	const Unique<VkImageView>		colorAttachmentView	(makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
199 	const Unique<VkRenderPass>		renderPass			(makeRenderPass(vk, device, colorFormat));
200 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
201 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout(vk, device, *descriptorSetLayout));
202 	const Unique<VkCommandPool>		cmdPool				(makeCommandPool(vk, device, queueFamilyIndex));
203 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
204 
205 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
206 		.setRenderSize				  (renderSize)
207 		.setVertexInputSingleAttribute(vertexFormat, vertexStride)
208 		.setPatchControlPoints		  (inPatchSize)
209 		.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
210 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
211 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
212 		.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL)
213 		.build						  (vk, device, *pipelineLayout, *renderPass));
214 
215 	// Draw commands
216 
217 	deUint32 numPassedCases = 0;
218 
219 	for (deUint32 tessLevelCaseNdx = 0; tessLevelCaseNdx < tessLevelCases.size(); ++tessLevelCaseNdx)
220 	{
221 		context.getTestContext().getLog()
222 			<< tcu::TestLog::Message
223 			<< "Tessellation levels: " << getTessellationLevelsString(tessLevelCases[tessLevelCaseNdx], caseDef.primitiveType)
224 			<< tcu::TestLog::EndMessage;
225 
226 		// Upload tessellation levels data to the input buffer
227 		{
228 			const Allocation& alloc = tessLevelsBuffer.getAllocation();
229 			TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
230 			*bufferTessLevels = tessLevelCases[tessLevelCaseNdx];
231 			flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
232 		}
233 
234 		// Reset the command buffer and begin recording.
235 		beginCommandBuffer(vk, *cmdBuffer);
236 
237 		// Change color attachment image layout
238 		{
239 			// State is slightly different on the first iteration.
240 			const VkImageLayout currentLayout = (tessLevelCaseNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
241 			const VkAccessFlags srcFlags	  = (tessLevelCaseNdx == 0 ? (VkAccessFlags)0 : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
242 
243 			const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
244 				srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
245 				currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
246 				*colorAttachmentImage, colorImageSubresourceRange);
247 
248 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
249 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
250 		}
251 
252 		// Begin render pass
253 		{
254 			const VkRect2D renderArea = {
255 				makeOffset2D(0, 0),
256 				makeExtent2D(renderSize.x(), renderSize.y()),
257 			};
258 			const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
259 
260 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
261 		}
262 
263 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
264 		vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
265 		{
266 			const VkDeviceSize vertexBufferOffset = 0ull;
267 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
268 		}
269 
270 		// Process enough vertices to make a patch.
271 		vk.cmdDraw(*cmdBuffer, inPatchSize, 1u, 0u, 0u);
272 		endRenderPass(vk, *cmdBuffer);
273 
274 		// Copy render result to a host-visible buffer
275 		{
276 			const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
277 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
278 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
279 				*colorAttachmentImage, colorImageSubresourceRange);
280 
281 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
282 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
283 		}
284 		{
285 			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
286 			vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
287 		}
288 		{
289 			const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
290 				VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
291 
292 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
293 				0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
294 		}
295 
296 		endCommandBuffer(vk, *cmdBuffer);
297 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
298 
299 		{
300 			const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
301 			invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes);
302 
303 			// Verify case result
304 			const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
305 
306 			// Load reference image
307 			const std::string referenceImagePath = caseDef.referenceImagePathPrefix + "_" + de::toString(tessLevelCaseNdx) + ".png";
308 			tcu::TextureLevel referenceImage;
309 			tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), referenceImagePath.c_str());
310 
311 			if (tcu::fuzzyCompare(context.getTestContext().getLog(), "ImageComparison", "Image Comparison",
312 								  referenceImage.getAccess(), resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT))
313 				++numPassedCases;
314 		}
315 	} // tessLevelCaseNdx
316 
317 	return (numPassedCases == tessLevelCases.size() ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
318 }
319 
getTessLevelsSSBODeclaration(void)320 inline const char* getTessLevelsSSBODeclaration (void)
321 {
322 	return	"layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
323 			"    float inner0;\n"
324 			"    float inner1;\n"
325 			"    float outer0;\n"
326 			"    float outer1;\n"
327 			"    float outer2;\n"
328 			"    float outer3;\n"
329 			"} sb_levels;\n";
330 }
331 
332 //! Add vertex, fragment, and tessellation control shaders.
initCommonPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)333 void initCommonPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
334 {
335 	DE_ASSERT(!programCollection.glslSources.contains("vert"));
336 	DE_ASSERT(!programCollection.glslSources.contains("tesc"));
337 	DE_ASSERT(!programCollection.glslSources.contains("frag"));
338 
339 	// Vertex shader
340 	{
341 		std::ostringstream src;
342 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
343 			<< "\n"
344 			<< "layout(location = 0) in  highp vec2 in_v_position;\n"
345 			<< "layout(location = 0) out highp vec2 in_tc_position;\n"
346 			<< "\n"
347 			<< "void main (void)\n"
348 			<< "{\n"
349 			<< "    in_tc_position = in_v_position;\n"
350 			<< "}\n";
351 
352 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
353 	}
354 
355 	// Tessellation control shader
356 	{
357 		const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
358 
359 		std::ostringstream src;
360 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
361 			<< "#extension GL_EXT_tessellation_shader : require\n"
362 			<< "\n"
363 			<< "layout(vertices = " << numVertices << ") out;\n"
364 			<< "\n"
365 			<< getTessLevelsSSBODeclaration()
366 			<< "\n"
367 			<< "layout(location = 0) in  highp vec2 in_tc_position[];\n"
368 			<< "layout(location = 0) out highp vec2 in_te_position[];\n"
369 			<< "\n"
370 			<< "void main (void)\n"
371 			<< "{\n"
372 			<< "    in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
373 			<< "\n"
374 			<< "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
375 			<< "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
376 			<< "\n"
377 			<< "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
378 			<< "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
379 			<< "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
380 			<< "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
381 			<< "}\n";
382 
383 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
384 	}
385 
386 	// Fragment shader
387 	{
388 		std::ostringstream src;
389 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
390 			<< "\n"
391 			<< "layout(location = 0) in  highp   vec4 in_f_color;\n"
392 			<< "layout(location = 0) out mediump vec4 o_color;\n"
393 			<< "\n"
394 			<< "void main (void)\n"
395 			<< "{\n"
396 			<< "    o_color = in_f_color;\n"
397 			<< "}\n";
398 
399 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
400 	}
401 }
402 
initProgramsFillCoverCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)403 void initProgramsFillCoverCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
404 {
405 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
406 
407 	initCommonPrograms(programCollection, caseDef);
408 
409 	// Tessellation evaluation shader
410 	{
411 		std::ostringstream src;
412 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
413 			<< "#extension GL_EXT_tessellation_shader : require\n"
414 			<< "\n"
415 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
416 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
417 			<< "\n"
418 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
419 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
420 			<< "\n"
421 			<< "void main (void)\n"
422 			<< "{\n"
423 			<<	(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
424 					"    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
425 					"    highp vec2 corner0 = in_te_position[0];\n"
426 					"    highp vec2 corner1 = in_te_position[1];\n"
427 					"    highp vec2 corner2 = in_te_position[2];\n"
428 					"    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
429 					"    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2) / 3.0;\n"
430 					"    highp float f = (1.0 - length(fromCenter)) * (1.5 - d);\n"
431 					"    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
432 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
433 				: caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
434 					"    highp vec2 corner0 = in_te_position[0];\n"
435 					"    highp vec2 corner1 = in_te_position[1];\n"
436 					"    highp vec2 corner2 = in_te_position[2];\n"
437 					"    highp vec2 corner3 = in_te_position[3];\n"
438 					"    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
439 					"                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
440 					"                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
441 					"                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
442 					"    highp float d = 2.0 * min(abs(gl_TessCoord.x-0.5), abs(gl_TessCoord.y-0.5));\n"
443 					"    highp vec2 fromCenter = pos - (corner0 + corner1 + corner2 + corner3) / 4.0;\n"
444 					"    highp float f = (1.0 - length(fromCenter)) * sqrt(1.7 - d);\n"
445 					"    pos += 0.75 * f * fromCenter / (length(fromCenter) + 0.3);\n"
446 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
447 				: "")
448 			<< "    in_f_color = vec4(1.0);\n"
449 			<< "}\n";
450 
451 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
452 	}
453 }
454 
initProgramsFillNonOverlapCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)455 void initProgramsFillNonOverlapCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
456 {
457 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
458 
459 	initCommonPrograms(programCollection, caseDef);
460 
461 	// Tessellation evaluation shader
462 	{
463 		std::ostringstream src;
464 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
465 			<< "#extension GL_EXT_tessellation_shader : require\n"
466 			<< "\n"
467 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
468 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
469 			<< "\n"
470 			<< getTessLevelsSSBODeclaration()
471 			<< "\n"
472 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
473 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
474 			<< "\n"
475 			<< "void main (void)\n"
476 			<< "{\n"
477 			<<	(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
478 					"    highp vec2 corner0 = in_te_position[0];\n"
479 					"    highp vec2 corner1 = in_te_position[1];\n"
480 					"    highp vec2 corner2 = in_te_position[2];\n"
481 					"    highp vec2 pos =  corner0*gl_TessCoord.x + corner1*gl_TessCoord.y + corner2*gl_TessCoord.z;\n"
482 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
483 					"    highp int numConcentricTriangles = int(round(sb_levels.inner0)) / 2 + 1;\n"
484 					"    highp float d = 3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z));\n"
485 					"    highp int phase = int(d*float(numConcentricTriangles)) % 3;\n"
486 					"    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
487 					"               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
488 					"               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
489 				: caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
490 					"    highp vec2 corner0 = in_te_position[0];\n"
491 					"    highp vec2 corner1 = in_te_position[1];\n"
492 					"    highp vec2 corner2 = in_te_position[2];\n"
493 					"    highp vec2 corner3 = in_te_position[3];\n"
494 					"    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
495 					"                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
496 					"                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
497 					"                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
498 					"    gl_Position = vec4(pos, 0.0, 1.0);\n"
499 					"    highp int phaseX = int(round((0.5 - abs(gl_TessCoord.x-0.5)) * sb_levels.inner0));\n"
500 					"    highp int phaseY = int(round((0.5 - abs(gl_TessCoord.y-0.5)) * sb_levels.inner1));\n"
501 					"    highp int phase = min(phaseX, phaseY) % 3;\n"
502 					"    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
503 					"               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
504 					"               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
505 					: "")
506 			<< "}\n";
507 
508 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
509 	}
510 }
511 
initProgramsIsolinesCase(vk::SourceCollections & programCollection,const CaseDefinition caseDef)512 void initProgramsIsolinesCase (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
513 {
514 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_ISOLINES);
515 
516 	initCommonPrograms(programCollection, caseDef);
517 
518 	// Tessellation evaluation shader
519 	{
520 		std::ostringstream src;
521 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
522 			<< "#extension GL_EXT_tessellation_shader : require\n"
523 			<< "\n"
524 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
525 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
526 			<< "\n"
527 			<< getTessLevelsSSBODeclaration()
528 			<< "\n"
529 			<< "layout(location = 0) in  highp vec2 in_te_position[];\n"
530 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
531 			<< "\n"
532 			<< "void main (void)\n"
533 			<< "{\n"
534 			<< "    highp vec2 corner0 = in_te_position[0];\n"
535 			<< "    highp vec2 corner1 = in_te_position[1];\n"
536 			<< "    highp vec2 corner2 = in_te_position[2];\n"
537 			<< "    highp vec2 corner3 = in_te_position[3];\n"
538 			<< "    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner0\n"
539 			<< "                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*corner1\n"
540 			<< "                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*corner2\n"
541 			<< "                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*corner3;\n"
542 			<< "    pos.y += 0.15*sin(gl_TessCoord.x*10.0);\n"
543 			<< "    gl_Position = vec4(pos, 0.0, 1.0);\n"
544 			<< "    highp int phaseX = int(round(gl_TessCoord.x*sb_levels.outer1));\n"
545 			<< "    highp int phaseY = int(round(gl_TessCoord.y*sb_levels.outer0));\n"
546 			<< "    highp int phase = (phaseX + phaseY) % 3;\n"
547 			<< "    in_f_color = phase == 0 ? vec4(1.0, 0.0, 0.0, 1.0)\n"
548 			<< "               : phase == 1 ? vec4(0.0, 1.0, 0.0, 1.0)\n"
549 			<< "               :              vec4(0.0, 0.0, 1.0, 1.0);\n"
550 			<< "}\n";
551 
552 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
553 	}
554 }
555 
getReferenceImagePathPrefix(const std::string & caseName)556 inline std::string getReferenceImagePathPrefix (const std::string& caseName)
557 {
558 	return "vulkan/data/tessellation/" + caseName + "_ref";
559 }
560 
561 } // anonymous
562 
563 //! These tests correspond to dEQP-GLES31.functional.tessellation.misc_draw.*
createMiscDrawTests(tcu::TestContext & testCtx)564 tcu::TestCaseGroup* createMiscDrawTests (tcu::TestContext& testCtx)
565 {
566 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "misc_draw", "Miscellaneous draw-result-verifying cases"));
567 
568 	static const TessPrimitiveType primitivesNoIsolines[] =
569 	{
570 		TESSPRIMITIVETYPE_TRIANGLES,
571 		TESSPRIMITIVETYPE_QUADS,
572 	};
573 
574 	// Triangle fill case
575 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
576 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
577 	{
578 		const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
579 		const SpacingMode		spacingMode	  = static_cast<SpacingMode>(spacingModeNdx);
580 		const std::string		caseName	  = std::string() + "fill_cover_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
581 
582 		addFunctionCaseWithPrograms(group.get(), caseName, "Check that there are no obvious gaps in the triangle-filled area of a tessellated shape",
583 									initProgramsFillCoverCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
584 	}
585 
586 	// Triangle non-overlap case
587 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitivesNoIsolines); ++primitiveTypeNdx)
588 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
589 	{
590 		const TessPrimitiveType primitiveType = primitivesNoIsolines[primitiveTypeNdx];
591 		const SpacingMode		spacingMode	  = static_cast<SpacingMode>(spacingModeNdx);
592 		const std::string		caseName	  = std::string() + "fill_overlap_" + getTessPrimitiveTypeShaderName(primitiveType) + "_" + getSpacingModeShaderName(spacingMode);
593 
594 		addFunctionCaseWithPrograms(group.get(), caseName, "Check that there are no obvious triangle overlaps in the triangle-filled area of a tessellated shape",
595 									initProgramsFillNonOverlapCase, runTest, makeCaseDefinition(primitiveType, spacingMode, getReferenceImagePathPrefix(caseName)));
596 	}
597 
598 	// Isolines
599 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
600 	{
601 		const SpacingMode spacingMode = static_cast<SpacingMode>(spacingModeNdx);
602 		const std::string caseName    = std::string() + "isolines_" + getSpacingModeShaderName(spacingMode);
603 
604 		addFunctionCaseWithPrograms(group.get(), caseName, "Basic isolines render test",
605 									initProgramsIsolinesCase, runTest, makeCaseDefinition(TESSPRIMITIVETYPE_ISOLINES, spacingMode, getReferenceImagePathPrefix(caseName)));
606 	}
607 
608 	return group.release();
609 }
610 
611 } // tessellation
612 } // vkt
613