Home | History | Annotate | Download | only in tessellation
      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 "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 enum Constants
     58 {
     59 	RENDER_SIZE = 256,
     60 };
     61 
     62 //! Generic test code used by all test cases.
     63 tcu::TestStatus runTest (Context&							context,
     64 						 const int							numPrimitives,
     65 						 const int							inPatchSize,
     66 						 const int							outPatchSize,
     67 						 const VkFormat						vertexFormat,
     68 						 const void*						vertexData,
     69 						 const VkDeviceSize					vertexDataSizeBytes,
     70 						 const tcu::ConstPixelBufferAccess&	referenceImageAccess)
     71 {
     72 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
     73 
     74 	const DeviceInterface&	vk					= context.getDeviceInterface();
     75 	const VkDevice			device				= context.getDevice();
     76 	const VkQueue			queue				= context.getUniversalQueue();
     77 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
     78 	Allocator&				allocator			= context.getDefaultAllocator();
     79 
     80 	// Vertex input: may be just some abstract numbers
     81 
     82 	const Buffer vertexBuffer(vk, device, allocator,
     83 		makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
     84 
     85 	{
     86 		const Allocation& alloc = vertexBuffer.getAllocation();
     87 		deMemcpy(alloc.getHostPtr(), vertexData, static_cast<std::size_t>(vertexDataSizeBytes));
     88 
     89 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
     90 		// No barrier needed, flushed memory is automatically visible
     91 	}
     92 
     93 	// Color attachment
     94 
     95 	const tcu::IVec2			  renderSize				 = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
     96 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
     97 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
     98 	const Image					  colorAttachmentImage		 (vk, device, allocator,
     99 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
    100 															 MemoryRequirement::Any);
    101 
    102 	// Color output buffer: image will be copied here for verification
    103 
    104 	const VkDeviceSize	colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
    105 	const Buffer		colorBuffer			 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
    106 
    107 	// Pipeline
    108 
    109 	const Unique<VkImageView>		colorAttachmentView(makeImageView						(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
    110 	const Unique<VkRenderPass>		renderPass		   (makeRenderPass						(vk, device, colorFormat));
    111 	const Unique<VkFramebuffer>		framebuffer		   (makeFramebuffer						(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
    112 	const Unique<VkPipelineLayout>	pipelineLayout	   (makePipelineLayoutWithoutDescriptors(vk, device));
    113 	const Unique<VkCommandPool>		cmdPool			   (makeCommandPool						(vk, device, queueFamilyIndex));
    114 	const Unique<VkCommandBuffer>	cmdBuffer		   (makeCommandBuffer					(vk, device, *cmdPool));
    115 
    116 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
    117 		.setRenderSize				  (renderSize)
    118 		.setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
    119 		.setPatchControlPoints		  (inPatchSize)
    120 		.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
    121 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
    122 		.setShader					  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
    123 		.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL)
    124 		.build						  (vk, device, *pipelineLayout, *renderPass));
    125 
    126 	{
    127 		tcu::TestLog& log = context.getTestContext().getLog();
    128 		log << tcu::TestLog::Message
    129 			<< "Note: input patch size is " << inPatchSize << ", output patch size is " << outPatchSize
    130 			<< tcu::TestLog::EndMessage;
    131 	}
    132 
    133 	// Draw commands
    134 
    135 	beginCommandBuffer(vk, *cmdBuffer);
    136 
    137 	// Change color attachment image layout
    138 	{
    139 		const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
    140 			(VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    141 			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    142 			*colorAttachmentImage, colorImageSubresourceRange);
    143 
    144 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
    145 			0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
    146 	}
    147 
    148 	// Begin render pass
    149 	{
    150 		const VkRect2D renderArea = {
    151 			makeOffset2D(0, 0),
    152 			makeExtent2D(renderSize.x(), renderSize.y()),
    153 		};
    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 	{
    171 		const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
    172 			VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
    173 			VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
    174 			*colorAttachmentImage, colorImageSubresourceRange);
    175 
    176 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
    177 			0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
    178 	}
    179 	{
    180 		const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
    181 		vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, *colorBuffer, 1u, &copyRegion);
    182 	}
    183 	{
    184 		const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
    185 			VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, *colorBuffer, 0ull, colorBufferSizeBytes);
    186 
    187 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
    188 			0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
    189 	}
    190 
    191 	endCommandBuffer(vk, *cmdBuffer);
    192 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
    193 
    194 	{
    195 		const Allocation& colorBufferAlloc = colorBuffer.getAllocation();
    196 		invalidateMappedMemoryRange(vk, device, colorBufferAlloc.getMemory(), colorBufferAlloc.getOffset(), colorBufferSizeBytes);
    197 
    198 		// Verify case result
    199 		const tcu::ConstPixelBufferAccess resultImageAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
    200 		tcu::TestLog& log = context.getTestContext().getLog();
    201 		const bool ok = tcu::fuzzyCompare(log, "ImageComparison", "Image Comparison", referenceImageAccess, resultImageAccess, 0.002f, tcu::COMPARE_LOG_RESULT);
    202 
    203 		return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
    204 	}
    205 }
    206 
    207 namespace PatchVertexCount
    208 {
    209 
    210 struct CaseDefinition
    211 {
    212 	int				inPatchSize;
    213 	int				outPatchSize;
    214 	std::string		referenceImagePath;
    215 };
    216 
    217 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
    218 {
    219 	// Vertex shader
    220 	{
    221 		std::ostringstream src;
    222 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    223 			<< "\n"
    224 			<< "layout(location = 0) in  highp float in_v_attr;\n"
    225 			<< "layout(location = 0) out highp float in_tc_attr;\n"
    226 			<< "\n"
    227 			<< "void main (void)\n"
    228 			<< "{\n"
    229 			<< "    in_tc_attr = in_v_attr;\n"
    230 			<< "}\n";
    231 
    232 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    233 	}
    234 
    235 	// Tessellation control shader
    236 	{
    237 		std::ostringstream src;
    238 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    239 			<< "#extension GL_EXT_tessellation_shader : require\n"
    240 			<< "\n"
    241 			<< "layout(vertices = " << caseDef.outPatchSize << ") out;\n"
    242 			<< "\n"
    243 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
    244 			<< "layout(location = 0) out highp float in_te_attr[];\n"
    245 			<< "\n"
    246 			<< "void main (void)\n"
    247 			<< "{\n"
    248 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID*" << caseDef.inPatchSize << "/" << caseDef.outPatchSize << "];\n"
    249 			<< "\n"
    250 			<< "    gl_TessLevelInner[0] = 5.0;\n"
    251 			<< "    gl_TessLevelInner[1] = 5.0;\n"
    252 			<< "\n"
    253 			<< "    gl_TessLevelOuter[0] = 5.0;\n"
    254 			<< "    gl_TessLevelOuter[1] = 5.0;\n"
    255 			<< "    gl_TessLevelOuter[2] = 5.0;\n"
    256 			<< "    gl_TessLevelOuter[3] = 5.0;\n"
    257 			<< "}\n";
    258 
    259 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    260 	}
    261 
    262 	// Tessellation evaluation shader
    263 	{
    264 		std::ostringstream src;
    265 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    266 			<< "#extension GL_EXT_tessellation_shader : require\n"
    267 			<< "\n"
    268 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
    269 			<< "\n"
    270 			<< "layout(location = 0) in  highp   float in_te_attr[];\n"
    271 			<< "layout(location = 0) out mediump vec4  in_f_color;\n"
    272 			<< "\n"
    273 			<< "void main (void)\n"
    274 			<< "{\n"
    275 			<< "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
    276 			<< "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << caseDef.outPatchSize << "-1)))];\n"
    277 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
    278 			<< "    in_f_color = vec4(1.0);\n"
    279 			<< "}\n";
    280 
    281 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
    282 	}
    283 
    284 	// Fragment shader
    285 	{
    286 		std::ostringstream src;
    287 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    288 			<< "\n"
    289 			<< "layout(location = 0) in  mediump vec4 in_f_color;\n"
    290 			<< "layout(location = 0) out mediump vec4 o_color;\n"
    291 			<< "\n"
    292 			<< "void main (void)\n"
    293 			<< "{\n"
    294 			<< "    o_color = in_f_color;\n"
    295 			<< "}\n";
    296 
    297 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    298 	}
    299 }
    300 
    301 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
    302 {
    303 	// Input vertex attribute data
    304 	std::vector<float> vertexData;
    305 	vertexData.reserve(caseDef.inPatchSize);
    306 	for (int i = 0; i < caseDef.inPatchSize; ++i)
    307 	{
    308 		const float f = static_cast<float>(i) / static_cast<float>(caseDef.inPatchSize - 1);
    309 		vertexData.push_back(f*f);
    310 	}
    311 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
    312 
    313 	// Load reference image
    314 	tcu::TextureLevel referenceImage;
    315 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str());
    316 
    317 	const int numPrimitives = 1;
    318 
    319 	return runTest(context, numPrimitives, caseDef.inPatchSize, caseDef.outPatchSize,
    320 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
    321 }
    322 
    323 } // PatchVertexCountTest ns
    324 
    325 namespace PerPatchData
    326 {
    327 
    328 enum CaseType
    329 {
    330 	CASETYPE_PRIMITIVE_ID_TCS,
    331 	CASETYPE_PRIMITIVE_ID_TES,
    332 	CASETYPE_PATCH_VERTICES_IN_TCS,
    333 	CASETYPE_PATCH_VERTICES_IN_TES,
    334 	CASETYPE_TESS_LEVEL_INNER0_TES,
    335 	CASETYPE_TESS_LEVEL_INNER1_TES,
    336 	CASETYPE_TESS_LEVEL_OUTER0_TES,
    337 	CASETYPE_TESS_LEVEL_OUTER1_TES,
    338 	CASETYPE_TESS_LEVEL_OUTER2_TES,
    339 	CASETYPE_TESS_LEVEL_OUTER3_TES,
    340 };
    341 
    342 enum Constants
    343 {
    344 	OUTPUT_PATCH_SIZE	= 5,
    345 	INPUT_PATCH_SIZE	= 10,
    346 };
    347 
    348 struct CaseDefinition
    349 {
    350 	CaseType		caseType;
    351 	std::string		caseName;
    352 	bool			usesReferenceImageFromFile;
    353 	std::string		referenceImagePath;
    354 	std::string		caseDescription;
    355 };
    356 
    357 int getNumPrimitives (const CaseType type)
    358 {
    359 	return (type == CASETYPE_PRIMITIVE_ID_TCS || type == CASETYPE_PRIMITIVE_ID_TES ? 8 : 1);
    360 }
    361 
    362 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
    363 {
    364 	// Vertex shader
    365 	{
    366 		std::ostringstream src;
    367 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    368 			<< "\n"
    369 			<< "layout(location = 0) in  highp float in_v_attr;\n"
    370 			<< "layout(location = 0) out highp float in_tc_attr;\n"
    371 			<< "\n"
    372 			<< "void main (void)\n"
    373 			<< "{\n"
    374 			<< "    in_tc_attr = in_v_attr;\n"
    375 			<< "}\n";
    376 
    377 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    378 	}
    379 
    380 	// Tessellation control shader
    381 	{
    382 		std::ostringstream src;
    383 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    384 			<< "#extension GL_EXT_tessellation_shader : require\n"
    385 			<< "\n"
    386 			<< "layout(vertices = " << OUTPUT_PATCH_SIZE << ") out;\n"
    387 			<< "\n"
    388 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
    389 			<< "layout(location = 0) out highp float in_te_attr[];\n"
    390 			<< "\n"
    391 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "layout(location = 1) patch out mediump int in_te_primitiveIDFromTCS;\n" :
    392 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch out mediump int in_te_patchVerticesInFromTCS;\n" : "")
    393 			<< "\n"
    394 			<< "void main (void)\n"
    395 			<< "{\n"
    396 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
    397 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "    in_te_primitiveIDFromTCS = gl_PrimitiveID;\n" :
    398 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "    in_te_patchVerticesInFromTCS = gl_PatchVerticesIn;\n" : "")
    399 			<< "\n"
    400 			<< "    gl_TessLevelInner[0] = 9.0;\n"
    401 			<< "    gl_TessLevelInner[1] = 8.0;\n"
    402 			<< "\n"
    403 			<< "    gl_TessLevelOuter[0] = 7.0;\n"
    404 			<< "    gl_TessLevelOuter[1] = 6.0;\n"
    405 			<< "    gl_TessLevelOuter[2] = 5.0;\n"
    406 			<< "    gl_TessLevelOuter[3] = 4.0;\n"
    407 			<< "}\n";
    408 
    409 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    410 	}
    411 
    412 	// Tessellation evaluation shader
    413 	{
    414 		const float xScale = 1.0f / static_cast<float>(getNumPrimitives(caseDef.caseType));
    415 
    416 		std::ostringstream src;
    417 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    418 			<< "#extension GL_EXT_tessellation_shader : require\n"
    419 			<< "\n"
    420 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
    421 			<< "\n"
    422 			<< "layout(location = 0) in  highp   float in_te_attr[];\n"
    423 			<< "layout(location = 0) out mediump vec4  in_f_color;\n"
    424 			<< "\n"
    425 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS	   ? "layout(location = 1) patch in mediump int in_te_primitiveIDFromTCS;\n" :
    426 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS ? "layout(location = 1) patch in mediump int in_te_patchVerticesInFromTCS;\n" : "")
    427 			<< "\n"
    428 			<< "void main (void)\n"
    429 			<< "{\n"
    430 			<< "    highp float x = (gl_TessCoord.x*float(" << xScale << ") + in_te_attr[0]) * 2.0 - 1.0;\n"
    431 			<< "    highp float y = gl_TessCoord.y*2.0 - 1.0;\n"
    432 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
    433 			<< (caseDef.caseType == CASETYPE_PRIMITIVE_ID_TCS		? "    bool ok = in_te_primitiveIDFromTCS == 3;\n" :
    434 				caseDef.caseType == CASETYPE_PRIMITIVE_ID_TES		? "    bool ok = gl_PrimitiveID == 3;\n" :
    435 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TCS	? "    bool ok = in_te_patchVerticesInFromTCS == " + de::toString(INPUT_PATCH_SIZE) + ";\n" :
    436 				caseDef.caseType == CASETYPE_PATCH_VERTICES_IN_TES	? "    bool ok = gl_PatchVerticesIn == " + de::toString(OUTPUT_PATCH_SIZE) + ";\n" :
    437 				caseDef.caseType == CASETYPE_TESS_LEVEL_INNER0_TES	? "    bool ok = abs(gl_TessLevelInner[0] - 9.0) < 0.1f;\n" :
    438 				caseDef.caseType == CASETYPE_TESS_LEVEL_INNER1_TES	? "    bool ok = abs(gl_TessLevelInner[1] - 8.0) < 0.1f;\n" :
    439 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER0_TES	? "    bool ok = abs(gl_TessLevelOuter[0] - 7.0) < 0.1f;\n" :
    440 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER1_TES	? "    bool ok = abs(gl_TessLevelOuter[1] - 6.0) < 0.1f;\n" :
    441 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER2_TES	? "    bool ok = abs(gl_TessLevelOuter[2] - 5.0) < 0.1f;\n" :
    442 				caseDef.caseType == CASETYPE_TESS_LEVEL_OUTER3_TES	? "    bool ok = abs(gl_TessLevelOuter[3] - 4.0) < 0.1f;\n" : "")
    443 			<< "    in_f_color = ok ? vec4(1.0) : vec4(vec3(0.0), 1.0);\n"
    444 			<< "}\n";
    445 
    446 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
    447 	}
    448 
    449 	// Fragment shader
    450 	{
    451 		std::ostringstream src;
    452 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    453 			<< "\n"
    454 			<< "layout(location = 0) in  mediump vec4 in_f_color;\n"
    455 			<< "layout(location = 0) out mediump vec4 o_color;\n"
    456 			<< "\n"
    457 			<< "void main (void)\n"
    458 			<< "{\n"
    459 			<< "    o_color = in_f_color;\n"
    460 			<< "}\n";
    461 
    462 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    463 	}
    464 }
    465 
    466 //! Resize an image and fill with white color.
    467 void initializeWhiteReferenceImage (tcu::TextureLevel& image, const int width, const int height)
    468 {
    469 	DE_ASSERT(width > 0 && height > 0);
    470 
    471 	image.setStorage(mapVkFormat(VK_FORMAT_R8G8B8A8_UNORM), width, height);
    472 	tcu::PixelBufferAccess access = image.getAccess();
    473 
    474 	const tcu::Vec4 white(1.0f, 1.0f, 1.0f, 1.0f);
    475 
    476 	for (int y = 0; y < height; ++y)
    477 	for (int x = 0; x < width; ++x)
    478 		access.setPixel(white, x, y);
    479 }
    480 
    481 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
    482 {
    483 	DE_ASSERT(!caseDef.usesReferenceImageFromFile || !caseDef.referenceImagePath.empty());
    484 
    485 	// Input vertex attribute data
    486 	const int		   numPrimitives	= getNumPrimitives(caseDef.caseType);
    487 	std::vector<float> vertexData		(INPUT_PATCH_SIZE * numPrimitives, 0.0f);
    488 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
    489 
    490 	for (int i = 0; i < numPrimitives; ++i)
    491 		vertexData[INPUT_PATCH_SIZE * i] = static_cast<float>(i) / static_cast<float>(numPrimitives);
    492 
    493 	tcu::TextureLevel referenceImage;
    494 	if (caseDef.usesReferenceImageFromFile)
    495 		tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), caseDef.referenceImagePath.c_str());
    496 	else
    497 		initializeWhiteReferenceImage(referenceImage, RENDER_SIZE, RENDER_SIZE);
    498 
    499 	return runTest(context, numPrimitives, INPUT_PATCH_SIZE, OUTPUT_PATCH_SIZE,
    500 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
    501 }
    502 
    503 } // PerPatchData ns
    504 
    505 namespace GLPosition
    506 {
    507 
    508 enum CaseType
    509 {
    510 	CASETYPE_VS_TO_TCS = 0,
    511 	CASETYPE_TCS_TO_TES,
    512 	CASETYPE_VS_TO_TCS_TO_TES,
    513 };
    514 
    515 void initPrograms (vk::SourceCollections& programCollection, const CaseType caseType)
    516 {
    517 	const bool vsToTCS  = caseType == CASETYPE_VS_TO_TCS  || caseType == CASETYPE_VS_TO_TCS_TO_TES;
    518 	const bool tcsToTES = caseType == CASETYPE_TCS_TO_TES || caseType == CASETYPE_VS_TO_TCS_TO_TES;
    519 
    520 	// Vertex shader
    521 	{
    522 		std::ostringstream src;
    523 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    524 			<< "\n"
    525 			<< "layout(location = 0) in  highp vec4 in_v_attr;\n"
    526 			<< (!vsToTCS ? "layout(location = 0) out highp vec4 in_tc_attr;\n" : "")
    527 			<< "\n"
    528 			<< "void main (void)\n"
    529 			<< "{\n"
    530 			<< "    " << (vsToTCS ? "gl_Position" : "in_tc_attr") << " = in_v_attr;\n"
    531 			<< "}\n";
    532 
    533 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    534 	}
    535 
    536 	// Tessellation control shader
    537 	{
    538 		std::ostringstream src;
    539 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    540 			<< "#extension GL_EXT_tessellation_shader : require\n"
    541 			<< "\n"
    542 			<< "layout(vertices = 3) out;\n"
    543 			<< "\n"
    544 			<< (!vsToTCS  ? "layout(location = 0) in  highp vec4 in_tc_attr[];\n" : "")
    545 			<< (!tcsToTES ? "layout(location = 0) out highp vec4 in_te_attr[];\n" : "")
    546 			<< "\n"
    547 			<< "void main (void)\n"
    548 			<< "{\n"
    549 			<< "    " << (tcsToTES ? "gl_out[gl_InvocationID].gl_Position" : "in_te_attr[gl_InvocationID]") << " = "
    550 					  << (vsToTCS  ? "gl_in[gl_InvocationID].gl_Position" : "in_tc_attr[gl_InvocationID]") << ";\n"
    551 			<< "\n"
    552 			<< "    gl_TessLevelInner[0] = 2.0;\n"
    553 			<< "    gl_TessLevelInner[1] = 3.0;\n"
    554 			<< "\n"
    555 			<< "    gl_TessLevelOuter[0] = 4.0;\n"
    556 			<< "    gl_TessLevelOuter[1] = 5.0;\n"
    557 			<< "    gl_TessLevelOuter[2] = 6.0;\n"
    558 			<< "    gl_TessLevelOuter[3] = 7.0;\n"
    559 			<< "}\n";
    560 
    561 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    562 	}
    563 
    564 	// Tessellation evaluation shader
    565 	{
    566 		const std::string tesIn0 = tcsToTES ? "gl_in[0].gl_Position" : "in_te_attr[0]";
    567 		const std::string tesIn1 = tcsToTES ? "gl_in[1].gl_Position" : "in_te_attr[1]";
    568 		const std::string tesIn2 = tcsToTES ? "gl_in[2].gl_Position" : "in_te_attr[2]";
    569 
    570 		std::ostringstream src;
    571 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    572 			<< "#extension GL_EXT_tessellation_shader : require\n"
    573 			<< "\n"
    574 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_TRIANGLES) << ") in;\n"
    575 			<< "\n"
    576 			<< (!tcsToTES ? "layout(location = 0) in  highp vec4 in_te_attr[];\n" : "")
    577 			<< "layout(location = 0) out highp vec4 in_f_color;\n"
    578 			<< "\n"
    579 			<< "void main (void)\n"
    580 			<< "{\n"
    581 			<< "    highp vec2 xy = gl_TessCoord.x * " << tesIn0 << ".xy\n"
    582 			<< "                  + gl_TessCoord.y * " << tesIn1 << ".xy\n"
    583 			<< "                  + gl_TessCoord.z * " << tesIn2 << ".xy;\n"
    584 			<< "    gl_Position = vec4(xy, 0.0, 1.0);\n"
    585 			<< "    in_f_color = vec4(" << tesIn0 << ".z + " << tesIn1 << ".w,\n"
    586 			<< "                      " << tesIn2 << ".z + " << tesIn0 << ".w,\n"
    587 			<< "                      " << tesIn1 << ".z + " << tesIn2 << ".w,\n"
    588 			<< "                      1.0);\n"
    589 			<< "}\n";
    590 
    591 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
    592 	}
    593 
    594 	// Fragment shader
    595 	{
    596 		std::ostringstream src;
    597 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    598 			<< "\n"
    599 			<< "layout(location = 0) in  highp   vec4 in_f_color;\n"
    600 			<< "layout(location = 0) out mediump vec4 o_color;\n"
    601 			<< "\n"
    602 			<< "void main (void)\n"
    603 			<< "{\n"
    604 			<< "    o_color = in_f_color;\n"
    605 			<< "}\n";
    606 
    607 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    608 	}
    609 }
    610 
    611 tcu::TestStatus test (Context& context, const CaseType caseType)
    612 {
    613 	DE_UNREF(caseType);
    614 
    615 	// Input vertex attribute data
    616 	static const float vertexData[3*4] =
    617 	{
    618 		-0.8f, -0.7f, 0.1f, 0.7f,
    619 		-0.5f,  0.4f, 0.2f, 0.5f,
    620 		 0.3f,  0.2f, 0.3f, 0.45f
    621 	};
    622 
    623 	tcu::TextureLevel referenceImage;
    624 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/gl_position_ref.png");
    625 
    626 	const int numPrimitives = 1;
    627 	const int inPatchSize   = 3;
    628 	const int outPatchSize  = 3;
    629 
    630 	return runTest(context, numPrimitives, inPatchSize, outPatchSize,
    631 				   VK_FORMAT_R32G32B32A32_SFLOAT, vertexData, sizeof(vertexData), referenceImage.getAccess());
    632 }
    633 
    634 } // GLPosition ns
    635 
    636 namespace Barrier
    637 {
    638 
    639 enum Constants
    640 {
    641 	NUM_VERTICES = 32,
    642 };
    643 
    644 void initPrograms (vk::SourceCollections& programCollection)
    645 {
    646 	// Vertex shader
    647 	{
    648 		std::ostringstream src;
    649 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    650 			<< "\n"
    651 			<< "layout(location = 0) in  highp float in_v_attr;\n"
    652 			<< "layout(location = 0) out highp float in_tc_attr;\n"
    653 			<< "\n"
    654 			<< "void main (void)\n"
    655 			<< "{\n"
    656 			<< "    in_tc_attr = in_v_attr;\n"
    657 			<< "}\n";
    658 
    659 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
    660 	}
    661 
    662 	// Tessellation control shader
    663 	{
    664 		std::ostringstream src;
    665 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    666 			<< "#extension GL_EXT_tessellation_shader : require\n"
    667 			<< "\n"
    668 			<< "layout(vertices = " << NUM_VERTICES << ") out;\n"
    669 			<< "\n"
    670 			<< "layout(location = 0) in  highp float in_tc_attr[];\n"
    671 			<< "layout(location = 0) out highp float in_te_attr[];\n"
    672 			<< "\n"
    673 			<< "layout(location = 1) patch out highp float in_te_patchAttr;\n"
    674 			<< "\n"
    675 			<< "void main (void)\n"
    676 			<< "{\n"
    677 			<< "    in_te_attr[gl_InvocationID] = in_tc_attr[gl_InvocationID];\n"
    678 			<< "    in_te_patchAttr = 0.0f;\n"
    679 			<< "\n"
    680 			<< "    barrier();\n"
    681 			<< "\n"
    682 			<< "    if (gl_InvocationID == 5)\n"
    683 			<< "		in_te_patchAttr = float(gl_InvocationID)*0.1;\n"
    684 			<< "\n"
    685 			<< "    barrier();\n"
    686 			<< "\n"
    687 			<< "    highp float temp = in_te_patchAttr + in_te_attr[gl_InvocationID];\n"
    688 			<< "\n"
    689 			<< "    barrier();\n"
    690 			<< "\n"
    691 			<< "    if (gl_InvocationID == " << NUM_VERTICES << "-1)\n"
    692 			<< "		in_te_patchAttr = float(gl_InvocationID);\n"
    693 			<< "\n"
    694 			<< "    barrier();\n"
    695 			<< "\n"
    696 			<< "    in_te_attr[gl_InvocationID] = temp;\n"
    697 			<< "\n"
    698 			<< "    barrier();\n"
    699 			<< "\n"
    700 			<< "    temp = temp + in_te_attr[(gl_InvocationID+1) % " << NUM_VERTICES << "];\n"
    701 			<< "\n"
    702 			<< "    barrier();\n"
    703 			<< "\n"
    704 			<< "    in_te_attr[gl_InvocationID] = 0.25*temp;\n"
    705 			<< "\n"
    706 			<< "    gl_TessLevelInner[0] = 32.0;\n"
    707 			<< "    gl_TessLevelInner[1] = 32.0;\n"
    708 			<< "\n"
    709 			<< "    gl_TessLevelOuter[0] = 32.0;\n"
    710 			<< "    gl_TessLevelOuter[1] = 32.0;\n"
    711 			<< "    gl_TessLevelOuter[2] = 32.0;\n"
    712 			<< "    gl_TessLevelOuter[3] = 32.0;\n"
    713 			<< "}\n";
    714 
    715 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    716 	}
    717 
    718 	// Tessellation evaluation shader
    719 	{
    720 		std::ostringstream src;
    721 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    722 			<< "#extension GL_EXT_tessellation_shader : require\n"
    723 			<< "\n"
    724 			<< "layout(" << getTessPrimitiveTypeShaderName(TESSPRIMITIVETYPE_QUADS) << ") in;\n"
    725 			<< "\n"
    726 			<< "layout(location = 0) in       highp float in_te_attr[];\n"
    727 			<< "layout(location = 1) patch in highp float in_te_patchAttr;\n"
    728 			<< "\n"
    729 			<< "layout(location = 0) out highp float in_f_blue;\n"
    730 			<< "\n"
    731 			<< "void main (void)\n"
    732 			<< "{\n"
    733 			<< "    highp float x = gl_TessCoord.x*2.0 - 1.0;\n"
    734 			<< "    highp float y = gl_TessCoord.y - in_te_attr[int(round(gl_TessCoord.x*float(" << NUM_VERTICES << "-1)))];\n"
    735 			<< "    gl_Position = vec4(x, y, 0.0, 1.0);\n"
    736 			<< "    in_f_blue = abs(in_te_patchAttr - float(" << NUM_VERTICES << "-1));\n"
    737 			<< "}\n";
    738 
    739 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
    740 	}
    741 
    742 	// Fragment shader
    743 	{
    744 		std::ostringstream src;
    745 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    746 			<< "\n"
    747 			<< "layout(location = 0) in  highp   float in_f_blue;\n"
    748 			<< "layout(location = 0) out mediump vec4  o_color;\n"
    749 			<< "\n"
    750 			<< "void main (void)\n"
    751 			<< "{\n"
    752 			<< "    o_color = vec4(1.0, 0.0, in_f_blue, 1.0);\n"
    753 			<< "}\n";
    754 
    755 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
    756 	}
    757 }
    758 
    759 tcu::TestStatus test (Context& context)
    760 {
    761 	// Input vertex attribute data
    762 	std::vector<float> vertexData		(NUM_VERTICES);
    763 	const VkDeviceSize vertexBufferSize = sizeof(float) * vertexData.size();
    764 
    765 	for (int i = 0; i < NUM_VERTICES; ++i)
    766 		vertexData[i] = static_cast<float>(i) / (NUM_VERTICES - 1);
    767 
    768 	tcu::TextureLevel referenceImage;
    769 	tcu::ImageIO::loadPNG(referenceImage, context.getTestContext().getArchive(), "vulkan/data/tessellation/barrier_ref.png");
    770 
    771 	const int numPrimitives = 1;
    772 	const int inPatchSize   = NUM_VERTICES;
    773 	const int outPatchSize  = NUM_VERTICES;
    774 
    775 	return runTest(context, numPrimitives, inPatchSize, outPatchSize,
    776 				   VK_FORMAT_R32_SFLOAT, &vertexData[0], vertexBufferSize, referenceImage.getAccess());
    777 }
    778 
    779 } // Barrier ns
    780 
    781 } // anonymous
    782 
    783 //! These tests correspond to dEQP-GLES31.functional.tessellation.shader_input_output.*
    784 tcu::TestCaseGroup* createShaderInputOutputTests (tcu::TestContext& testCtx)
    785 {
    786 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "shader_input_output", "Test tessellation control and evaluation shader inputs and outputs"));
    787 
    788 	// Patch vertex counts
    789 	{
    790 		static const struct
    791 		{
    792 			int inPatchSize;
    793 			int outPatchSize;
    794 		} patchVertexCountCases[] =
    795 		{
    796 			{  5, 10 },
    797 			{ 10,  5 }
    798 		};
    799 
    800 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(patchVertexCountCases); caseNdx++)
    801 		{
    802 			const int inSize	= patchVertexCountCases[caseNdx].inPatchSize;
    803 			const int outSize	= patchVertexCountCases[caseNdx].outPatchSize;
    804 
    805 			const std::string caseName = "patch_vertices_" + de::toString(inSize) + "_in_" + de::toString(outSize) + "_out";
    806 			const PatchVertexCount::CaseDefinition caseDef =
    807 			{
    808 				inSize, outSize, "vulkan/data/tessellation/" + caseName + "_ref.png"
    809 			};
    810 
    811 			addFunctionCaseWithPrograms(group.get(), caseName, "Test input and output patch vertex counts",
    812 										PatchVertexCount::initPrograms, PatchVertexCount::test, caseDef);
    813 		}
    814 	}
    815 
    816 	// Per patch data
    817 	{
    818 		static const PerPatchData::CaseDefinition cases[] =
    819 		{
    820 			{ 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" },
    821 			{ PerPatchData::CASETYPE_PRIMITIVE_ID_TES,		"primitive_id_tes",		  true, "vulkan/data/tessellation/primitive_id_tes_ref.png", "Read gl_PrimitiveID in TES" },
    822 			{ PerPatchData::CASETYPE_PATCH_VERTICES_IN_TCS,	"patch_vertices_in_tcs",  false, "", "Read gl_PatchVerticesIn in TCS and pass it as patch output to TES" },
    823 			{ PerPatchData::CASETYPE_PATCH_VERTICES_IN_TES,	"patch_vertices_in_tes",  false, "", "Read gl_PatchVerticesIn in TES" },
    824 			{ PerPatchData::CASETYPE_TESS_LEVEL_INNER0_TES,	"tess_level_inner_0_tes", false, "", "Read gl_TessLevelInner[0] in TES" },
    825 			{ PerPatchData::CASETYPE_TESS_LEVEL_INNER1_TES,	"tess_level_inner_1_tes", false, "", "Read gl_TessLevelInner[1] in TES" },
    826 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER0_TES,	"tess_level_outer_0_tes", false, "", "Read gl_TessLevelOuter[0] in TES" },
    827 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER1_TES,	"tess_level_outer_1_tes", false, "", "Read gl_TessLevelOuter[1] in TES" },
    828 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER2_TES,	"tess_level_outer_2_tes", false, "", "Read gl_TessLevelOuter[2] in TES" },
    829 			{ PerPatchData::CASETYPE_TESS_LEVEL_OUTER3_TES,	"tess_level_outer_3_tes", false, "", "Read gl_TessLevelOuter[3] in TES" },
    830 		};
    831 
    832 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
    833 			addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, cases[caseNdx].caseDescription,
    834 										PerPatchData::initPrograms, PerPatchData::test, cases[caseNdx]);
    835 	}
    836 
    837 	// gl_Position
    838 	{
    839 		static const struct
    840 		{
    841 			GLPosition::CaseType	type;
    842 			std::string				caseName;
    843 		} cases[] =
    844 		{
    845 			{ GLPosition::CASETYPE_VS_TO_TCS,		 "gl_position_vs_to_tcs"		},
    846 			{ GLPosition::CASETYPE_TCS_TO_TES,		 "gl_position_tcs_to_tes"		},
    847 			{ GLPosition::CASETYPE_VS_TO_TCS_TO_TES, "gl_position_vs_to_tcs_to_tes" },
    848 		};
    849 
    850 		for (int caseNdx = 0; caseNdx < DE_LENGTH_OF_ARRAY(cases); ++caseNdx)
    851 			addFunctionCaseWithPrograms(group.get(), cases[caseNdx].caseName, "Pass gl_Position between VS and TCS, or between TCS and TES",
    852 										GLPosition::initPrograms, GLPosition::test, cases[caseNdx].type);
    853 	}
    854 
    855 	// Barrier
    856 	addFunctionCaseWithPrograms(group.get(), "barrier", "Basic barrier usage", Barrier::initPrograms, Barrier::test);
    857 
    858 	return group.release();
    859 }
    860 
    861 } // tessellation
    862 } // vkt
    863