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