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