• 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 - Point Size
23 *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationGeometryPassthroughTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 
29 #include "tcuTestLog.hpp"
30 
31 #include "vkDefs.hpp"
32 #include "vkBarrierUtil.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkTypeUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkObjUtil.hpp"
39 #include "vkBufferWithMemory.hpp"
40 #include "vkImageWithMemory.hpp"
41 
42 #include "deUniquePtr.hpp"
43 
44 #include <string>
45 #include <vector>
46 
47 namespace vkt
48 {
49 namespace tessellation
50 {
51 
52 using namespace vk;
53 
54 namespace
55 {
56 
57 enum Constants
58 {
59 	RENDER_SIZE = 32,
60 };
61 
62 enum FlagBits
63 {
64 	FLAG_VERTEX_SET						= 1u << 0,		// !< set gl_PointSize in vertex shader
65 	FLAG_TESSELLATION_EVALUATION_SET	= 1u << 1,		// !< set gl_PointSize in tessellation evaluation shader
66 	FLAG_TESSELLATION_ADD				= 1u << 2,		// !< read and add to gl_PointSize in tessellation shader pair
67 	FLAG_GEOMETRY_SET					= 1u << 3,		// !< set gl_PointSize in geometry shader
68 	FLAG_GEOMETRY_ADD					= 1u << 4,		// !< read and add to gl_PointSize in geometry shader
69 };
70 typedef deUint32 Flags;
71 
checkPointSizeRequirements(const InstanceInterface & vki,const VkPhysicalDevice physDevice,const int maxPointSize)72 void checkPointSizeRequirements (const InstanceInterface& vki, const VkPhysicalDevice physDevice, const int maxPointSize)
73 {
74 	const VkPhysicalDeviceProperties properties = getPhysicalDeviceProperties(vki, physDevice);
75 	if (maxPointSize > static_cast<int>(properties.limits.pointSizeRange[1]))
76 		throw tcu::NotSupportedError("Test requires point size " + de::toString(maxPointSize));
77 	// Point size granularity must be 1.0 at most, so no need to check it for this test.
78 }
79 
getExpectedPointSize(const Flags flags)80 int getExpectedPointSize (const Flags flags)
81 {
82 	int addition = 0;
83 
84 	// geometry
85 	if (flags & FLAG_GEOMETRY_SET)
86 		return 6;
87 	else if (flags & FLAG_GEOMETRY_ADD)
88 		addition += 2;
89 
90 	// tessellation
91 	if (flags & FLAG_TESSELLATION_EVALUATION_SET)
92 		return 4 + addition;
93 	else if (flags & FLAG_TESSELLATION_ADD)
94 		addition += 2;
95 
96 	// vertex
97 	if (flags & FLAG_VERTEX_SET)
98 		return 2 + addition;
99 
100 	// undefined
101 	DE_ASSERT(false);
102 	return -1;
103 }
104 
isTessellationStage(const Flags flags)105 inline bool isTessellationStage (const Flags flags)
106 {
107 	return (flags & (FLAG_TESSELLATION_EVALUATION_SET | FLAG_TESSELLATION_ADD)) != 0;
108 }
109 
isGeometryStage(const Flags flags)110 inline bool isGeometryStage (const Flags flags)
111 {
112 	return (flags & (FLAG_GEOMETRY_SET | FLAG_GEOMETRY_ADD)) != 0;
113 }
114 
verifyImage(tcu::TestLog & log,const tcu::ConstPixelBufferAccess image,const int expectedSize)115 bool verifyImage (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image, const int expectedSize)
116 {
117 	log << tcu::TestLog::Message << "Verifying rendered point size. Expecting " << expectedSize << " pixels." << tcu::TestLog::EndMessage;
118 
119 	bool			resultAreaFound	= false;
120 	tcu::IVec4		resultArea;
121 	const tcu::Vec4	black(0.0, 0.0, 0.0, 1.0);
122 
123 	// Find rasterization output area
124 
125 	for (int y = 0; y < image.getHeight(); ++y)
126 	for (int x = 0; x < image.getWidth();  ++x)
127 		if (image.getPixel(x, y) != black)
128 		{
129 			if (!resultAreaFound)
130 			{
131 				// first fragment
132 				resultArea = tcu::IVec4(x, y, x + 1, y + 1);
133 				resultAreaFound = true;
134 			}
135 			else
136 			{
137 				// union area
138 				resultArea.x() = de::min(resultArea.x(), x);
139 				resultArea.y() = de::min(resultArea.y(), y);
140 				resultArea.z() = de::max(resultArea.z(), x+1);
141 				resultArea.w() = de::max(resultArea.w(), y+1);
142 			}
143 		}
144 
145 	if (!resultAreaFound)
146 	{
147 		log << tcu::TestLog::Message << "Verification failed, could not find any point fragments." << tcu::TestLog::EndMessage;
148 		return false;
149 	}
150 
151 	const tcu::IVec2 pointSize = resultArea.swizzle(2,3) - resultArea.swizzle(0, 1);
152 
153 	if (pointSize.x() != pointSize.y())
154 	{
155 		log << tcu::TestLog::Message << "ERROR! Rasterized point is not a square. Point size was " << pointSize << tcu::TestLog::EndMessage;
156 		return false;
157 	}
158 
159 	if (pointSize.x() != expectedSize)
160 	{
161 		log << tcu::TestLog::Message << "ERROR! Point size invalid, expected " << expectedSize << ", got " << pointSize.x() << tcu::TestLog::EndMessage;
162 		return false;
163 	}
164 
165 	return true;
166 }
167 
initPrograms(vk::SourceCollections & programCollection,const Flags flags)168 void initPrograms (vk::SourceCollections& programCollection, const Flags flags)
169 {
170 	// Vertex shader
171 	{
172 		std::ostringstream src;
173 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
174 			<< "\n"
175 			<< "void main (void)\n"
176 			<< "{\n"
177 			<< "    gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n";
178 
179 		if (flags & FLAG_VERTEX_SET)
180 			src << "    gl_PointSize = 2.0;\n";
181 
182 		src << "}\n";
183 
184 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
185 	}
186 
187 	// Fragment shader
188 	{
189 		std::ostringstream src;
190 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
191 			<< "layout(location = 0) out mediump vec4 fragColor;\n"
192 			<< "\n"
193 			<< "void main (void)\n"
194 			<< "{\n"
195 			<< "    fragColor = vec4(1.0);\n"
196 			<< "}\n";
197 
198 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
199 	}
200 
201 	if (isTessellationStage(flags))
202 	{
203 		// Tessellation control shader
204 		{
205 			std::ostringstream src;
206 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
207 				<< "#extension GL_EXT_tessellation_shader : require\n"
208 				<< "#extension GL_EXT_tessellation_point_size : require\n"
209 				<< "layout(vertices = 1) out;\n"
210 				<< "\n"
211 				<< "void main (void)\n"
212 				<< "{\n"
213 				<< "    gl_TessLevelOuter[0] = 3.0;\n"
214 				<< "    gl_TessLevelOuter[1] = 3.0;\n"
215 				<< "    gl_TessLevelOuter[2] = 3.0;\n"
216 				<< "    gl_TessLevelInner[0] = 3.0;\n"
217 				<< "\n"
218 				<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n";
219 
220 			if (flags & FLAG_TESSELLATION_ADD)
221 				src << "    // pass as is to eval\n"
222 					<< "    gl_out[gl_InvocationID].gl_PointSize = gl_in[gl_InvocationID].gl_PointSize;\n";
223 
224 			src << "}\n";
225 
226 			programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
227 		}
228 
229 		// Tessellation evaluation shader
230 		{
231 			std::ostringstream src;
232 			src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
233 				<< "#extension GL_EXT_tessellation_shader : require\n"
234 				<< "#extension GL_EXT_tessellation_point_size : require\n"
235 				<< "layout(triangles, point_mode) in;\n"
236 				<< "\n"
237 				<< "void main (void)\n"
238 				<< "{\n"
239 				<< "    // hide all but one vertex\n"
240 				<< "    if (gl_TessCoord.x < 0.99)\n"
241 				<< "        gl_Position = vec4(-2.0, 0.0, 0.0, 1.0);\n"
242 				<< "    else\n"
243 				<< "        gl_Position = gl_in[0].gl_Position;\n";
244 
245 			if (flags & FLAG_TESSELLATION_ADD)
246 				src << "\n"
247 					<< "    // add to point size\n"
248 					<< "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
249 			else if (flags & FLAG_TESSELLATION_EVALUATION_SET)
250 				src << "\n"
251 					<< "    // set point size\n"
252 					<< "    gl_PointSize = 4.0;\n";
253 
254 			src << "}\n";
255 
256 			programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
257 		}
258 	}
259 
260 	if (isGeometryStage(flags))
261 	{
262 		// Geometry shader
263 		std::ostringstream src;
264 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
265 			<< "#extension GL_EXT_geometry_shader : require\n"
266 			<< "#extension GL_EXT_geometry_point_size : require\n"
267 			<< "layout(points) in;\n"
268 			<< "layout(points, max_vertices = 1) out;\n"
269 			<< "\n"
270 			<< "void main (void)\n"
271 			<< "{\n"
272 			<< "    gl_Position  = gl_in[0].gl_Position;\n";
273 
274 		if (flags & FLAG_GEOMETRY_SET)
275 			src << "    gl_PointSize = 6.0;\n";
276 		else if (flags & FLAG_GEOMETRY_ADD)
277 			src << "    gl_PointSize = gl_in[0].gl_PointSize + 2.0;\n";
278 
279 		src << "\n"
280 			<< "    EmitVertex();\n"
281 			<< "}\n";
282 
283 		programCollection.glslSources.add("geom") << glu::GeometrySource(src.str());
284 	}
285 }
286 
test(Context & context,const Flags flags)287 tcu::TestStatus test (Context& context, const Flags flags)
288 {
289 	const int expectedPointSize = getExpectedPointSize(flags);
290 	{
291 		const InstanceInterface& vki        = context.getInstanceInterface();
292 		const VkPhysicalDevice   physDevice = context.getPhysicalDevice();
293 
294 		requireFeatures           (vki, physDevice, FEATURE_TESSELLATION_SHADER | FEATURE_GEOMETRY_SHADER | FEATURE_SHADER_TESSELLATION_AND_GEOMETRY_POINT_SIZE);
295 		checkPointSizeRequirements(vki, physDevice, expectedPointSize);
296 	}
297 	{
298 		tcu::TestLog& log = context.getTestContext().getLog();
299 
300 		if (flags & FLAG_VERTEX_SET)
301 			log << tcu::TestLog::Message << "Setting point size in vertex shader to 2.0." << tcu::TestLog::EndMessage;
302 		if (flags & FLAG_TESSELLATION_EVALUATION_SET)
303 			log << tcu::TestLog::Message << "Setting point size in tessellation evaluation shader to 4.0." << tcu::TestLog::EndMessage;
304 		if (flags & FLAG_TESSELLATION_ADD)
305 			log << tcu::TestLog::Message << "Reading point size in tessellation control shader and adding 2.0 to it in evaluation." << tcu::TestLog::EndMessage;
306 		if (flags & FLAG_GEOMETRY_SET)
307 			log << tcu::TestLog::Message << "Setting point size in geometry shader to 6.0." << tcu::TestLog::EndMessage;
308 		if (flags & FLAG_GEOMETRY_ADD)
309 			log << tcu::TestLog::Message << "Reading point size in geometry shader and adding 2.0." << tcu::TestLog::EndMessage;
310 	}
311 
312 	const DeviceInterface&	vk					= context.getDeviceInterface();
313 	const VkDevice			device				= context.getDevice();
314 	const VkQueue			queue				= context.getUniversalQueue();
315 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
316 	Allocator&				allocator			= context.getDefaultAllocator();
317 
318 	// Color attachment
319 
320 	const tcu::IVec2			  renderSize				 = tcu::IVec2(RENDER_SIZE, RENDER_SIZE);
321 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
322 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
323 	const ImageWithMemory		  colorAttachmentImage		 (vk, device, allocator,
324 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
325 															 MemoryRequirement::Any);
326 
327 	// Color output buffer
328 
329 	const VkDeviceSize		colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
330 	const BufferWithMemory	colorBuffer          (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
331 
332 	// Pipeline
333 
334 	const Unique<VkImageView>		colorAttachmentView	(makeImageView			(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
335 	const Unique<VkRenderPass>		renderPass			(makeRenderPass			(vk, device, colorFormat));
336 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer		(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
337 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout		(vk, device));
338 	const Unique<VkCommandPool>		cmdPool				(makeCommandPool		(vk, device, queueFamilyIndex));
339 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer	(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
340 
341 	GraphicsPipelineBuilder			pipelineBuilder;
342 
343 	pipelineBuilder
344 		.setPrimitiveTopology		  (VK_PRIMITIVE_TOPOLOGY_POINT_LIST)
345 		.setRenderSize				  (renderSize)
346 		.setPatchControlPoints		  (1)
347 		.setShader					  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
348 		.setShader					  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL);
349 
350 	if (isTessellationStage(flags))
351 		pipelineBuilder
352 			.setShader				  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
353 			.setShader				  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL);
354 
355 	if (isGeometryStage(flags))
356 		pipelineBuilder
357 			.setShader				  (vk, device, VK_SHADER_STAGE_GEOMETRY_BIT,				context.getBinaryCollection().get("geom"), DE_NULL);
358 
359 	const Unique<VkPipeline> pipeline(pipelineBuilder.build(vk, device, *pipelineLayout, *renderPass));
360 
361 	// Draw commands
362 
363 	beginCommandBuffer(vk, *cmdBuffer);
364 
365 	{
366 		const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
367 			(VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
368 			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
369 			*colorAttachmentImage, colorImageSubresourceRange);
370 
371 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
372 			0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
373 	}
374 
375 	// Begin render pass
376 	{
377 		const VkRect2D	renderArea	= makeRect2D(renderSize);
378 		const tcu::Vec4	clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
379 
380 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
381 	}
382 
383 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
384 
385 	vk.cmdDraw(*cmdBuffer, 1u, 1u, 0u, 0u);
386 	endRenderPass(vk, *cmdBuffer);
387 
388 	// Copy render result to a host-visible buffer
389 	copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
390 
391 	endCommandBuffer(vk, *cmdBuffer);
392 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
393 
394 	// Verify results
395 	{
396 		const Allocation&			alloc	= colorBuffer.getAllocation();
397 		tcu::TestLog&				log		= context.getTestContext().getLog();
398 
399 		invalidateAlloc(vk, device, alloc);
400 
401 		tcu::ConstPixelBufferAccess	image	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, alloc.getHostPtr());
402 
403 		log << tcu::LogImage("color0", "", image);
404 
405 		if (verifyImage(log, image, expectedPointSize))
406 			return tcu::TestStatus::pass("OK");
407 		else
408 			return tcu::TestStatus::fail("Didn't render expected point");
409 	}
410 }
411 
getTestCaseName(const Flags flags)412 std::string getTestCaseName (const Flags flags)
413 {
414 	std::ostringstream buf;
415 
416 	// join per-bit descriptions into a single string with '_' separator
417 	if (flags & FLAG_VERTEX_SET)					buf																		<< "vertex_set";
418 	if (flags & FLAG_TESSELLATION_EVALUATION_SET)	buf << ((flags & (FLAG_TESSELLATION_EVALUATION_SET-1))	? ("_") : (""))	<< "evaluation_set";
419 	if (flags & FLAG_TESSELLATION_ADD)				buf << ((flags & (FLAG_TESSELLATION_ADD-1))				? ("_") : (""))	<< "control_pass_eval_add";
420 	if (flags & FLAG_GEOMETRY_SET)					buf << ((flags & (FLAG_GEOMETRY_SET-1))					? ("_") : (""))	<< "geometry_set";
421 	if (flags & FLAG_GEOMETRY_ADD)					buf << ((flags & (FLAG_GEOMETRY_ADD-1))					? ("_") : (""))	<< "geometry_add";
422 
423 	return buf.str();
424 }
425 
checkSupportTess(Context & context,const Flags flags)426 void checkSupportTess (Context& context, const Flags flags)
427 {
428 #ifndef CTS_USES_VULKANSC
429 	if (isTessellationStage(flags))
430 		if (const vk::VkPhysicalDevicePortabilitySubsetFeaturesKHR* const features = getPortability(context))
431 			checkPointMode(*features);
432 #else
433 	DE_UNREF(context);
434 	DE_UNREF(flags);
435 #endif // CTS_USES_VULKANSC
436 }
437 
438 } // anonymous
439 
440 //! Ported from dEQP-GLES31.functional.tessellation_geometry_interaction.point_size.*
441 //! with the exception of the default 1.0 point size cases (not valid in Vulkan).
createGeometryPointSizeTests(tcu::TestContext & testCtx)442 tcu::TestCaseGroup* createGeometryPointSizeTests (tcu::TestContext& testCtx)
443 {
444 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "point_size"));
445 
446 	static const Flags caseFlags[] =
447 	{
448 		FLAG_VERTEX_SET,
449 							FLAG_TESSELLATION_EVALUATION_SET,
450 																	FLAG_GEOMETRY_SET,
451 		FLAG_VERTEX_SET	|	FLAG_TESSELLATION_EVALUATION_SET,
452 		FLAG_VERTEX_SET |											FLAG_GEOMETRY_SET,
453 		FLAG_VERTEX_SET	|	FLAG_TESSELLATION_EVALUATION_SET	|	FLAG_GEOMETRY_SET,
454 		FLAG_VERTEX_SET	|	FLAG_TESSELLATION_ADD				|	FLAG_GEOMETRY_ADD,
455 	};
456 
457 	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(caseFlags); ++ndx)
458 	{
459 		const std::string name = getTestCaseName       (caseFlags[ndx]);
460 
461 		addFunctionCaseWithPrograms(group.get(), name, checkSupportTess, initPrograms, test, caseFlags[ndx]);
462 	}
463 
464 	return group.release();
465 }
466 
467 } // tessellation
468 } // vkt
469