• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2021 The Khronos Group Inc.
6  * Copyright (c) 2021 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 Test for VK_EXT_multi_draw
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktDrawMultiExtTests.hpp"
26 
27 #include "vkTypeUtil.hpp"
28 #include "vkImageWithMemory.hpp"
29 #include "vkObjUtil.hpp"
30 #include "vkBuilderUtil.hpp"
31 #include "vkCmdUtil.hpp"
32 #include "vkBufferWithMemory.hpp"
33 #include "vkImageUtil.hpp"
34 #include "vkBarrierUtil.hpp"
35 
36 #include "tcuTexture.hpp"
37 #include "tcuMaybe.hpp"
38 #include "tcuImageCompare.hpp"
39 
40 #include "deUniquePtr.hpp"
41 #include "deMath.h"
42 #include "deRandom.hpp"
43 
44 #include <vector>
45 #include <sstream>
46 #include <algorithm>
47 #include <iterator>
48 #include <limits>
49 
50 using namespace vk;
51 
52 namespace vkt
53 {
54 namespace Draw
55 {
56 
57 namespace
58 {
59 
60 // Normal or indexed draws.
61 enum class DrawType { NORMAL = 0, INDEXED };
62 
63 // How to apply the vertex offset in indexed draws.
64 enum class VertexOffsetType
65 {
66 	MIXED = 0,			// Do not use pVertexOffset and mix values in struct-indicated offsets.
67 	CONSTANT_RANDOM,	// Use a constant value for pVertexOffset and fill offset struct members with random values.
68 	CONSTANT_PACK,		// Use a constant value for pVertexOffset and a stride that removes the vertex offset member in structs.
69 };
70 
71 // Triangle mesh type.
72 enum class MeshType { MOSAIC = 0, OVERLAPPING };
73 
74 // Vertex offset parameters.
75 struct VertexOffsetParams
76 {
77 	VertexOffsetType	offsetType;
78 	deUint32			offset;
79 };
80 
81 // Test parameters.
82 struct TestParams
83 {
84 	MeshType						meshType;
85 	DrawType						drawType;
86 	deUint32						drawCount;
87 	deUint32						instanceCount;
88 	deUint32						firstInstance;
89 	deUint32						stride;
90 	tcu::Maybe<VertexOffsetParams>	vertexOffset;	// Only used for indexed draws.
91 	deUint32						seed;
92 	bool							useTessellation;
93 	bool							useGeometry;
94 	bool							multiview;
95 	const SharedGroupParams			groupParams;
96 
maxInstanceIndexvkt::Draw::__anoneb0b3f2c0111::TestParams97 	deUint32 maxInstanceIndex () const
98 	{
99 		if (instanceCount == 0u)
100 			return 0u;
101 		return (firstInstance + instanceCount - 1u);
102 	}
103 };
104 
105 // For the color attachment. Must match what the fragment shader expects.
getColorFormat()106 VkFormat getColorFormat ()
107 {
108 	return VK_FORMAT_R8G8B8A8_UINT;
109 }
110 
111 // Compatible with getColorFormat() but better when used with the image logging facilities.
getVerificationFormat()112 VkFormat getVerificationFormat ()
113 {
114 	return VK_FORMAT_R8G8B8A8_UNORM;
115 }
116 
117 // Find a suitable format for the depth/stencil buffer.
chooseDepthStencilFormat(const InstanceInterface & vki,VkPhysicalDevice physDev)118 VkFormat chooseDepthStencilFormat (const InstanceInterface& vki, VkPhysicalDevice physDev)
119 {
120 	// The spec mandates support for one of these two formats.
121 	const VkFormat candidates[] = { VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT };
122 
123 	for (const auto& format : candidates)
124 	{
125 		const auto properties = getPhysicalDeviceFormatProperties(vki, physDev, format);
126 		if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) != 0u)
127 			return format;
128 	}
129 
130 	TCU_FAIL("No suitable depth/stencil format found");
131 	return VK_FORMAT_UNDEFINED; // Unreachable.
132 }
133 
134 // Format used when verifying the stencil aspect.
getStencilVerificationFormat()135 VkFormat getStencilVerificationFormat ()
136 {
137 	return VK_FORMAT_S8_UINT;
138 }
139 
getTriangleCount()140 deUint32 getTriangleCount ()
141 {
142 	return 1024u;	// This matches the minumum allowed limit for maxMultiDrawCount, so we can submit a single triangle per draw call.
143 }
144 
145 // Base class for creating triangles.
146 class TriangleGenerator
147 {
148 public:
149 	// Append a new triangle for ID (x, y).
150 	virtual void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) = 0;
151 };
152 
153 // Class that helps creating triangle vertices for each framebuffer pixel, forming a mosaic of triangles.
154 class TriangleMosaicGenerator : public TriangleGenerator
155 {
156 private:
157 	// Normalized width and height taking into account the framebuffer's width and height are two units (from -1 to 1).
158 	float	m_pixelWidth;
159 	float	m_pixelHeight;
160 
161 	float	m_deltaX;
162 	float	m_deltaY;
163 
164 public:
TriangleMosaicGenerator(deUint32 width,deUint32 height)165 	TriangleMosaicGenerator (deUint32 width, deUint32 height)
166 		: m_pixelWidth	(2.0f / static_cast<float>(width))
167 		, m_pixelHeight	(2.0f / static_cast<float>(height))
168 		, m_deltaX		(m_pixelWidth * 0.25f)
169 		, m_deltaY		(m_pixelHeight * 0.25f)
170 	{}
171 
172 	// Creates a triangle for framebuffer pixel (x, y) around its center. Appends the triangle vertices to the given list.
appendTriangle(deUint32 x,deUint32 y,std::vector<tcu::Vec4> & vertices)173 	void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) override
174 	{
175 		// Pixel center.
176 		const float coordX	= (static_cast<float>(x) + 0.5f) * m_pixelWidth - 1.0f;
177 		const float coordY	= (static_cast<float>(y) + 0.5f) * m_pixelHeight - 1.0f;
178 
179 		// Triangle around it.
180 		const float topY	= coordY - m_deltaY;
181 		const float bottomY	= coordY + m_deltaY;
182 
183 		const float leftX	= coordX - m_deltaX;
184 		const float rightX	= coordX + m_deltaX;
185 
186 		// Note: clockwise.
187 		vertices.emplace_back(leftX,	bottomY,	0.0f, 1.0f);
188 		vertices.emplace_back(coordX,	topY,		0.0f, 1.0f);
189 		vertices.emplace_back(rightX,	bottomY,	0.0f, 1.0f);
190 	}
191 };
192 
193 // Class that helps create full-screen triangles that overlap each other.
194 // This generator will generate width*height full-screen triangles with decreasing depth from 0.75 to 0.25.
195 class TriangleOverlapGenerator : public TriangleGenerator
196 {
197 private:
198 	// Normalized width and height taking into account the framebuffer's width and height are two units (from -1 to 1).
199 	deUint32	m_width;
200 	deUint32	m_totalPixels;
201 	float		m_depthStep;
202 
203 	static constexpr float kMinDepth	= 0.25f;
204 	static constexpr float kMaxDepth	= 0.75f;
205 	static constexpr float kDepthRange	= kMaxDepth - kMinDepth;
206 
207 public:
TriangleOverlapGenerator(deUint32 width,deUint32 height)208 	TriangleOverlapGenerator (deUint32 width, deUint32 height)
209 		: m_width		(width)
210 		, m_totalPixels (width * height)
211 		, m_depthStep	(kDepthRange / static_cast<float>(m_totalPixels))
212 	{}
213 
214 	// Creates full-screen triangle with 2D id (x, y) and decreasing depth with increasing ids.
appendTriangle(deUint32 x,deUint32 y,std::vector<tcu::Vec4> & vertices)215 	void appendTriangle(deUint32 x, deUint32 y, std::vector<tcu::Vec4>& vertices) override
216 	{
217 		const auto pixelId	= static_cast<float>(y * m_width + x);
218 		const auto depth	= kMaxDepth - m_depthStep * pixelId;
219 
220 		// Note: clockwise.
221 		vertices.emplace_back(-1.0f,	-1.0f,	depth, 1.0f);
222 		vertices.emplace_back(4.0f,		-1.0f,	depth, 1.0f);
223 		vertices.emplace_back(-1.0f,	4.0f,	depth, 1.0f);
224 	}
225 };
226 
227 // Class that helps creating a suitable draw info vector.
228 class DrawInfoPacker
229 {
230 private:
231 	DrawType						m_drawType;
232 	tcu::Maybe<VertexOffsetType>	m_offsetType;	// Offset type when m_drawType is DrawType::INDEXED.
233 	deUint32						m_stride;		// Desired stride. Must be zero or at least as big as the needed VkMultiDraw*InfoExt.
234 	deUint32						m_extraBytes;	// Used to match the desired stride.
235 	de::Random						m_random;		// Used to generate random offsets.
236 	deUint32						m_infoCount;	// How many infos have we appended so far?
237 	std::vector<deUint8>			m_dataVec;		// Data vector in generic form.
238 
239 	// Are draws indexed and using the offset member of VkMultiDrawIndexedInfoEXT?
indexedWithOffset(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType)240 	static bool indexedWithOffset (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType)
241 	{
242 		return (drawType == DrawType::INDEXED && *offsetType != VertexOffsetType::CONSTANT_PACK);
243 	}
244 
245 	// Size in bytes for the base structure used with the given draw type.
baseSize(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType)246 	static deUint32 baseSize (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType)
247 	{
248 		return static_cast<deUint32>(indexedWithOffset(drawType, offsetType) ? sizeof(VkMultiDrawIndexedInfoEXT) : sizeof(VkMultiDrawInfoEXT));
249 	}
250 
251 	// Number of extra bytes per entry according to the given stride.
calcExtraBytes(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType,deUint32 stride)252 	static deUint32 calcExtraBytes (DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType, deUint32 stride)
253 	{
254 		// Stride 0 is a special allowed case.
255 		if (stride == 0u)
256 			return 0u;
257 
258 		const auto minStride = baseSize(drawType, offsetType);
259 		DE_ASSERT(stride >= minStride);
260 		return (stride - minStride);
261 	}
262 
263 	// Entry size in bytes taking into account the number of extra bytes due to stride.
entrySize() const264 	deUint32 entrySize () const
265 	{
266 		return baseSize(m_drawType, m_offsetType) + m_extraBytes;
267 	}
268 
269 public:
DrawInfoPacker(DrawType drawType,const tcu::Maybe<VertexOffsetType> & offsetType,deUint32 stride,deUint32 estimatedInfoCount,deUint32 seed)270 	DrawInfoPacker	(DrawType drawType, const tcu::Maybe<VertexOffsetType>& offsetType, deUint32 stride, deUint32 estimatedInfoCount, deUint32 seed)
271 		: m_drawType	(drawType)
272 		, m_offsetType	(offsetType)
273 		, m_stride		(stride)
274 		, m_extraBytes	(calcExtraBytes(drawType, offsetType, stride))
275 		, m_random		(seed)
276 		, m_infoCount	(0u)
277 		, m_dataVec		()
278 	{
279 		// estimatedInfoCount is used to avoid excessive reallocation.
280 		if (estimatedInfoCount > 0u)
281 			m_dataVec.reserve(estimatedInfoCount * entrySize());
282 	}
283 
addDrawInfo(deUint32 first,deUint32 count,deInt32 offset)284 	void addDrawInfo (deUint32 first, deUint32 count, deInt32 offset)
285 	{
286 		std::vector<deUint8> entry(entrySize(), 0);
287 
288 		if (indexedWithOffset(m_drawType, m_offsetType))
289 		{
290 			const auto usedOffset = ((*m_offsetType == VertexOffsetType::CONSTANT_RANDOM) ? m_random.getInt32() : offset);
291 			const VkMultiDrawIndexedInfoEXT info = { first, count, usedOffset };
292 			deMemcpy(entry.data(), &info, sizeof(info));
293 		}
294 		else
295 		{
296 			const VkMultiDrawInfoEXT info = { first, count };
297 			deMemcpy(entry.data(), &info, sizeof(info));
298 		}
299 
300 		std::copy(begin(entry), end(entry), std::back_inserter(m_dataVec));
301 		++m_infoCount;
302 	}
303 
drawInfoCount() const304 	deUint32 drawInfoCount () const
305 	{
306 		return m_infoCount;
307 	}
308 
drawInfoData() const309 	const void* drawInfoData () const
310 	{
311 		return m_dataVec.data();
312 	}
313 
stride() const314 	deUint32 stride () const
315 	{
316 		return m_stride;
317 	}
318 };
319 
320 class MultiDrawTest : public vkt::TestCase
321 {
322 public:
323 					MultiDrawTest	(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params);
~MultiDrawTest(void)324 	virtual			~MultiDrawTest	(void) {}
325 
326 	void			initPrograms	(vk::SourceCollections& programCollection) const override;
327 	TestInstance*	createInstance	(Context& context) const override;
328 	void			checkSupport	(Context& context) const override;
329 
330 private:
331 	TestParams		m_params;
332 };
333 
334 class MultiDrawInstance : public vkt::TestInstance
335 {
336 public:
337 						MultiDrawInstance		(Context& context, const TestParams& params);
~MultiDrawInstance(void)338 	virtual				~MultiDrawInstance		(void) {}
339 
340 	tcu::TestStatus		iterate					(void) override;
341 
342 protected:
343 	void				beginSecondaryCmdBuffer	(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
344 												 VkFormat depthStencilFormat, VkRenderingFlagsKHR renderingFlags, deUint32 viewMask) const;
345 	void				preRenderingCommands	(VkCommandBuffer cmdBuffer,
346 												 VkImage colorImage, const VkImageSubresourceRange colorSubresourceRange,
347 												 VkImage dsImage, const VkImageSubresourceRange dsSubresourceRange) const;
348 	void				drawCommands			(VkCommandBuffer cmdBuffer, VkPipeline pipeline,
349 												 VkBuffer vertexBuffer, VkDeviceSize vertexBufferOffset, deInt32 vertexOffset,
350 												 VkBuffer indexBuffer, VkDeviceSize indexBufferOffset,
351 												 bool isMixedMode, const DrawInfoPacker& drawInfos) const;
352 
353 private:
354 	TestParams			m_params;
355 };
356 
MultiDrawTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestParams & params)357 MultiDrawTest::MultiDrawTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestParams& params)
358 	: vkt::TestCase	(testCtx, name, description)
359 	, m_params		(params)
360 {}
361 
createInstance(Context & context) const362 TestInstance* MultiDrawTest::createInstance (Context& context) const
363 {
364 	return new MultiDrawInstance(context, m_params);
365 }
366 
checkSupport(Context & context) const367 void MultiDrawTest::checkSupport (Context& context) const
368 {
369 	context.requireDeviceFunctionality("VK_EXT_multi_draw");
370 
371 	if (m_params.useTessellation)
372 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
373 
374 	if (m_params.useGeometry)
375 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
376 
377 	if (m_params.multiview)
378 	{
379 		const auto& multiviewFeatures = context.getMultiviewFeatures();
380 
381 		if (!multiviewFeatures.multiview)
382 			TCU_THROW(NotSupportedError, "Multiview not supported");
383 
384 		if (m_params.useTessellation && !multiviewFeatures.multiviewTessellationShader)
385 			TCU_THROW(NotSupportedError, "Multiview not supported with tesellation shaders");
386 
387 		if (m_params.useGeometry && !multiviewFeatures.multiviewGeometryShader)
388 			TCU_THROW(NotSupportedError, "Multiview not supported with geometry shaders");
389 	}
390 
391 	if (m_params.groupParams->useDynamicRendering)
392 		context.requireDeviceFunctionality("VK_KHR_dynamic_rendering");
393 }
394 
initPrograms(vk::SourceCollections & programCollection) const395 void MultiDrawTest::initPrograms (vk::SourceCollections& programCollection) const
396 {
397 	// The general idea behind these tests is to have a 32x32 framebuffer with 1024 pixels and 1024 triangles to draw.
398 	//
399 	// When using a mosaic mesh, the tests will generally draw a single triangle around the center of each of these pixels. When
400 	// using an overlapping mesh, each single triangle will cover the whole framebuffer using a different depth value, and the depth
401 	// test will be enabled.
402 	//
403 	// The color of each triangle will depend on the instance index, the draw index and, when using multiview, the view index. This
404 	// way, it's possible to draw those 1024 triangles with a single draw call or to draw each triangle with a separate draw call,
405 	// with up to 1024 draw calls. Combinations in between are possible.
406 	//
407 	// With overlapping meshes, the resulting color buffer will be uniform in color. With mosaic meshes, it depends on the submitted
408 	// draw count. In some cases, all pixels will be slightly different in color.
409 	//
410 	// The color buffer will be cleared to transparent black when beginning the render pass, and in some special cases some or all
411 	// pixels will preserve that clear color because they will not be drawn into. This happens, for example, if the instance count
412 	// or draw count is zero and in some cases of meshed geometry with stride zero.
413 	//
414 	// The output color for each pixel will:
415 	// - Have the draw index split into the R and G components.
416 	// - Have the instance index I stored into the B component as 255-I.
417 	//
418 	// In addition, the tests will use a depth/stencil buffer. The stencil buffer will be cleared to zero and the depth buffer to an
419 	// appropriate initial value (0.0 or 1.0, depending on triangle order). The stencil component will be increased with each draw
420 	// on each pixel. This will allow us to verify that not only the last draw for the last instance has set the proper color, but
421 	// that all draw operations have taken place.
422 
423 	// Make sure the blue channel can be calculated without issues.
424 	DE_ASSERT(m_params.maxInstanceIndex() <= 255u);
425 
426 	std::ostringstream vert;
427 	vert
428 		<< "#version 460\n"
429 		<< (m_params.multiview ? "#extension GL_EXT_multiview : enable\n" : "")
430 		<< "\n"
431 		<< "out gl_PerVertex\n"
432 		<< "{\n"
433 		<< "    vec4 gl_Position;\n"
434 		<< "};\n"
435 		<< "\n"
436 		<< "layout (location=0) in vec4 inPos;\n"
437 		<< "layout (location=0) out uvec4 outColor;\n"
438 		<< "\n"
439 		<< "void main()\n"
440 		<< "{\n"
441 		<< "    gl_Position = inPos;\n"
442 		<< "    const uint uDrawIndex = uint(gl_DrawID);\n"
443 		<< "    outColor.r = ((uDrawIndex >> 8u) & 0xFFu);\n"
444 		<< "    outColor.g = ((uDrawIndex      ) & 0xFFu);\n"
445 		<< "    outColor.b = 255u - uint(gl_InstanceIndex);\n"
446 		<< "    outColor.a = 255u" << (m_params.multiview ? " - uint(gl_ViewIndex)" : "") << ";\n"
447 		<< "}\n"
448 		;
449 	programCollection.glslSources.add("vert") << glu::VertexSource(vert.str());
450 
451 	std::ostringstream frag;
452 	frag
453 		<< "#version 460\n"
454 		<< "\n"
455 		<< "layout (location=0) flat in uvec4 inColor;\n"
456 		<< "layout (location=0) out uvec4 outColor;\n"
457 		<< "\n"
458 		<< "void main ()\n"
459 		<< "{\n"
460 		<< "    outColor = inColor;\n"
461 		<< "}\n"
462 		;
463 	programCollection.glslSources.add("frag") << glu::FragmentSource(frag.str());
464 
465 	if (m_params.useTessellation)
466 	{
467 		std::ostringstream tesc;
468 		tesc
469 			<< "#version 460\n"
470 			<< "\n"
471 			<< "layout (vertices=3) out;\n"
472 			<< "in gl_PerVertex\n"
473 			<< "{\n"
474 			<< "    vec4 gl_Position;\n"
475 			<< "} gl_in[gl_MaxPatchVertices];\n"
476 			<< "out gl_PerVertex\n"
477 			<< "{\n"
478 			<< "    vec4 gl_Position;\n"
479 			<< "} gl_out[];\n"
480 			<< "\n"
481 			<< "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
482 			<< "layout (location=0) out uvec4 outColor[];\n"
483 			<< "\n"
484 			<< "void main (void)\n"
485 			<< "{\n"
486 			<< "    gl_TessLevelInner[0] = 1.0;\n"
487 			<< "    gl_TessLevelInner[1] = 1.0;\n"
488 			<< "    gl_TessLevelOuter[0] = 1.0;\n"
489 			<< "    gl_TessLevelOuter[1] = 1.0;\n"
490 			<< "    gl_TessLevelOuter[2] = 1.0;\n"
491 			<< "    gl_TessLevelOuter[3] = 1.0;\n"
492 			<< "    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
493 			<< "    outColor[gl_InvocationID] = inColor[gl_InvocationID];\n"
494 			<< "}\n"
495 			;
496 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
497 
498 		std::ostringstream tese;
499 		tese
500 			<< "#version 460\n"
501 			<< "\n"
502 			<< "layout (triangles, fractional_odd_spacing, cw) in;\n"
503 			<< "in gl_PerVertex\n"
504 			<< "{\n"
505 			<< "    vec4 gl_Position;\n"
506 			<< "} gl_in[gl_MaxPatchVertices];\n"
507 			<< "out gl_PerVertex\n"
508 			<< "{\n"
509 			<< "    vec4 gl_Position;\n"
510 			<< "};\n"
511 			<< "\n"
512 			<< "layout (location=0) in uvec4 inColor[gl_MaxPatchVertices];\n"
513 			<< "layout (location=0) out uvec4 outColor;\n"
514 			<< "\n"
515 			<< "void main (void)\n"
516 			<< "{\n"
517 			<< "    gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
518 			<< "                  (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
519 			<< "                  (gl_TessCoord.z * gl_in[2].gl_Position);\n"
520 			<< "    outColor = inColor[0];\n"
521 			<< "}\n"
522 			;
523 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
524 	}
525 
526 	if (m_params.useGeometry)
527 	{
528 		std::ostringstream geom;
529 		geom
530 			<< "#version 460\n"
531 			<< "\n"
532 			<< "layout (triangles) in;\n"
533 			<< "layout (triangle_strip, max_vertices=3) out;\n"
534 			<< "in gl_PerVertex\n"
535 			<< "{\n"
536 			<< "    vec4 gl_Position;\n"
537 			<< "} gl_in[3];\n"
538 			<< "out gl_PerVertex\n"
539 			<< "{\n"
540 			<< "    vec4 gl_Position;\n"
541 			<< "};\n"
542 			<< "\n"
543 			<< "layout (location=0) in uvec4 inColor[3];\n"
544 			<< "layout (location=0) out uvec4 outColor;\n"
545 			<< "\n"
546 			<< "void main ()\n"
547 			<< "{\n"
548 			<< "    gl_Position = gl_in[0].gl_Position; outColor = inColor[0]; EmitVertex();\n"
549 			<< "    gl_Position = gl_in[1].gl_Position; outColor = inColor[1]; EmitVertex();\n"
550 			<< "    gl_Position = gl_in[2].gl_Position; outColor = inColor[2]; EmitVertex();\n"
551 			<< "}\n"
552 			;
553 		programCollection.glslSources.add("geom") << glu::GeometrySource(geom.str());
554 	}
555 }
556 
MultiDrawInstance(Context & context,const TestParams & params)557 MultiDrawInstance::MultiDrawInstance (Context& context, const TestParams& params)
558 	: vkt::TestInstance	(context)
559 	, m_params			(params)
560 {}
561 
appendPaddingVertices(std::vector<tcu::Vec4> & vertices,deUint32 count)562 void appendPaddingVertices (std::vector<tcu::Vec4>& vertices, deUint32 count)
563 {
564 	for (deUint32 i = 0u; i < count; ++i)
565 		vertices.emplace_back(0.0f, 0.0f, 0.0f, 1.0f);
566 }
567 
568 // Creates a render pass with multiple subpasses, one per layer.
makeMultidrawRenderPass(const DeviceInterface & vk,VkDevice device,VkFormat colorFormat,VkFormat depthStencilFormat,deUint32 layerCount)569 Move<VkRenderPass> makeMultidrawRenderPass (const DeviceInterface&	vk,
570 											VkDevice				device,
571 											VkFormat				colorFormat,
572 											VkFormat				depthStencilFormat,
573 											deUint32				layerCount)
574 {
575 	const VkAttachmentDescription colorAttachmentDescription =
576 	{
577 		0u,											// VkAttachmentDescriptionFlags    flags
578 		colorFormat,								// VkFormat                        format
579 		VK_SAMPLE_COUNT_1_BIT,						// VkSampleCountFlagBits           samples
580 		VK_ATTACHMENT_LOAD_OP_CLEAR,				// VkAttachmentLoadOp              loadOp
581 		VK_ATTACHMENT_STORE_OP_STORE,				// VkAttachmentStoreOp             storeOp
582 		VK_ATTACHMENT_LOAD_OP_DONT_CARE,			// VkAttachmentLoadOp              stencilLoadOp
583 		VK_ATTACHMENT_STORE_OP_DONT_CARE,			// VkAttachmentStoreOp             stencilStoreOp
584 		VK_IMAGE_LAYOUT_UNDEFINED,					// VkImageLayout                   initialLayout
585 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	// VkImageLayout                   finalLayout
586 	};
587 
588 	const VkAttachmentDescription depthStencilAttachmentDescription =
589 	{
590 		0u,													// VkAttachmentDescriptionFlags    flags
591 		depthStencilFormat,									// VkFormat                        format
592 		VK_SAMPLE_COUNT_1_BIT,								// VkSampleCountFlagBits           samples
593 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp              loadOp
594 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp             storeOp
595 		VK_ATTACHMENT_LOAD_OP_CLEAR,						// VkAttachmentLoadOp              stencilLoadOp
596 		VK_ATTACHMENT_STORE_OP_STORE,						// VkAttachmentStoreOp             stencilStoreOp
597 		VK_IMAGE_LAYOUT_UNDEFINED,							// VkImageLayout                   initialLayout
598 		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	// VkImageLayout                   finalLayout
599 	};
600 
601 	const std::vector<VkAttachmentDescription>	attachmentDescriptions		= { colorAttachmentDescription, depthStencilAttachmentDescription };
602 	const VkAttachmentReference					colorAttachmentRef			= makeAttachmentReference(0u, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
603 	const VkAttachmentReference					depthStencilAttachmentRef	= makeAttachmentReference(1u, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
604 
605 	const VkSubpassDescription subpassDescription =
606 	{
607 		0u,									// VkSubpassDescriptionFlags       flags
608 		VK_PIPELINE_BIND_POINT_GRAPHICS,	// VkPipelineBindPoint             pipelineBindPoint
609 		0u,									// deUint32                        inputAttachmentCount
610 		nullptr,							// const VkAttachmentReference*    pInputAttachments
611 		1u,									// deUint32                        colorAttachmentCount
612 		&colorAttachmentRef,				// const VkAttachmentReference*    pColorAttachments
613 		nullptr,							// const VkAttachmentReference*    pResolveAttachments
614 		&depthStencilAttachmentRef,			// const VkAttachmentReference*    pDepthStencilAttachment
615 		0u,									// deUint32                        preserveAttachmentCount
616 		nullptr								// const deUint32*                 pPreserveAttachments
617 	};
618 
619 	std::vector<VkSubpassDescription> subpassDescriptions;
620 
621 	subpassDescriptions.reserve(layerCount);
622 	for (deUint32 subpassIdx = 0u; subpassIdx < layerCount; ++subpassIdx)
623 		subpassDescriptions.push_back(subpassDescription);
624 
625 	using MultiviewInfoPtr = de::MovePtr<VkRenderPassMultiviewCreateInfo>;
626 
627 	MultiviewInfoPtr multiviewCreateInfo;
628 	std::vector<deUint32> viewMasks;
629 
630 	if (layerCount > 1u)
631 	{
632 		multiviewCreateInfo		= MultiviewInfoPtr(new VkRenderPassMultiviewCreateInfo);
633 		*multiviewCreateInfo	= initVulkanStructure();
634 
635 		viewMasks.resize(subpassDescriptions.size());
636 		for (deUint32 subpassIdx = 0u; subpassIdx < static_cast<deUint32>(viewMasks.size()); ++subpassIdx)
637 			viewMasks[subpassIdx] = (1u << subpassIdx);
638 
639 		multiviewCreateInfo->subpassCount	= static_cast<deUint32>(viewMasks.size());
640 		multiviewCreateInfo->pViewMasks		= de::dataOrNull(viewMasks);
641 	}
642 
643 	// Dependencies between subpasses for color and depth/stencil read/writes.
644 	std::vector<VkSubpassDependency> dependencies;
645 	if (layerCount > 1u)
646 		dependencies.reserve((layerCount - 1u) * 2u);
647 
648 	const auto fragmentTestStages	= (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
649 	const auto dsWrites				= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
650 	const auto dsReadWrites			= (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT);
651 	const auto colorStage			= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
652 	const auto colorWrites			= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
653 	const auto colorReadWrites		= (VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
654 
655 	for (deUint32 subpassIdx = 1u; subpassIdx < layerCount; ++subpassIdx)
656 	{
657 		const auto prev = subpassIdx - 1u;
658 
659 		const VkSubpassDependency dsDep =
660 		{
661 			prev,							//	deUint32				srcSubpass;
662 			subpassIdx,						//	deUint32				dstSubpass;
663 			fragmentTestStages,				//	VkPipelineStageFlags	srcStageMask;
664 			fragmentTestStages,				//	VkPipelineStageFlags	dstStageMask;
665 			dsWrites,						//	VkAccessFlags			srcAccessMask;
666 			dsReadWrites,					//	VkAccessFlags			dstAccessMask;
667 			VK_DEPENDENCY_BY_REGION_BIT,	//	VkDependencyFlags		dependencyFlags;
668 		};
669 		dependencies.push_back(dsDep);
670 
671 		const VkSubpassDependency colorDep =
672 		{
673 			prev,							//	deUint32				srcSubpass;
674 			subpassIdx,						//	deUint32				dstSubpass;
675 			colorStage,						//	VkPipelineStageFlags	srcStageMask;
676 			colorStage,						//	VkPipelineStageFlags	dstStageMask;
677 			colorWrites,					//	VkAccessFlags			srcAccessMask;
678 			colorReadWrites,				//	VkAccessFlags			dstAccessMask;
679 			VK_DEPENDENCY_BY_REGION_BIT,	//	VkDependencyFlags		dependencyFlags;
680 		};
681 		dependencies.push_back(colorDep);
682 	}
683 
684 	const VkRenderPassCreateInfo renderPassInfo =
685 	{
686 		VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,				// VkStructureType                   sType
687 		multiviewCreateInfo.get(),								// const void*                       pNext
688 		0u,														// VkRenderPassCreateFlags           flags
689 		static_cast<deUint32>(attachmentDescriptions.size()),	// deUint32                          attachmentCount
690 		de::dataOrNull(attachmentDescriptions),					// const VkAttachmentDescription*    pAttachments
691 		static_cast<deUint32>(subpassDescriptions.size()),		// deUint32                          subpassCount
692 		de::dataOrNull(subpassDescriptions),					// const VkSubpassDescription*       pSubpasses
693 		static_cast<deUint32>(dependencies.size()),				// deUint32                          dependencyCount
694 		de::dataOrNull(dependencies),							// const VkSubpassDependency*        pDependencies
695 	};
696 
697 	return createRenderPass(vk, device, &renderPassInfo, nullptr);
698 }
699 
beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer,VkFormat colorFormat,VkFormat depthStencilFormat,VkRenderingFlagsKHR renderingFlags,deUint32 viewMask) const700 void MultiDrawInstance::beginSecondaryCmdBuffer(VkCommandBuffer cmdBuffer, VkFormat colorFormat,
701 												VkFormat depthStencilFormat, VkRenderingFlagsKHR renderingFlags, deUint32 viewMask) const
702 {
703 	VkCommandBufferInheritanceRenderingInfoKHR inheritanceRenderingInfo
704 	{
705 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO_KHR,		// VkStructureType					sType;
706 		DE_NULL,																// const void*						pNext;
707 		renderingFlags,															// VkRenderingFlagsKHR				flags;
708 		viewMask,																// uint32_t							viewMask;
709 		1u,																		// uint32_t							colorAttachmentCount;
710 		&colorFormat,															// const VkFormat*					pColorAttachmentFormats;
711 		depthStencilFormat,														// VkFormat							depthAttachmentFormat;
712 		depthStencilFormat,														// VkFormat							stencilAttachmentFormat;
713 		VK_SAMPLE_COUNT_1_BIT,													// VkSampleCountFlagBits			rasterizationSamples;
714 	};
715 
716 	const VkCommandBufferInheritanceInfo bufferInheritanceInfo = initVulkanStructure(&inheritanceRenderingInfo);
717 
718 	VkCommandBufferUsageFlags usageFlags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
719 	if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
720 		usageFlags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
721 
722 	const VkCommandBufferBeginInfo commandBufBeginParams
723 	{
724 		VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,							// VkStructureType					sType;
725 		DE_NULL,																// const void*						pNext;
726 		usageFlags,																// VkCommandBufferUsageFlags		flags;
727 		&bufferInheritanceInfo
728 	};
729 
730 	const DeviceInterface& vk = m_context.getDeviceInterface();
731 	VK_CHECK(vk.beginCommandBuffer(cmdBuffer, &commandBufBeginParams));
732 }
733 
preRenderingCommands(VkCommandBuffer cmdBuffer,VkImage colorImage,const VkImageSubresourceRange colorSubresourceRange,VkImage dsImage,const VkImageSubresourceRange dsSubresourceRange) const734 void MultiDrawInstance::preRenderingCommands(VkCommandBuffer cmdBuffer,
735 											 VkImage colorImage, const VkImageSubresourceRange colorSubresourceRange,
736 											 VkImage dsImage, const VkImageSubresourceRange dsSubresourceRange) const
737 {
738 	const auto& vk = m_context.getDeviceInterface();
739 
740 	// Transition color and depth stencil attachment to the proper initial layout for dynamic rendering
741 	const auto colorPreBarrier = makeImageMemoryBarrier(
742 		0u,
743 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
744 		VK_IMAGE_LAYOUT_UNDEFINED,
745 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
746 		colorImage, colorSubresourceRange);
747 
748 	vk.cmdPipelineBarrier(
749 		cmdBuffer,
750 		VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
751 		VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
752 		0u, 0u, nullptr, 0u, nullptr, 1u, &colorPreBarrier);
753 
754 	const auto dsPreBarrier = makeImageMemoryBarrier(
755 		0u,
756 		VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
757 		VK_IMAGE_LAYOUT_UNDEFINED,
758 		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
759 		dsImage, dsSubresourceRange);
760 
761 	vk.cmdPipelineBarrier(
762 		cmdBuffer,
763 		VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
764 		(VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT),
765 		0u, 0u, nullptr, 0u, nullptr, 1u, &dsPreBarrier);
766 }
767 
drawCommands(VkCommandBuffer cmdBuffer,VkPipeline pipeline,VkBuffer vertexBuffer,VkDeviceSize vertexBufferOffset,deInt32 vertexOffset,VkBuffer indexBuffer,VkDeviceSize indexBufferOffset,bool isMixedMode,const DrawInfoPacker & drawInfos) const768 void MultiDrawInstance::drawCommands(VkCommandBuffer cmdBuffer, VkPipeline pipeline,
769 									 VkBuffer vertexBuffer, VkDeviceSize vertexBufferOffset, deInt32 vertexOffset,
770 									 VkBuffer indexBuffer, VkDeviceSize indexBufferOffset,
771 									 bool isMixedMode, const DrawInfoPacker& drawInfos) const
772 {
773 	const auto& vk = m_context.getDeviceInterface();
774 
775 	vk.cmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
776 	vk.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer, &vertexBufferOffset);
777 
778 	if (indexBuffer == DE_NULL)
779 	{
780 		const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawInfoEXT*>(drawInfos.drawInfoData());
781 		vk.cmdDrawMultiEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride());
782 	}
783 	else
784 	{
785 		vk.cmdBindIndexBuffer(cmdBuffer, indexBuffer, indexBufferOffset, VK_INDEX_TYPE_UINT32);
786 
787 		const auto drawInfoPtr = reinterpret_cast<const VkMultiDrawIndexedInfoEXT*>(drawInfos.drawInfoData());
788 		const auto offsetPtr = (isMixedMode ? nullptr : &vertexOffset);
789 		vk.cmdDrawMultiIndexedEXT(cmdBuffer, drawInfos.drawInfoCount(), drawInfoPtr, m_params.instanceCount, m_params.firstInstance, drawInfos.stride(), offsetPtr);
790 	}
791 }
792 
iterate(void)793 tcu::TestStatus MultiDrawInstance::iterate (void)
794 {
795 	const auto&	vki				= m_context.getInstanceInterface();
796 	const auto	physDev			= m_context.getPhysicalDevice();
797 	const auto&	vkd				= m_context.getDeviceInterface();
798 	const auto	device			= m_context.getDevice();
799 	auto&		alloc			= m_context.getDefaultAllocator();
800 	const auto	queue			= m_context.getUniversalQueue();
801 	const auto	qIndex			= m_context.getUniversalQueueFamilyIndex();
802 
803 	const auto	colorFormat		= getColorFormat();
804 	const auto	dsFormat		= chooseDepthStencilFormat(vki, physDev);
805 	const auto	tcuColorFormat	= mapVkFormat(colorFormat);
806 	const auto	triangleCount	= getTriangleCount();
807 	const auto	imageDim		= static_cast<deUint32>(deSqrt(static_cast<double>(triangleCount)));
808 	const auto	imageExtent		= makeExtent3D(imageDim, imageDim, 1u);
809 	const auto	imageLayers		= (m_params.multiview ? 2u : 1u);
810 	const auto	imageViewType	= ((imageLayers > 1u) ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D);
811 	const auto	colorUsage		= (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
812 	const auto	dsUsage			= (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
813 	const auto	pixelCount		= imageExtent.width * imageExtent.height;
814 	const auto	vertexCount		= pixelCount * 3u; // Triangle list.
815 	const auto	isIndexed		= (m_params.drawType == DrawType::INDEXED);
816 	const auto	isMixedMode		= (isIndexed && m_params.vertexOffset && m_params.vertexOffset->offsetType == VertexOffsetType::MIXED);
817 	const auto	extraVertices	= (m_params.vertexOffset ? m_params.vertexOffset->offset : 0u);
818 	const auto	isMosaic		= (m_params.meshType == MeshType::MOSAIC);
819 
820 	// Make sure we're providing a vertex offset for indexed cases.
821 	DE_ASSERT(!isIndexed || static_cast<bool>(m_params.vertexOffset));
822 
823 	// Make sure overlapping draws use a single instance.
824 	DE_ASSERT(isMosaic || m_params.instanceCount <= 1u);
825 
826 	// Color buffer.
827 	const VkImageCreateInfo imageCreateInfo =
828 	{
829 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
830 		nullptr,								//	const void*				pNext;
831 		0u,										//	VkImageCreateFlags		flags;
832 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
833 		colorFormat,							//	VkFormat				format;
834 		imageExtent,							//	VkExtent3D				extent;
835 		1u,										//	deUint32				mipLevels;
836 		imageLayers,							//	deUint32				arrayLayers;
837 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
838 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
839 		colorUsage,								//	VkImageUsageFlags		usage;
840 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
841 		0u,										//	deUint32				queueFamilyIndexCount;
842 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
843 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
844 	};
845 
846 	ImageWithMemory	colorBuffer				(vkd, device, alloc, imageCreateInfo, MemoryRequirement::Any);
847 	const auto		colorSubresourceRange	= makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, imageLayers);
848 	const auto		colorBufferView			= makeImageView(vkd, device, colorBuffer.get(), imageViewType, colorFormat, colorSubresourceRange);
849 
850 	// Depth/stencil buffer.
851 	const VkImageCreateInfo dsCreateInfo =
852 	{
853 		VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
854 		nullptr,								//	const void*				pNext;
855 		0u,										//	VkImageCreateFlags		flags;
856 		VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
857 		dsFormat,								//	VkFormat				format;
858 		imageExtent,							//	VkExtent3D				extent;
859 		1u,										//	deUint32				mipLevels;
860 		imageLayers,							//	deUint32				arrayLayers;
861 		VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
862 		VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
863 		dsUsage,								//	VkImageUsageFlags		usage;
864 		VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
865 		0u,										//	deUint32				queueFamilyIndexCount;
866 		nullptr,								//	const deUint32*			pQueueFamilyIndices;
867 		VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
868 	};
869 
870 	ImageWithMemory dsBuffer			(vkd, device, alloc, dsCreateInfo, MemoryRequirement::Any);
871 	const auto		dsSubresourceRange	= makeImageSubresourceRange((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, imageLayers);
872 	const auto		dsBufferView		= makeImageView(vkd, device, dsBuffer.get(), imageViewType, dsFormat, dsSubresourceRange);
873 
874 	// Output buffers to verify attachments.
875 	using BufferWithMemoryPtr = de::MovePtr<BufferWithMemory>;
876 
877 	// Buffers to read color attachment.
878 	const auto outputBufferSize = pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuColorFormat));
879 	const auto bufferCreateInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
880 
881 	std::vector<BufferWithMemoryPtr> outputBuffers;
882 	for (deUint32 i = 0u; i < imageLayers; ++i)
883 		outputBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, bufferCreateInfo, MemoryRequirement::HostVisible)));
884 
885 	// Buffer to read depth/stencil attachment. Note: this supposes we'll only copy the stencil aspect. See below.
886 	const auto			tcuStencilFmt			= mapVkFormat(getStencilVerificationFormat());
887 	const auto			stencilOutBufferSize	= pixelCount * static_cast<VkDeviceSize>(tcu::getPixelSize(tcuStencilFmt));
888 	const auto			stencilOutCreateInfo	= makeBufferCreateInfo(stencilOutBufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
889 
890 	std::vector<BufferWithMemoryPtr> stencilOutBuffers;
891 	for (deUint32 i = 0u; i < imageLayers; ++i)
892 		stencilOutBuffers.push_back(BufferWithMemoryPtr(new BufferWithMemory(vkd, device, alloc, stencilOutCreateInfo, MemoryRequirement::HostVisible)));
893 
894 	// Shaders.
895 	const auto				vertModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
896 	const auto				fragModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
897 	Move<VkShaderModule>	tescModule;
898 	Move<VkShaderModule>	teseModule;
899 	Move<VkShaderModule>	geomModule;
900 
901 	if (m_params.useGeometry)
902 		geomModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
903 
904 	if (m_params.useTessellation)
905 	{
906 		tescModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
907 		teseModule = createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
908 	}
909 
910 	DescriptorSetLayoutBuilder	layoutBuilder;
911 	const auto					descriptorSetLayout	= layoutBuilder.build(vkd, device);
912 	const auto					pipelineLayout		= makePipelineLayout(vkd, device, descriptorSetLayout.get());
913 
914 	Move<VkRenderPass>			renderPass;
915 	Move<VkFramebuffer>			framebuffer;
916 
917 	// Render pass and Framebuffer (note layers is always 1 as required by the spec).
918 	if (!m_params.groupParams->useDynamicRendering)
919 	{
920 		renderPass = makeMultidrawRenderPass(vkd, device, colorFormat, dsFormat, imageLayers);
921 		const std::vector<VkImageView> attachments { colorBufferView.get(), dsBufferView.get() };
922 		framebuffer = makeFramebuffer(vkd, device, renderPass.get(), static_cast<deUint32>(attachments.size()), de::dataOrNull(attachments), imageExtent.width, imageExtent.height, 1u);
923 	}
924 
925 	// Viewports and scissors.
926 	const auto						viewport	= makeViewport(imageExtent);
927 	const std::vector<VkViewport>	viewports	(1u, viewport);
928 	const auto						scissor		= makeRect2D(imageExtent);
929 	const std::vector<VkRect2D>		scissors	(1u, scissor);
930 
931 	// Indexed draws will have triangle vertices in reverse order. See index buffer creation below.
932 	const auto										frontFace			= (isIndexed ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE);
933 	const VkPipelineRasterizationStateCreateInfo	rasterizationInfo	=
934 	{
935 		VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
936 		nullptr,													//	const void*								pNext;
937 		0u,															//	VkPipelineRasterizationStateCreateFlags	flags;
938 		VK_FALSE,													//	VkBool32								depthClampEnable;
939 		VK_FALSE,													//	VkBool32								rasterizerDiscardEnable;
940 		VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
941 		VK_CULL_MODE_BACK_BIT,										//	VkCullModeFlags							cullMode;
942 		frontFace,													//	VkFrontFace								frontFace;
943 		VK_FALSE,													//	VkBool32								depthBiasEnable;
944 		0.0f,														//	float									depthBiasConstantFactor;
945 		0.0f,														//	float									depthBiasClamp;
946 		0.0f,														//	float									depthBiasSlopeFactor;
947 		1.0f,														//	float									lineWidth;
948 	};
949 
950 	const auto frontStencilState	= makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_WRAP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_ALWAYS, 0xFFu, 0xFFu, 0u);
951 	const auto backStencilState		= makeStencilOpState(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER, 0xFFu, 0xFFu, 0u);
952 	const auto depthTestEnable		= (isMosaic ? VK_FALSE : VK_TRUE);
953 	const auto depthWriteEnable		= depthTestEnable;
954 	const auto depthCompareOp		= (isMosaic ? VK_COMPARE_OP_ALWAYS : (isIndexed ? VK_COMPARE_OP_GREATER : VK_COMPARE_OP_LESS));
955 
956 	const VkPipelineDepthStencilStateCreateInfo depthStencilInfo =
957 	{
958 		VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		//	VkStructureType							sType;
959 		nullptr,														//	const void*								pNext;
960 		0u,																//	VkPipelineDepthStencilStateCreateFlags	flags;
961 		depthTestEnable,												//	VkBool32								depthTestEnable;
962 		depthWriteEnable,												//	VkBool32								depthWriteEnable;
963 		depthCompareOp,													//	VkCompareOp								depthCompareOp;
964 		VK_FALSE,														//	VkBool32								depthBoundsTestEnable;
965 		VK_TRUE,														//	VkBool32								stencilTestEnable;
966 		frontStencilState,												//	VkStencilOpState						front;
967 		backStencilState,												//	VkStencilOpState						back;
968 		0.0f,															//	float									minDepthBounds;
969 		1.0f,															//	float									maxDepthBounds;
970 	};
971 
972 	vk::VkPipelineRenderingCreateInfoKHR renderingCreateInfo
973 	{
974 		vk::VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR,
975 		DE_NULL,
976 		0u,
977 		1u,
978 		&colorFormat,
979 		dsFormat,
980 		dsFormat
981 	};
982 
983 	vk::VkPipelineRenderingCreateInfoKHR* nextPtr = nullptr;
984 	if (m_params.groupParams->useDynamicRendering)
985 		nextPtr = &renderingCreateInfo;
986 
987 	const auto primitiveTopology	= (m_params.useTessellation ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
988 	const auto patchControlPoints	= (m_params.useTessellation ? 3u : 0u);
989 
990 	// Pipelines.
991 	std::vector<Move<VkPipeline>> pipelines;
992 	pipelines.reserve(imageLayers);
993 	for (deUint32 subpassIdx = 0u; subpassIdx < imageLayers; ++subpassIdx)
994 	{
995 		renderingCreateInfo.viewMask = m_params.multiview ? (1u << subpassIdx) : 0u;
996 		pipelines.emplace_back(makeGraphicsPipeline(vkd, device, pipelineLayout.get(),
997 			vertModule.get(), tescModule.get(), teseModule.get(), geomModule.get(), fragModule.get(),
998 			renderPass.get(), viewports, scissors, primitiveTopology, m_params.groupParams->useDynamicRendering ? 0u : subpassIdx, patchControlPoints,
999 			nullptr/*vertexInputStateCreateInfo*/, &rasterizationInfo, nullptr/*multisampleStateCreateInfo*/, &depthStencilInfo,
1000 			nullptr/*colorBlendStateCreateInfo*/, nullptr/*dynamicStateCreateInfo*/, nextPtr));
1001 	}
1002 
1003 	// Command pool and buffer.
1004 	const auto								cmdPool			= makeCommandPool(vkd, device, qIndex);
1005 	Move<VkCommandBuffer>					cmdBufferPtr	= allocateCommandBuffer(vkd, device, cmdPool.get(), VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1006 	VkCommandBuffer							cmdBuffer		= cmdBufferPtr.get();
1007 	std::vector<Move<VkCommandBuffer> >		secCmdBuffers;
1008 
1009 	// Create vertex buffer.
1010 	std::vector<tcu::Vec4> triangleVertices;
1011 	triangleVertices.reserve(vertexCount + extraVertices);
1012 
1013 	// Vertex count per draw call.
1014 	const bool atLeastOneDraw	= (m_params.drawCount > 0u);
1015 	const bool moreThanOneDraw	= (m_params.drawCount > 1u);
1016 	const auto trianglesPerDraw	= (atLeastOneDraw ? pixelCount / m_params.drawCount : 0u);
1017 	const auto verticesPerDraw	= trianglesPerDraw * 3u;
1018 
1019 	if (atLeastOneDraw)
1020 		DE_ASSERT(pixelCount % m_params.drawCount == 0u);
1021 
1022 	{
1023 		using TriangleGeneratorPtr = de::MovePtr<TriangleGenerator>;
1024 		TriangleGeneratorPtr triangleGen;
1025 
1026 		if (m_params.meshType == MeshType::MOSAIC)
1027 			triangleGen = TriangleGeneratorPtr(new TriangleMosaicGenerator(imageExtent.width, imageExtent.height));
1028 		else if (m_params.meshType == MeshType::OVERLAPPING)
1029 			triangleGen = TriangleGeneratorPtr(new TriangleOverlapGenerator(imageExtent.width, imageExtent.height));
1030 		else
1031 			DE_ASSERT(false);
1032 
1033 		// When applying a vertex offset in nonmixed modes, there will be a few extra vertices at the start of the vertex buffer.
1034 		if (isIndexed && !isMixedMode)
1035 			appendPaddingVertices(triangleVertices, extraVertices);
1036 
1037 		for (deUint32 y = 0u; y < imageExtent.height; ++y)
1038 		for (deUint32 x = 0u; x < imageExtent.width; ++x)
1039 		{
1040 			// When applying a vertex offset in mixed mode, there will be some extra padding between the triangles for the first
1041 			// block and the rest, so that the vertex offset will not be constant in all draw info structures. This way, the first
1042 			// triangles will always have offset zero, and the number of them depends on the given draw count.
1043 			const auto pixelIndex = y * imageExtent.width + x;
1044 			if (isIndexed && isMixedMode && moreThanOneDraw && pixelIndex == trianglesPerDraw)
1045 				appendPaddingVertices(triangleVertices, extraVertices);
1046 
1047 			triangleGen->appendTriangle(x, y, triangleVertices);
1048 		}
1049 	}
1050 
1051 	const auto			vertexBufferSize	= static_cast<VkDeviceSize>(de::dataSize(triangleVertices));
1052 	const auto			vertexBufferInfo	= makeBufferCreateInfo(vertexBufferSize, (VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
1053 	BufferWithMemory	vertexBuffer		(vkd, device, alloc, vertexBufferInfo, MemoryRequirement::HostVisible);
1054 	auto&				vertexBufferAlloc	= vertexBuffer.getAllocation();
1055 	const auto			vertexBufferOffset	= vertexBufferAlloc.getOffset();
1056 	void*				vertexBufferData	= vertexBufferAlloc.getHostPtr();
1057 
1058 	deMemcpy(vertexBufferData, triangleVertices.data(), de::dataSize(triangleVertices));
1059 	flushAlloc(vkd, device, vertexBufferAlloc);
1060 
1061 	// Index buffer if needed.
1062 	de::MovePtr<BufferWithMemory>	indexBuffer;
1063 	VkDeviceSize					indexBufferOffset = 0ull;
1064 	VkBuffer						indexBufferHandle = DE_NULL;
1065 
1066 	if (isIndexed)
1067 	{
1068 		// Indices will be given in reverse order, so they effectively also make the triangles have reverse winding order.
1069 		std::vector<deUint32> indices;
1070 		indices.reserve(vertexCount);
1071 		for (deUint32 i = 0u; i < vertexCount; ++i)
1072 			indices.push_back(vertexCount - i - 1u);
1073 
1074 		const auto	indexBufferSize		= static_cast<VkDeviceSize>(de::dataSize(indices));
1075 		const auto	indexBufferInfo		= makeBufferCreateInfo(indexBufferSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1076 					indexBuffer			= de::MovePtr<BufferWithMemory>(new BufferWithMemory(vkd, device, alloc, indexBufferInfo, MemoryRequirement::HostVisible));
1077 		auto&		indexBufferAlloc	= indexBuffer->getAllocation();
1078 					indexBufferOffset	= indexBufferAlloc.getOffset();
1079 		void*		indexBufferData		= indexBufferAlloc.getHostPtr();
1080 
1081 		deMemcpy(indexBufferData, indices.data(), de::dataSize(indices));
1082 		flushAlloc(vkd, device, indexBufferAlloc);
1083 		indexBufferHandle = indexBuffer->get();
1084 	}
1085 
1086 	// Prepare draw information.
1087 	const auto offsetType	= (m_params.vertexOffset ? tcu::just(m_params.vertexOffset->offsetType) : tcu::Nothing);
1088 	const auto vertexOffset	= static_cast<deInt32>(extraVertices);
1089 
1090 	DrawInfoPacker drawInfos(m_params.drawType, offsetType, m_params.stride, m_params.drawCount, m_params.seed);
1091 
1092 	if (m_params.drawCount > 0u)
1093 	{
1094 		deUint32 vertexIndex = 0u;
1095 		for (deUint32 drawIdx = 0u; drawIdx < m_params.drawCount; ++drawIdx)
1096 		{
1097 			// For indexed draws in mixed offset mode, taking into account vertex indices have been stored in reversed order and
1098 			// there may be a padding in the vertex buffer after the first verticesPerDraw vertices, we need to use offset 0 in the
1099 			// last draw call. That draw will contain the indices for the first verticesPerDraw vertices, which are stored without
1100 			// any offset, while other draw calls will use indices which are off by extraVertices vertices. This will make sure not
1101 			// every draw call will use the same offset and the implementation handles that.
1102 			const auto drawOffset = ((isIndexed && (!isMixedMode || (moreThanOneDraw && drawIdx < m_params.drawCount - 1u))) ? vertexOffset : 0);
1103 			drawInfos.addDrawInfo(vertexIndex, verticesPerDraw, drawOffset);
1104 			vertexIndex += verticesPerDraw;
1105 		}
1106 	}
1107 
1108 	std::vector<VkClearValue> clearValues;
1109 	clearValues.reserve(2u);
1110 	clearValues.push_back(makeClearValueColorU32(0u, 0u, 0u, 0u));
1111 	clearValues.push_back(makeClearValueDepthStencil(((isMosaic || isIndexed) ? 0.0f : 1.0f), 0u));
1112 
1113 	if (m_params.groupParams->useSecondaryCmdBuffer)
1114 	{
1115 		secCmdBuffers.resize(imageLayers);
1116 		for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1117 		{
1118 			secCmdBuffers[layerIdx]			= allocateCommandBuffer(vkd, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_SECONDARY);
1119 			VkCommandBuffer	secCmdBuffer	= *secCmdBuffers[layerIdx];
1120 			const deUint32	viewMask		= m_params.multiview ? (1u << layerIdx) : 0u;
1121 
1122 			// record secondary command buffer
1123 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1124 			{
1125 				beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, viewMask);
1126 				beginRendering(vkd, secCmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1127 							   vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1128 							   VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, viewMask);
1129 			}
1130 			else
1131 				beginSecondaryCmdBuffer(secCmdBuffer, colorFormat, dsFormat, 0u, viewMask);
1132 
1133 			drawCommands(secCmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1134 						 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1135 
1136 			if (m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1137 				endRendering(vkd, secCmdBuffer);
1138 
1139 			endCommandBuffer(vkd, secCmdBuffer);
1140 		}
1141 
1142 		// record primary command buffer
1143 		beginCommandBuffer(vkd, cmdBuffer, 0u);
1144 		preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1145 
1146 		for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1147 		{
1148 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1149 			{
1150 				beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1151 							   vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1152 							   VK_ATTACHMENT_LOAD_OP_CLEAR, VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT, imageLayers,
1153 							   m_params.multiview ? (1u << layerIdx) : 0u);
1154 			}
1155 
1156 			vkd.cmdExecuteCommands(cmdBuffer, 1u, &*secCmdBuffers[layerIdx]);
1157 
1158 			if (!m_params.groupParams->secondaryCmdBufferCompletelyContainsDynamicRenderpass)
1159 				endRendering(vkd, cmdBuffer);
1160 		}
1161 	}
1162 	else
1163 	{
1164 		beginCommandBuffer(vkd, cmdBuffer);
1165 
1166 		if (m_params.groupParams->useDynamicRendering)
1167 			preRenderingCommands(cmdBuffer, *colorBuffer, colorSubresourceRange, *dsBuffer, dsSubresourceRange);
1168 		else
1169 			beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), scissor, static_cast<deUint32>(clearValues.size()), de::dataOrNull(clearValues));
1170 
1171 		for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1172 		{
1173 			if (m_params.groupParams->useDynamicRendering)
1174 				beginRendering(vkd, cmdBuffer, *colorBufferView, *dsBufferView, true, scissor, clearValues[0], clearValues[1],
1175 					vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1176 					VK_ATTACHMENT_LOAD_OP_CLEAR, 0, imageLayers, m_params.multiview ? (1u << layerIdx) : 0u);
1177 			else if (layerIdx > 0u)
1178 				vkd.cmdNextSubpass(cmdBuffer, VK_SUBPASS_CONTENTS_INLINE);
1179 
1180 			drawCommands(cmdBuffer, pipelines[layerIdx].get(), vertexBuffer.get(), vertexBufferOffset, vertexOffset,
1181 						 indexBufferHandle, indexBufferOffset, isMixedMode, drawInfos);
1182 
1183 			if (m_params.groupParams->useDynamicRendering)
1184 				endRendering(vkd, cmdBuffer);
1185 		}
1186 
1187 		if (!m_params.groupParams->useDynamicRendering)
1188 			endRenderPass(vkd, cmdBuffer);
1189 	}
1190 
1191 	// Prepare images for copying.
1192 	const auto colorBufferBarrier = makeImageMemoryBarrier(
1193 		VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1194 		VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1195 		colorBuffer.get(), colorSubresourceRange);
1196 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &colorBufferBarrier);
1197 
1198 	const auto dsBufferBarrier = makeImageMemoryBarrier(
1199 		VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
1200 		VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1201 		dsBuffer.get(), dsSubresourceRange);
1202 	vkd.cmdPipelineBarrier(cmdBuffer, (VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT), VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, nullptr, 0u, nullptr, 1u, &dsBufferBarrier);
1203 
1204 	// Copy images to output buffers.
1205 	for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1206 	{
1207 		const auto colorSubresourceLayers	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, layerIdx, 1u);
1208 		const auto colorCopyRegion			= makeBufferImageCopy(imageExtent, colorSubresourceLayers);
1209 		vkd.cmdCopyImageToBuffer(cmdBuffer, colorBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffers[layerIdx]->get(), 1u, &colorCopyRegion);
1210 	}
1211 
1212 	// Note: this only copies the stencil aspect. See stencilOutBuffer creation.
1213 	for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1214 	{
1215 		const auto stencilSubresourceLayers	= makeImageSubresourceLayers(VK_IMAGE_ASPECT_STENCIL_BIT, 0u, layerIdx, 1u);
1216 		const auto stencilCopyRegion		= makeBufferImageCopy(imageExtent, stencilSubresourceLayers);
1217 		vkd.cmdCopyImageToBuffer(cmdBuffer, dsBuffer.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, stencilOutBuffers[layerIdx]->get(), 1u, &stencilCopyRegion);
1218 	}
1219 
1220 	// Prepare buffers for host reading.
1221 	const auto outputBufferBarrier		= makeMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT);
1222 	vkd.cmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 1u, &outputBufferBarrier, 0u, nullptr, 0u, nullptr);
1223 
1224 	endCommandBuffer(vkd, cmdBuffer);
1225 	submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1226 
1227 	// Read output buffers and verify their contents.
1228 
1229 	// With stride zero, mosaic meshes increment the stencil buffer as many times as draw operations for affected pixels and
1230 	// overlapping meshes increment the stencil buffer only in the first draw operation (the rest fail the depth test) as many times
1231 	// as triangles per draw.
1232 	//
1233 	// With nonzero stride, mosaic meshes increment the stencil buffer once per pixel. Overlapping meshes increment it once per
1234 	// triangle.
1235 	const auto	stencilIncrements		=	((m_params.stride == 0u)
1236 											? (isMosaic ? drawInfos.drawInfoCount() : trianglesPerDraw)
1237 											: (isMosaic ? 1u : triangleCount));
1238 	const auto	maxInstanceIndex		= m_params.maxInstanceIndex();
1239 	const auto	colorVerificationFormat	= mapVkFormat(getVerificationFormat());
1240 	const auto	iWidth					= static_cast<int>(imageExtent.width);
1241 	const auto	iHeight					= static_cast<int>(imageExtent.height);
1242 	auto&		log						= m_context.getTestContext().getLog();
1243 	const auto	logMode					= tcu::CompareLogMode::COMPARE_LOG_ON_ERROR;
1244 
1245 	for (deUint32 layerIdx = 0u; layerIdx < imageLayers; ++layerIdx)
1246 	{
1247 		auto& outputBufferAlloc = outputBuffers[layerIdx]->getAllocation();
1248 		invalidateAlloc(vkd, device, outputBufferAlloc);
1249 		const void* outputBufferData = outputBufferAlloc.getHostPtr();
1250 
1251 		auto& stencilOutBufferAlloc = stencilOutBuffers[layerIdx]->getAllocation();
1252 		invalidateAlloc(vkd, device, stencilOutBufferAlloc);
1253 		const void* stencilOutBufferData = stencilOutBufferAlloc.getHostPtr();
1254 
1255 		tcu::ConstPixelBufferAccess	colorAccess				(colorVerificationFormat, iWidth, iHeight, 1, outputBufferData);
1256 		tcu::ConstPixelBufferAccess	stencilAccess			(tcuStencilFmt, iWidth, iHeight, 1, stencilOutBufferData);
1257 
1258 		// Generate reference images.
1259 		tcu::TextureLevel			refColorLevel		(colorVerificationFormat, iWidth, iHeight);
1260 		tcu::PixelBufferAccess		refColorAccess		= refColorLevel.getAccess();
1261 		tcu::TextureLevel			refStencilLevel		(tcuStencilFmt, iWidth, iHeight);
1262 		tcu::PixelBufferAccess		refStencilAccess	= refStencilLevel.getAccess();
1263 		tcu::IVec4					referenceColor;
1264 		int							referenceStencil;
1265 
1266 		for (int y = 0; y < iHeight; ++y)
1267 		for (int x = 0; x < iWidth; ++x)
1268 		{
1269 			const auto pixelNumber		= static_cast<deUint32>(y * iWidth + x);
1270 			const auto triangleIndex	= (isIndexed ? (pixelCount - 1u - pixelNumber) : pixelNumber); // Reverse order for indexed draws.
1271 
1272 			if (m_params.instanceCount == 0u || drawInfos.drawInfoCount() == 0u ||
1273 				(m_params.stride == 0u && triangleIndex >= trianglesPerDraw && isMosaic))
1274 			{
1275 				// Some pixels may not be drawn into when there are no instances or draws, or when the stride is zero in mosaic mode.
1276 				referenceColor		= tcu::IVec4(0, 0, 0, 0);
1277 				referenceStencil	= 0;
1278 			}
1279 			else
1280 			{
1281 				// This must match the vertex shader.
1282 				//
1283 				// With stride zero, the same block is drawn over and over again in each draw call. This affects both the draw index and
1284 				// the values in the depth/stencil buffer and, with overlapping meshes, only the first draw passes the depth test.
1285 				//
1286 				// With nonzero stride, the draw index depends on the triangle index and the number of triangles per draw and, for
1287 				// overlapping meshes, the draw index is always the last one.
1288 				const auto drawIndex =	(m_params.stride == 0u
1289 										? (isMosaic ? (drawInfos.drawInfoCount() - 1u) : 0u)
1290 										: (isMosaic ? (triangleIndex / trianglesPerDraw) : (drawInfos.drawInfoCount() - 1u)));
1291 				referenceColor = tcu::IVec4(
1292 					static_cast<int>((drawIndex >> 8) & 0xFFu),
1293 					static_cast<int>((drawIndex     ) & 0xFFu),
1294 					static_cast<int>(255u - maxInstanceIndex),
1295 					static_cast<int>(255u - layerIdx));
1296 
1297 				referenceStencil = static_cast<int>((m_params.instanceCount * stencilIncrements) % 256u); // VK_STENCIL_OP_INCREMENT_AND_WRAP.
1298 			}
1299 
1300 			refColorAccess.setPixel(referenceColor, x, y);
1301 			refStencilAccess.setPixStencil(referenceStencil, x, y);
1302 		}
1303 
1304 		const auto layerIdxStr		= de::toString(layerIdx);
1305 		const auto colorSetName		= "ColorTestResultLayer" + layerIdxStr;
1306 		const auto stencilSetName	= "StencilTestResultLayer" + layerIdxStr;
1307 
1308 		if (!tcu::intThresholdCompare(log, colorSetName.c_str(), "", refColorAccess, colorAccess, tcu::UVec4(0u, 0u, 0u, 0u), logMode))
1309 			return tcu::TestStatus::fail("Color image comparison failed; check log for more details");
1310 
1311 		if (!tcu::dsThresholdCompare(log, stencilSetName.c_str(), "", refStencilAccess, stencilAccess, 0.0f, logMode))
1312 			return tcu::TestStatus::fail("Stencil image comparison failed; check log for more details");
1313 	}
1314 
1315 	return tcu::TestStatus::pass("Pass");
1316 }
1317 
1318 } // anonymous
1319 
createDrawMultiExtTests(tcu::TestContext & testCtx,const SharedGroupParams groupParams)1320 tcu::TestCaseGroup*	createDrawMultiExtTests (tcu::TestContext& testCtx, const SharedGroupParams groupParams)
1321 {
1322 	using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
1323 
1324 	GroupPtr drawMultiGroup (new tcu::TestCaseGroup(testCtx, "multi_draw", "VK_EXT_multi_draw tests"));
1325 
1326 	const struct
1327 	{
1328 		MeshType	meshType;
1329 		const char*	name;
1330 	} meshTypeCases[] =
1331 	{
1332 		{ MeshType::MOSAIC,			"mosaic"		},
1333 		{ MeshType::OVERLAPPING,	"overlapping"	},
1334 	};
1335 
1336 	const struct
1337 	{
1338 		DrawType	drawType;
1339 		const char*	name;
1340 	} drawTypeCases[] =
1341 	{
1342 		{ DrawType::NORMAL,		"normal"	},
1343 		{ DrawType::INDEXED,	"indexed"	},
1344 	};
1345 
1346 	const struct
1347 	{
1348 		tcu::Maybe<VertexOffsetType>	vertexOffsetType;
1349 		const char*						name;
1350 	} offsetTypeCases[] =
1351 	{
1352 		{ tcu::Nothing,							""			},
1353 		{ VertexOffsetType::MIXED,				"mixed"		},
1354 		{ VertexOffsetType::CONSTANT_RANDOM,	"random"	},
1355 		{ VertexOffsetType::CONSTANT_PACK,		"packed"	},
1356 	};
1357 
1358 	const struct
1359 	{
1360 		deUint32	drawCount;
1361 		const char*	name;
1362 	} drawCountCases[] =
1363 	{
1364 		{ 0u,					"no_draws"	},
1365 		{ 1u,					"one_draw"	},
1366 		{ 16u,					"16_draws"	},
1367 		{ getTriangleCount(),	"max_draws"	},
1368 	};
1369 
1370 	const struct
1371 	{
1372 		int			extraBytes;
1373 		const char*	name;
1374 	} strideCases[] =
1375 	{
1376 		{ -1,		"stride_zero"		},
1377 		{  0,		"standard_stride"	},
1378 		{  4,		"stride_extra_4"	},
1379 		{ 12,		"stride_extra_12"	},
1380 	};
1381 
1382 	const struct
1383 	{
1384 		deUint32	firstInstance;
1385 		deUint32	instanceCount;
1386 		const char*	name;
1387 	} instanceCases[] =
1388 	{
1389 		{	0u,		0u,		"no_instances"			},
1390 		{	0u,		1u,		"1_instance"			},
1391 		{	0u,		10u,	"10_instances"			},
1392 		{	3u,		2u,		"2_instances_base_3"	},
1393 	};
1394 
1395 	const struct
1396 	{
1397 		bool		useTessellation;
1398 		bool		useGeometry;
1399 		const char*	name;
1400 	} shaderCases[] =
1401 	{
1402 		{ false,	false,		"vert_only"	},
1403 		{ false,	true,		"with_geom"	},
1404 		{ true,		false,		"with_tess"	},
1405 		{ true,		true,		"tess_geom"	},
1406 	};
1407 
1408 	const struct
1409 	{
1410 		bool		multiview;
1411 		const char*	name;
1412 	} multiviewCases[] =
1413 	{
1414 		{ false,	"single_view"	},
1415 		{ true,		"multiview"		},
1416 	};
1417 
1418 	constexpr deUint32 kSeed = 1621260419u;
1419 
1420 	for (const auto& meshTypeCase : meshTypeCases)
1421 	{
1422 		// reduce number of tests for dynamic rendering cases where secondary command buffer is used
1423 		if (groupParams->useSecondaryCmdBuffer && (meshTypeCase.meshType != MeshType::MOSAIC))
1424 			continue;
1425 
1426 		GroupPtr meshTypeGroup(new tcu::TestCaseGroup(testCtx, meshTypeCase.name, ""));
1427 
1428 		for (const auto& drawTypeCase : drawTypeCases)
1429 		{
1430 			for (const auto& offsetTypeCase : offsetTypeCases)
1431 			{
1432 				// reduce number of tests for dynamic rendering cases where secondary command buffer is used
1433 				if (groupParams->useSecondaryCmdBuffer && offsetTypeCase.vertexOffsetType && (*offsetTypeCase.vertexOffsetType != VertexOffsetType::CONSTANT_RANDOM))
1434 					continue;
1435 
1436 				const auto hasOffsetType = static_cast<bool>(offsetTypeCase.vertexOffsetType);
1437 				if ((drawTypeCase.drawType == DrawType::NORMAL && hasOffsetType) ||
1438 					(drawTypeCase.drawType == DrawType::INDEXED && !hasOffsetType))
1439 				{
1440 					continue;
1441 				}
1442 
1443 				std::string drawGroupName = drawTypeCase.name;
1444 				if (hasOffsetType)
1445 					drawGroupName += std::string("_") + offsetTypeCase.name;
1446 
1447 				GroupPtr drawTypeGroup(new tcu::TestCaseGroup(testCtx, drawGroupName.c_str(), ""));
1448 
1449 				for (const auto& drawCountCase : drawCountCases)
1450 				{
1451 					// reduce number of tests for dynamic rendering cases where secondary command buffer is used
1452 					if (groupParams->useSecondaryCmdBuffer && (drawCountCase.drawCount != 1u))
1453 						continue;
1454 
1455 					GroupPtr drawCountGroup(new tcu::TestCaseGroup(testCtx, drawCountCase.name, ""));
1456 
1457 					for (const auto& strideCase : strideCases)
1458 					{
1459 						GroupPtr strideGroup(new tcu::TestCaseGroup(testCtx, strideCase.name, ""));
1460 
1461 						for (const auto& instanceCase : instanceCases)
1462 						{
1463 							GroupPtr instanceGroup(new tcu::TestCaseGroup(testCtx, instanceCase.name, ""));
1464 
1465 							for (const auto& shaderCase : shaderCases)
1466 							{
1467 								GroupPtr shaderGroup(new tcu::TestCaseGroup(testCtx, shaderCase.name, ""));
1468 
1469 								for (const auto& multiviewCase : multiviewCases)
1470 								{
1471 									GroupPtr multiviewGroup(new tcu::TestCaseGroup(testCtx, multiviewCase.name, ""));
1472 
1473 									const auto	isIndexed	= (drawTypeCase.drawType == DrawType::INDEXED);
1474 									const auto	isPacked	= (offsetTypeCase.vertexOffsetType && *offsetTypeCase.vertexOffsetType == VertexOffsetType::CONSTANT_PACK);
1475 									const auto	baseStride	= ((isIndexed && !isPacked) ? sizeof(VkMultiDrawIndexedInfoEXT) : sizeof(VkMultiDrawInfoEXT));
1476 									const auto&	extraBytes	= strideCase.extraBytes;
1477 									const auto	testOffset	= (isIndexed ? tcu::just(VertexOffsetParams{*offsetTypeCase.vertexOffsetType, 0u }) : tcu::Nothing);
1478 									deUint32	testStride	= 0u;
1479 
1480 									if (extraBytes >= 0)
1481 										testStride = static_cast<deUint32>(baseStride) + static_cast<deUint32>(extraBytes);
1482 
1483 									// For overlapping triangles we will skip instanced drawing.
1484 									if (instanceCase.instanceCount > 1u && meshTypeCase.meshType == MeshType::OVERLAPPING)
1485 										continue;
1486 
1487 									TestParams params
1488 									{
1489 										meshTypeCase.meshType,			//	MeshType						meshType;
1490 										drawTypeCase.drawType,			//	DrawType						drawType;
1491 										drawCountCase.drawCount,		//	deUint32						drawCount;
1492 										instanceCase.instanceCount,		//	deUint32						instanceCount;
1493 										instanceCase.firstInstance,		//	deUint32						firstInstance;
1494 										testStride,						//	deUint32						stride;
1495 										testOffset,						//	tcu::Maybe<VertexOffsetParams>>	vertexOffset;	// Only used for indexed draws.
1496 										kSeed,							//	deUint32						seed;
1497 										shaderCase.useTessellation,		//	bool							useTessellation;
1498 										shaderCase.useGeometry,			//	bool							useGeometry;
1499 										multiviewCase.multiview,		//	bool							multiview;
1500 										groupParams,					//	SharedGroupParams				groupParams;
1501 									};
1502 
1503 									multiviewGroup->addChild(new MultiDrawTest(testCtx, "no_offset", "", params));
1504 
1505 									if (isIndexed)
1506 									{
1507 										params.vertexOffset->offset = 6u;
1508 										multiviewGroup->addChild(new MultiDrawTest(testCtx, "offset_6", "", params));
1509 									}
1510 
1511 									shaderGroup->addChild(multiviewGroup.release());
1512 								}
1513 
1514 								instanceGroup->addChild(shaderGroup.release());
1515 							}
1516 
1517 							strideGroup->addChild(instanceGroup.release());
1518 						}
1519 
1520 						drawCountGroup->addChild(strideGroup.release());
1521 					}
1522 
1523 					drawTypeGroup->addChild(drawCountGroup.release());
1524 				}
1525 
1526 				meshTypeGroup->addChild(drawTypeGroup.release());
1527 			}
1528 		}
1529 
1530 		drawMultiGroup->addChild(meshTypeGroup.release());
1531 	}
1532 
1533 	return drawMultiGroup.release();
1534 }
1535 
1536 } // Draw
1537 } // vkt
1538