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