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