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