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