• 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 Shader Input/Output Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationShaderInputOutputTests.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 
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 
47 #include <string>
48 #include <vector>
49 
50 namespace vkt
51 {
52 namespace tessellation
53 {
54 
55 using namespace vk;
56 
57 namespace
58 {
59 
60 enum Constants
61 {
62 	RENDER_SIZE = 256,
63 };
64 
65 //! Generic test code used by all test cases.
runTest(Context & context,const int numPrimitives,const int inPatchSize,const int outPatchSize,const VkFormat vertexFormat,const void * vertexData,const VkDeviceSize vertexDataSizeBytes,const tcu::ConstPixelBufferAccess & referenceImageAccess)66 tcu::TestStatus runTest (Context&							context,
67 						 const int							numPrimitives,
68 						 const int							inPatchSize,
69 						 const int							outPatchSize,
70 						 const VkFormat						vertexFormat,
71 						 const void*						vertexData,
72 						 const VkDeviceSize					vertexDataSizeBytes,
73 						 const tcu::ConstPixelBufferAccess&	referenceImageAccess)
74 {
75 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
76 
77 	const DeviceInterface&	vk					= context.getDeviceInterface();
78 	const VkDevice			device				= context.getDevice();
79 	const VkQueue			queue				= context.getUniversalQueue();
80 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
81 	Allocator&				allocator			= context.getDefaultAllocator();
82 
83 	// Vertex input: may be just some abstract numbers
84 
85 	const Buffer vertexBuffer(vk, device, allocator,
86 		makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
87 
88 	{
89 		const Allocation& alloc = vertexBuffer.getAllocation();
90 
91 		deMemcpy(alloc.getHostPtr(), vertexData, static_cast<std::size_t>(vertexDataSizeBytes));
92 		flushAlloc(vk, device, alloc);
93 		// No barrier needed, flushed memory is automatically visible
94 	}
95 
96 	// Color attachment
97 
98 	const tcu::IVec2			  renderSize				 = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
99 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
100 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
101 	const Image					  colorAttachmentImage		 (vk, device, allocator,
102 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
103 															 MemoryRequirement::Any);
104 
105 	// Color output buffer: image will be copied here for verification
106 
107 	const VkDeviceSize	colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
108 	const Buffer		colorBuffer			 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
109 
110 	// Pipeline
111 
112 	const Unique<VkImageView>		colorAttachmentView	(makeImageView			(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
113 	const Unique<VkRenderPass>		renderPass			(makeRenderPass			(vk, device, colorFormat));
114 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer		(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
115 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout		(vk, device));
116 	const Unique<VkCommandPool>		cmdPool				(makeCommandPool		(vk, device, queueFamilyIndex));
117 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer	(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
118 
119 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
120 		.setRenderSize				  (renderSize)
121 		.setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
122 		.setPatchControlPoints		  (inPatchSize)
123 		.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
124 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
125 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
126 		.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL)
127 		.build						  (vk, device, *pipelineLayout, *renderPass));
128 
129 	{
130 		tcu::TestLog& log = context.getTestContext().getLog();
131 		log << tcu::TestLog::Message
132 			<< "Note: input patch size is " << inPatchSize << ", output patch size is " << outPatchSize
133 			<< tcu::TestLog::EndMessage;
134 	}
135 
136 	// Draw commands
137 
138 	beginCommandBuffer(vk, *cmdBuffer);
139 
140 	// Change color attachment image layout
141 	{
142 		const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
143 			(VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
144 			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
145 			*colorAttachmentImage, colorImageSubresourceRange);
146 
147 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
148 			0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
149 	}
150 
151 	// Begin render pass
152 	{
153 		const VkRect2D	renderArea	= makeRect2D(renderSize);
154 		const tcu::Vec4	clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
155 
156 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
157 	}
158 
159 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
160 	{
161 		const VkDeviceSize vertexBufferOffset = 0ull;
162 		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
163 	}
164 
165 	// Process enough vertices to make a patch.
166 	vk.cmdDraw(*cmdBuffer, numPrimitives * inPatchSize, 1u, 0u, 0u);
167 	endRenderPass(vk, *cmdBuffer);
168 
169 	// Copy render result to a host-visible buffer
170 	copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
171 
172 	endCommandBuffer(vk, *cmdBuffer);
173 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
174 
175 	{
176 		const Allocation&					colorBufferAlloc	= colorBuffer.getAllocation();
177 
178 		invalidateAlloc(vk, device, colorBufferAlloc);
179 
180 		// Verify case result
181 		const tcu::ConstPixelBufferAccess	resultImageAccess	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
182 		tcu::TestLog&						log					= context.getTestContext().getLog();
183 		const bool							ok					= tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", referenceImageAccess, resultImageAccess,
184 																  0.002f, tcu::COMPARE_LOG_RESULT);
185 
186 		return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
187 	}
188 }
189 
190 //! Resize an image and fill with white color.
initializeWhiteReferenceImage(tcu::TextureLevel & image,const int width,const int height)191 void initializeWhiteReferenceImage (tcu::TextureLevel& image, const int width, const int height)
192 {
193 	DE_ASSERT(width > 0 && height > 0);
194 
195 	image.setStorage(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), width, height);
196 	tcu::PixelBufferAccess access = image.getAccess();
197 
198 	const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f);
199 
200 	for (int y = 0; y < height; ++y)
201 	for (int x = 0; x < width; ++x)
202 		access.setPixel(white, x, y);
203 }
204 
205 namespace PatchVertexCount
206 {
207 
208 struct CaseDefinition
209 {
210 	int				inPatchSize;
211 	int				outPatchSize;
212 	std::string		referenceImagePath;
213 };
214 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)215 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
216 {
217 	// Vertex shader
218 	{
219 		std::ostringstream src;
220 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
221 			<< "\n"
222 			<< "layout(location = 0) in  highp float in_v_attr;\n"
223 			<< "layout(location = 0) out highp float in_tc_attr;\n"
224 			<< "\n"
225 			<< "void main (void)\n"
226 			<< "{\n"
227 			<< "    in_tc_attr = in_v_attr;\n"
228 			<< "}\n";
229 
230 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
231 	}
232 
233 	// Tessellation control shader
234 	{
235 		std::ostringstream src;
236 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
237 			<< "#extension GL_EXT_tessellation_shader : require\n"
238 			<< "\n"
239 			<< "layout(vertices = " << caseDef.outPatchSize << ") out;\n"
240 			<< "\n"
241 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
242 			<< "layout(location = 0) out highp float in_te_attr[];\n"
243 			<< "\n"
244 			<< "void main (void)\n"
245 			<< "{\n"
246 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" << caseDef.inPatchSize << "/" << caseDef.outPatchSize << "];\n"
247 			<< "\n"
248 			<< "    gl_TessLevelInner[0] = 5.0;\n"
249 			<< "    gl_TessLevelInner[1] = 5.0;\n"
250 			<< "\n"
251 			<< "    gl_TessLevelOuter[0] = 5.0;\n"
252 			<< "    gl_TessLevelOuter[1] = 5.0;\n"
253 			<< "    gl_TessLevelOuter[2] = 5.0;\n"
254 			<< "    gl_TessLevelOuter[3] = 5.0;\n"
255 			<< "}\n";
256 
257 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
258 	}
259 
260 	// Tessellation evaluation shader
261 	{
262 		std::ostringstream src;
263 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
264 			<< "#extension GL_EXT_tessellation_shader : require\n"
265 			<< "\n"
266 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
267 			<< "\n"
268 			<< "layout(location = 0) in  highp   float in_te_attr[];\n"
269 			<< "layout(location = 0) out mediump vec4  in_f_color;\n"
270 			<< "\n"
271 			<< "void main (void)\n"
272 			<< "{\n"
273 			<< "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
274 			<< "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << caseDef.outPatchSize << "-1)))];\n"
275 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
276 			<< "    in_f_color = vec4(1.0);\n"
277 			<< "}\n";
278 
279 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
280 	}
281 
282 	// Fragment shader
283 	{
284 		std::ostringstream src;
285 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
286 			<< "\n"
287 			<< "layout(location = 0) in  mediump vec4 in_f_color;\n"
288 			<< "layout(location = 0) out mediump vec4 o_color;\n"
289 			<< "\n"
290 			<< "void main (void)\n"
291 			<< "{\n"
292 			<< "    o_color = in_f_color;\n"
293 			<< "}\n";
294 
295 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
296 	}
297 }
298 
test(Context & context,const CaseDefinition caseDef)299 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
300 {
301 	// Input vertex attribute data
302 	std::vector<float> vertexData;
303 	vertexData.reserve(caseDef.inPatchSize);
304 	for (int i = 0; i < caseDef.inPatchSize; ++i)
305 	{
306 		const float f = static_cast<float>(i) / static_cast<float>(caseDef.inPatchSize - 1);
307 		vertexData.push_back(f*f);
308 	}
309 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
310 
311 	// Load reference image
312 	tcu::TextureLevel referenceImage;
313 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str());
314 
315 	const int numPrimitives = 1;
316 
317 	return runTest(context, numPrimitives, caseDef.inPatchSize, caseDef.outPatchSize,
318 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
319 }
320 
321 } // PatchVertexCountTest ns
322 
323 namespace PerPatchData
324 {
325 
326 enum CaseType
327 {
328 	CASETYPE_PRIMITIVE_ID_TCS,
329 	CASETYPE_PRIMITIVE_ID_TES,
330 	CASETYPE_PATCH_VERTICES_IN_TCS,
331 	CASETYPE_PATCH_VERTICES_IN_TES,
332 	CASETYPE_TESS_LEVEL_INNER0_TES,
333 	CASETYPE_TESS_LEVEL_INNER1_TES,
334 	CASETYPE_TESS_LEVEL_OUTER0_TES,
335 	CASETYPE_TESS_LEVEL_OUTER1_TES,
336 	CASETYPE_TESS_LEVEL_OUTER2_TES,
337 	CASETYPE_TESS_LEVEL_OUTER3_TES,
338 };
339 
340 enum Constants
341 {
342 	OUTPUT_PATCH_SIZE	= 5,
343 	INPUT_PATCH_SIZE	= 10,
344 };
345 
346 struct CaseDefinition
347 {
348 	CaseType		caseType;
349 	std::string		caseName;
350 	bool			usesReferenceImageFromFile;
351 	std::string		referenceImagePath;
352 	std::string		caseDescription;
353 };
354 
getNumPrimitives(const CaseType type)355 int getNumPrimitives (const CaseType type)
356 {
357 	return (type == CASETYPE_PRIMITIVE_ID_TCS || type == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1);
358 }
359 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)360 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
361 {
362 	// Vertex shader
363 	{
364 		std::ostringstream src;
365 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
366 			<< "\n"
367 			<< "layout(location = 0) in  highp float in_v_attr;\n"
368 			<< "layout(location = 0) out highp float in_tc_attr;\n"
369 			<< "\n"
370 			<< "void main (void)\n"
371 			<< "{\n"
372 			<< "    in_tc_attr = in_v_attr;\n"
373 			<< "}\n";
374 
375 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
376 	}
377 
378 	// Tessellation control shader
379 	{
380 		std::ostringstream src;
381 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
382 			<< "#extension GL_EXT_tessellation_shader : require\n"
383 			<< "\n"
384 			<< "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n"
385 			<< "\n"
386 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
387 			<< "layout(location = 0) out highp float in_te_attr[];\n"
388 			<< "\n"
389 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "layout(location = 1) patch out mediump int in_te_primitiveIDFromTCS;\n" :
390 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch out mediump int in_te_patchVerticesInFromTCS;\n" : "")
391 			<< "\n"
392 			<< "void main (void)\n"
393 			<< "{\n"
394 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
395 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "    in_te_primitiveIDFromTCS = gl_PrimitiveID;\n" :
396 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "    in_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n" : "")
397 			<< "\n"
398 			<< "    gl_TessLevelInner[0] = 9.0;\n"
399 			<< "    gl_TessLevelInner[1] = 8.0;\n"
400 			<< "\n"
401 			<< "    gl_TessLevelOuter[0] = 7.0;\n"
402 			<< "    gl_TessLevelOuter[1] = 6.0;\n"
403 			<< "    gl_TessLevelOuter[2] = 5.0;\n"
404 			<< "    gl_TessLevelOuter[3] = 4.0;\n"
405 			<< "}\n";
406 
407 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
408 	}
409 
410 	// Tessellation evaluation shader
411 	{
412 		const float xScale = 1.0f / static_cast<float>(getNumPrimitives(caseDef.caseType));
413 
414 		std::ostringstream src;
415 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
416 			<< "#extension GL_EXT_tessellation_shader : require\n"
417 			<< "\n"
418 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
419 			<< "\n"
420 			<< "layout(location = 0) in  highp   float in_te_attr[];\n"
421 			<< "layout(location = 0) out mediump vec4  in_f_color;\n"
422 			<< "\n"
423 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "layout(location = 1) patch in mediump int in_te_primitiveIDFromTCS;\n" :
424 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch in mediump int in_te_patchVerticesInFromTCS;\n" : "")
425 			<< "\n"
426 			<< "void main (void)\n"
427 			<< "{\n"
428 			<< "    highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n"
429 			<< "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
430 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
431 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS		? "    bool ok = in_te_primitiveIDFromTCS == 3;\n" :
432 				caseDef.caseType == CASETYPE_PRIMITIVE_ID_TES		? "    bool ok = gl_PrimitiveID == 3;\n" :
433 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "    bool ok = in_te_patchVerticesInFromTCS == " + de::toString(INPUT_PATCH_SIZE) + ";\n" :
434 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TES	? "    bool ok = gl_PatchVerticesIn == " + de::toString(OUTPUT_PATCH_SIZE) + ";\n" :
435 				caseDef.caseType == CASETYPE_TESS_LEVEL_INNER0_TES	? "    bool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n" :
436 				caseDef.caseType == CASETYPE_TESS_LEVEL_INNER1_TES	? "    bool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n" :
437 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER0_TES	? "    bool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n" :
438 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER1_TES	? "    bool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n" :
439 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER2_TES	? "    bool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n" :
440 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER3_TES	? "    bool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n" : "")
441 			<< "    in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
442 			<< "}\n";
443 
444 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
445 	}
446 
447 	// Fragment shader
448 	{
449 		std::ostringstream src;
450 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
451 			<< "\n"
452 			<< "layout(location = 0) in  mediump vec4 in_f_color;\n"
453 			<< "layout(location = 0) out mediump vec4 o_color;\n"
454 			<< "\n"
455 			<< "void main (void)\n"
456 			<< "{\n"
457 			<< "    o_color = in_f_color;\n"
458 			<< "}\n";
459 
460 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
461 	}
462 }
463 
test(Context & context,const CaseDefinition caseDef)464 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
465 {
466 	DE_ASSERT(!caseDef.usesReferenceImageFromFile || !caseDef.referenceImagePath.empty());
467 
468 	// Input vertex attribute data
469 	const int		   numPrimitives	= getNumPrimitives(caseDef.caseType);
470 	std::vector<float> vertexData		(INPUT_PATCH_SIZE * numPrimitives, 0.0f);
471 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
472 
473 	for (int i = 0; i < numPrimitives; ++i)
474 		vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives);
475 
476 	tcu::TextureLevel referenceImage;
477 	if (caseDef.usesReferenceImageFromFile)
478 		tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str());
479 	else
480 		initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE);
481 
482 	return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE,
483 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
484 }
485 
486 } // PerPatchData ns
487 
488 namespace GLPosition
489 {
490 
491 enum CaseType
492 {
493 	CASETYPE_VS_TO_TCS = 0,
494 	CASETYPE_TCS_TO_TES,
495 	CASETYPE_VS_TO_TCS_TO_TES,
496 };
497 
initPrograms(vk::SourceCollections & programCollection,const CaseType caseType)498 void initPrograms (vk::SourceCollections& programCollection, const CaseType caseType)
499 {
500 	const bool vsToTCS  = caseType == CASETYPE_VS_TO_TCS  || caseType == CASETYPE_VS_TO_TCS_TO_TES;
501 	const bool tcsToTES = caseType == CASETYPE_TCS_TO_TES || caseType == CASETYPE_VS_TO_TCS_TO_TES;
502 
503 	// Vertex shader
504 	{
505 		std::ostringstream src;
506 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
507 			<< "\n"
508 			<< "layout(location = 0) in  highp vec4 in_v_attr;\n"
509 			<< (!vsToTCS ? "layout(location = 0) out highp vec4 in_tc_attr;\n" : "")
510 			<< "\n"
511 			<< "void main (void)\n"
512 			<< "{\n"
513 			<< "    " << (vsToTCS ? "gl_Position" : "in_tc_attr") << " = in_v_attr;\n"
514 			<< "}\n";
515 
516 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
517 	}
518 
519 	// Tessellation control shader
520 	{
521 		std::ostringstream src;
522 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
523 			<< "#extension GL_EXT_tessellation_shader : require\n"
524 			<< "\n"
525 			<< "layout(vertices = 3) out;\n"
526 			<< "\n"
527 			<< (!vsToTCS  ? "layout(location = 0) in  highp vec4 in_tc_attr[];\n" : "")
528 			<< (!tcsToTES ? "layout(location = 0) out highp vec4 in_te_attr[];\n" : "")
529 			<< "\n"
530 			<< "void main (void)\n"
531 			<< "{\n"
532 			<< "    " << (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") << " = "
533 					  << (vsToTCS  ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") << ";\n"
534 			<< "\n"
535 			<< "    gl_TessLevelInner[0] = 2.0;\n"
536 			<< "    gl_TessLevelInner[1] = 3.0;\n"
537 			<< "\n"
538 			<< "    gl_TessLevelOuter[0] = 4.0;\n"
539 			<< "    gl_TessLevelOuter[1] = 5.0;\n"
540 			<< "    gl_TessLevelOuter[2] = 6.0;\n"
541 			<< "    gl_TessLevelOuter[3] = 7.0;\n"
542 			<< "}\n";
543 
544 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
545 	}
546 
547 	// Tessellation evaluation shader
548 	{
549 		const std::string tesIn0 = tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
550 		const std::string tesIn1 = tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
551 		const std::string tesIn2 = tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
552 
553 		std::ostringstream src;
554 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
555 			<< "#extension GL_EXT_tessellation_shader : require\n"
556 			<< "\n"
557 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_TRIANGLES) << ") in;\n"
558 			<< "\n"
559 			<< (!tcsToTES ? "layout(location = 0) in  highp vec4 in_te_attr[];\n" : "")
560 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
561 			<< "\n"
562 			<< "void main (void)\n"
563 			<< "{\n"
564 			<< "    highp vec2 xy = gl_TessCoord.x * " << tesIn0 << ".xy\n"
565 			<< "                  + gl_TessCoord.y * " << tesIn1 << ".xy\n"
566 			<< "                  + gl_TessCoord.z * " << tesIn2 << ".xy;\n"
567 			<< "    gl_Position = vec4(xy, 0.0, 1.0);\n"
568 			<< "    in_f_color = vec4(" << tesIn0 << ".z + " << tesIn1 << ".w,\n"
569 			<< "                      " << tesIn2 << ".z + " << tesIn0 << ".w,\n"
570 			<< "                      " << tesIn1 << ".z + " << tesIn2 << ".w,\n"
571 			<< "                      1.0);\n"
572 			<< "}\n";
573 
574 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
575 	}
576 
577 	// Fragment shader
578 	{
579 		std::ostringstream src;
580 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
581 			<< "\n"
582 			<< "layout(location = 0) in  highp   vec4 in_f_color;\n"
583 			<< "layout(location = 0) out mediump vec4 o_color;\n"
584 			<< "\n"
585 			<< "void main (void)\n"
586 			<< "{\n"
587 			<< "    o_color = in_f_color;\n"
588 			<< "}\n";
589 
590 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
591 	}
592 }
593 
test(Context & context,const CaseType caseType)594 tcu::TestStatus test (Context& context, const CaseType caseType)
595 {
596 	DE_UNREF(caseType);
597 
598 	// Input vertex attribute data
599 	static const float vertexData[3*4] =
600 	{
601 		-0.8f, -0.7f, 0.1f, 0.7f,
602 		-0.5f,  0.4f, 0.2f, 0.5f,
603 		 0.3f,  0.2f, 0.3f, 0.45f
604 	};
605 
606 	tcu::TextureLevel referenceImage;
607 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/gl_position_ref.png");
608 
609 	const int numPrimitives = 1;
610 	const int inPatchSize   = 3;
611 	const int outPatchSize  = 3;
612 
613 	return runTest(context, numPrimitives, inPatchSize, outPatchSize,
614 				   VK_FORMAT_R32G32B32A32_SFLOAT, vertexData, sizeof(vertexData), referenceImage.getAccess());
615 }
616 
617 } // GLPosition ns
618 
619 namespace Barrier
620 {
621 
622 enum Constants
623 {
624 	NUM_VERTICES = 32,
625 };
626 
initPrograms(vk::SourceCollections & programCollection)627 void initPrograms (vk::SourceCollections& programCollection)
628 {
629 	// Vertex shader
630 	{
631 		std::ostringstream src;
632 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
633 			<< "\n"
634 			<< "layout(location = 0) in  highp float in_v_attr;\n"
635 			<< "layout(location = 0) out highp float in_tc_attr;\n"
636 			<< "\n"
637 			<< "void main (void)\n"
638 			<< "{\n"
639 			<< "    in_tc_attr = in_v_attr;\n"
640 			<< "}\n";
641 
642 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
643 	}
644 
645 	// Tessellation control shader
646 	{
647 		std::ostringstream src;
648 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
649 			<< "#extension GL_EXT_tessellation_shader : require\n"
650 			<< "\n"
651 			<< "layout(vertices = " << NUM_VERTICES << ") out;\n"
652 			<< "\n"
653 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
654 			<< "layout(location = 0) out highp float in_te_attr[];\n"
655 			<< "\n"
656 			<< "layout(location = 1) patch out highp float in_te_patchAttr;\n"
657 			<< "\n"
658 			<< "void main (void)\n"
659 			<< "{\n"
660 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
661 			<< "    in_te_patchAttr = 0.0f;\n"
662 			<< "\n"
663 			<< "    barrier();\n"
664 			<< "\n"
665 			<< "    if (gl_InvocationID == 5)\n"
666 			<< "		in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
667 			<< "\n"
668 			<< "    barrier();\n"
669 			<< "\n"
670 			<< "    highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
671 			<< "\n"
672 			<< "    barrier();\n"
673 			<< "\n"
674 			<< "    if (gl_InvocationID == " << NUM_VERTICES << "-1)\n"
675 			<< "		in_te_patchAttr = float(gl_InvocationID);\n"
676 			<< "\n"
677 			<< "    barrier();\n"
678 			<< "\n"
679 			<< "    in_te_attr[gl_InvocationID] = temp;\n"
680 			<< "\n"
681 			<< "    barrier();\n"
682 			<< "\n"
683 			<< "    temp = temp + in_te_attr[(gl_InvocationID+1) % " << NUM_VERTICES << "];\n"
684 			<< "\n"
685 			<< "    barrier();\n"
686 			<< "\n"
687 			<< "    in_te_attr[gl_InvocationID] = 0.25*temp;\n"
688 			<< "\n"
689 			<< "    gl_TessLevelInner[0] = 32.0;\n"
690 			<< "    gl_TessLevelInner[1] = 32.0;\n"
691 			<< "\n"
692 			<< "    gl_TessLevelOuter[0] = 32.0;\n"
693 			<< "    gl_TessLevelOuter[1] = 32.0;\n"
694 			<< "    gl_TessLevelOuter[2] = 32.0;\n"
695 			<< "    gl_TessLevelOuter[3] = 32.0;\n"
696 			<< "}\n";
697 
698 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
699 	}
700 
701 	// Tessellation evaluation shader
702 	{
703 		std::ostringstream src;
704 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
705 			<< "#extension GL_EXT_tessellation_shader : require\n"
706 			<< "\n"
707 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
708 			<< "\n"
709 			<< "layout(location = 0) in       highp float in_te_attr[];\n"
710 			<< "layout(location = 1) patch in highp float in_te_patchAttr;\n"
711 			<< "\n"
712 			<< "layout(location = 0) out highp float in_f_blue;\n"
713 			<< "\n"
714 			<< "void main (void)\n"
715 			<< "{\n"
716 			<< "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
717 			<< "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << NUM_VERTICES << "-1)))];\n"
718 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
719 			<< "    in_f_blue = abs(in_te_patchAttr - float(" << NUM_VERTICES << "-1));\n"
720 			<< "}\n";
721 
722 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
723 	}
724 
725 	// Fragment shader
726 	{
727 		std::ostringstream src;
728 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
729 			<< "\n"
730 			<< "layout(location = 0) in  highp   float in_f_blue;\n"
731 			<< "layout(location = 0) out mediump vec4  o_color;\n"
732 			<< "\n"
733 			<< "void main (void)\n"
734 			<< "{\n"
735 			<< "    o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
736 			<< "}\n";
737 
738 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
739 	}
740 }
741 
test(Context & context)742 tcu::TestStatus test (Context& context)
743 {
744 	// Input vertex attribute data
745 	std::vector<float> vertexData		(NUM_VERTICES);
746 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
747 
748 	for (int i = 0; i < NUM_VERTICES; ++i)
749 		vertexData[i] = static_cast<float>(i) / (NUM_VERTICES - 1);
750 
751 	tcu::TextureLevel referenceImage;
752 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/barrier_ref.png");
753 
754 	const int numPrimitives = 1;
755 	const int inPatchSize   = NUM_VERTICES;
756 	const int outPatchSize  = NUM_VERTICES;
757 
758 	return runTest(context, numPrimitives, inPatchSize, outPatchSize,
759 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
760 }
761 
762 } // Barrier ns
763 
764 namespace CrossInvocation
765 {
766 
767 enum Constants
768 {
769 	OUTPUT_PATCH_SIZE	= 3,
770 	INPUT_PATCH_SIZE	= 10
771 };
772 
773 enum CaseType
774 {
775 	CASETYPE_PER_VERTEX,
776 	CASETYPE_PER_PATCH
777 };
778 
779 enum DataType
780 {
781 	DATATYPE_INT,
782 	DATATYPE_UINT,
783 	DATATYPE_FLOAT,
784 	DATATYPE_VEC3,
785 	DATATYPE_VEC4,
786 	DATATYPE_MAT4X3
787 };
788 
789 struct CaseDefinition
790 {
791 	CaseType	caseType;
792 	DataType	dataType;
793 };
794 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)795 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
796 {
797 	static const std::string	typeStr[]		=
798 	{
799 		"int",
800 		"uint",
801 		"float",
802 		"vec3",
803 		"vec4",
804 		"mat4x3"
805 	};
806 	const std::string			dataType		= typeStr[caseDef.dataType];
807 	const int					varyingSize[]	= { 1, 1, 1, 1, 1, 4 };
808 
809 	// Vertex shader
810 	{
811 		std::ostringstream src;
812 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
813 			<< "\n"
814 			<< "layout(location = 0) in  highp float in_v_attr;\n"
815 			<< "layout(location = 0) out highp float in_tc_attr;\n"
816 			<< "\n"
817 			<< "void main (void)\n"
818 			<< "{\n"
819 			<< "    in_tc_attr = in_v_attr;\n"
820 			<< "}\n";
821 
822 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
823 	}
824 
825 	// Tessellation control shader
826 	{
827 		std::ostringstream src;
828 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
829 			<< "#extension GL_EXT_tessellation_shader : require\n"
830 			<< "\n"
831 			<< "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n"
832 			<< "\n"
833 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
834 			<< "layout(location = 0) out highp float in_te_attr[];\n"
835 			<< "\n";
836 
837 		if (caseDef.caseType == CASETYPE_PER_VERTEX)
838 			src << "layout(location = 1) out mediump " << dataType << " in_te_data0[];\n"
839 				<< "layout(location = " << varyingSize[caseDef.dataType] + 1 << ") out mediump " << dataType << " in_te_data1[];\n";
840 		else
841 			src << "layout(location = 1) patch out mediump " << dataType << " in_te_data0[" << OUTPUT_PATCH_SIZE << "];\n"
842 				<< "layout(location = " << OUTPUT_PATCH_SIZE * varyingSize[caseDef.dataType] + 1 << ") patch out mediump " << dataType << " in_te_data1[" << OUTPUT_PATCH_SIZE << "];\n";
843 
844 		src	<< "\n"
845 			<< "void main (void)\n"
846 			<< "{\n"
847 			<< "    " << dataType << " d = " << dataType << "(gl_InvocationID);\n"
848 			<< "    in_te_data0[gl_InvocationID] = d;\n"
849 			<< "    barrier();\n"
850 			<< "    in_te_data1[gl_InvocationID] = d + in_te_data0[(gl_InvocationID + 1) % " << OUTPUT_PATCH_SIZE << "];\n"
851 			<< "\n"
852 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
853 			<< "\n"
854 			<< "    gl_TessLevelInner[0] = 1.0;\n"
855 			<< "    gl_TessLevelInner[1] = 1.0;\n"
856 			<< "\n"
857 			<< "    gl_TessLevelOuter[0] = 1.0;\n"
858 			<< "    gl_TessLevelOuter[1] = 1.0;\n"
859 			<< "    gl_TessLevelOuter[2] = 1.0;\n"
860 			<< "    gl_TessLevelOuter[3] = 1.0;\n"
861 			<< "}\n";
862 
863 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
864 	}
865 
866 	// Tessellation evaluation shader
867 	{
868 		const float xScale = 1.0f / 8.0f;
869 
870 		std::ostringstream src;
871 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
872 			<< "#extension GL_EXT_tessellation_shader : require\n"
873 			<< "\n"
874 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
875 			<< "\n"
876 			<< "layout(location = 0) in  highp   float in_te_attr[];\n"
877 			<< "layout(location = 0) out mediump vec4  in_f_color;\n"
878 			<< "\n";
879 
880 		if (caseDef.caseType == CASETYPE_PER_VERTEX)
881 			src << "layout(location = 1) in mediump " << dataType << " in_te_data0[];\n"
882 				<< "layout(location = " << varyingSize[caseDef.dataType] + 1 << ") in mediump " << dataType << " in_te_data1[];\n";
883 		else
884 			src << "layout(location = 1) patch in mediump " << dataType << " in_te_data0[" << OUTPUT_PATCH_SIZE << "];\n"
885 				<< "layout(location = " << OUTPUT_PATCH_SIZE * varyingSize[caseDef.dataType] + 1 << ") patch in mediump " << dataType << " in_te_data1[" << OUTPUT_PATCH_SIZE << "];\n";
886 
887 		src << "\n"
888 			<< "void main (void)\n"
889 			<< "{\n"
890 			<< "    highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n"
891 			<< "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
892 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
893 			<< "    bool ok = true;\n"
894 			<< "    for (int i = 0; i < " << OUTPUT_PATCH_SIZE << "; i++)\n"
895 			<< "    {\n"
896 			<< "         int ref = i + (i + 1) % " << OUTPUT_PATCH_SIZE << ";\n"
897 			<< "         if (in_te_data1[i] != " << dataType << "(ref)) ok = false;\n"
898 			<< "    }\n"
899 			<< "    in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
900 			<< "}\n";
901 
902 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
903 	}
904 
905 	// Fragment shader
906 	{
907 		std::ostringstream src;
908 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
909 			<< "\n"
910 			<< "layout(location = 0) in  mediump vec4 in_f_color;\n"
911 			<< "layout(location = 0) out mediump vec4 o_color;\n"
912 			<< "\n"
913 			<< "void main (void)\n"
914 			<< "{\n"
915 			<< "    o_color = in_f_color;\n"
916 			<< "}\n";
917 
918 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
919 	}
920 }
921 
test(Context & context,const CaseDefinition caseDef)922 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
923 {
924 	DE_UNREF(caseDef);
925 	// Input vertex attribute data
926 	const int		   numPrimitives	= 8;
927 	std::vector<float> vertexData		(INPUT_PATCH_SIZE * numPrimitives, 0.0f);
928 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
929 
930 	for (int i = 0; i < numPrimitives; ++i)
931 		vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives);
932 
933 	tcu::TextureLevel referenceImage;
934 	initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE);
935 
936 	return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE,
937 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
938 }
939 
940 } // CrossInvocation ns
941 
942 } // anonymous
943 
944 //! These tests correspond to dEQP-GLES31.functional.tessellation.shader_input_output.*
createShaderInputOutputTests(tcu::TestContext & testCtx)945 tcu::TestCaseGroup* createShaderInputOutputTests (tcu::TestContext& testCtx)
946 {
947 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs"));
948 
949 	// Patch vertex counts
950 	{
951 		static const struct
952 		{
953 			int inPatchSize;
954 			int outPatchSize;
955 		} patchVertexCountCases[] =
956 		{
957 			{  5, 10 },
958 			{ 10,  5 }
959 		};
960 
961 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
962 		{
963 			const int inSize	= patchVertexCountCases[caseNdx].inPatchSize;
964 			const int outSize	= patchVertexCountCases[caseNdx].outPatchSize;
965 
966 			const std::string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
967 			const PatchVertexCount::CaseDefinition caseDef =
968 			{
969 				inSize, outSize, "vulkan/data/tessellation/" + caseName + "_ref.png"
970 			};
971 
972 			addFunctionCaseWithPrograms(group.get(), caseName, "Test input and output patch vertex counts",
973 										PatchVertexCount::initPrograms, PatchVertexCount::test, caseDef);
974 		}
975 	}
976 
977 	// Per patch data
978 	{
979 		static const PerPatchData::CaseDefinition cases[] =
980 		{
981 			{ PerPatchData::CASETYPE_PRIMITIVE_ID_TCS,		"primitive_id_tcs",		  true, "vulkan/data/tessellation/primitive_id_tcs_ref.png", "Read gl_PrimitiveID in TCS and pass it as patch output to TES" },
982 			{ PerPatchData::CASETYPE_PRIMITIVE_ID_TES,		"primitive_id_tes",		  true, "vulkan/data/tessellation/primitive_id_tes_ref.png", "Read gl_PrimitiveID in TES" },
983 			{ PerPatchData::CASETYPE_PATCH_VERTICES_IN_TCS,	"patch_vertices_in_tcs",  false, "", "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES" },
984 			{ PerPatchData::CASETYPE_PATCH_VERTICES_IN_TES,	"patch_vertices_in_tes",  false, "", "Read gl_PatchVerticesIn in TES" },
985 			{ PerPatchData::CASETYPE_TESS_LEVEL_INNER0_TES,	"tess_level_inner_0_tes", false, "", "Read gl_TessLevelInner[0] in TES" },
986 			{ PerPatchData::CASETYPE_TESS_LEVEL_INNER1_TES,	"tess_level_inner_1_tes", false, "", "Read gl_TessLevelInner[1] in TES" },
987 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER0_TES,	"tess_level_outer_0_tes", false, "", "Read gl_TessLevelOuter[0] in TES" },
988 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER1_TES,	"tess_level_outer_1_tes", false, "", "Read gl_TessLevelOuter[1] in TES" },
989 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER2_TES,	"tess_level_outer_2_tes", false, "", "Read gl_TessLevelOuter[2] in TES" },
990 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER3_TES,	"tess_level_outer_3_tes", false, "", "Read gl_TessLevelOuter[3] in TES" },
991 		};
992 
993 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
994 			addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, cases[caseNdx].caseDescription,
995 										PerPatchData::initPrograms, PerPatchData::test, cases[caseNdx]);
996 	}
997 
998 	// gl_Position
999 	{
1000 		static const struct
1001 		{
1002 			GLPosition::CaseType	type;
1003 			std::string				caseName;
1004 		} cases[] =
1005 		{
1006 			{ GLPosition::CASETYPE_VS_TO_TCS,		 "gl_position_vs_to_tcs"		},
1007 			{ GLPosition::CASETYPE_TCS_TO_TES,		 "gl_position_tcs_to_tes"		},
1008 			{ GLPosition::CASETYPE_VS_TO_TCS_TO_TES, "gl_position_vs_to_tcs_to_tes" },
1009 		};
1010 
1011 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
1012 			addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, "Pass gl_Position between VS and TCS, or between TCS and TES",
1013 										GLPosition::initPrograms, GLPosition::test, cases[caseNdx].type);
1014 	}
1015 
1016 	// Barrier
1017 	addFunctionCaseWithPrograms(group.get(), "barrier", "Basic barrier usage", Barrier::initPrograms, Barrier::test);
1018 
1019 	// Cross invocation communication
1020 	{
1021 		static const struct
1022 		{
1023 			CrossInvocation::CaseType	caseType;
1024 			std::string					name;
1025 		} caseTypes[] =
1026 		{
1027 			{ CrossInvocation::CASETYPE_PER_VERTEX,	 "cross_invocation_per_vertex"	},
1028 			{ CrossInvocation::CASETYPE_PER_PATCH,	 "cross_invocation_per_patch"	}
1029 		};
1030 
1031 		static const struct
1032 		{
1033 			CrossInvocation::DataType	dataType;
1034 			std::string					name;
1035 		} dataTypes[] =
1036 		{
1037 			{ CrossInvocation::DATATYPE_INT,	"int"		},
1038 			{ CrossInvocation::DATATYPE_UINT,	"uint"		},
1039 			{ CrossInvocation::DATATYPE_FLOAT,	"float"		},
1040 			{ CrossInvocation::DATATYPE_VEC3,	"vec3"		},
1041 			{ CrossInvocation::DATATYPE_VEC4,	"vec4"		},
1042 			{ CrossInvocation::DATATYPE_MAT4X3,	"mat4x3"	}
1043 		};
1044 
1045 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(caseTypes); ++caseNdx)
1046 			for (int dataTypeNdx = 0; dataTypeNdx < DE_LENGTH_OF_ARRAY(dataTypes); ++dataTypeNdx)
1047 			{
1048 				std::string						testName	= caseTypes[caseNdx].name + "_" + dataTypes[dataTypeNdx].name;
1049 				CrossInvocation::CaseDefinition	caseDef		= { caseTypes[caseNdx].caseType, dataTypes[dataTypeNdx].dataType };
1050 
1051 				addFunctionCaseWithPrograms(group.get(), testName, "Write output varyings from multiple invocations.",
1052 						CrossInvocation::initPrograms, CrossInvocation::test, caseDef);
1053 			}
1054 	}
1055 
1056 	return group.release();
1057 }
1058 
1059 } // tessellation
1060 } // vkt
1061