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 Geometry Interaction - Passthrough
     23 *//*--------------------------------------------------------------------*/
     24 
     25 #include "vktTessellationGeometryPassthroughTests.hpp"
     26 #include "vktTestCaseUtil.hpp"
     27 #include "vktTessellationUtil.hpp"
     28 
     29 #include "tcuTestLog.hpp"
     30 #include "tcuImageCompare.hpp"
     31 
     32 #include "vkDefs.hpp"
     33 #include "vkQueryUtil.hpp"
     34 #include "vkBuilderUtil.hpp"
     35 #include "vkTypeUtil.hpp"
     36 #include "vkImageUtil.hpp"
     37 
     38 #include "deUniquePtr.hpp"
     39 
     40 #include <string>
     41 #include <vector>
     42 
     43 namespace vkt
     44 {
     45 namespace tessellation
     46 {
     47 
     48 using namespace vk;
     49 
     50 namespace
     51 {
     52 
     53 void addVertexAndFragmentShaders (vk::SourceCollections&  programCollection)
     54 {
     55 	// Vertex shader
     56 	{
     57 		std::ostringstream src;
     58 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
     59 			<< "\n"
     60 			<< "layout(location = 0) in  highp vec4 a_position;\n"
     61 			<< "layout(location = 0) out highp vec4 v_vertex_color;\n"
     62 			<< "\n"
     63 			<< "void main (void)\n"
     64 			<< "{\n"
     65 			<< "    gl_Position = a_position;\n"
     66 			<< "    v_vertex_color = vec4(a_position.x * 0.5 + 0.5, a_position.y * 0.5 + 0.5, 1.0, 0.4);\n"
     67 			<< "}\n";
     68 
     69 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
     70 	}
     71 
     72 	// Fragment shader
     73 	{
     74 		std::ostringstream src;
     75 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
     76 			<< "\n"
     77 			<< "layout(location = 0) in  highp   vec4 v_fragment_color;\n"
     78 			<< "layout(location = 0) out mediump vec4 fragColor;\n"
     79 			<< "void main (void)\n"
     80 			<< "{\n"
     81 			<< "	fragColor = v_fragment_color;\n"
     82 			<< "}\n";
     83 
     84 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
     85 	}
     86 }
     87 
     88 //! Tessellation evaluation shader used in passthrough geometry shader case.
     89 std::string generateTessellationEvaluationShader (const TessPrimitiveType primitiveType, const std::string& colorOutputName)
     90 {
     91 	std::ostringstream	src;
     92 	src <<	glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
     93 		<< "#extension GL_EXT_tessellation_shader : require\n"
     94 		<< "layout(" << getTessPrimitiveTypeShaderName(primitiveType) << ") in;\n"
     95 		<< "\n"
     96 		<< "layout(location = 0) in  highp vec4 v_patch_color[];\n"
     97 		<< "layout(location = 0) out highp vec4 " << colorOutputName << ";\n"
     98 		<< "\n"
     99 		<< "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
    100 		<< "void main (void)\n"
    101 		<< "{\n";
    102 
    103 	if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
    104 		src << "    vec3 weights = vec3(pow(gl_TessCoord.x, 1.3), pow(gl_TessCoord.y, 1.3), pow(gl_TessCoord.z, 1.3));\n"
    105 			<< "    vec3 cweights = gl_TessCoord;\n"
    106 			<< "    gl_Position = vec4(weights.x * gl_in[0].gl_Position.xyz + weights.y * gl_in[1].gl_Position.xyz + weights.z * gl_in[2].gl_Position.xyz, 1.0);\n"
    107 			<< "    " << colorOutputName << " = cweights.x * v_patch_color[0] + cweights.y * v_patch_color[1] + cweights.z * v_patch_color[2];\n";
    108 	else if (primitiveType == TESSPRIMITIVETYPE_QUADS || primitiveType == TESSPRIMITIVETYPE_ISOLINES)
    109 		src << "    vec2 normalizedCoord = (gl_TessCoord.xy * 2.0 - vec2(1.0));\n"
    110 			<< "    vec2 normalizedWeights = normalizedCoord * (vec2(1.0) - 0.3 * cos(normalizedCoord.yx * 1.57));\n"
    111 			<< "    vec2 weights = normalizedWeights * 0.5 + vec2(0.5);\n"
    112 			<< "    vec2 cweights = gl_TessCoord.xy;\n"
    113 			<< "    gl_Position = mix(mix(gl_in[0].gl_Position, gl_in[1].gl_Position, weights.y), mix(gl_in[2].gl_Position, gl_in[3].gl_Position, weights.y), weights.x);\n"
    114 			<< "    " << colorOutputName << " = mix(mix(v_patch_color[0], v_patch_color[1], cweights.y), mix(v_patch_color[2], v_patch_color[3], cweights.y), cweights.x);\n";
    115 	else
    116 		DE_ASSERT(false);
    117 
    118 	src <<	"}\n";
    119 
    120 	return src.str();
    121 }
    122 
    123 class IdentityGeometryShaderTestCase : public TestCase
    124 {
    125 public:
    126 	void			initPrograms	(vk::SourceCollections& programCollection) const;
    127 	TestInstance*	createInstance	(Context& context) const;
    128 
    129 	IdentityGeometryShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
    130 		: TestCase			(testCtx, name, description)
    131 		, m_primitiveType	(primitiveType)
    132 	{
    133 	}
    134 
    135 private:
    136 	const TessPrimitiveType m_primitiveType;
    137 };
    138 
    139 void IdentityGeometryShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
    140 {
    141 	addVertexAndFragmentShaders(programCollection);
    142 
    143 	// Tessellation control
    144 	{
    145 		std::ostringstream src;
    146 		src <<	glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    147 			<< "#extension GL_EXT_tessellation_shader : require\n"
    148 			<< "layout(vertices = 4) out;\n"
    149 			<< "\n"
    150 			<< "layout(set = 0, binding = 0, std430) readonly restrict buffer TessLevels {\n"
    151 			<< "    float inner0;\n"
    152 			<< "    float inner1;\n"
    153 			<< "    float outer0;\n"
    154 			<< "    float outer1;\n"
    155 			<< "    float outer2;\n"
    156 			<< "    float outer3;\n"
    157 			<< "} sb_levels;\n"
    158 			<< "\n"
    159 			<< "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
    160 			<< "layout(location = 0) out highp vec4 v_patch_color[];\n"
    161 			<< "\n"
    162 			<< "void main (void)\n"
    163 			<< "{\n"
    164 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    165 			<< "    v_patch_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
    166 			<< "\n"
    167 			<< "    gl_TessLevelInner[0] = sb_levels.inner0;\n"
    168 			<< "    gl_TessLevelInner[1] = sb_levels.inner1;\n"
    169 			<< "    gl_TessLevelOuter[0] = sb_levels.outer0;\n"
    170 			<< "    gl_TessLevelOuter[1] = sb_levels.outer1;\n"
    171 			<< "    gl_TessLevelOuter[2] = sb_levels.outer2;\n"
    172 			<< "    gl_TessLevelOuter[3] = sb_levels.outer3;\n"
    173 			<<	"}\n";
    174 
    175 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    176 	}
    177 
    178 	// Tessellation evaluation shader
    179 	{
    180 		programCollection.glslSources.add("tese_to_frag")
    181 			<< glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_fragment_color"));
    182 		programCollection.glslSources.add("tese_to_geom")
    183 			<< glu::TessellationEvaluationSource(generateTessellationEvaluationShader(m_primitiveType, "v_evaluated_color"));
    184 	}
    185 
    186 	// Geometry shader
    187 	{
    188 		std::ostringstream	src;
    189 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    190 			<< "#extension GL_EXT_geometry_shader : require\n"
    191 			<< "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(m_primitiveType, false) << ") in;\n"
    192 			<< "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(m_primitiveType, false)
    193 						 << ", max_vertices=" << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
    194 			<< "\n"
    195 			<< "layout(location = 0) in  highp vec4 v_evaluated_color[];\n"
    196 			<< "layout(location = 0) out highp vec4 v_fragment_color;\n"
    197 			<< "\n"
    198 			<< "void main (void)\n"
    199 			<< "{\n"
    200 			<< "    for (int ndx = 0; ndx < gl_in.length(); ++ndx)\n"
    201 			<< "    {\n"
    202 			<< "        gl_Position = gl_in[ndx].gl_Position;\n"
    203 			<< "        v_fragment_color = v_evaluated_color[ndx];\n"
    204 			<< "        EmitVertex();\n"
    205 			<< "    }\n"
    206 			<< "}\n";
    207 
    208 		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
    209 	}
    210 }
    211 
    212 class IdentityTessellationShaderTestCase : public TestCase
    213 {
    214 public:
    215 	void			initPrograms	(vk::SourceCollections& programCollection) const;
    216 	TestInstance*	createInstance	(Context& context) const;
    217 
    218 	IdentityTessellationShaderTestCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TessPrimitiveType primitiveType)
    219 		: TestCase			(testCtx, name, description)
    220 		, m_primitiveType	(primitiveType)
    221 	{
    222 	}
    223 
    224 private:
    225 	const TessPrimitiveType m_primitiveType;
    226 };
    227 
    228 //! Geometry shader used in passthrough tessellation shader case.
    229 std::string generateGeometryShader (const TessPrimitiveType primitiveType, const std::string& colorSourceName)
    230 {
    231 	const int numEmitVertices = (primitiveType == TESSPRIMITIVETYPE_ISOLINES ? 11 : 8);
    232 
    233 	std::ostringstream src;
    234 	src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    235 		<< "#extension GL_EXT_geometry_shader : require\n"
    236 		<< "layout(" << getGeometryShaderInputPrimitiveTypeShaderName(primitiveType, false) << ") in;\n"
    237 		<< "layout(" << getGeometryShaderOutputPrimitiveTypeShaderName(primitiveType, false)
    238 					  << ", max_vertices=" << numEmitVertices << ") out;\n"
    239 		<< "\n"
    240 		<< "layout(location = 0) in  highp vec4 " << colorSourceName << "[];\n"
    241 		<< "layout(location = 0) out highp vec4 v_fragment_color;\n"
    242 		<< "\n"
    243 		<< "void main (void)\n"
    244 		<< "{\n";
    245 
    246 	if (primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
    247 	{
    248 		src << "	vec4 centerPos = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3.0f;\n"
    249 			<< "\n"
    250 			<< "	for (int ndx = 0; ndx < 4; ++ndx)\n"
    251 			<< "	{\n"
    252 			<< "		gl_Position = centerPos + (centerPos - gl_in[ndx % 3].gl_Position);\n"
    253 			<< "		v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
    254 			<< "		EmitVertex();\n"
    255 			<< "\n"
    256 			<< "		gl_Position = centerPos + 0.7 * (centerPos - gl_in[ndx % 3].gl_Position);\n"
    257 			<< "		v_fragment_color = " << colorSourceName << "[ndx % 3];\n"
    258 			<< "		EmitVertex();\n"
    259 			<< "	}\n";
    260 	}
    261 	else if (primitiveType == TESSPRIMITIVETYPE_ISOLINES)
    262 	{
    263 		src << "	vec4 mdir = vec4(gl_in[0].gl_Position.y - gl_in[1].gl_Position.y, gl_in[1].gl_Position.x - gl_in[0].gl_Position.x, 0.0, 0.0);\n"
    264 			<< "	for (int i = 0; i <= 10; ++i)\n"
    265 			<< "	{\n"
    266 			<< "		float xweight = cos(float(i) / 10.0 * 6.28) * 0.5 + 0.5;\n"
    267 			<< "		float mweight = sin(float(i) / 10.0 * 6.28) * 0.1 + 0.1;\n"
    268 			<< "		gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, xweight) + mweight * mdir;\n"
    269 			<< "		v_fragment_color = mix(" << colorSourceName << "[0], " << colorSourceName << "[1], xweight);\n"
    270 			<< "		EmitVertex();\n"
    271 			<< "	}\n";
    272 	}
    273 	else
    274 		DE_ASSERT(false);
    275 
    276 	src << "}\n";
    277 
    278 	return src.str();
    279 }
    280 
    281 void IdentityTessellationShaderTestCase::initPrograms (vk::SourceCollections& programCollection) const
    282 {
    283 	addVertexAndFragmentShaders(programCollection);
    284 
    285 	// Tessellation control
    286 	{
    287 		std::ostringstream src;
    288 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    289 			<< "#extension GL_EXT_tessellation_shader : require\n"
    290 			<< "layout(vertices = " << numVerticesPerPrimitive(m_primitiveType, false) << ") out;\n"
    291 			<< "\n"
    292 			<< "layout(location = 0) in  highp vec4 v_vertex_color[];\n"
    293 			<< "layout(location = 0) out highp vec4 v_control_color[];\n"
    294 			<< "\n"
    295 			<< "void main (void)\n"
    296 			<< "{\n"
    297 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
    298 			<< "    v_control_color[gl_InvocationID] = v_vertex_color[gl_InvocationID];\n"
    299 			<< "\n"
    300 			<< "    gl_TessLevelInner[0] = 1.0;\n"
    301 			<< "    gl_TessLevelInner[1] = 1.0;\n"
    302 			<< "    gl_TessLevelOuter[0] = 1.0;\n"
    303 			<< "    gl_TessLevelOuter[1] = 1.0;\n"
    304 			<< "    gl_TessLevelOuter[2] = 1.0;\n"
    305 			<< "    gl_TessLevelOuter[3] = 1.0;\n"
    306 			<<	"}\n";
    307 
    308 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
    309 	}
    310 
    311 	// Tessellation evaluation shader
    312 	{
    313 		std::ostringstream src;
    314 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
    315 			<< "#extension GL_EXT_tessellation_shader : require\n"
    316 			<< "layout(" << getTessPrimitiveTypeShaderName(m_primitiveType) << ") in;\n"
    317 			<< "\n"
    318 			<< "layout(location = 0) in  highp vec4 v_control_color[];\n"
    319 			<< "layout(location = 0) out highp vec4 v_evaluated_color;\n"
    320 			<< "\n"
    321 			<< "// note: No need to use precise gl_Position since we do not require gapless geometry\n"
    322 			<< "void main (void)\n"
    323 			<< "{\n";
    324 
    325 		if (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
    326 			src << "    gl_Position = gl_TessCoord.x * gl_in[0].gl_Position + gl_TessCoord.y * gl_in[1].gl_Position + gl_TessCoord.z * gl_in[2].gl_Position;\n"
    327 				<< "    v_evaluated_color = gl_TessCoord.x * v_control_color[0] + gl_TessCoord.y * v_control_color[1] + gl_TessCoord.z * v_control_color[2];\n";
    328 		else if (m_primitiveType == TESSPRIMITIVETYPE_ISOLINES)
    329 			src << "    gl_Position = mix(gl_in[0].gl_Position, gl_in[1].gl_Position, gl_TessCoord.x);\n"
    330 				<< "    v_evaluated_color = mix(v_control_color[0], v_control_color[1], gl_TessCoord.x);\n";
    331 		else
    332 			DE_ASSERT(false);
    333 
    334 		src << "}\n";
    335 
    336 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
    337 	}
    338 
    339 	// Geometry shader
    340 	{
    341 		programCollection.glslSources.add("geom_from_tese") << glu::GeometrySource(
    342 			generateGeometryShader(m_primitiveType, "v_evaluated_color"));
    343 		programCollection.glslSources.add("geom_from_vert") << glu::GeometrySource(
    344 			generateGeometryShader(m_primitiveType, "v_vertex_color"));
    345 	}
    346 }
    347 
    348 inline tcu::ConstPixelBufferAccess getPixelBufferAccess (const DeviceInterface& vk,
    349 														 const VkDevice			device,
    350 														 const Buffer&			colorBuffer,
    351 														 const VkFormat			colorFormat,
    352 														 const VkDeviceSize		colorBufferSizeBytes,
    353 														 const tcu::IVec2&		renderSize)
    354 {
    355 	const Allocation& alloc = colorBuffer.getAllocation();
    356 	invalidateMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), colorBufferSizeBytes);
    357 	return tcu::ConstPixelBufferAccess(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
    358 }
    359 
    360 //! When a test case disables tessellation stage and we need to derive a primitive type.
    361 VkPrimitiveTopology getPrimitiveTopology (const TessPrimitiveType primitiveType)
    362 {
    363 	switch (primitiveType)
    364 	{
    365 		case TESSPRIMITIVETYPE_TRIANGLES:
    366 		case TESSPRIMITIVETYPE_QUADS:
    367 			return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
    368 
    369 		case TESSPRIMITIVETYPE_ISOLINES:
    370 			return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
    371 
    372 		default:
    373 			DE_ASSERT(false);
    374 			return VK_PRIMITIVE_TOPOLOGY_LAST;
    375 	}
    376 }
    377 
    378 enum Constants
    379 {
    380 	PIPELINE_CASES	= 2,
    381 	RENDER_SIZE		= 256,
    382 };
    383 
    384 class PassthroughTestInstance : public TestInstance
    385 {
    386 public:
    387 	struct PipelineDescription
    388 	{
    389 		bool		useTessellation;
    390 		bool		useGeometry;
    391 		std::string	tessEvalShaderName;
    392 		std::string	geomShaderName;
    393 		std::string description;
    394 
    395 		PipelineDescription (void) : useTessellation(), useGeometry() {}
    396 	};
    397 
    398 	struct Params
    399 	{
    400 		bool					useTessLevels;
    401 		TessLevels				tessLevels;
    402 		TessPrimitiveType		primitiveType;
    403 		int						inputPatchVertices;
    404 		std::vector<tcu::Vec4>	vertices;
    405 		PipelineDescription		pipelineCases[PIPELINE_CASES];	//!< Each test case renders with two pipelines and compares results
    406 		std::string				message;
    407 
    408 		Params (void) : useTessLevels(), tessLevels(), primitiveType(), inputPatchVertices() {}
    409 	};
    410 
    411 								PassthroughTestInstance	(Context& context, const Params& params) : TestInstance(context), m_params(params) {}
    412 	tcu::TestStatus				iterate					(void);
    413 
    414 private:
    415 	const Params				m_params;
    416 };
    417 
    418 tcu::TestStatus PassthroughTestInstance::iterate (void)
    419 {
    420 	requireFeatures(m_context.getInstanceInterface(), m_context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER);
    421 	DE_STATIC_ASSERT(PIPELINE_CASES == 2);
    422 
    423 	const DeviceInterface&	vk					= m_context.getDeviceInterface();
    424 	const VkDevice			device				= m_context.getDevice();
    425 	const VkQueue			queue				= m_context.getUniversalQueue();
    426 	const deUint32			queueFamilyIndex	= m_context.getUniversalQueueFamilyIndex();
    427 	Allocator&				allocator			= m_context.getDefaultAllocator();
    428 
    429 	// Tessellation levels
    430 	const Buffer tessLevelsBuffer (vk, device, allocator, makeBufferCreateInfo(sizeof(TessLevels), VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), MemoryRequirement::HostVisible);
    431 
    432 	if (m_params.useTessLevels)
    433 	{
    434 		const Allocation& alloc = tessLevelsBuffer.getAllocation();
    435 		TessLevels* const bufferTessLevels = static_cast<TessLevels*>(alloc.getHostPtr());
    436 		*bufferTessLevels = m_params.tessLevels;
    437 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), sizeof(TessLevels));
    438 	}
    439 
    440 	// Vertex attributes
    441 
    442 	const VkDeviceSize	vertexDataSizeBytes = sizeInBytes(m_params.vertices);
    443 	const VkFormat		vertexFormat		= VK_FORMAT_R32G32B32A32_SFLOAT;
    444 	const Buffer		vertexBuffer		(vk, device, allocator, makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT), MemoryRequirement::HostVisible);
    445 
    446 	{
    447 		const Allocation& alloc = vertexBuffer.getAllocation();
    448 		deMemcpy(alloc.getHostPtr(), &m_params.vertices[0], static_cast<std::size_t>(vertexDataSizeBytes));
    449 		flushMappedMemoryRange(vk, device, alloc.getMemory(), alloc.getOffset(), vertexDataSizeBytes);
    450 	}
    451 
    452 	// Descriptors - make descriptor for tessellation levels, even if we don't use them, to simplify code
    453 
    454 	const Unique<VkDescriptorSetLayout> descriptorSetLayout(DescriptorSetLayoutBuilder()
    455 		.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
    456 		.build(vk, device));
    457 
    458 	const Unique<VkDescriptorPool> descriptorPool(DescriptorPoolBuilder()
    459 		.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)
    460 		.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
    461 
    462 	const Unique<VkDescriptorSet> descriptorSet		   (makeDescriptorSet(vk, device, *descriptorPool, *descriptorSetLayout));
    463 	const VkDescriptorBufferInfo  tessLevelsBufferInfo = makeDescriptorBufferInfo(*tessLevelsBuffer, 0ull, sizeof(TessLevels));
    464 
    465 	DescriptorSetUpdateBuilder()
    466 		.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &tessLevelsBufferInfo)
    467 		.update(vk, device);
    468 
    469 	// Color attachment
    470 
    471 	const tcu::IVec2			  renderSize				 = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
    472 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
    473 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
    474 	const Image					  colorAttachmentImage		 (vk, device, allocator,
    475 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
    476 															 MemoryRequirement::Any);
    477 
    478 	// Color output buffer: image will be copied here for verification.
    479 	//                      We use two buffers, one for each case.
    480 
    481 	const VkDeviceSize	colorBufferSizeBytes		= renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
    482 	const Buffer		colorBuffer1				(vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
    483 	const Buffer		colorBuffer2				(vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
    484 	const Buffer* const colorBuffer[PIPELINE_CASES] = { &colorBuffer1, &colorBuffer2 };
    485 
    486 	// Pipeline
    487 
    488 	const Unique<VkImageView>		colorAttachmentView(makeImageView(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
    489 	const Unique<VkRenderPass>		renderPass		   (makeRenderPass(vk, device, colorFormat));
    490 	const Unique<VkFramebuffer>		framebuffer		   (makeFramebuffer(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y(), 1u));
    491 	const Unique<VkPipelineLayout>	pipelineLayout	   (makePipelineLayout(vk, device, *descriptorSetLayout));
    492 	const Unique<VkCommandPool>		cmdPool			   (makeCommandPool(vk, device, queueFamilyIndex));
    493 	const Unique<VkCommandBuffer>	cmdBuffer		   (allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
    494 
    495 	// Message explaining the test
    496 	{
    497 		tcu::TestLog& log = m_context.getTestContext().getLog();
    498 		log << tcu::TestLog::Message << m_params.message << tcu::TestLog::EndMessage;
    499 
    500 		if (m_params.useTessLevels)
    501 			log << tcu::TestLog::Message << "Tessellation levels: " << getTessellationLevelsString(m_params.tessLevels, m_params.primitiveType) << tcu::TestLog::EndMessage;
    502 	}
    503 
    504 	for (int pipelineNdx = 0; pipelineNdx < PIPELINE_CASES; ++pipelineNdx)
    505 	{
    506 		const PipelineDescription& pipelineDescription = m_params.pipelineCases[pipelineNdx];
    507 		GraphicsPipelineBuilder	   pipelineBuilder;
    508 
    509 		pipelineBuilder
    510 			.setPrimitiveTopology		  (getPrimitiveTopology(m_params.primitiveType))
    511 			.setRenderSize				  (renderSize)
    512 			.setBlend					  (true)
    513 			.setVertexInputSingleAttribute(vertexFormat, tcu::getPixelSize(mapVkFormat(vertexFormat)))
    514 			.setPatchControlPoints		  (m_params.inputPatchVertices)
    515 			.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					m_context.getBinaryCollection().get("vert"), DE_NULL)
    516 			.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				m_context.getBinaryCollection().get("frag"), DE_NULL);
    517 
    518 		if (pipelineDescription.useTessellation)
    519 			pipelineBuilder
    520 				.setShader				  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	m_context.getBinaryCollection().get("tesc"), DE_NULL)
    521 				.setShader				  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, m_context.getBinaryCollection().get(pipelineDescription.tessEvalShaderName), DE_NULL);
    522 
    523 		if (pipelineDescription.useGeometry)
    524 			pipelineBuilder
    525 				.setShader				  (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,				m_context.getBinaryCollection().get(pipelineDescription.geomShaderName), DE_NULL);
    526 
    527 		const Unique<VkPipeline> pipeline (pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
    528 
    529 		// Draw commands
    530 
    531 		beginCommandBuffer(vk, *cmdBuffer);
    532 
    533 		// Change color attachment image layout
    534 		{
    535 			// State is slightly different on the first iteration.
    536 			const VkImageLayout currentLayout = (pipelineNdx == 0 ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
    537 			const VkAccessFlags srcFlags	  = (pipelineNdx == 0 ? (VkAccessFlags)0          : (VkAccessFlags)VK_ACCESS_TRANSFER_READ_BIT);
    538 
    539 			const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
    540 				srcFlags, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
    541 				currentLayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
    542 				*colorAttachmentImage, colorImageSubresourceRange);
    543 
    544 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u,
    545 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
    546 		}
    547 
    548 		// Begin render pass
    549 		{
    550 			const VkRect2D renderArea = {
    551 				makeOffset2D(0, 0),
    552 				makeExtent2D(renderSize.x(), renderSize.y()),
    553 			};
    554 			const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
    555 
    556 			beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
    557 		}
    558 
    559 		vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
    560 		{
    561 			const VkDeviceSize vertexBufferOffset = 0ull;
    562 			vk.cmdBindVertexBuffers(*cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
    563 		}
    564 
    565 		if (m_params.useTessLevels)
    566 			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipelineLayout, 0u, 1u, &descriptorSet.get(), 0u, DE_NULL);
    567 
    568 		vk.cmdDraw(*cmdBuffer, static_cast<deUint32>(m_params.vertices.size()), 1u, 0u, 0u);
    569 		endRenderPass(vk, *cmdBuffer);
    570 
    571 		// Copy render result to a host-visible buffer
    572 		{
    573 			const VkImageMemoryBarrier colorAttachmentPreCopyBarrier = makeImageMemoryBarrier(
    574 				VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
    575 				VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
    576 				*colorAttachmentImage, colorImageSubresourceRange);
    577 
    578 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u,
    579 				0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentPreCopyBarrier);
    580 		}
    581 		{
    582 			const VkBufferImageCopy copyRegion = makeBufferImageCopy(makeExtent3D(renderSize.x(), renderSize.y(), 1), makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u));
    583 			vk.cmdCopyImageToBuffer(*cmdBuffer, *colorAttachmentImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorBuffer[pipelineNdx]->get(), 1u, &copyRegion);
    584 		}
    585 		{
    586 			const VkBufferMemoryBarrier postCopyBarrier = makeBufferMemoryBarrier(
    587 				VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, colorBuffer[pipelineNdx]->get(), 0ull, colorBufferSizeBytes);
    588 
    589 			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u,
    590 				0u, DE_NULL, 1u, &postCopyBarrier, 0u, DE_NULL);
    591 		}
    592 
    593 		endCommandBuffer(vk, *cmdBuffer);
    594 		submitCommandsAndWait(vk, device, queue, *cmdBuffer);
    595 	}
    596 
    597 	// Verify results
    598 
    599 	tcu::ConstPixelBufferAccess image0 = getPixelBufferAccess(vk, device, *colorBuffer[0], colorFormat, colorBufferSizeBytes, renderSize);
    600 	tcu::ConstPixelBufferAccess image1 = getPixelBufferAccess(vk, device, *colorBuffer[1], colorFormat, colorBufferSizeBytes, renderSize);
    601 
    602 	const tcu::UVec4 colorThreshold    (8, 8, 8, 255);
    603 	const tcu::IVec3 positionDeviation (1, 1, 0);		// 3x3 search kernel
    604 	const bool		 ignoreOutOfBounds = true;
    605 
    606 	tcu::TestLog& log = m_context.getTestContext().getLog();
    607 	log << tcu::TestLog::Message
    608 		<< "In image comparison:\n"
    609 		<< "  Reference - " << m_params.pipelineCases[0].description << "\n"
    610 		<< "  Result    - " << m_params.pipelineCases[1].description << "\n"
    611 		<< tcu::TestLog::EndMessage;
    612 
    613 	const bool ok = tcu::intThresholdPositionDeviationCompare(
    614 		log, "ImageCompare", "Image comparison", image0, image1, colorThreshold, positionDeviation, ignoreOutOfBounds, tcu::COMPARE_LOG_RESULT);
    615 
    616 	return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Image comparison failed"));
    617 }
    618 
    619 TestInstance* IdentityGeometryShaderTestCase::createInstance (Context& context) const
    620 {
    621 	PassthroughTestInstance::Params params;
    622 
    623 	const float level		   = 14.0;
    624 	params.useTessLevels	   = true;
    625 	params.tessLevels.inner[0] = level;
    626 	params.tessLevels.inner[1] = level;
    627 	params.tessLevels.outer[0] = level;
    628 	params.tessLevels.outer[1] = level;
    629 	params.tessLevels.outer[2] = level;
    630 	params.tessLevels.outer[3] = level;
    631 
    632 	params.primitiveType	   = m_primitiveType;
    633 	params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
    634 
    635 	params.vertices.push_back(tcu::Vec4( -0.9f, -0.9f, 0.0f, 1.0f ));
    636 	params.vertices.push_back(tcu::Vec4( -0.9f,  0.9f, 0.0f, 1.0f ));
    637 	params.vertices.push_back(tcu::Vec4(  0.9f, -0.9f, 0.0f, 1.0f ));
    638 	params.vertices.push_back(tcu::Vec4(  0.9f,  0.9f, 0.0f, 1.0f ));
    639 
    640 	params.pipelineCases[0].useTessellation		= true;
    641 	params.pipelineCases[0].useGeometry			= true;
    642 	params.pipelineCases[0].tessEvalShaderName	= "tese_to_geom";
    643 	params.pipelineCases[0].geomShaderName		= "geom";
    644 	params.pipelineCases[0].description			= "passthrough geometry shader";
    645 
    646 	params.pipelineCases[1].useTessellation		= true;
    647 	params.pipelineCases[1].useGeometry			= false;
    648 	params.pipelineCases[1].tessEvalShaderName	= "tese_to_frag";
    649 	params.pipelineCases[1].geomShaderName		= "geom";
    650 	params.pipelineCases[1].description			= "no geometry shader in the pipeline";
    651 
    652 	params.message = "Testing tessellating shader program output does not change when a passthrough geometry shader is attached.\n"
    653 					 "Rendering two images, first with and second without a geometry shader. Expecting similar results.\n"
    654 					 "Using additive blending to detect overlap.\n";
    655 
    656 	return new PassthroughTestInstance(context, params);
    657 };
    658 
    659 TestInstance* IdentityTessellationShaderTestCase::createInstance (Context& context) const
    660 {
    661 	PassthroughTestInstance::Params params;
    662 
    663 	params.useTessLevels	   = false;
    664 	params.primitiveType	   = m_primitiveType;
    665 	params.inputPatchVertices  = (m_primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 2);
    666 
    667 	params.vertices.push_back(	  tcu::Vec4( -0.4f,  0.4f, 0.0f, 1.0f ));
    668 	params.vertices.push_back(	  tcu::Vec4(  0.0f, -0.5f, 0.0f, 1.0f ));
    669 	if (params.inputPatchVertices == 3)
    670 		params.vertices.push_back(tcu::Vec4(  0.4f,  0.4f, 0.0f, 1.0f ));
    671 
    672 	params.pipelineCases[0].useTessellation		= true;
    673 	params.pipelineCases[0].useGeometry			= true;
    674 	params.pipelineCases[0].tessEvalShaderName	= "tese";
    675 	params.pipelineCases[0].geomShaderName		= "geom_from_tese";
    676 	params.pipelineCases[0].description			= "passthrough tessellation shaders";
    677 
    678 	params.pipelineCases[1].useTessellation		= false;
    679 	params.pipelineCases[1].useGeometry			= true;
    680 	params.pipelineCases[1].tessEvalShaderName	= "tese";
    681 	params.pipelineCases[1].geomShaderName		= "geom_from_vert";
    682 	params.pipelineCases[1].description			= "no tessellation shaders in the pipeline";
    683 
    684 	params.message = "Testing geometry shading shader program output does not change when a passthrough tessellation shader is attached.\n"
    685 					 "Rendering two images, first with and second without a tessellation shader. Expecting similar results.\n"
    686 					 "Using additive blending to detect overlap.\n";
    687 
    688 	return new PassthroughTestInstance(context, params);
    689 };
    690 
    691 inline TestCase* makeIdentityGeometryShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
    692 {
    693 	return new IdentityGeometryShaderTestCase(
    694 		testCtx,
    695 		"tessellate_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_passthrough_geometry_no_change",
    696 		"Passthrough geometry shader has no effect",
    697 		primitiveType);
    698 }
    699 
    700 inline TestCase* makeIdentityTessellationShaderCase (tcu::TestContext& testCtx, const TessPrimitiveType primitiveType)
    701 {
    702 	return new IdentityTessellationShaderTestCase(
    703 		testCtx,
    704 		"passthrough_tessellation_geometry_shade_" + de::toString(getTessPrimitiveTypeShaderName(primitiveType)) + "_no_change",
    705 		"Passthrough tessellation shader has no effect",
    706 		primitiveType);
    707 }
    708 
    709 } // anonymous
    710 
    711 
    712 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.render.passthrough.*
    713 tcu::TestCaseGroup* createGeometryPassthroughTests (tcu::TestContext& testCtx)
    714 {
    715 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "passthrough", "Render various types with either passthrough geometry or tessellation shader"));
    716 
    717 	// Passthrough geometry shader
    718 	group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
    719 	group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_QUADS));
    720 	group->addChild(makeIdentityGeometryShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
    721 
    722 	// Passthrough tessellation shader
    723 	group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_TRIANGLES));
    724 	group->addChild(makeIdentityTessellationShaderCase(testCtx, TESSPRIMITIVETYPE_ISOLINES));
    725 
    726 	return group.release();
    727 }
    728 
    729 } // tessellation
    730 } // vkt
    731