• 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 Common Edge Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktTessellationCommonEdgeTests.hpp"
26 #include "vktTestCaseUtil.hpp"
27 #include "vktTessellationUtil.hpp"
28 
29 #include "tcuTestLog.hpp"
30 #include "tcuTexture.hpp"
31 
32 #include "vkDefs.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkBuilderUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkBarrierUtil.hpp"
37 #include "vkTypeUtil.hpp"
38 #include "vkStrUtil.hpp"
39 #include "vkCmdUtil.hpp"
40 #include "vkObjUtil.hpp"
41 #include "vkBufferWithMemory.hpp"
42 #include "vkImageWithMemory.hpp"
43 
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 
47 #include <string>
48 #include <vector>
49 
50 namespace vkt
51 {
52 namespace tessellation
53 {
54 
55 using namespace vk;
56 
57 namespace
58 {
59 
60 enum CaseType
61 {
62 	CASETYPE_BASIC = 0,		//!< Order patch vertices such that when two patches share a vertex, it's at the same index for both.
63 	CASETYPE_PRECISE,		//!< Vertex indices don't match like for CASETYPE_BASIC, but other measures are taken, using the 'precise' qualifier.
64 
65 	CASETYPE_LAST
66 };
67 
68 struct CaseDefinition
69 {
70 	TessPrimitiveType	primitiveType;
71 	SpacingMode			spacingMode;
72 	CaseType			caseType;
73 };
74 
75 //! Check that a certain rectangle in the image contains no black pixels.
76 //! Returns true if an image successfully passess the verification.
verifyResult(tcu::TestLog & log,const tcu::ConstPixelBufferAccess image)77 bool verifyResult (tcu::TestLog& log, const tcu::ConstPixelBufferAccess image)
78 {
79 	const int startX = static_cast<int>(0.15f * (float)image.getWidth());
80 	const int endX	 = static_cast<int>(0.85f * (float)image.getWidth());
81 	const int startY = static_cast<int>(0.15f * (float)image.getHeight());
82 	const int endY	 = static_cast<int>(0.85f * (float)image.getHeight());
83 
84 	for (int y = startY; y < endY; ++y)
85 	for (int x = startX; x < endX; ++x)
86 	{
87 		const tcu::Vec4 pixel = image.getPixel(x, y);
88 
89 		if (pixel.x() == 0 && pixel.y() == 0 && pixel.z() == 0)
90 		{
91 			log << tcu::TestLog::Message << "Failure: there seem to be cracks in the rendered result" << tcu::TestLog::EndMessage
92 				<< tcu::TestLog::Message << "Note: pixel with zero r, g and b channels found at " << tcu::IVec2(x, y) << tcu::TestLog::EndMessage;
93 
94 			return false;
95 		}
96 	}
97 
98 	log << tcu::TestLog::Message << "Success: there seem to be no cracks in the rendered result" << tcu::TestLog::EndMessage;
99 
100 	return true;
101 }
102 
initPrograms(vk::SourceCollections & programCollection,const CaseDefinition caseDef)103 void initPrograms (vk::SourceCollections& programCollection, const CaseDefinition caseDef)
104 {
105 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
106 
107 	// Vertex shader
108 	{
109 		std::ostringstream src;
110 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
111 			<< "\n"
112 			<< "layout(location = 0) in highp vec2  in_v_position;\n"
113 			<< "layout(location = 1) in highp float in_v_tessParam;\n"
114 			<< "\n"
115 			<< "layout(location = 0) out highp vec2  in_tc_position;\n"
116 			<< "layout(location = 1) out highp float in_tc_tessParam;\n"
117 			<< "\n"
118 			<< "void main (void)\n"
119 			<< "{\n"
120 			<< "    in_tc_position = in_v_position;\n"
121 			<< "    in_tc_tessParam = in_v_tessParam;\n"
122 			<< "}\n";
123 
124 		programCollection.glslSources.add("vert") << glu::VertexSource(src.str());
125 	}
126 
127 	// Tessellation control shader
128 	{
129 		const int numVertices = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
130 
131 		std::ostringstream src;
132 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
133 			<< "#extension GL_EXT_tessellation_shader : require\n"
134 			<< (caseDef.caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "")
135 			<< "\n"
136 			<< "layout(vertices = " << numVertices << ") out;\n"
137 			<< "\n"
138 			<< "layout(location = 0) in highp vec2  in_tc_position[];\n"
139 			<< "layout(location = 1) in highp float in_tc_tessParam[];\n"
140 			<< "\n"
141 			<< "layout(location = 0) out highp vec2 in_te_position[];\n"
142 			<< "\n"
143 			<< (caseDef.caseType == CASETYPE_PRECISE ? "precise gl_TessLevelOuter;\n\n" : "")
144 			<< "void main (void)\n"
145 			<< "{\n"
146 			<< "    in_te_position[gl_InvocationID] = in_tc_position[gl_InvocationID];\n"
147 			<< "\n"
148 			<< "    gl_TessLevelInner[0] = 5.0;\n"
149 			<< "    gl_TessLevelInner[1] = 5.0;\n"
150 			<< "\n"
151 			<< (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ?
152 				"    gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[2]);\n"
153 				"    gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[0]);\n"
154 				"    gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[1]);\n"
155 				: caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS ?
156 				"    gl_TessLevelOuter[0] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[0] + in_tc_tessParam[2]);\n"
157 				"    gl_TessLevelOuter[1] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[1] + in_tc_tessParam[0]);\n"
158 				"    gl_TessLevelOuter[2] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[3] + in_tc_tessParam[1]);\n"
159 				"    gl_TessLevelOuter[3] = 1.0 + 59.0 * 0.5 * (in_tc_tessParam[2] + in_tc_tessParam[3]);\n"
160 				: "")
161 			<< "}\n";
162 
163 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(src.str());
164 	}
165 
166 	// Tessellation evaluation shader
167 	{
168 		std::ostringstream primitiveSpecificCode;
169 		if (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
170 			primitiveSpecificCode
171 			<< "    highp vec2 pos = gl_TessCoord.x*in_te_position[0] + gl_TessCoord.y*in_te_position[1] + gl_TessCoord.z*in_te_position[2];\n"
172 			<< "\n"
173 			<< "    highp float f = sqrt(3.0 * min(gl_TessCoord.x, min(gl_TessCoord.y, gl_TessCoord.z))) * 0.5 + 0.5;\n"
174 			<< "    in_f_color = vec4(gl_TessCoord*f, 1.0);\n";
175 		else if (caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
176 			primitiveSpecificCode
177 			<< (caseDef.caseType == CASETYPE_BASIC ?
178 				"    highp vec2 pos = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0]\n"
179 				"                   + (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1]\n"
180 				"                   + (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2]\n"
181 				"                   + (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
182 				: caseDef.caseType == CASETYPE_PRECISE ?
183 				"    highp vec2 a = (1.0-gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[0];\n"
184 				"    highp vec2 b = (    gl_TessCoord.x)*(1.0-gl_TessCoord.y)*in_te_position[1];\n"
185 				"    highp vec2 c = (1.0-gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[2];\n"
186 				"    highp vec2 d = (    gl_TessCoord.x)*(    gl_TessCoord.y)*in_te_position[3];\n"
187 				"    highp vec2 pos = a+b+c+d;\n"
188 				: "")
189 			<< "\n"
190 			<< "    highp float f = sqrt(1.0 - 2.0 * max(abs(gl_TessCoord.x - 0.5), abs(gl_TessCoord.y - 0.5)))*0.5 + 0.5;\n"
191 			<< "    in_f_color = vec4(0.1, gl_TessCoord.xy*f, 1.0);\n";
192 
193 		std::ostringstream src;
194 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
195 			<< "#extension GL_EXT_tessellation_shader : require\n"
196 			<< (caseDef.caseType == CASETYPE_PRECISE ? "#extension GL_EXT_gpu_shader5 : require\n" : "")
197 			<< "\n"
198 			<< "layout(" << getTessPrimitiveTypeShaderName(caseDef.primitiveType) << ", "
199 						 << getSpacingModeShaderName(caseDef.spacingMode) << ") in;\n"
200 			<< "\n"
201 			<< "layout(location = 0) in highp vec2 in_te_position[];\n"
202 			<< "\n"
203 			<< "layout(location = 0) out mediump vec4 in_f_color;\n"
204 			<< "\n"
205 			<< (caseDef.caseType == CASETYPE_PRECISE ? "precise gl_Position;\n\n" : "")
206 			<< "void main (void)\n"
207 			<< "{\n"
208 			<< primitiveSpecificCode.str()
209 			<< "\n"
210 			<< "    // Offset the position slightly, based on the parity of the bits in the float representation.\n"
211 			<< "    // This is done to detect possible small differences in edge vertex positions between patches.\n"
212 			<< "    uvec2 bits = floatBitsToUint(pos);\n"
213 			<< "    uint numBits = 0u;\n"
214 			<< "    for (uint i = 0u; i < 32u; i++)\n"
215 			<< "        numBits += ((bits[0] >> i) & 1u) + ((bits[1] >> i) & 1u);\n"
216 			<< "    pos += float(numBits&1u)*0.04;\n"
217 			<< "\n"
218 			<< "    gl_Position = vec4(pos, 0.0, 1.0);\n"
219 			<< "}\n";
220 
221 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(src.str());
222 	}
223 
224 	// Fragment shader
225 	{
226 		std::ostringstream src;
227 		src << glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_310_ES) << "\n"
228 			<< "\n"
229 			<< "layout(location = 0) in mediump vec4 in_f_color;\n"
230 			<< "\n"
231 			<< "layout(location = 0) out mediump vec4 o_color;\n"
232 			<< "\n"
233 			<< "void main (void)\n"
234 			<< "{\n"
235 			<< "    o_color = in_f_color;\n"
236 			<< "}\n";
237 
238 		programCollection.glslSources.add("frag") << glu::FragmentSource(src.str());
239 	}
240 }
241 
242 //! Generic test code used by all test cases.
test(Context & context,const CaseDefinition caseDef)243 tcu::TestStatus test (Context& context, const CaseDefinition caseDef)
244 {
245 	DE_ASSERT(caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES || caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS);
246 	DE_ASSERT(caseDef.caseType == CASETYPE_BASIC || caseDef.caseType == CASETYPE_PRECISE);
247 
248 	requireFeatures(context.getInstanceInterface(), context.getPhysicalDevice(), FEATURE_TESSELLATION_SHADER);
249 
250 	const DeviceInterface&	vk					= context.getDeviceInterface();
251 	const VkDevice			device				= context.getDevice();
252 	const VkQueue			queue				= context.getUniversalQueue();
253 	const deUint32			queueFamilyIndex	= context.getUniversalQueueFamilyIndex();
254 	Allocator&				allocator			= context.getDefaultAllocator();
255 
256 	// Prepare test data
257 
258 	std::vector<float>		gridPosComps;
259 	std::vector<float>		gridTessParams;
260 	std::vector<deUint16>	gridIndices;
261 
262 	{
263 		const int gridWidth				= 4;
264 		const int gridHeight			= 4;
265 		const int numVertices			= (gridWidth+1)*(gridHeight+1);
266 		const int numIndices			= gridWidth*gridHeight * (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3*2 : 4);
267 		const int numPosCompsPerVertex	= 2;
268 		const int totalNumPosComps		= numPosCompsPerVertex*numVertices;
269 
270 		gridPosComps.reserve(totalNumPosComps);
271 		gridTessParams.reserve(numVertices);
272 		gridIndices.reserve(numIndices);
273 
274 		{
275 			for (int i = 0; i < gridHeight+1; ++i)
276 			for (int j = 0; j < gridWidth+1; ++j)
277 			{
278 				gridPosComps.push_back(-1.0f + 2.0f * ((float)j + 0.5f) / (float)(gridWidth+1));
279 				gridPosComps.push_back(-1.0f + 2.0f * ((float)i + 0.5f) / (float)(gridHeight+1));
280 				gridTessParams.push_back((float)(i*(gridWidth+1) + j) / (float)(numVertices-1));
281 			}
282 		}
283 
284 		// Generate patch vertex indices.
285 		// \note If CASETYPE_BASIC, the vertices are ordered such that when multiple
286 		//		 triangles/quads share a vertex, it's at the same index for everyone.
287 
288 		if (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES)
289 		{
290 			for (int i = 0; i < gridHeight; i++)
291 			for (int j = 0; j < gridWidth; j++)
292 			{
293 				const deUint16 corners[4] =
294 				{
295 					(deUint16)((i+0)*(gridWidth+1) + j+0),
296 					(deUint16)((i+0)*(gridWidth+1) + j+1),
297 					(deUint16)((i+1)*(gridWidth+1) + j+0),
298 					(deUint16)((i+1)*(gridWidth+1) + j+1)
299 				};
300 
301 				const int secondTriangleVertexIndexOffset = caseDef.caseType == CASETYPE_BASIC   ? 0 : 1;
302 
303 				for (int k = 0; k < 3; k++)
304 					gridIndices.push_back(corners[(k+0 + i + (2-j%3)) % 3]);
305 				for (int k = 0; k < 3; k++)
306 					gridIndices.push_back(corners[(k+2 + i + (2-j%3) + secondTriangleVertexIndexOffset) % 3 + 1]);
307 			}
308 		}
309 		else if (caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS)
310 		{
311 			for (int i = 0; i < gridHeight; ++i)
312 			for (int j = 0; j < gridWidth; ++j)
313 			{
314 				for (int m = 0; m < 2; m++)
315 				for (int n = 0; n < 2; n++)
316 					gridIndices.push_back((deUint16)((i+(i+m)%2)*(gridWidth+1) + j+(j+n)%2));
317 
318 				if (caseDef.caseType == CASETYPE_PRECISE && (i+j) % 2 == 0)
319 					std::reverse(gridIndices.begin() + (gridIndices.size() - 4),
320 								 gridIndices.begin() + gridIndices.size());
321 			}
322 		}
323 		else
324 			DE_ASSERT(false);
325 
326 		DE_ASSERT(static_cast<int>(gridPosComps.size()) == totalNumPosComps);
327 		DE_ASSERT(static_cast<int>(gridTessParams.size()) == numVertices);
328 		DE_ASSERT(static_cast<int>(gridIndices.size()) == numIndices);
329 	}
330 
331 	// Vertex input buffer: we put both attributes and indices in here.
332 
333 	const VkDeviceSize vertexDataSizeBytes    = sizeInBytes(gridPosComps) + sizeInBytes(gridTessParams) + sizeInBytes(gridIndices);
334 	const std::size_t  vertexPositionsOffset  = 0;
335 	const std::size_t  vertexTessParamsOffset = sizeInBytes(gridPosComps);
336 	const std::size_t  vertexIndicesOffset    = vertexTessParamsOffset + sizeInBytes(gridTessParams);
337 
338 	const BufferWithMemory vertexBuffer(vk, device, allocator,
339 		makeBufferCreateInfo(vertexDataSizeBytes, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT), MemoryRequirement::HostVisible);
340 
341 	{
342 		const Allocation& alloc = vertexBuffer.getAllocation();
343 		deUint8* const pData = static_cast<deUint8*>(alloc.getHostPtr());
344 
345 		deMemcpy(pData + vertexPositionsOffset,  &gridPosComps[0],   static_cast<std::size_t>(sizeInBytes(gridPosComps)));
346 		deMemcpy(pData + vertexTessParamsOffset, &gridTessParams[0], static_cast<std::size_t>(sizeInBytes(gridTessParams)));
347 		deMemcpy(pData + vertexIndicesOffset,    &gridIndices[0],    static_cast<std::size_t>(sizeInBytes(gridIndices)));
348 
349 		flushAlloc(vk, device, alloc);
350 		// No barrier needed, flushed memory is automatically visible
351 	}
352 
353 	// Color attachment
354 
355 	const tcu::IVec2			  renderSize				 = tcu::IVec2(256, 256);
356 	const VkFormat				  colorFormat				 = VK_FORMAT_R8G8B8A8_UNORM;
357 	const VkImageSubresourceRange colorImageSubresourceRange = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
358 	const ImageWithMemory		  colorAttachmentImage		 (vk, device, allocator,
359 															 makeImageCreateInfo(renderSize, colorFormat, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, 1u),
360 															 MemoryRequirement::Any);
361 
362 	// Color output buffer: image will be copied here for verification
363 
364 	const VkDeviceSize		colorBufferSizeBytes = renderSize.x()*renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
365 	const BufferWithMemory	colorBuffer			 (vk, device, allocator, makeBufferCreateInfo(colorBufferSizeBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT), MemoryRequirement::HostVisible);
366 
367 	// Pipeline
368 
369 	const Unique<VkImageView>		colorAttachmentView	(makeImageView			(vk, device, *colorAttachmentImage, VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorImageSubresourceRange));
370 	const Unique<VkRenderPass>		renderPass			(makeRenderPass			(vk, device, colorFormat));
371 	const Unique<VkFramebuffer>		framebuffer			(makeFramebuffer		(vk, device, *renderPass, *colorAttachmentView, renderSize.x(), renderSize.y()));
372 	const Unique<VkCommandPool>		cmdPool				(makeCommandPool		(vk, device, queueFamilyIndex));
373 	const Unique<VkCommandBuffer>	cmdBuffer			(allocateCommandBuffer	(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY));
374 	const Unique<VkPipelineLayout>	pipelineLayout		(makePipelineLayout		(vk, device));
375 
376 	const int inPatchSize = (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? 3 : 4);
377 	const Unique<VkPipeline> pipeline(GraphicsPipelineBuilder()
378 		.setRenderSize		  (renderSize)
379 		.setPatchControlPoints(inPatchSize)
380 		.addVertexBinding	  (makeVertexInputBindingDescription(0u, sizeof(tcu::Vec2), VK_VERTEX_INPUT_RATE_VERTEX))
381 		.addVertexBinding	  (makeVertexInputBindingDescription(1u, sizeof(float),     VK_VERTEX_INPUT_RATE_VERTEX))
382 		.addVertexAttribute	  (makeVertexInputAttributeDescription(0u, 0u, VK_FORMAT_R32G32_SFLOAT, 0u))
383 		.addVertexAttribute	  (makeVertexInputAttributeDescription(1u, 1u, VK_FORMAT_R32_SFLOAT,    0u))
384 		.setShader			  (vk, device, VK_SHADER_STAGE_VERTEX_BIT,					context.getBinaryCollection().get("vert"), DE_NULL)
385 		.setShader			  (vk, device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT,	context.getBinaryCollection().get("tesc"), DE_NULL)
386 		.setShader			  (vk, device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, context.getBinaryCollection().get("tese"), DE_NULL)
387 		.setShader			  (vk, device, VK_SHADER_STAGE_FRAGMENT_BIT,				context.getBinaryCollection().get("frag"), DE_NULL)
388 		.build				  (vk, device, *pipelineLayout, *renderPass));
389 
390 	// Draw commands
391 
392 	beginCommandBuffer(vk, *cmdBuffer);
393 
394 	// Change color attachment image layout
395 	{
396 		const VkImageMemoryBarrier colorAttachmentLayoutBarrier = makeImageMemoryBarrier(
397 			(VkAccessFlags)0, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
398 			VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
399 			*colorAttachmentImage, colorImageSubresourceRange);
400 
401 		vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0u,
402 			0u, DE_NULL, 0u, DE_NULL, 1u, &colorAttachmentLayoutBarrier);
403 	}
404 
405 	// Begin render pass
406 	{
407 		const VkRect2D	renderArea	= makeRect2D(renderSize);
408 		const tcu::Vec4	clearColor	(0.0f, 0.0f, 0.0f, 1.0f);
409 
410 		beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
411 	}
412 
413 	vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
414 	{
415 		const VkBuffer buffers[] = { *vertexBuffer, *vertexBuffer };
416 		const VkDeviceSize offsets[] = { vertexPositionsOffset, vertexTessParamsOffset, };
417 		vk.cmdBindVertexBuffers(*cmdBuffer, 0u, DE_LENGTH_OF_ARRAY(buffers), buffers, offsets);
418 
419 		vk.cmdBindIndexBuffer(*cmdBuffer, *vertexBuffer, vertexIndicesOffset, VK_INDEX_TYPE_UINT16);
420 	}
421 
422 	vk.cmdDrawIndexed(*cmdBuffer, static_cast<deUint32>(gridIndices.size()), 1u, 0u, 0, 0u);
423 	endRenderPass(vk, *cmdBuffer);
424 
425 	// Copy render result to a host-visible buffer
426 	copyImageToBuffer(vk, *cmdBuffer, *colorAttachmentImage, *colorBuffer, renderSize);
427 
428 	endCommandBuffer(vk, *cmdBuffer);
429 	submitCommandsAndWait(vk, device, queue, *cmdBuffer);
430 
431 	{
432 		// Log the result image.
433 
434 		const Allocation&					colorBufferAlloc	= colorBuffer.getAllocation();
435 
436 		invalidateAlloc(vk, device, colorBufferAlloc);
437 
438 		const tcu::ConstPixelBufferAccess	imagePixelAccess	(mapVkFormat(colorFormat), renderSize.x(), renderSize.y(), 1, colorBufferAlloc.getHostPtr());
439 		tcu::TestLog&						log					= context.getTestContext().getLog();
440 
441 		log << tcu::TestLog::Image("color0", "Rendered image", imagePixelAccess)
442 			<< tcu::TestLog::Message
443 			<< "Note: coloring is done to clarify the positioning and orientation of the "
444 			<< (caseDef.primitiveType == TESSPRIMITIVETYPE_TRIANGLES ? "triangles" :
445 				caseDef.primitiveType == TESSPRIMITIVETYPE_QUADS	 ? "quads"	   : "")
446 			<< "; the color of a vertex corresponds to the index of that vertex in the patch"
447 			<< tcu::TestLog::EndMessage;
448 
449 		if (caseDef.caseType == CASETYPE_BASIC)
450 			log << tcu::TestLog::Message << "Note: each shared vertex has the same index among the primitives it belongs to" << tcu::TestLog::EndMessage;
451 		else if (caseDef.caseType == CASETYPE_PRECISE)
452 			log << tcu::TestLog::Message << "Note: the 'precise' qualifier is used to avoid cracks between primitives" << tcu::TestLog::EndMessage;
453 		else
454 			DE_ASSERT(false);
455 
456 		// Verify the result.
457 		const bool ok = verifyResult(log, imagePixelAccess);
458 		return (ok ? tcu::TestStatus::pass("OK") : tcu::TestStatus::fail("Failure"));
459 	}
460 }
461 
getCaseName(const TessPrimitiveType primitiveType,const SpacingMode spacingMode,const CaseType caseType)462 std::string getCaseName (const TessPrimitiveType primitiveType, const SpacingMode spacingMode, const CaseType caseType)
463 {
464 	std::ostringstream str;
465 	str << getTessPrimitiveTypeShaderName(primitiveType) << "_" << getSpacingModeShaderName(spacingMode)
466 		<< (caseType == CASETYPE_PRECISE ? "_precise" : "");
467 	return str.str();
468 }
469 
470 } // anonymous
471 
472 //! These tests correspond to dEQP-GLES31.functional.tessellation.common_edge.*
createCommonEdgeTests(tcu::TestContext & testCtx)473 tcu::TestCaseGroup* createCommonEdgeTests (tcu::TestContext& testCtx)
474 {
475 	de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "common_edge", "Draw multiple adjacent shapes and check that no cracks appear between them"));
476 
477 	static const TessPrimitiveType primitiveTypes[] =
478 	{
479 		TESSPRIMITIVETYPE_TRIANGLES,
480 		TESSPRIMITIVETYPE_QUADS,
481 	};
482 
483 	for (int primitiveTypeNdx = 0; primitiveTypeNdx < DE_LENGTH_OF_ARRAY(primitiveTypes); ++primitiveTypeNdx)
484 	for (int caseTypeNdx = 0; caseTypeNdx < CASETYPE_LAST; ++caseTypeNdx)
485 	for (int spacingModeNdx = 0; spacingModeNdx < SPACINGMODE_LAST; ++spacingModeNdx)
486 	{
487 		const TessPrimitiveType primitiveType = primitiveTypes[primitiveTypeNdx];
488 		const CaseType			caseType	  = static_cast<CaseType>(caseTypeNdx);
489 		const SpacingMode		spacingMode   = static_cast<SpacingMode>(spacingModeNdx);
490 		const CaseDefinition	caseDef		  = { primitiveType, spacingMode, caseType };
491 
492 		addFunctionCaseWithPrograms(group.get(), getCaseName(primitiveType, spacingMode, caseType), "", initPrograms, test, caseDef);
493 	}
494 
495 	return group.release();
496 }
497 
498 } // tessellation
499 } // vkt
500