• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Valve Corporation.
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 Tests with shaders that do not write to the Position built-in.
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineNoPositionTests.hpp"
26 #include "vktTestCase.hpp"
27 
28 #include "vkQueryUtil.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkCmdUtil.hpp"
33 #include "vkImageWithMemory.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vktPipelineImageUtil.hpp"
36 #include "vkImageUtil.hpp"
37 #include "vkBarrierUtil.hpp"
38 #include "vkBuilderUtil.hpp"
39 
40 #include "tcuVector.hpp"
41 #include "tcuTestLog.hpp"
42 
43 #include "deUniquePtr.hpp"
44 
45 #include <vector>
46 #include <set>
47 #include <sstream>
48 #include <array>
49 
50 namespace vkt
51 {
52 namespace pipeline
53 {
54 
55 namespace
56 {
57 
58 using namespace vk;
59 
60 enum ShaderStageBits
61 {
62 	STAGE_VERTEX			= (1 << 0),
63 	STAGE_TESS_CONTROL		= (1 << 1),
64 	STAGE_TESS_EVALUATION	= (1 << 2),
65 	STAGE_GEOMETRY			= (1 << 3),
66 	STAGE_MASK_COUNT		= (1 << 4),
67 };
68 
69 using ShaderStageFlags = deUint32;
70 
71 constexpr deUint32 kStageCount = 4u;
72 
73 static_assert((1u << kStageCount) == static_cast<deUint32>(STAGE_MASK_COUNT),
74 			  "Total stage count does not match stage mask bits");
75 
76 struct TestParams
77 {
78 	ShaderStageFlags	selectedStages;			// Stages that will be present in the pipeline.
79 	ShaderStageFlags	writeStages;			// Subset of selectedStages that will write to the Position built-in.
80 	deUint32			numViews;				// Number of views for multiview.
81 	bool				explicitDeclarations;	// Explicitly declare the input and output blocks or not.
82 	bool				useSSBO;				// Write to an SSBO from the selected stages.
83 
84 	// Commonly used checks.
tessellationvkt::pipeline::__anon2e95e3930111::TestParams85 	bool tessellation	(void) const { return (selectedStages & (STAGE_TESS_CONTROL | STAGE_TESS_EVALUATION));	}
geometryvkt::pipeline::__anon2e95e3930111::TestParams86 	bool geometry		(void) const { return (selectedStages & STAGE_GEOMETRY);								}
87 };
88 
89 // Generates the combinations list of stage flags for writeStages when a given subset of stages are selected.
getWriteSubCases(ShaderStageFlags selectedStages)90 std::vector<ShaderStageFlags> getWriteSubCases (ShaderStageFlags selectedStages)
91 {
92 	std::set<ShaderStageFlags> uniqueCases;
93 	for (ShaderStageFlags stages = 0; stages < STAGE_MASK_COUNT; ++stages)
94 		uniqueCases.insert(stages & selectedStages);
95 	return std::vector<ShaderStageFlags>(begin(uniqueCases), end(uniqueCases));
96 }
97 
98 class NoPositionCase : public vkt::TestCase
99 {
100 public:
101 							NoPositionCase		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~NoPositionCase(void)102 	virtual					~NoPositionCase		(void) {}
103 
104 	virtual void			initPrograms		(vk::SourceCollections& programCollection) const;
105 	virtual TestInstance*	createInstance		(Context& context) const;
106 	virtual void			checkSupport		(Context& context) const;
107 
getBackGroundColor(void)108 	static tcu::Vec4		getBackGroundColor	(void) { return tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f); }
getImageFormat(void)109 	static VkFormat			getImageFormat		(void) { return VK_FORMAT_R8G8B8A8_UNORM; }
getImageExtent(void)110 	static VkExtent3D		getImageExtent		(void) { return makeExtent3D(64u, 64u, 1u); }
111 
112 private:
113 	TestParams				m_params;
114 };
115 
116 class NoPositionInstance : public vkt::TestInstance
117 {
118 public:
119 								NoPositionInstance	(Context& context, const TestParams& params);
~NoPositionInstance(void)120 	virtual						~NoPositionInstance	(void) {}
121 
122 	virtual tcu::TestStatus		iterate				(void);
123 
124 private:
125 	TestParams					m_params;
126 };
127 
NoPositionCase(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)128 NoPositionCase::NoPositionCase (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
129 	: vkt::TestCase	(testCtx, name, description)
130 	, m_params		(params)
131 {
132 	DE_ASSERT(params.numViews >= 1u);
133 }
134 
initPrograms(vk::SourceCollections & programCollection) const135 void NoPositionCase::initPrograms (vk::SourceCollections& programCollection) const
136 {
137 	// Add shaders for the selected stages and write to gl_Position in the subset of stages marked for writing.
138 
139 	// Optional writes, extensions and declarations.
140 	std::string ssboDecl;
141 	std::string extensions;
142 	std::string vertSSBOWrite;
143 	std::string tescSSBOWrite;
144 	std::string teseSSBOWrite;
145 	std::string geomSSBOWrite;
146 
147 	const bool multiview = (m_params.numViews > 1u);
148 
149 	if (multiview)
150 		extensions = "#extension GL_EXT_multiview : require\n";
151 
152 	if (m_params.useSSBO)
153 	{
154 		const auto stageCountStr	= de::toString(kStageCount);
155 		const auto ssboElementCount	= kStageCount * m_params.numViews;
156 		ssboDecl = "layout (set=0, binding=0, std430) buffer StorageBlock { uint counters[" + de::toString(ssboElementCount) + "]; } ssbo;\n";
157 
158 		const std::array<std::string*, kStageCount> writeStrings = {{ &vertSSBOWrite, &tescSSBOWrite, &teseSSBOWrite, &geomSSBOWrite }};
159 		for (size_t i = 0; i < writeStrings.size(); ++i)
160 			*writeStrings[i] = "    atomicAdd(ssbo.counters[" + de::toString(i) + (multiview ? (" + uint(gl_ViewIndex) * " + stageCountStr) : "") + "], 1u);\n";
161 	}
162 
163 	if (m_params.selectedStages & STAGE_VERTEX)
164 	{
165 		std::ostringstream vert;
166 		vert
167 			<< "#version 450\n"
168 			<< extensions
169 			<< ssboDecl
170 			<< "layout (location=0) in vec4 in_pos;\n"
171 			<< (m_params.explicitDeclarations ?
172 				"out gl_PerVertex\n"
173 				"{\n"
174 				"    vec4 gl_Position;\n"
175 				"    float gl_PointSize;\n"
176 				"    float gl_ClipDistance[];\n"
177 				"    float gl_CullDistance[];\n"
178 				"};\n"
179 				: "")
180 			<< "void main (void)\n"
181 			<< "{\n"
182 			<< ((m_params.writeStages & STAGE_VERTEX) ? "    gl_Position = in_pos;\n" : "")
183 			<< vertSSBOWrite
184 			<< "}\n"
185 			;
186 
187 		programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
188 	}
189 
190 	if (m_params.selectedStages & STAGE_TESS_CONTROL)
191 	{
192 		std::ostringstream tesc;
193 		tesc
194 			<< "#version 450\n"
195 			<< extensions
196 			<< ssboDecl
197 			<< "layout (vertices = 3) out;\n"
198 			<< (m_params.explicitDeclarations ?
199 				"in gl_PerVertex\n"
200 				"{\n"
201 				"    vec4 gl_Position;\n"
202 				"    float gl_PointSize;\n"
203 				"    float gl_ClipDistance[];\n"
204 				"    float gl_CullDistance[];\n"
205 				"} gl_in[gl_MaxPatchVertices];\n"
206 				"out gl_PerVertex\n"
207 				"{\n"
208 				"    vec4 gl_Position;\n"
209 				"    float gl_PointSize;\n"
210 				"    float gl_ClipDistance[];\n"
211 				"    float gl_CullDistance[];\n"
212 				"} gl_out[];\n"
213 				: "")
214 			<< "void main (void)\n"
215 			<< "{\n"
216 			<< "    gl_TessLevelInner[0] = 1.0;\n"
217 			<< "    gl_TessLevelInner[1] = 1.0;\n"
218 			<< "    gl_TessLevelOuter[0] = 1.0;\n"
219 			<< "    gl_TessLevelOuter[1] = 1.0;\n"
220 			<< "    gl_TessLevelOuter[2] = 1.0;\n"
221 			<< "    gl_TessLevelOuter[3] = 1.0;\n"
222 			<< "\n"
223 			<< ((m_params.writeStages & STAGE_TESS_CONTROL) ? "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" : "")
224 			<< tescSSBOWrite
225 			<< "}\n"
226 			;
227 
228 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
229 	}
230 
231 	if (m_params.selectedStages & STAGE_TESS_EVALUATION)
232 	{
233 		std::ostringstream tese;
234 		tese
235 			<< "#version 450\n"
236 			<< extensions
237 			<< ssboDecl
238 			<< "layout (triangles, fractional_odd_spacing, cw) in;\n"
239 			<< (m_params.explicitDeclarations ?
240 				"in gl_PerVertex\n"
241 				"{\n"
242 				"    vec4 gl_Position;\n"
243 				"    float gl_PointSize;\n"
244 				"    float gl_ClipDistance[];\n"
245 				"    float gl_CullDistance[];\n"
246 				"} gl_in[gl_MaxPatchVertices];\n"
247 				"out gl_PerVertex\n"
248 				"{\n"
249 				"    vec4 gl_Position;\n"
250 				"    float gl_PointSize;\n"
251 				"    float gl_ClipDistance[];\n"
252 				"    float gl_CullDistance[];\n"
253 				"};\n"
254 				: "")
255 			<< "void main (void)\n"
256 			<< "{\n"
257 			<< ((m_params.writeStages & STAGE_TESS_EVALUATION) ?
258 				"    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
259 				"                  (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
260 				"                  (gl_TessCoord.z * gl_in[2].gl_Position);\n"
261 				: "")
262 			<< teseSSBOWrite
263 			<< "}\n"
264 			;
265 
266 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
267 	}
268 
269 	if (m_params.selectedStages & STAGE_GEOMETRY)
270 	{
271 		std::ostringstream geom;
272 		geom
273 			<< "#version 450\n"
274 			<< extensions
275 			<< ssboDecl
276 			<< "layout (triangles) in;\n"
277 			<< "layout (triangle_strip, max_vertices=3) out;\n"
278 			<< (m_params.explicitDeclarations ?
279 				"in gl_PerVertex\n"
280 				"{\n"
281 				"    vec4 gl_Position;\n"
282 				"    float gl_PointSize;\n"
283 				"    float gl_ClipDistance[];\n"
284 				"    float gl_CullDistance[];\n"
285 				"} gl_in[3];\n"
286 				"out gl_PerVertex\n"
287 				"{\n"
288 				"    vec4 gl_Position;\n"
289 				"    float gl_PointSize;\n"
290 				"    float gl_ClipDistance[];\n"
291 				"    float gl_CullDistance[];\n"
292 				"};\n"
293 				: "")
294 			<< "void main (void)\n"
295 			<< "{\n"
296 			<< "    for (int i = 0; i < 3; i++)\n"
297 			<< "    {\n"
298 			<< ((m_params.writeStages & STAGE_GEOMETRY) ? "        gl_Position = gl_in[i].gl_Position;\n" : "")
299 			<< "        EmitVertex();\n"
300 			<< "    }\n"
301 			<< geomSSBOWrite
302 			<< "}\n"
303 			;
304 
305 		programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
306 	}
307 
308 	{
309 		const auto backgroundColor = getBackGroundColor();
310 
311 		std::ostringstream colorStr;
312 		colorStr << "vec4(" << backgroundColor.x() << ", " << backgroundColor.y() << ", " << backgroundColor.z() << ", " << backgroundColor.w() << ")";
313 
314 		std::ostringstream frag;
315 		frag
316 			<< "#version 450\n"
317 			<< "layout (location=0) out vec4 out_color;\n"
318 			<< "void main (void)\n"
319 			<< "{\n"
320 			<< "    out_color = " << colorStr.str() << ";\n"
321 			<< "}\n"
322 			;
323 
324 		programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
325 	}
326 }
327 
createInstance(Context & context) const328 TestInstance* NoPositionCase::createInstance (Context& context) const
329 {
330 	return new NoPositionInstance (context, m_params);
331 }
332 
checkSupport(Context & context) const333 void NoPositionCase::checkSupport (Context& context) const
334 {
335 	const auto features	= getPhysicalDeviceFeatures(context.getInstanceInterface(), context.getPhysicalDevice());
336 	const bool hasTess	= m_params.tessellation();
337 	const bool hasGeom	= m_params.geometry();
338 
339 	if (hasTess && !features.tessellationShader)
340 		TCU_THROW(NotSupportedError, "Tessellation shaders not supported");
341 
342 	if (hasGeom && !features.geometryShader)
343 		TCU_THROW(NotSupportedError, "Geometry shaders not supported");
344 
345 	if (m_params.numViews > 1u)
346 	{
347 		context.requireDeviceFunctionality("VK_KHR_multiview");
348 		const auto& multiviewFeatures = context.getMultiviewFeatures();
349 
350 		if (!multiviewFeatures.multiview)
351 			TCU_THROW(NotSupportedError, "Multiview not supported");
352 
353 		if (hasTess && !multiviewFeatures.multiviewTessellationShader)
354 			TCU_THROW(NotSupportedError, "Multiview not supported with tessellation shaders");
355 
356 		if (hasGeom && !multiviewFeatures.multiviewGeometryShader)
357 			TCU_THROW(NotSupportedError, "Multiview not supported with geometry shaders");
358 	}
359 
360 	if (m_params.useSSBO)
361 	{
362 		if (!features.vertexPipelineStoresAndAtomics)
363 			TCU_THROW(NotSupportedError, "Vertex pipeline stores and atomics not supported");
364 	}
365 }
366 
NoPositionInstance(Context & context,const TestParams & params)367 NoPositionInstance::NoPositionInstance (Context& context, const TestParams& params)
368 	: vkt::TestInstance	(context)
369 	, m_params			(params)
370 {}
371 
iterate(void)372 tcu::TestStatus NoPositionInstance::iterate (void)
373 {
374 	const	auto&				vkd			= m_context.getDeviceInterface();
375 	const	auto				device		= m_context.getDevice();
376 	const	auto				queue		= m_context.getUniversalQueue();
377 	const	auto				qIndex		= m_context.getUniversalQueueFamilyIndex();
378 			auto&				alloc		= m_context.getDefaultAllocator();
379 	const	auto				format		= NoPositionCase::getImageFormat();
380 	const	auto				extent		= NoPositionCase::getImageExtent();
381 	const	auto				color		= NoPositionCase::getBackGroundColor();
382 	const	VkImageUsageFlags	usage		= (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
383 	const	auto				viewType	= (m_params.numViews > 1u ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
384 	const	bool				tess		= m_params.tessellation();
385 			VkShaderStageFlags	stageFlags	= 0u;
386 
387 	// Shader modules.
388 	Move<VkShaderModule> vert;
389 	Move<VkShaderModule> tesc;
390 	Move<VkShaderModule> tese;
391 	Move<VkShaderModule> geom;
392 	Move<VkShaderModule> frag;
393 
394 	if (m_params.selectedStages & STAGE_VERTEX)
395 	{
396 		vert = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
397 		stageFlags |= VK_SHADER_STAGE_VERTEX_BIT;
398 	}
399 	if (m_params.selectedStages & STAGE_TESS_CONTROL)
400 	{
401 		tesc = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
402 		stageFlags |= VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
403 	}
404 	if (m_params.selectedStages & STAGE_TESS_EVALUATION)
405 	{
406 		tese = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
407 		stageFlags |= VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
408 	}
409 	if (m_params.selectedStages & STAGE_GEOMETRY)
410 	{
411 		geom = createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
412 		stageFlags |= VK_SHADER_STAGE_GEOMETRY_BIT;
413 	}
414 
415 	frag = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
416 	stageFlags |= VK_SHADER_STAGE_FRAGMENT_BIT;
417 
418 	// Color attachment.
419 	const VkImageCreateInfo colorImageInfo =
420 	{
421 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
422 		nullptr,								//	const void*				pNext;
423 		0u,										//	VkImageCreateFlags		flags;
424 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
425 		format,									//	VkFormat				format;
426 		extent,									//	VkExtent3D				extent;
427 		1u,										//	deUint32				mipLevels;
428 		m_params.numViews,						//	deUint32				arrayLayers;
429 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
430 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
431 		usage,									//	VkImageUsageFlags		usage;
432 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
433 		0u,										//	deUint32				queueFamilyIndexCount;
434 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
435 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
436 	};
437 	ImageWithMemory colorImage (vkd, device, alloc, colorImageInfo, MemoryRequirement::Any);
438 
439 	const auto subresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, m_params.numViews);
440 	const auto colorImageView	= makeImageView(vkd, device, colorImage.get(), viewType, format, subresourceRange);
441 
442 	// Vertices and vertex buffer.
443 	std::vector<tcu::Vec4> vertices =
444 	{
445 		tcu::Vec4( 0.0f, -0.5f,  0.0f,  1.0f),
446 		tcu::Vec4( 0.5f,  0.5f,  0.0f,  1.0f),
447 		tcu::Vec4(-0.5f,  0.5f,  0.0f,  1.0f),
448 	};
449 
450 	const auto vertexBufferSize		= static_cast<VkDeviceSize>(vertices.size() * sizeof(decltype(vertices)::value_type));
451 	const auto vertexBufferInfo		= makeBufferCreateInfo(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
452 	const auto vertexBufferOffset	= static_cast<VkDeviceSize>(0);
453 	BufferWithMemory vertexBuffer (vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
454 
455 	auto& vertexBufferAlloc	= vertexBuffer.getAllocation();
456 	void* vertexBufferPtr	= vertexBufferAlloc.getHostPtr();
457 	deMemcpy(vertexBufferPtr, vertices.data(), static_cast<size_t>(vertexBufferSize));
458 	flushAlloc(vkd, device, vertexBufferAlloc);
459 
460 	// Render pass.
461 	const VkAttachmentDescription colorAttachment =
462 	{
463 		0u,											//	VkAttachmentDescriptionFlags	flags;
464 		format,										//	VkFormat						format;
465 		VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
466 		VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
467 		VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
468 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
469 		VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
470 		VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
471 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
472 	};
473 
474 	const VkAttachmentReference colorAttachmentReference =
475 	{
476 		0u,											//	deUint32		attachment;
477 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
478 	};
479 
480 	const VkSubpassDescription subpassDescription =
481 	{
482 		0u,									//	VkSubpassDescriptionFlags		flags;
483 		VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
484 		0u,									//	deUint32						inputAttachmentCount;
485 		nullptr,							//	const VkAttachmentReference*	pInputAttachments;
486 		1u,									//	deUint32						colorAttachmentCount;
487 		&colorAttachmentReference,			//	const VkAttachmentReference*	pColorAttachments;
488 		0u,									//	const VkAttachmentReference*	pResolveAttachments;
489 		nullptr,							//	const VkAttachmentReference*	pDepthStencilAttachment;
490 		0u,									//	deUint32						preserveAttachmentCount;
491 		nullptr,							//	const deUint32*					pPreserveAttachments;
492 	};
493 
494 	de::MovePtr<VkRenderPassMultiviewCreateInfo>	multiviewInfo;
495 	deUint32										viewMask		= 0u;
496 	deUint32										correlationMask	= 0u;
497 
498 	if (m_params.numViews > 1u)
499 	{
500 		for (deUint32 viewIdx = 0u; viewIdx < m_params.numViews; ++viewIdx)
501 		{
502 			viewMask		|= (1 << viewIdx);
503 			correlationMask	|= (1 << viewIdx);
504 		}
505 
506 		multiviewInfo = de::MovePtr<VkRenderPassMultiviewCreateInfo>(new VkRenderPassMultiviewCreateInfo
507 		{
508 			VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,	//	VkStructureType	sType;
509 			nullptr,												//	const void*		pNext;
510 			1u,														//	deUint32		subpassCount;
511 			&viewMask,												//	const deUint32*	pViewMasks;
512 			0u,														//	deUint32		dependencyCount;
513 			nullptr,												//	const deInt32*	pViewOffsets;
514 			1u,														//	deUint32		correlationMaskCount;
515 			&correlationMask,										//	const deUint32*	pCorrelationMasks;
516 		});
517 	}
518 
519 	const VkRenderPassCreateInfo renderPassInfo =
520 	{
521 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,	//	VkStructureType					sType;
522 		multiviewInfo.get(),						//	const void*						pNext;
523 		0u,											//	VkRenderPassCreateFlags			flags;
524 		1u,											//	deUint32						attachmentCount;
525 		&colorAttachment,							//	const VkAttachmentDescription*	pAttachments;
526 		1u,											//	deUint32						subpassCount;
527 		&subpassDescription,						//	const VkSubpassDescription*		pSubpasses;
528 		0u,											//	deUint32						dependencyCount;
529 		nullptr,									//	const VkSubpassDependency*		pDependencies;
530 	};
531 
532 	const auto renderPass = createRenderPass(vkd, device, &renderPassInfo);
533 
534 	// Framebuffer.
535 	const auto framebuffer = makeFramebuffer(vkd, device, renderPass.get(), colorImageView.get(), extent.width, extent.height);
536 
537 	// Descriptor set layout and pipeline layout.
538 	DescriptorSetLayoutBuilder layoutBuilder;
539 	if (m_params.useSSBO)
540 	{
541 		layoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, stageFlags);
542 	}
543 	const auto descriptorSetLayout	= layoutBuilder.build(vkd, device);
544 	const auto pipelineLayout		= makePipelineLayout(vkd, device, descriptorSetLayout.get());
545 
546 	// Pipeline.
547 	const std::vector<VkViewport>	viewports		(1u, makeViewport(extent));
548 	const std::vector<VkRect2D>		scissors		(1u, makeRect2D(extent));
549 
550 	const deUint32	patchControlPoints	= (tess ? 3u : 0u);
551 	const auto		primitiveTopology	= (tess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
552 
553 	const auto pipeline = makeGraphicsPipeline(
554 		vkd, device, pipelineLayout.get(),
555 		vert.get(), tesc.get(), tese.get(), geom.get(), frag.get(),
556 		renderPass.get(), viewports, scissors, primitiveTopology,
557 		0u /* Subpass */, patchControlPoints);
558 
559 	// Descriptor set and output SSBO if needed.
560 	Move<VkDescriptorPool>			descriptorPool;
561 	Move<VkDescriptorSet>			descriptorSet;
562 	de::MovePtr<BufferWithMemory>	ssboBuffer;
563 	const auto						ssboElementCount	= kStageCount * m_params.numViews;
564 	const auto						ssboBufferSize		= static_cast<VkDeviceSize>(ssboElementCount * sizeof(deUint32));
565 
566 	if (m_params.useSSBO)
567 	{
568 		// Output SSBO.
569 		const auto	ssboBufferInfo	= makeBufferCreateInfo(ssboBufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
570 					ssboBuffer		= de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, ssboBufferInfo, MemoryRequirement::HostVisible));
571 		auto&		ssboBufferAlloc	= ssboBuffer->getAllocation();
572 
573 		deMemset(ssboBufferAlloc.getHostPtr(), 0, static_cast<size_t>(ssboBufferSize));
574 		flushAlloc(vkd, device, ssboBufferAlloc);
575 
576 		// Descriptor pool.
577 		DescriptorPoolBuilder poolBuilder;
578 		poolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
579 		descriptorPool = poolBuilder.build(vkd, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
580 
581 		// Descriptor set.
582 		descriptorSet = makeDescriptorSet(vkd, device, descriptorPool.get(), descriptorSetLayout.get());
583 		const auto ssboWriteInfo = makeDescriptorBufferInfo(ssboBuffer->get(), 0ull, ssboBufferSize);
584 		DescriptorSetUpdateBuilder updateBuilder;
585 		updateBuilder.writeSingle(descriptorSet.get(), DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &ssboWriteInfo);
586 		updateBuilder.update(vkd, device);
587 	}
588 
589 	// Output verification buffer.
590 	const auto tcuFormat	= mapVkFormat(format);
591 	const auto pixelSize	= static_cast<deUint32>(tcu::getPixelSize(tcuFormat));
592 	const auto layerPixels	= extent.width * extent.height;
593 	const auto layerBytes	= layerPixels * pixelSize;
594 	const auto totalPixels	= layerPixels * m_params.numViews;
595 	const auto totalBytes	= totalPixels * pixelSize;
596 
597 	const auto verificationBufferInfo = makeBufferCreateInfo(totalBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
598 	BufferWithMemory verificationBuffer(vkd, device, alloc, verificationBufferInfo, MemoryRequirement::HostVisible);
599 
600 	// Command pool and buffer.
601 	const auto cmdPool		= makeCommandPool(vkd, device, qIndex);
602 	const auto cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
603 	const auto cmdBuffer	= cmdBufferPtr.get();
604 
605 	// Render triangle.
606 	beginCommandBuffer(vkd, cmdBuffer);
607 	beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissors.front(), color);
608 	vkd.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.get());
609 	vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vertexBufferOffset);
610 	if (m_params.useSSBO)
611 		vkd.cmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout.get(), 0u, 1u, &descriptorSet.get(), 0u, nullptr);
612 	vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
613 	endRenderPass(vkd, cmdBuffer);
614 
615 	// Copy output image to verification buffer.
616 	const auto preTransferBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, colorImage.get(), subresourceRange);
617 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &preTransferBarrier);
618 
619 	const auto				subresourceLayers	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, m_params.numViews);
620 	const VkBufferImageCopy	copyRegion			=
621 	{
622 		0ull,					//	VkDeviceSize				bufferOffset;
623 		0u,						//	deUint32					bufferRowLength;
624 		0u,						//	deUint32					bufferImageHeight;
625 		subresourceLayers,		//	VkImageSubresourceLayers	imageSubresource;
626 		makeOffset3D(0, 0, 0),	//	VkOffset3D					imageOffset;
627 		extent,					//	VkExtent3D					imageExtent;
628 	};
629 	vkd.cmdCopyImageToBuffer(cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, verificationBuffer.get(), 1u, &copyRegion);
630 
631 	const auto postTransferBarrier = makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
632 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &postTransferBarrier, 0u, nullptr, 0u, nullptr);
633 
634 	// Output SSBO to host barrier.
635 	if (m_params.useSSBO)
636 	{
637 		const auto ssboBarrier = makeMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
638 		vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &ssboBarrier, 0u, nullptr, 0u, nullptr);
639 	}
640 
641 	// Submit commands.
642 	endCommandBuffer(vkd, cmdBuffer);
643 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
644 
645 	// Verify the image has the background color.
646 	auto&	verificationBufferAlloc	= verificationBuffer.getAllocation();
647 	auto	verificationBufferPtr	= reinterpret_cast<const char*>(verificationBufferAlloc.getHostPtr());
648 	invalidateAlloc(vkd, device, verificationBufferAlloc);
649 
650 	const auto iWidth	= static_cast<int>(extent.width);
651 	const auto iHeight	= static_cast<int>(extent.height);
652 	const auto iDepth	= static_cast<int>(extent.depth);
653 
654 	for (deUint32 layer = 0u; layer < m_params.numViews; ++layer)
655 	{
656 		const auto pixels = tcu::ConstPixelBufferAccess(tcuFormat, iWidth, iHeight, iDepth, reinterpret_cast<const void*>(verificationBufferPtr + layer * layerBytes));
657 
658 		for (int y = 0; y < iHeight;	++y)
659 		for (int x = 0; x < iWidth;		++x)
660 		{
661 			const auto pixel = pixels.getPixel(x, y);
662 			if (pixel != color)
663 			{
664 				std::ostringstream msg;
665 				msg << "Unexpected color found at pixel (" << x << ", " << y << ") in layer " << layer;
666 
667 				auto& log = m_context.getTestContext().getLog();
668 				log << tcu::TestLog::Message << msg.str() << tcu::TestLog::EndMessage;
669 				log << tcu::TestLog::Image("Result", "Result Image", pixels);
670 				TCU_FAIL(msg.str());
671 			}
672 		}
673 	}
674 
675 	// Verify SSBO if used.
676 	if (m_params.useSSBO)
677 	{
678 		// Get stored counters.
679 		const auto	ssboBufferSizeSz	= static_cast<size_t>(ssboBufferSize);
680 		auto&		ssboAlloc			= ssboBuffer->getAllocation();
681 		invalidateAlloc(vkd, device, ssboAlloc);
682 
683 		std::vector<deUint32> ssboCounters;
684 		ssboCounters.resize(ssboElementCount);
685 		DE_ASSERT(ssboBufferSizeSz == ssboCounters.size() * sizeof(decltype(ssboCounters)::value_type));
686 		deMemcpy(ssboCounters.data(), ssboAlloc.getHostPtr(), ssboBufferSizeSz);
687 
688 		// Minimum accepted counter values.
689 		// Vertex, Tesellation Evaluation, Tessellation Control, Geometry.
690 		deUint32 expectedCounters[kStageCount] = { 3u, 3u, 3u, 1u };
691 
692 		// Verify.
693 		for (deUint32 viewIdx = 0u; viewIdx < m_params.numViews; ++viewIdx)
694 		for (deUint32 stageIdx = 0u; stageIdx < kStageCount; ++stageIdx)
695 		{
696 			// If the stage is not selected, the expected value is exactly zero. Otherwise, it must be at least as expectedCounters.
697 			const deUint32	minVal		= ((m_params.selectedStages & (1u << stageIdx)) ? expectedCounters[stageIdx] : 0u);
698 			const deUint32	storedVal	= ssboCounters[stageIdx + viewIdx * kStageCount];
699 			const bool		ok			= ((minVal == 0u) ? (storedVal == minVal) : (storedVal >= minVal));
700 
701 			if (!ok)
702 			{
703 				const char* stageNames[kStageCount] =
704 				{
705 					"vertex",
706 					"tessellation evaluation",
707 					"tessellation control",
708 					"geometry",
709 				};
710 
711 				std::ostringstream msg;
712 				msg << "Unexpected SSBO counter value in view " << viewIdx
713 					<< " for the " << stageNames[stageIdx] << " shader:"
714 					<< " got " << storedVal << " but expected " << minVal;
715 				TCU_FAIL(msg.str());
716 			}
717 		}
718 	}
719 
720 	return tcu::TestStatus::pass("Pass");
721 }
722 
723 } // anonymous
724 
createNoPositionTests(tcu::TestContext & testCtx)725 tcu::TestCaseGroup*	createNoPositionTests (tcu::TestContext& testCtx)
726 {
727 	de::MovePtr<tcu::TestCaseGroup> group(new tcu::TestCaseGroup(testCtx, "no_position", "Tests with shaders that do not write to the Position built-in"));
728 
729 	for (int aux = 0; aux < 2; ++aux)
730 	{
731 		const bool						explicitDeclarations	= (aux == 1);
732 		const std::string				declGroupName			(explicitDeclarations ? "explicit_declarations" : "implicit_declarations");
733 		de::MovePtr<tcu::TestCaseGroup>	declGroup				(new tcu::TestCaseGroup(testCtx, declGroupName.c_str(), ""));
734 
735 		for (int aux2 = 0; aux2 < 2; ++aux2)
736 		{
737 			const bool useSSBO = (aux2 == 1);
738 			const std::string ssboGroupName (useSSBO ? "ssbo_writes" : "basic");
739 			de::MovePtr<tcu::TestCaseGroup> ssboGroup (new tcu::TestCaseGroup(testCtx, ssboGroupName.c_str(), ""));
740 
741 			for (deUint32 viewCount = 1u; viewCount <= 2u; ++viewCount)
742 			{
743 				const std::string				viewGroupName	((viewCount == 1u) ? "single_view" : "multiview");
744 				de::MovePtr<tcu::TestCaseGroup>	viewGroup		(new tcu::TestCaseGroup(testCtx, viewGroupName.c_str(), ""));
745 
746 				for (ShaderStageFlags stages = 0u; stages < STAGE_MASK_COUNT; ++stages)
747 				{
748 					// Vertex must always be present.
749 					if (! (stages & STAGE_VERTEX))
750 						continue;
751 
752 					// Tessellation stages must both be present or none must be.
753 					if (static_cast<bool>(stages & STAGE_TESS_CONTROL) != static_cast<bool>(stages & STAGE_TESS_EVALUATION))
754 						continue;
755 
756 					const auto writeMaskCases = getWriteSubCases(stages);
757 					for (const auto writeMask : writeMaskCases)
758 					{
759 						std::string testName;
760 						if (stages & STAGE_VERTEX)			testName += (testName.empty() ? "" : "_") + std::string("v") + ((writeMask & STAGE_VERTEX)			? "1" : "0");
761 						if (stages & STAGE_TESS_CONTROL)	testName += (testName.empty() ? "" : "_") + std::string("c") + ((writeMask & STAGE_TESS_CONTROL)	? "1" : "0");
762 						if (stages & STAGE_TESS_EVALUATION)	testName += (testName.empty() ? "" : "_") + std::string("e") + ((writeMask & STAGE_TESS_EVALUATION)	? "1" : "0");
763 						if (stages & STAGE_GEOMETRY)		testName += (testName.empty() ? "" : "_") + std::string("g") + ((writeMask & STAGE_GEOMETRY)		? "1" : "0");
764 
765 						TestParams params = { stages, writeMask, viewCount, explicitDeclarations, true };
766 						viewGroup->addChild(new NoPositionCase(testCtx, testName, "", params));
767 					}
768 				}
769 
770 				ssboGroup->addChild(viewGroup.release());
771 			}
772 
773 			declGroup->addChild(ssboGroup.release());
774 		}
775 
776 		group->addChild(declGroup.release());
777 	}
778 
779 	return group.release();
780 }
781 
782 } // pipeline
783 } // vkt
784