• 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 Extended dynamic state tests
23 *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineExtendedDynamicStateTests.hpp"
26 #include "vktPipelineImageUtil.hpp"
27 #include "vktTestCase.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38 
39 #include "tcuVector.hpp"
40 #include "tcuMaybe.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43 
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46 
47 #include <vector>
48 #include <sstream>
49 #include <algorithm>
50 #include <utility>
51 #include <iterator>
52 #include <string>
53 #include <limits>
54 #include <memory>
55 #include <functional>
56 
57 namespace vkt
58 {
59 namespace pipeline
60 {
61 
62 namespace
63 {
64 
makeVkBool32(bool value)65 inline vk::VkBool32 makeVkBool32(bool value)
66 {
67 	return (value ? VK_TRUE : VK_FALSE);
68 }
69 
70 // Test versions
71 constexpr deUint32 TEST_VERSION_extended_dynamic_state = 1;
72 constexpr deUint32 TEST_VERSION_vertex_input_dynamic_state = 2;
73 constexpr deUint32 TEST_VERSION_extended_dynamic_state2 = 3;
74 
75 // Framebuffer size.
76 constexpr deUint32	kFramebufferWidth	= 64u;
77 constexpr deUint32	kFramebufferHeight	= 64u;
78 
79 // Image formats.
80 constexpr	vk::VkFormat	kColorFormat	= vk::VK_FORMAT_R8G8B8A8_UNORM;
81 constexpr	vk::VkFormat	kIntColorFormat = vk::VK_FORMAT_R8G8B8A8_UINT;
82 const		tcu::Vec4		kColorThreshold	(0.005f); // 1/255 < 0.005 < 2/255.
83 
84 struct DepthStencilFormat
85 {
86 	vk::VkFormat	imageFormat;
87 	float			depthThreshold;
88 };
89 
90 const DepthStencilFormat kDepthStencilFormats[] =
91 {
92 	{ vk::VK_FORMAT_D32_SFLOAT_S8_UINT,	0.0f		},
93 	{ vk::VK_FORMAT_D24_UNORM_S8_UINT,	1.0e-07f	},	// 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
94 };
95 
96 // We will use several data types in vertex bindings. Each type will need to define a few things.
97 class GeometryVertex
98 {
99 public:
100 	// For GLSL.
101 
102 	// Vertex input attribute declarations in GLSL form. One sentence per element.
103 	virtual std::vector<std::string>							getAttributeDeclarations()	const = 0;
104 
105 	// Get statements to calculate a vec2 called "vertexCoords" using the vertex input attributes.
106 	virtual std::vector<std::string>							getVertexCoordCalc()		const = 0;
107 
108 
109 	// For the pipeline.
110 
111 	// Vertex attributes for VkPipelineVertexInputStateCreateInfo.
112 	virtual std::vector<vk::VkVertexInputAttributeDescription>	getAttributeDescriptions(deUint32 offset)	const = 0;
113 
114 	// Size of each vertex.
115 	virtual size_t												getVertexDataSize()			const = 0;
116 
117 	// Array of bytes containing vertex data. .size() should match getVertexDataSize().
118 	virtual std::vector<deUint8>								getVertexData()				const = 0;
119 
120 	// Offset to the coords data.
121 	virtual size_t												getCoordsOffset()			const = 0;
122 
123 	// Offset to the padding data.
124 	virtual size_t												getPaddingOffset()			const = 0;
125 };
126 
127 // Vertices in buffers will have 2 components and a padding to properly test the stride.
128 // This is the vertex type that will be used normally.
129 class VertexWithPadding : public GeometryVertex
130 {
131 protected:
132 	tcu::Vec2 coords;
133 	tcu::Vec2 padding;
134 
135 public:
VertexWithPadding(const tcu::Vec2 & coords_)136 	VertexWithPadding (const tcu::Vec2& coords_)
137 		: coords	(coords_)
138 		, padding	(0.0f, 0.0f)
139 	{}
140 
getAttributeDeclarations() const141 	virtual std::vector<std::string> getAttributeDeclarations() const override
142 	{
143 		std::vector<std::string> declarations;
144 		declarations.push_back("layout(location=0) in vec2 position;");
145 		return declarations;
146 	}
147 
getVertexCoordCalc() const148 	virtual std::vector<std::string> getVertexCoordCalc() const override
149 	{
150 		std::vector<std::string> statements;
151 		statements.push_back("vec2 vertexCoords = position;");
152 		return statements;
153 	}
154 
getAttributeDescriptions(deUint32 offset) const155 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions(deUint32 offset) const override
156 	{
157 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
158 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, offset));
159 		return descriptions;
160 	}
161 
getVertexDataSize() const162 	virtual size_t getVertexDataSize() const override
163 	{
164 		return sizeof(coords) + sizeof(padding);
165 	}
166 
getVertexData() const167 	virtual std::vector<deUint8> getVertexData() const override
168 	{
169 		const auto				dataSize	= getVertexDataSize();
170 		std::vector<deUint8>	vertexData	(dataSize);
171 
172 		deMemcpy(&vertexData[0], &coords, sizeof(coords));
173 		deMemcpy(&vertexData[sizeof(coords)], &padding, sizeof(padding));
174 		return vertexData;
175 	}
176 
getCoordsOffset() const177 	virtual size_t getCoordsOffset() const override
178 	{
179 		return 0;
180 	}
181 
getPaddingOffset() const182 	virtual size_t getPaddingOffset() const override
183 	{
184 		return sizeof coords;
185 	}
186 };
187 
188 class VertexWithExtraAttributes : public GeometryVertex
189 {
190 protected:
191 	tcu::Vec2 coords;
192 	tcu::Vec2 padding[10];
193 	tcu::Vec2 ones;
194 
195 public:
VertexWithExtraAttributes(const tcu::Vec2 & coords_)196 	VertexWithExtraAttributes (const tcu::Vec2& coords_)
197 		: coords	(coords_)
198 		, ones		(1.0f, 1.0f)
199 	{
200 		deMemset(padding, 0, sizeof(padding));
201 	}
202 
getAttributeDeclarations() const203 	virtual std::vector<std::string> getAttributeDeclarations() const override
204 	{
205 		std::vector<std::string> declarations;
206 		declarations.push_back("layout(location=0) in vec2 position;");
207 		declarations.push_back("layout(location=1) in vec2 ones;");
208 		return declarations;
209 	}
210 
getVertexCoordCalc() const211 	virtual std::vector<std::string> getVertexCoordCalc() const override
212 	{
213 		std::vector<std::string> statements;
214 		statements.push_back("vec2 vertexCoords = position;");
215 		statements.push_back("vertexCoords = vertexCoords * ones;");
216 		return statements;
217 	}
218 
getAttributeDescriptions(deUint32 offset) const219 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions(deUint32 offset) const override
220 	{
221 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
222 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, offset));
223 		descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(sizeof(coords) + sizeof(padding))));
224 		return descriptions;
225 	}
226 
getVertexDataSize() const227 	virtual size_t getVertexDataSize() const override
228 	{
229 		return sizeof(coords) + sizeof(padding) + sizeof(ones);
230 	}
231 
getVertexData() const232 	virtual std::vector<deUint8> getVertexData() const override
233 	{
234 		const auto				dataSize	= getVertexDataSize();
235 		std::vector<deUint8>	vertexData	(dataSize);
236 
237 		deMemcpy(&vertexData[0], &coords, sizeof(coords));
238 		deMemcpy(&vertexData[sizeof(coords)], &padding, sizeof(padding));
239 		deMemcpy(&vertexData[sizeof(coords) + sizeof(padding)], &ones, sizeof(ones));
240 		return vertexData;
241 	}
242 
getCoordsOffset() const243 	virtual size_t getCoordsOffset() const override
244 	{
245 		return 0;
246 	}
247 
getPaddingOffset() const248 	virtual size_t getPaddingOffset() const override
249 	{
250 		return sizeof coords;
251 	}
252 };
253 
254 constexpr auto kCoordsSize = static_cast<vk::VkDeviceSize>(sizeof(tcu::Vec2));
255 
256 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
257 struct StencilOpParams
258 {
259 	vk::VkStencilFaceFlags  faceMask;
260 	vk::VkStencilOp         failOp;
261 	vk::VkStencilOp         passOp;
262 	vk::VkStencilOp         depthFailOp;
263 	vk::VkCompareOp         compareOp;
264 };
265 
266 const StencilOpParams kDefaultStencilOpParams =
267 {
268 	vk::VK_STENCIL_FACE_FRONT_AND_BACK,
269 	vk::VK_STENCIL_OP_KEEP,
270 	vk::VK_STENCIL_OP_KEEP,
271 	vk::VK_STENCIL_OP_KEEP,
272 	vk::VK_COMPARE_OP_ALWAYS
273 };
274 
275 using ViewportVec	= std::vector<vk::VkViewport>;
276 using ScissorVec	= std::vector<vk::VkRect2D>;
277 using StencilOpVec	= std::vector<StencilOpParams>;
278 
279 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
280 template<typename T>
281 struct StaticAndDynamicPair
282 {
283 	T				staticValue;
284 	tcu::Maybe<T>	dynamicValue;
285 
286 	// Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair287 	StaticAndDynamicPair (const T& value)
288 		: staticValue	(value)
289 		, dynamicValue	(tcu::nothing<T>())
290 	{
291 	}
292 
293 	// Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair294 	StaticAndDynamicPair (const T& sVal, const T& dVal)
295 		: staticValue	(sVal)
296 		, dynamicValue	(tcu::just<T>(dVal))
297 	{
298 	}
299 
300 	// If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair301 	void swapValues (void)
302 	{
303 		if (!dynamicValue)
304 			return;
305 		std::swap(staticValue, dynamicValue.get());
306 	}
307 };
308 
309 // For anything boolean, see below.
310 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
311 
312 // Configuration for every aspect of the extended dynamic state.
313 using CullModeConfig				= StaticAndDynamicPair<vk::VkCullModeFlags>;
314 using FrontFaceConfig				= StaticAndDynamicPair<vk::VkFrontFace>;
315 using TopologyConfig				= StaticAndDynamicPair<vk::VkPrimitiveTopology>;
316 using ViewportConfig				= StaticAndDynamicPair<ViewportVec>;	// At least one element.
317 using ScissorConfig					= StaticAndDynamicPair<ScissorVec>;		// At least one element.
318 using StrideConfig					= StaticAndDynamicPair<vk::VkDeviceSize>;
319 using DepthTestEnableConfig			= BooleanFlagConfig;
320 using DepthWriteEnableConfig		= BooleanFlagConfig;
321 using DepthCompareOpConfig			= StaticAndDynamicPair<vk::VkCompareOp>;
322 using DepthBoundsTestEnableConfig	= BooleanFlagConfig;
323 using StencilTestEnableConfig		= BooleanFlagConfig;
324 using StencilOpConfig				= StaticAndDynamicPair<StencilOpVec>;	// At least one element.
325 using VertexInputConfig				= StaticAndDynamicPair<deUint32>;
326 using DepthBiasEnableConfig			= BooleanFlagConfig;
327 using RastDiscardEnableConfig		= BooleanFlagConfig;
328 using PrimRestartEnableConfig		= BooleanFlagConfig;
329 using LogicOpConfig					= StaticAndDynamicPair<vk::VkLogicOp>;
330 using PatchControlPointsConfig		= StaticAndDynamicPair<deUint8>;
331 
332 const tcu::Vec4	kDefaultTriangleColor	(0.0f, 0.0f, 1.0f, 1.0f);	// Opaque blue.
333 const tcu::Vec4	kDefaultClearColor		(0.0f, 0.0f, 0.0f, 1.0f);	// Opaque black.
334 const tcu::Vec4	kGreenClearColor		(0.0f, 1.0f, 0.0f, 1.0f);	// Opaque green.
335 const tcu::Vec4	kCyanColor				(0.0f, 1.0f, 1.0f, 1.0f);	// Opaque cyan
336 
337 struct MeshParams
338 {
339 	tcu::Vec4	color;
340 	float		depth;
341 	bool		reversed;
342 	float		scaleX;
343 	float		scaleY;
344 	float		offsetX;
345 	float		offsetY;
346 
MeshParamsvkt::pipeline::__anonc593e7400111::MeshParams347 	MeshParams (const tcu::Vec4&	color_		= kDefaultTriangleColor,
348 				float				depth_		= 0.0f,
349 				bool				reversed_	= false,
350 				float				scaleX_		= 1.0f,
351 				float				scaleY_		= 1.0f,
352 				float				offsetX_	= 0.0f,
353 				float				offsetY_	= 0.0f)
354 		: color		(color_)
355 		, depth		(depth_)
356 		, reversed	(reversed_)
357 		, scaleX	(scaleX_)
358 		, scaleY	(scaleY_)
359 		, offsetX	(offsetX_)
360 		, offsetY	(offsetY_)
361 	{}
362 };
363 
364 enum class SequenceOrdering
365 {
366 	CMD_BUFFER_START	= 0,	// Set state at the start of the command buffer.
367 	BEFORE_DRAW			= 1,	// After binding dynamic pipeline and just before drawing.
368 	BETWEEN_PIPELINES	= 2,	// After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
369 	AFTER_PIPELINES		= 3,	// After a static state pipeline and a second dynamic state pipeline have been bound.
370 	BEFORE_GOOD_STATIC	= 4,	// Before a static state pipeline with the correct values has been bound.
371 	TWO_DRAWS_DYNAMIC	= 5,	// Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
372 	TWO_DRAWS_STATIC	= 6,	// Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
373 };
374 
375 using ReferenceColorGenerator = std::function<void(tcu::PixelBufferAccess&)>;
376 
377 // Most tests expect a single output color in the whole image.
378 class SingleColorGenerator
379 {
380 public:
SingleColorGenerator(const tcu::Vec4 & color)381 	SingleColorGenerator (const tcu::Vec4& color)
382 		: m_color(color)
383 	{}
384 
operator ()(tcu::PixelBufferAccess & access)385 	void operator()(tcu::PixelBufferAccess& access)
386 	{
387 		constexpr auto kWidth	= static_cast<int>(kFramebufferWidth);
388 		constexpr auto kHeight	= static_cast<int>(kFramebufferHeight);
389 
390 		for (int y = 0; y < kHeight; ++y)
391 		for (int x = 0; x < kWidth; ++x)
392 		{
393 			access.setPixel(m_color, x, y);
394 		}
395 	}
396 
397 private:
398 	const tcu::Vec4 m_color;
399 };
400 
401 // Some tests expect the upper half and the lower half having different color values.
402 class HorizontalSplitGenerator
403 {
404 public:
HorizontalSplitGenerator(const tcu::Vec4 & top,const tcu::Vec4 & bottom)405 	HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
406 		: m_top(top), m_bottom(bottom)
407 	{}
408 
operator ()(tcu::PixelBufferAccess & access)409 	void operator()(tcu::PixelBufferAccess& access)
410 	{
411 		constexpr auto kWidth		= static_cast<int>(kFramebufferWidth);
412 		constexpr auto kHeight		= static_cast<int>(kFramebufferHeight);
413 		constexpr auto kHalfHeight	= kHeight / 2;
414 
415 		for (int y = 0; y < kHeight; ++y)
416 		for (int x = 0; x < kWidth; ++x)
417 		{
418 			const auto& color = (y < kHalfHeight ? m_top : m_bottom);
419 			access.setPixel(color, x, y);
420 		}
421 	}
422 
423 private:
424 	const tcu::Vec4 m_top;
425 	const tcu::Vec4 m_bottom;
426 };
427 
428 using VertexFactory = de::MovePtr<GeometryVertex> (*)(const tcu::Vec2&);
429 
getVertexWithPadding(const tcu::Vec2 & coords)430 de::MovePtr<GeometryVertex> getVertexWithPadding(const tcu::Vec2& coords)
431 {
432 	return de::MovePtr<GeometryVertex>(new VertexWithPadding(coords));
433 }
434 
getVertexWithExtraAttributes(const tcu::Vec2 & coords)435 de::MovePtr<GeometryVertex> getVertexWithExtraAttributes(const tcu::Vec2& coords)
436 {
437 	return de::MovePtr<GeometryVertex>(new VertexWithExtraAttributes(coords));
438 }
439 
440 struct TestConfig
441 {
442 	// Main sequence ordering.
443 	SequenceOrdering			sequenceOrdering;
444 
445 	// Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
446 	std::vector<MeshParams>		meshParams;			// Mesh parameters for each full-screen layer of geometry.
447 	deUint32					referenceStencil;	// Reference stencil value.
448 
449 	// Clearing parameters for the framebuffer.
450 	tcu::Vec4					clearColorValue;
451 	float						clearDepthValue;
452 	deUint32					clearStencilValue;
453 
454 	// Expected output in the attachments.
455 	ReferenceColorGenerator		referenceColor;
456 	float						expectedDepth;
457 	deUint32					expectedStencil;
458 
459 	// Depth bounds parameters for the pipeline.
460 	float						minDepthBounds;
461 	float						maxDepthBounds;
462 
463 	// Force inclusion of passthrough geometry shader or not.
464 	bool						forceGeometryShader;
465 
466 	// Version 1 = VK_EXT_extended_dynamic_state
467 	// Version 2 = VK_EXT_vertex_input_dynamic_state
468 	// Version 3 = VK_EXT_extended_dynamic_state2
469 	deUint32					testExtendedDynamicStateVersion;
470 
471 	// For VK_EXT_extended_dynamic_state2
472 	bool						testExtendedDynamicState2LogicOp;
473 	bool						testExtendedDynamicState2PatchControlPoints;
474 
475 	// Use index buffer for rendering
476 	bool						useIndexBuffer;
477 
478 	bool						useTessellation;
479 
480 	// Vertex factory function.
481 	VertexFactory				vertexFactory;
482 
483 	// Offset and extra room after the vertex buffer data.
484 	vk::VkDeviceSize			vertexDataOffset;
485 	vk::VkDeviceSize			vertexDataExtraBytes;
486 
487 	// Static and dynamic pipeline configuration.
488 	CullModeConfig				cullModeConfig;
489 	FrontFaceConfig				frontFaceConfig;
490 	TopologyConfig				topologyConfig;
491 	ViewportConfig				viewportConfig;
492 	ScissorConfig				scissorConfig;
493 	StrideConfig				strideConfig;
494 	DepthTestEnableConfig		depthTestEnableConfig;
495 	DepthWriteEnableConfig		depthWriteEnableConfig;
496 	DepthCompareOpConfig		depthCompareOpConfig;
497 	DepthBoundsTestEnableConfig	depthBoundsTestEnableConfig;
498 	StencilTestEnableConfig		stencilTestEnableConfig;
499 	StencilOpConfig				stencilOpConfig;
500 	VertexInputConfig			vertexInputConfig;
501 	DepthBiasEnableConfig		depthBiasEnableConfig;
502 	RastDiscardEnableConfig		rastDiscardEnableConfig;
503 	PrimRestartEnableConfig		primRestartEnableConfig;
504 	LogicOpConfig				logicOpConfig;
505 	PatchControlPointsConfig	patchControlPointsConfig;
506 
507 	// Sane defaults.
TestConfigvkt::pipeline::__anonc593e7400111::TestConfig508 	TestConfig (SequenceOrdering ordering, VertexFactory vertexFactory_ = getVertexWithPadding)
509 		: sequenceOrdering				(ordering)
510 		, meshParams					(1u, MeshParams())
511 		, referenceStencil				(0u)
512 		, clearColorValue				(kDefaultClearColor)
513 		, clearDepthValue				(1.0f)
514 		, clearStencilValue				(0u)
515 		, referenceColor				(SingleColorGenerator(kDefaultTriangleColor))
516 		, expectedDepth					(1.0f)
517 		, expectedStencil				(0u)
518 		, minDepthBounds				(0.0f)
519 		, maxDepthBounds				(1.0f)
520 		, forceGeometryShader			(false)
521 		, testExtendedDynamicStateVersion(TEST_VERSION_extended_dynamic_state)
522 		, testExtendedDynamicState2LogicOp(false)
523 		, testExtendedDynamicState2PatchControlPoints(false)
524 		, useIndexBuffer				(false)
525 		, useTessellation				(false)
526 		, vertexFactory					(vertexFactory_)
527 		, vertexDataOffset				(0ull)
528 		, vertexDataExtraBytes			(0ull)
529 		, cullModeConfig				(static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
530 		, frontFaceConfig				(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
531 		// By default we will use a triangle fan with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
532 		, topologyConfig				(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
533 		, viewportConfig				(ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
534 		, scissorConfig					(ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
535 		// By default, the vertex stride is the size of a vertex according to the chosen vertex type.
536 		, strideConfig					(static_cast<vk::VkDeviceSize>(vertexFactory(tcu::Vec2(0.0f, 0.0f))->getVertexDataSize()))
537 		, depthTestEnableConfig			(false)
538 		, depthWriteEnableConfig		(false)
539 		, depthCompareOpConfig			(vk::VK_COMPARE_OP_NEVER)
540 		, depthBoundsTestEnableConfig	(false)
541 		, stencilTestEnableConfig		(false)
542 		, stencilOpConfig				(StencilOpVec(1u, kDefaultStencilOpParams))
543 		, vertexInputConfig				(static_cast<deUint32>(vertexFactory(tcu::Vec2(0.0f, 0.0f))->getCoordsOffset()))
544 		, depthBiasEnableConfig			(false)
545 		, rastDiscardEnableConfig		(false)
546 		, primRestartEnableConfig		(false)
547 		, logicOpConfig					(vk::VK_LOGIC_OP_CLEAR)
548 		, patchControlPointsConfig		(1)
549 		, m_swappedValues				(false)
550 	{
551 	}
552 
553 	// Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anonc593e7400111::TestConfig554 	const ViewportVec& getActiveViewportVec () const
555 	{
556 		return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() : viewportConfig.staticValue);
557 	}
558 
559 	// Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anonc593e7400111::TestConfig560 	bool isMultiViewport () const
561 	{
562 		return (getActiveViewportVec().size() > 1);
563 	}
564 
565 	// Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anonc593e7400111::TestConfig566 	bool needsGeometryShader () const
567 	{
568 		// Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
569 		// commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
570 		return (isMultiViewport() || forceGeometryShader);
571 	}
572 
573 	// Returns true if we should use the static and dynamic values exchanged.
574 	// This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anonc593e7400111::TestConfig575 	bool isReversed () const
576 	{
577 		return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
578 				sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
579 	}
580 
581 	// Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anonc593e7400111::TestConfig582 	void swapValues ()
583 	{
584 		cullModeConfig.swapValues();
585 		frontFaceConfig.swapValues();
586 		topologyConfig.swapValues();
587 		viewportConfig.swapValues();
588 		scissorConfig.swapValues();
589 		strideConfig.swapValues();
590 		depthTestEnableConfig.swapValues();
591 		depthWriteEnableConfig.swapValues();
592 		depthCompareOpConfig.swapValues();
593 		depthBoundsTestEnableConfig.swapValues();
594 		stencilTestEnableConfig.swapValues();
595 		stencilOpConfig.swapValues();
596 		vertexInputConfig.swapValues();
597 		depthBiasEnableConfig.swapValues();
598 		rastDiscardEnableConfig.swapValues();
599 		primRestartEnableConfig.swapValues();
600 		logicOpConfig.swapValues();
601 		patchControlPointsConfig.swapValues();
602 
603 		m_swappedValues = !m_swappedValues;
604 	}
605 
606 	// Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anonc593e7400111::TestConfig607 	deUint32 numIterations () const
608 	{
609 		deUint32 iterations = 0u;
610 
611 		switch (sequenceOrdering)
612 		{
613 		case SequenceOrdering::TWO_DRAWS_DYNAMIC:
614 		case SequenceOrdering::TWO_DRAWS_STATIC:
615 			iterations = 2u;
616 			break;
617 		default:
618 			iterations = 1u;
619 			break;
620 		}
621 
622 		return iterations;
623 	}
624 
625 private:
626 	// Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
627 	// has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
628 	// expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
629 	// pipeline with wrong values and a static one with good values.
630 	//
631 	// Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
632 	// dynamic values and to know if we should do it for a given test case. However, we need to know were the good value is at any
633 	// given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
634 	bool m_swappedValues;
635 };
636 
637 struct PushConstants
638 {
639 	tcu::Vec4	triangleColor;
640 	float		meshDepth;
641 	deInt32		viewPortIndex;
642 	float		scaleX;
643 	float		scaleY;
644 	float		offsetX;
645 	float		offsetY;
646 };
647 
copy(vk::VkStencilOpState & dst,const StencilOpParams & src)648 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
649 {
650 	dst.failOp		= src.failOp;
651 	dst.passOp		= src.passOp;
652 	dst.depthFailOp	= src.depthFailOp;
653 	dst.compareOp	= src.compareOp;
654 }
655 
656 enum class TopologyClass
657 {
658 	POINT,
659 	LINE,
660 	TRIANGLE,
661 	PATCH,
662 	INVALID,
663 };
664 
topologyClassName(TopologyClass tclass)665 std::string topologyClassName (TopologyClass tclass)
666 {
667 	switch (tclass)
668 	{
669 	case TopologyClass::POINT:		return "point";
670 	case TopologyClass::LINE:		return "line";
671 	case TopologyClass::TRIANGLE:	return "triangle";
672 	case TopologyClass::PATCH:		return "patch";
673 	default:
674 		break;
675 	}
676 
677 	DE_ASSERT(false);
678 	return "";
679 }
680 
getTopologyClass(vk::VkPrimitiveTopology topology)681 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
682 {
683 	switch (topology)
684 	{
685 	case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
686 		return TopologyClass::POINT;
687 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
688 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
689 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
690 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
691 		return TopologyClass::LINE;
692 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
693 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
694 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
695 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
696 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
697 		return TopologyClass::TRIANGLE;
698 	case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
699 		return TopologyClass::PATCH;
700 	default:
701 		break;
702 	}
703 
704 	DE_ASSERT(false);
705 	return TopologyClass::INVALID;
706 }
707 
708 class ExtendedDynamicStateTest : public vkt::TestCase
709 {
710 public:
711 							ExtendedDynamicStateTest		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ExtendedDynamicStateTest(void)712 	virtual					~ExtendedDynamicStateTest		(void) {}
713 
714 	virtual void			checkSupport					(Context& context) const;
715 	virtual void			initPrograms					(vk::SourceCollections& programCollection) const;
716 	virtual TestInstance*	createInstance					(Context& context) const;
717 
718 private:
719 	TestConfig				m_testConfig;
720 };
721 
722 class ExtendedDynamicStateInstance : public vkt::TestInstance
723 {
724 public:
725 								ExtendedDynamicStateInstance	(Context& context, const TestConfig& testConfig);
~ExtendedDynamicStateInstance(void)726 	virtual						~ExtendedDynamicStateInstance	(void) {}
727 
728 	virtual tcu::TestStatus		iterate							(void);
729 
730 private:
731 	TestConfig					m_testConfig;
732 };
733 
ExtendedDynamicStateTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)734 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
735 	: vkt::TestCase	(testCtx, name, description)
736 	, m_testConfig	(testConfig)
737 {
738 	const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
739 	DE_UNREF(staticTopologyClass); // For release builds.
740 
741 	// Matching topology classes.
742 	DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
743 			  staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
744 
745 	// Supported topology classes for these tests.
746 	DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE
747 		|| staticTopologyClass == TopologyClass::PATCH);
748 }
749 
checkSupport(Context & context) const750 void ExtendedDynamicStateTest::checkSupport (Context& context) const
751 {
752 	const auto&	vki				= context.getInstanceInterface();
753 	const auto	physicalDevice	= context.getPhysicalDevice();
754 
755 	if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_extended_dynamic_state)
756 		context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
757 
758 	if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_vertex_input_dynamic_state)
759 		context.requireDeviceFunctionality("VK_EXT_vertex_input_dynamic_state");
760 
761 	// Needed for extended state included as part of VK_EXT_extended_dynamic_state2
762 	if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_extended_dynamic_state2) {
763 		context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state2");
764 
765 		const vk::VkPhysicalDeviceExtendedDynamicState2FeaturesEXT& extendedDynamicState2Features = context.getExtendedDynamicState2FeaturesEXT();
766 
767 		if (m_testConfig.testExtendedDynamicState2LogicOp && extendedDynamicState2Features.extendedDynamicState2LogicOp == DE_FALSE)
768 			TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing LogicOp dynamically is not supported");
769 
770 		if (m_testConfig.testExtendedDynamicState2PatchControlPoints && extendedDynamicState2Features.extendedDynamicState2PatchControlPoints == DE_FALSE)
771 			TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing patch control points dynamically is not supported");
772 	}
773 
774 	// Check the number of viewports needed and the corresponding limits.
775 	const auto&	viewportConfig	= m_testConfig.viewportConfig;
776 	auto		numViewports	= viewportConfig.staticValue.size();
777 
778 	if (viewportConfig.dynamicValue)
779 		numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
780 
781 	if (numViewports > 1)
782 	{
783 		const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
784 		if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
785 			TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
786 	}
787 
788 	const auto&	dbTestEnable	= m_testConfig.depthBoundsTestEnableConfig;
789 	const bool	useDepthBounds	= (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
790 	if (useDepthBounds || m_testConfig.needsGeometryShader())
791 	{
792 		const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
793 
794 		// Check depth bounds test support.
795 		if (useDepthBounds && !features.depthBounds)
796 			TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
797 
798 		// Check geometry shader support.
799 		if (m_testConfig.needsGeometryShader() && !features.geometryShader)
800 			TCU_THROW(NotSupportedError, "Geometry shader not supported");
801 
802 		// Check tessellation support
803 		if (m_testConfig.useTessellation && !features.tessellationShader)
804 			TCU_THROW(NotSupportedError, "Tessellation feature not supported");
805 	}
806 
807 	// Check color image format support (depth/stencil will be chosen at runtime).
808 	const vk::VkFormatFeatureFlags	kColorFeatures	= (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
809 
810 	// Pick int color format for logic op
811 	vk::VkFormat					colorFormat		= m_testConfig.logicOpConfig.dynamicValue ? kIntColorFormat : kColorFormat;
812 	const auto						colorProperties	= vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, colorFormat);
813 
814 	if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
815 		TCU_THROW(NotSupportedError, "Required color image features not supported");
816 }
817 
initPrograms(vk::SourceCollections & programCollection) const818 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
819 {
820 	std::ostringstream pushSource;
821 	std::ostringstream vertSource;
822 	std::ostringstream fragSource;
823 	std::ostringstream geomSource;
824 	std::ostringstream tescSource;
825 	std::ostringstream teseSource;
826 
827 	pushSource
828 		<< "layout(push_constant, std430) uniform PushConstantsBlock {\n"
829 		<< "    vec4  triangleColor;\n"
830 		<< "    float depthValue;\n"
831 		<< "    int   viewPortIndex;\n"
832 		<< "    float scaleX;\n"
833 		<< "    float scaleY;\n"
834 		<< "    float offsetX;\n"
835 		<< "    float offsetY;\n"
836 		<< "} pushConstants;\n"
837 		;
838 	const auto pushConstants = pushSource.str();
839 
840 	const auto			dummyVertex	= m_testConfig.vertexFactory(tcu::Vec2(0.0f, 0.0f));
841 	const auto			attribDecls	= dummyVertex->getAttributeDeclarations();
842 	const auto			coordCalcs	= dummyVertex->getVertexCoordCalc();
843 	std::ostringstream	attributes;
844 	std::ostringstream	calculations;
845 
846 	for (const auto& decl : attribDecls)
847 		attributes << decl << "\n";
848 
849 	for (const auto& statement : coordCalcs)
850 		calculations << "    " << statement << "\n";
851 
852 	vertSource
853 		<< "#version 450\n"
854 		<< pushConstants
855 		<< attributes.str()
856 		<< "out gl_PerVertex\n"
857 		<< "{\n"
858 		<< "    vec4 gl_Position;\n"
859 		<< "};\n"
860 		<< "void main() {\n"
861 		<< calculations.str()
862 		<< "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
863 		<< "}\n"
864 		;
865 
866 	fragSource
867 		<< "#version 450\n"
868 		<< pushConstants
869 		<< "layout(location=0) out vec4 color;\n"
870 		<< "void main() {\n"
871 		<< "    color = pushConstants.triangleColor;\n"
872 		<< "}\n"
873 		;
874 
875 	if (m_testConfig.needsGeometryShader())
876 	{
877 		const auto			topologyClass	= getTopologyClass(m_testConfig.topologyConfig.staticValue);
878 		const std::string	inputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
879 		const deUint32		vertexCount		= ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
880 		const std::string	outputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
881 
882 		geomSource
883 			<< "#version 450\n"
884 			<< "layout (" << inputPrimitive << ") in;\n"
885 			<< "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
886 			<< (m_testConfig.isMultiViewport() ? pushConstants : "")
887 			<< "in gl_PerVertex\n"
888 			<< "{\n"
889 			<< "    vec4 gl_Position;\n"
890 			<< "} gl_in[" << vertexCount << "];\n"
891 			<< "out gl_PerVertex\n"
892 			<< "{\n"
893 			<< "    vec4 gl_Position;\n"
894 			<< "};\n"
895 			<< "void main() {\n"
896 			<< (m_testConfig.isMultiViewport() ? "    gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "")
897 			;
898 
899 		for (deUint32 i = 0; i < vertexCount; ++i)
900 		{
901 			geomSource
902 				<< "    gl_Position = gl_in[" << i << "].gl_Position;\n"
903 				<< "    EmitVertex();\n"
904 				;
905 		}
906 
907 		geomSource
908 			<< "}\n"
909 			;
910 	}
911 
912 	if (m_testConfig.useTessellation)
913 	{
914 		tescSource
915 			<< "#version 450\n"
916 			<< "#extension GL_EXT_tessellation_shader : require\n"
917 			<< "layout(vertices=3) out;\n"
918 			<< "in gl_PerVertex\n"
919 			<< "{\n"
920 			<< "    vec4 gl_Position;\n"
921 			<< "} gl_in[];\n"
922 			<< "void main() {\n"
923 			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
924 			<< "  gl_TessLevelOuter[0] = 3.0;\n"
925 			<< "  gl_TessLevelOuter[1] = 3.0;\n"
926 			<< "  gl_TessLevelOuter[2] = 3.0;\n"
927 			<< "  gl_TessLevelInner[0] = 3.0;\n"
928 			<< "}\n"
929 			;
930 		teseSource
931 			<< "#version 450\n"
932 			<< "#extension GL_EXT_tessellation_shader : require\n"
933 			<< "layout(triangles) in;\n"
934 			<< "void main() {\n"
935 			<< "  gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
936 			<< "                 gl_in[1].gl_Position * gl_TessCoord.y + \n"
937 			<< "                 gl_in[2].gl_Position * gl_TessCoord.z);\n"
938 			<< "}\n";
939 			;
940 	}
941 
942 
943 	programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
944 	programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
945 	if (m_testConfig.needsGeometryShader())
946 		programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
947 	if (m_testConfig.useTessellation)
948 	{
949 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
950 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
951 	}
952 }
953 
createInstance(Context & context) const954 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
955 {
956 	return new ExtendedDynamicStateInstance(context, m_testConfig);
957 }
958 
ExtendedDynamicStateInstance(Context & context,const TestConfig & testConfig)959 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
960 	: vkt::TestInstance	(context)
961 	, m_testConfig		(testConfig)
962 {
963 }
964 
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)965 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
966 {
967 	log << tcu::TestLog::ImageSet(setName, setDesc)
968 		<< tcu::TestLog::Image(setName + "Result", "Result image", result)
969 		<< tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
970 		<< tcu::TestLog::EndImageSet;
971 }
972 
973 // Fill a section of the given buffer (from offset to offset+count) with repeating copies of the given data.
fillWithPattern(vk::BufferWithMemory & buffer,size_t offset,size_t count,const void * src,size_t srcSize)974 void fillWithPattern(vk::BufferWithMemory& buffer, size_t offset, size_t count, const void* src, size_t srcSize)
975 {
976 	auto&	alloc	= buffer.getAllocation();
977 	auto	ptr		= reinterpret_cast<char*>(alloc.getHostPtr());
978 	size_t	done	= 0u;
979 	size_t	pending	= count;
980 
981 	while (pending > 0u)
982 	{
983 		const size_t stepSize = de::min(srcSize, pending);
984 		deMemcpy(ptr + offset + done, src, stepSize);
985 		done += stepSize;
986 		pending -= stepSize;
987 	}
988 }
989 
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)990 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
991 {
992 	auto&	alloc	= buffer.getAllocation();
993 	auto	dst		= reinterpret_cast<char*>(alloc.getHostPtr());
994 
995 	deMemcpy(dst + offset, src, size);
996 	vk::flushAlloc(vkd, device, alloc);
997 }
998 
concatenateVertexData(const std::vector<GeometryVertex * > & vertices)999 std::vector<deUint8> concatenateVertexData(const std::vector<GeometryVertex*>& vertices)
1000 {
1001 	std::vector<deUint8> concatenatedData;
1002 
1003 	if (vertices.empty())
1004 		return concatenatedData;
1005 
1006 	const auto dataSize = vertices.size() * vertices[0]->getVertexDataSize();
1007 	concatenatedData.reserve(dataSize);
1008 
1009 	auto backInserter = std::back_inserter(concatenatedData);
1010 	for (const auto ptr : vertices)
1011 	{
1012 		const auto singleData = ptr->getVertexData();
1013 		std::copy(begin(singleData), end(singleData), backInserter);
1014 	}
1015 
1016 	return concatenatedData;
1017 }
1018 
1019 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)1020 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
1021 {
1022 	if (testConfig.cullModeConfig.dynamicValue)
1023 		vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
1024 
1025 	if (testConfig.frontFaceConfig.dynamicValue)
1026 		vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
1027 
1028 	if (testConfig.topologyConfig.dynamicValue)
1029 		vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
1030 
1031 	if (testConfig.viewportConfig.dynamicValue)
1032 	{
1033 		const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
1034 		vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
1035 	}
1036 
1037 	if (testConfig.scissorConfig.dynamicValue)
1038 	{
1039 		const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
1040 		vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
1041 	}
1042 
1043 	if (testConfig.depthTestEnableConfig.dynamicValue)
1044 		vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
1045 
1046 	if (testConfig.depthWriteEnableConfig.dynamicValue)
1047 		vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
1048 
1049 	if (testConfig.depthCompareOpConfig.dynamicValue)
1050 		vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
1051 
1052 	if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
1053 		vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
1054 
1055 	if (testConfig.stencilTestEnableConfig.dynamicValue)
1056 		vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
1057 
1058 	if (testConfig.depthBiasEnableConfig.dynamicValue)
1059 		vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
1060 
1061 	if (testConfig.rastDiscardEnableConfig.dynamicValue)
1062 		vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
1063 
1064 	if (testConfig.primRestartEnableConfig.dynamicValue)
1065 		vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
1066 
1067 	if (testConfig.logicOpConfig.dynamicValue)
1068 		vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
1069 
1070 	if (testConfig.patchControlPointsConfig.dynamicValue)
1071 		vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
1072 
1073 	if (testConfig.stencilOpConfig.dynamicValue)
1074 	{
1075 		for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
1076 			vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
1077 	}
1078 
1079 	if (testConfig.vertexInputConfig.dynamicValue)
1080 	{
1081 		const vk::VkVertexInputBindingDescription2EXT vertexBinding =
1082 		{
1083 			vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,	//	VkStructureType		sType;
1084 			nullptr,														//	void*				pNext;
1085 			0u,																//	deUint32			binding;
1086 			static_cast<deUint32>(testConfig.strideConfig.staticValue),		//	deUint32			stride;
1087 			vk::VK_VERTEX_INPUT_RATE_VERTEX,								//	VkVertexInputRate	inputRate;
1088 			1u,																//	deUint32			divisor;
1089 		};
1090 		const vk::VkVertexInputAttributeDescription2EXT vertexAttribute =
1091 		{
1092 			vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,				//	VkStructureType	sType;
1093 			nullptr,																	//	void*			pNext;
1094 			0u,																			//	deUint32		location;
1095 			0u,																			//	deUint32		binding;
1096 			vk::VK_FORMAT_R32G32_SFLOAT,												//	VkFormat		format;
1097 			static_cast<deUint32>(testConfig.vertexInputConfig.dynamicValue.get()),		//	deUint32		offset;
1098 		};
1099 		vkd.cmdSetVertexInputEXT(cmdBuffer, 1, &vertexBinding, 1, &vertexAttribute);
1100 	}
1101 }
1102 
1103 // Bind the appropriate vertex buffer with a dynamic stride if the test configuration needs a dynamic stride.
1104 // Return true if the vertex buffer was bound.
maybeBindVertexBufferDynStride(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,size_t meshIdx,vk::VkBuffer vertBuffer,vk::VkBuffer rvertBuffer,vk::VkDeviceSize vertDataSize)1105 bool maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, vk::VkBuffer vertBuffer, vk::VkBuffer rvertBuffer, vk::VkDeviceSize vertDataSize)
1106 {
1107 	if (testConfig.strideConfig.dynamicValue)
1108 	{
1109 		const auto& viewportVec = testConfig.getActiveViewportVec();
1110 		DE_UNREF(viewportVec); // For release builds.
1111 
1112 		// When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
1113 		// orderings if we have several viewports or meshes.
1114 		DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
1115 					|| testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
1116 					|| testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1117 
1118 		const auto strideValue = (testConfig.strideConfig.dynamicValue ? testConfig.strideConfig.dynamicValue.get() : testConfig.strideConfig.staticValue);
1119 		vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, 1u, (testConfig.meshParams[meshIdx].reversed ? &rvertBuffer : &vertBuffer), &testConfig.vertexDataOffset, &vertDataSize, &strideValue);
1120 		return true;
1121 	}
1122 
1123 	return false;
1124 }
1125 
iterate(void)1126 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
1127 {
1128 	using ImageWithMemoryVec	= std::vector<std::unique_ptr<vk::ImageWithMemory>>;
1129 	using ImageViewVec			= std::vector<vk::Move<vk::VkImageView>>;
1130 	using FramebufferVec		= std::vector<vk::Move<vk::VkFramebuffer>>;
1131 
1132 	const auto&	vki					= m_context.getInstanceInterface();
1133 	const auto&	vkd					= m_context.getDeviceInterface();
1134 	const auto	physicalDevice		= m_context.getPhysicalDevice();
1135 	const auto	device				= m_context.getDevice();
1136 	auto&		allocator			= m_context.getDefaultAllocator();
1137 	const auto	queue				= m_context.getUniversalQueue();
1138 	const auto	queueIndex			= m_context.getUniversalQueueFamilyIndex();
1139 	auto&		log					= m_context.getTestContext().getLog();
1140 
1141 	const auto	kReversed			= m_testConfig.isReversed();
1142 	const auto	kNumIterations		= m_testConfig.numIterations();
1143 	const auto	kSequenceOrdering	= m_testConfig.sequenceOrdering;
1144 
1145 	const auto						kFramebufferExtent	= vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
1146 	const vk::VkImageUsageFlags		kColorUsage			= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1147 	const vk::VkImageUsageFlags		kDSUsage			= (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1148 	const vk::VkFormatFeatureFlags	kDSFeatures			= (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1149 
1150 	// Pick int color format for logic op
1151 	vk::VkFormat					colorFormat = m_testConfig.logicOpConfig.dynamicValue ? kIntColorFormat : kColorFormat;
1152 
1153 	// Choose depth/stencil format.
1154 	const DepthStencilFormat* dsFormatInfo = nullptr;
1155 
1156 	for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++formatIdx)
1157 	{
1158 		const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[formatIdx].imageFormat);
1159 		if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
1160 		{
1161 			dsFormatInfo = kDepthStencilFormats + formatIdx;
1162 			break;
1163 		}
1164 	}
1165 
1166 	// Note: Not Supported insted of Fail because the transfer feature is not mandatory.
1167 	if (!dsFormatInfo)
1168 		TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
1169 	log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
1170 
1171 	// Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
1172 	// where we will bind the static pipeline last before drawing.
1173 	if (kReversed)
1174 		m_testConfig.swapValues();
1175 
1176 	// Create color and depth/stencil images.
1177 	ImageWithMemoryVec colorImages;
1178 	ImageWithMemoryVec dsImages;
1179 
1180 	const vk::VkImageCreateInfo colorImageInfo =
1181 	{
1182 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
1183 		nullptr,									//	const void*				pNext;
1184 		0u,											//	VkImageCreateFlags		flags;
1185 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
1186 		colorFormat,								//	VkFormat				format;
1187 		kFramebufferExtent,							//	VkExtent3D				extent;
1188 		1u,											//	deUint32				mipLevels;
1189 		1u,											//	deUint32				arrayLayers;
1190 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
1191 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
1192 		kColorUsage,								//	VkImageUsageFlags		usage;
1193 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
1194 		1u,											//	deUint32				queueFamilyIndexCount;
1195 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
1196 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
1197 	};
1198 	for (deUint32 i = 0u; i < kNumIterations; ++i)
1199 		colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
1200 
1201 	const vk::VkImageCreateInfo dsImageInfo =
1202 	{
1203 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
1204 		nullptr,									//	const void*				pNext;
1205 		0u,											//	VkImageCreateFlags		flags;
1206 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
1207 		dsFormatInfo->imageFormat,					//	VkFormat				format;
1208 		kFramebufferExtent,							//	VkExtent3D				extent;
1209 		1u,											//	deUint32				mipLevels;
1210 		1u,											//	deUint32				arrayLayers;
1211 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
1212 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
1213 		kDSUsage,									//	VkImageUsageFlags		usage;
1214 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
1215 		1u,											//	deUint32				queueFamilyIndexCount;
1216 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
1217 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
1218 	};
1219 	for (deUint32 i = 0u; i < kNumIterations; ++i)
1220 		dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
1221 
1222 	const auto colorSubresourceRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1223 	const auto dsSubresourceRange		= vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
1224 
1225 	ImageViewVec colorImageViews;
1226 	ImageViewVec dsImageViews;
1227 
1228 	for (const auto& img : colorImages)
1229 		colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
1230 
1231 	for (const auto& img : dsImages)
1232 		dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
1233 
1234 	// Vertex buffer.
1235 	const auto									topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
1236 	std::vector<de::MovePtr<GeometryVertex>>	vertexPtrs;
1237 	std::vector<deUint32>		indices{ 0, 1, 2, 3, 0xFFFFFFFF, 4, 5, 0, 3 };
1238 
1239 	if (topologyClass == TopologyClass::TRIANGLE)
1240 	{
1241 		// Full-screen triangle fan with 6 vertices.
1242 		//
1243 		// 4        3        2
1244 		//  +-------+-------+
1245 		//  |X      X      X|
1246 		//  | X     X     X |
1247 		//  |  X    X    X  |
1248 		//  |   X   X   X   |
1249 		//  |    X  X  X    |
1250 		//  |     X X X     |
1251 		//  |      XXX      |
1252 		//  +-------+-------+
1253 		// 5        0        1
1254 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.0f,  1.0f)));
1255 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f,  1.0f)));
1256 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f, -1.0f)));
1257 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.0f, -1.0f)));
1258 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, -1.0f)));
1259 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f,  1.0f)));
1260 	}
1261 	else if (topologyClass == TopologyClass::PATCH)
1262 	{
1263 		// 2 triangles making a quad
1264 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, 1.0f)));
1265 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, 1.0f)));
1266 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, -1.0f)));
1267 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, -1.0f)));
1268 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, -1.0f)));
1269 		vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, 1.0f)));
1270 	}
1271 	else // TopologyClass::LINE
1272 	{
1273 		// Draw one segmented line per output row of pixels that could be wrongly interpreted as a list of lines that would not cover the whole screen.
1274 		const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
1275 		for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
1276 		{
1277 			// Offset of 0.5 pixels + one line per row from -1 to 1.
1278 			const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
1279 			vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, yCoord)));
1280 			vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-0.5f, yCoord)));
1281 			vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.5f, yCoord)));
1282 			vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f, yCoord)));
1283 		}
1284 	}
1285 
1286 	std::vector<GeometryVertex*> vertexRawPtrs;
1287 	vertexRawPtrs.reserve(vertexPtrs.size());
1288 	std::transform(begin(vertexPtrs), end(vertexPtrs), std::back_inserter(vertexRawPtrs),
1289 				   [](const de::MovePtr<GeometryVertex>& p) { return p.get(); });
1290 
1291 	// Reversed vertices, except for the first one (0, 5, 4, 3, 2, 1): clockwise mesh for triangles. Not to be used with lines.
1292 	std::vector<GeometryVertex*> reversedVertexRawPtrs;
1293 	reversedVertexRawPtrs.push_back(vertexRawPtrs[0]);
1294 	if (topologyClass == TopologyClass::TRIANGLE)
1295 	{
1296 		std::copy_n(vertexRawPtrs.rbegin(), vertexRawPtrs.size() - 1u, std::back_inserter(reversedVertexRawPtrs));
1297 	}
1298 
1299 	if (topologyClass == TopologyClass::LINE)
1300 	{
1301 		for (const auto& mesh : m_testConfig.meshParams)
1302 		{
1303 			DE_UNREF(mesh); // For release builds.
1304 			DE_ASSERT(!mesh.reversed);
1305 		}
1306 	}
1307 
1308 	DE_ASSERT(!vertexRawPtrs.empty());
1309 	const auto vertDataSize				= static_cast<vk::VkDeviceSize>(vertexRawPtrs.size() * vertexRawPtrs[0]->getVertexDataSize());
1310 	const auto vertBufferSize			= m_testConfig.vertexDataOffset + vertDataSize + m_testConfig.vertexDataExtraBytes;
1311 	const auto vertBufferInfo			= vk::makeBufferCreateInfo(vertBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1312 	vk::BufferWithMemory vertBuffer		(vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
1313 	vk::BufferWithMemory rvertBuffer	(vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
1314 
1315 
1316 	const auto indexDataSize = static_cast<vk::VkDeviceSize>(indices.size() * sizeof(deUint32));
1317 	const auto indexBufferInfo = vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1318 	vk::BufferWithMemory indexBuffer(vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible);
1319 
1320 
1321 	// Copy data to vertex/index buffers and flush allocations.
1322 	{
1323 		const auto				offScreenVertexPtr	= m_testConfig.vertexFactory(tcu::Vec2(0.0f, 3.0f));
1324 		const auto				offScreenVertex		= offScreenVertexPtr->getVertexData();
1325 		const auto				offScreenVertexSz	= offScreenVertex.size();
1326 		const auto				dataSize			= static_cast<size_t>(vertDataSize);
1327 		const auto				offset				= static_cast<size_t>(m_testConfig.vertexDataOffset);
1328 		const auto				extraSize			= static_cast<size_t>(m_testConfig.vertexDataExtraBytes);
1329 
1330 		std::vector<vk::BufferWithMemory*> buffersToFill = { &vertBuffer, &rvertBuffer };
1331 		for (auto b : buffersToFill)
1332 		{
1333 			// Fill bytes surrounding vertex data with the offScreenVertex.
1334 			fillWithPattern(*b, 0u, offset, offScreenVertex.data(), offScreenVertexSz);
1335 			fillWithPattern(*b, offset + dataSize, extraSize, offScreenVertex.data(), offScreenVertexSz);
1336 		}
1337 
1338 		// Create vectors with all vertex data and all reversed vertex data concatenated in order to fill the buffers.
1339 		const auto vertices			= concatenateVertexData(vertexRawPtrs);
1340 		const auto reversedVertices	= concatenateVertexData(reversedVertexRawPtrs);
1341 
1342 		copyAndFlush(vkd, device, vertBuffer, offset, vertices.data(), static_cast<size_t>(vertices.size() * sizeof(vertices[0])));
1343 		copyAndFlush(vkd, device, rvertBuffer, offset, reversedVertices.data(), static_cast<size_t>(reversedVertices.size() * sizeof(reversedVertices[0])));
1344 		copyAndFlush(vkd, device, indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
1345 	}
1346 
1347 	// Descriptor set layout.
1348 	vk::DescriptorSetLayoutBuilder layoutBuilder;
1349 	const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1350 
1351 	// Pipeline layout.
1352 	vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1353 	if (m_testConfig.isMultiViewport())
1354 		pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1355 
1356 	const vk::VkPushConstantRange pushConstantRange =
1357 	{
1358 		pushConstantStageFlags,							//	VkShaderStageFlags	stageFlags;
1359 		0u,												//	deUint32			offset;
1360 		static_cast<deUint32>(sizeof(PushConstants)),	//	deUint32			size;
1361 	};
1362 
1363 	const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1364 	{
1365 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//	VkStructureType					sType;
1366 		nullptr,											//	const void*						pNext;
1367 		0u,													//	VkPipelineLayoutCreateFlags		flags;
1368 		1u,													//	deUint32						setLayoutCount;
1369 		&descriptorSetLayout.get(),							//	const VkDescriptorSetLayout*	pSetLayouts;
1370 		1u,													//	deUint32						pushConstantRangeCount;
1371 		&pushConstantRange,									//	const VkPushConstantRange*		pPushConstantRanges;
1372 	};
1373 	const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
1374 
1375 	// Render pass with single subpass.
1376 	const vk::VkAttachmentReference colorAttachmentReference =
1377 	{
1378 		0u,												//	deUint32		attachment;
1379 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1380 	};
1381 
1382 	const vk::VkAttachmentReference dsAttachmentReference =
1383 	{
1384 		1u,														//	deUint32		attachment;
1385 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1386 	};
1387 
1388 	const vk::VkSubpassDescription subpassDescription =
1389 	{
1390 		0u,										//	VkSubpassDescriptionFlags		flags;
1391 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
1392 		0u,										//	deUint32						inputAttachmentCount;
1393 		nullptr,								//	const VkAttachmentReference*	pInputAttachments;
1394 		1u,										//	deUint32						colorAttachmentCount;
1395 		&colorAttachmentReference,				//	const VkAttachmentReference*	pColorAttachments;
1396 		nullptr,								//	const VkAttachmentReference*	pResolveAttachments;
1397 		&dsAttachmentReference,					//	const VkAttachmentReference*	pDepthStencilAttachment;
1398 		0u,										//	deUint32						preserveAttachmentCount;
1399 		nullptr,								//	const deUint32*					pPreserveAttachments;
1400 	};
1401 
1402 	std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
1403 
1404 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
1405 	{
1406 		0u,												//	VkAttachmentDescriptionFlags	flags;
1407 		colorFormat,									//	VkFormat						format;
1408 		vk::VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
1409 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
1410 		vk::VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
1411 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
1412 		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
1413 		vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
1414 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1415 	});
1416 
1417 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
1418 	{
1419 		0u,														//	VkAttachmentDescriptionFlags	flags;
1420 		dsFormatInfo->imageFormat,								//	VkFormat						format;
1421 		vk::VK_SAMPLE_COUNT_1_BIT,								//	VkSampleCountFlagBits			samples;
1422 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				loadOp;
1423 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				storeOp;
1424 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				stencilLoadOp;
1425 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				stencilStoreOp;
1426 		vk::VK_IMAGE_LAYOUT_UNDEFINED,							//	VkImageLayout					initialLayout;
1427 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1428 	});
1429 
1430 	const vk::VkRenderPassCreateInfo renderPassCreateInfo =
1431 	{
1432 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			//	VkStructureType					sType;
1433 		nullptr,												//	const void*						pNext;
1434 		0u,														//	VkRenderPassCreateFlags			flags;
1435 		static_cast<deUint32>(attachmentDescriptions.size()),	//	deUint32						attachmentCount;
1436 		attachmentDescriptions.data(),							//	const VkAttachmentDescription*	pAttachments;
1437 		1u,														//	deUint32						subpassCount;
1438 		&subpassDescription,									//	const VkSubpassDescription*		pSubpasses;
1439 		0u,														//	deUint32						dependencyCount;
1440 		nullptr,												//	const VkSubpassDependency*		pDependencies;
1441 	};
1442 	const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
1443 
1444 	// Framebuffers.
1445 	FramebufferVec framebuffers;
1446 
1447 	DE_ASSERT(colorImageViews.size() == dsImageViews.size());
1448 	for (size_t imgIdx = 0; imgIdx < colorImageViews.size(); ++imgIdx)
1449 	{
1450 		std::vector<vk::VkImageView> attachments;
1451 		attachments.push_back(colorImageViews[imgIdx].get());
1452 		attachments.push_back(dsImageViews[imgIdx].get());
1453 
1454 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
1455 		{
1456 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	//	VkStructureType				sType;
1457 			nullptr,										//	const void*					pNext;
1458 			0u,												//	VkFramebufferCreateFlags	flags;
1459 			renderPass.get(),								//	VkRenderPass				renderPass;
1460 			static_cast<deUint32>(attachments.size()),		//	deUint32					attachmentCount;
1461 			attachments.data(),								//	const VkImageView*			pAttachments;
1462 			kFramebufferWidth,								//	deUint32					width;
1463 			kFramebufferHeight,								//	deUint32					height;
1464 			1u,												//	deUint32					layers;
1465 		};
1466 
1467 		framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
1468 	}
1469 
1470 	// Shader modules.
1471 	const auto						vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
1472 	const auto						fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
1473 	vk::Move<vk::VkShaderModule>	geomModule;
1474 
1475 	if (m_testConfig.needsGeometryShader())
1476 		geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
1477 
1478 	vk::Move<vk::VkShaderModule>	tescModule;
1479 	vk::Move<vk::VkShaderModule>	teseModule;
1480 
1481 	if (m_testConfig.useTessellation)
1482 	{
1483 		tescModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
1484 		teseModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
1485 	}
1486 
1487 	// Shader stages.
1488 	std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
1489 
1490 	vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
1491 	{
1492 		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
1493 		nullptr,													//	const void*							pNext;
1494 		0u,															//	VkPipelineShaderStageCreateFlags	flags;
1495 		vk::VK_SHADER_STAGE_VERTEX_BIT,								//	VkShaderStageFlagBits				stage;
1496 		vertModule.get(),											//	VkShaderModule						module;
1497 		"main",														//	const char*							pName;
1498 		nullptr,													//	const VkSpecializationInfo*			pSpecializationInfo;
1499 	};
1500 
1501 	shaderStages.push_back(shaderStageCreateInfo);
1502 	shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
1503 	shaderStageCreateInfo.module = fragModule.get();
1504 	shaderStages.push_back(shaderStageCreateInfo);
1505 
1506 	if (m_testConfig.needsGeometryShader())
1507 	{
1508 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1509 		shaderStageCreateInfo.module = geomModule.get();
1510 		shaderStages.push_back(shaderStageCreateInfo);
1511 	}
1512 
1513 	if (m_testConfig.useTessellation)
1514 	{
1515 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
1516 		shaderStageCreateInfo.module = tescModule.get();
1517 		shaderStages.push_back(shaderStageCreateInfo);
1518 
1519 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1520 		shaderStageCreateInfo.module = teseModule.get();
1521 		shaderStages.push_back(shaderStageCreateInfo);
1522 	}
1523 
1524 	// Input state.
1525 	DE_ASSERT(!vertexRawPtrs.empty());
1526 	const auto vertexBinding	= vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(m_testConfig.strideConfig.staticValue), vk::VK_VERTEX_INPUT_RATE_VERTEX);
1527 	const auto vertexAttributes	= vertexRawPtrs[0]->getAttributeDescriptions(static_cast<deUint32>(m_testConfig.vertexInputConfig.staticValue));
1528 
1529 	const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
1530 	{
1531 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
1532 		nullptr,														//	const void*									pNext;
1533 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
1534 		1u,																//	deUint32									vertexBindingDescriptionCount;
1535 		&vertexBinding,													//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
1536 		static_cast<deUint32>(vertexAttributes.size()),					//	deUint32									vertexAttributeDescriptionCount;
1537 		vertexAttributes.data(),										//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
1538 	};
1539 
1540 	// Input assembly.
1541 	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
1542 	{
1543 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
1544 		nullptr,															//	const void*								pNext;
1545 		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
1546 		m_testConfig.topologyConfig.staticValue,							//	VkPrimitiveTopology						topology;
1547 		makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue),		//	VkBool32								primitiveRestartEnable;
1548 	};
1549 
1550 	// Viewport state.
1551 	if (m_testConfig.viewportConfig.dynamicValue)
1552 		DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
1553 	else
1554 		DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
1555 
1556 	if (m_testConfig.scissorConfig.dynamicValue)
1557 		DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
1558 	else
1559 		DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
1560 
1561 	// The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
1562 	const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
1563 
1564 	// For the static pipeline.
1565 	const vk::VkPipelineViewportStateCreateInfo staticViewportStateCreateInfo =
1566 	{
1567 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,					//	VkStructureType						sType;
1568 		nullptr,																	//	const void*							pNext;
1569 		0u,																			//	VkPipelineViewportStateCreateFlags	flags;
1570 		minStaticCount,																//	deUint32							viewportCount;
1571 		m_testConfig.viewportConfig.staticValue.data(),								//	const VkViewport*					pViewports;
1572 		minStaticCount,																//	deUint32							scissorCount;
1573 		m_testConfig.scissorConfig.staticValue.data(),								//	const VkRect2D*						pScissors;
1574 	};
1575 
1576 	// For the dynamic pipeline.
1577 	const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
1578 		? m_testConfig.viewportConfig.dynamicValue.get().size()
1579 		: m_testConfig.viewportConfig.staticValue.size());
1580 
1581 	const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
1582 		? m_testConfig.scissorConfig.dynamicValue.get().size()
1583 		: m_testConfig.scissorConfig.staticValue.size());
1584 
1585 	const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
1586 
1587 	// The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
1588 	const vk::VkPipelineViewportStateCreateInfo dynamicViewportStateCreateInfo =
1589 	{
1590 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,					//	VkStructureType						sType;
1591 		nullptr,																	//	const void*							pNext;
1592 		0u,																			//	VkPipelineViewportStateCreateFlags	flags;
1593 		(m_testConfig.viewportConfig.dynamicValue ? 0u : minDynamicCount),			//	deUint32							viewportCount;
1594 		m_testConfig.viewportConfig.staticValue.data(),								//	const VkViewport*					pViewports;
1595 		(m_testConfig.scissorConfig.dynamicValue ? 0u : minDynamicCount),			//	deUint32							scissorCount;
1596 		m_testConfig.scissorConfig.staticValue.data(),								//	const VkRect2D*						pScissors;
1597 	};
1598 
1599 	// Rasterization state.
1600 	vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
1601 	{
1602 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
1603 		nullptr,														//	const void*								pNext;
1604 		0u,																//	VkPipelineRasterizationStateCreateFlags	flags;
1605 		VK_FALSE,														//	VkBool32								depthClampEnable;
1606 		makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue),	//	VkBool32								rasterizerDiscardEnable;
1607 		vk::VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
1608 		m_testConfig.cullModeConfig.staticValue,						//	VkCullModeFlags							cullMode;
1609 		m_testConfig.frontFaceConfig.staticValue,						//	VkFrontFace								frontFace;
1610 		makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue),	//	VkBool32								depthBiasEnable;
1611 		// Change the depth bias parameters if depth bias is dynamic
1612 		m_testConfig.depthBiasEnableConfig.dynamicValue ? 2e7f : 0.0f,	//	float									depthBiasConstantFactor;
1613 		m_testConfig.depthBiasEnableConfig.dynamicValue ? 0.25f : 0.0f,	//	float									depthBiasClamp;
1614 		0.0f,															//	float									depthBiasSlopeFactor;
1615 		1.0f,															//	float									lineWidth;
1616 	};
1617 
1618 	// Multisample state.
1619 	const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
1620 	{
1621 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
1622 		nullptr,														//	const void*								pNext;
1623 		0u,																//	VkPipelineMultisampleStateCreateFlags	flags;
1624 		vk::VK_SAMPLE_COUNT_1_BIT,										//	VkSampleCountFlagBits					rasterizationSamples;
1625 		VK_FALSE,														//	VkBool32								sampleShadingEnable;
1626 		0.0f,															//	float									minSampleShading;
1627 		nullptr,														//	const VkSampleMask*						pSampleMask;
1628 		VK_FALSE,														//	VkBool32								alphaToCoverageEnable;
1629 		VK_FALSE,														//	VkBool32								alphaToOneEnable;
1630 	};
1631 
1632 	// Depth/stencil state.
1633 	vk::VkStencilOpState	staticFrontStencil;
1634 	vk::VkStencilOpState	staticBackStencil;
1635 	bool					staticFrontStencilSet	= false;
1636 	bool					staticBackStencilSet	= false;
1637 
1638 	// Common setup for the front and back operations.
1639 	staticFrontStencil.compareMask	= 0xFFu;
1640 	staticFrontStencil.writeMask	= 0xFFu;
1641 	staticFrontStencil.reference	= m_testConfig.referenceStencil;
1642 	staticBackStencil				= staticFrontStencil;
1643 
1644 	for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
1645 	{
1646 		if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
1647 		{
1648 			copy(staticFrontStencil, op);
1649 			staticFrontStencilSet = true;
1650 		}
1651 		if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
1652 		{
1653 			copy(staticBackStencil, op);
1654 			staticBackStencilSet = true;
1655 		}
1656 	}
1657 
1658 	// Default values for the static part.
1659 	if (!staticFrontStencilSet)
1660 		copy(staticFrontStencil, kDefaultStencilOpParams);
1661 	if (!staticBackStencilSet)
1662 		copy(staticBackStencil, kDefaultStencilOpParams);
1663 
1664 	const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
1665 	{
1666 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		//	VkStructureType							sType;
1667 		nullptr,															//	const void*								pNext;
1668 		0u,																	//	VkPipelineDepthStencilStateCreateFlags	flags;
1669 		makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),		//	VkBool32								depthTestEnable;
1670 		makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),		//	VkBool32								depthWriteEnable;
1671 		m_testConfig.depthCompareOpConfig.staticValue,						//	VkCompareOp								depthCompareOp;
1672 		makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue),	//	VkBool32								depthBoundsTestEnable;
1673 		makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),		//	VkBool32								stencilTestEnable;
1674 		staticFrontStencil,													//	VkStencilOpState						front;
1675 		staticBackStencil,													//	VkStencilOpState						back;
1676 		m_testConfig.minDepthBounds,										//	float									minDepthBounds;
1677 		m_testConfig.maxDepthBounds,										//	float									maxDepthBounds;
1678 	};
1679 
1680 	// Dynamic state. Here we will set all states which have a dynamic value.
1681 	std::vector<vk::VkDynamicState> dynamicStates;
1682 
1683 	if (m_testConfig.cullModeConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
1684 	if (m_testConfig.frontFaceConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
1685 	if (m_testConfig.topologyConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
1686 	if (m_testConfig.viewportConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
1687 	if (m_testConfig.scissorConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
1688 	if (m_testConfig.strideConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
1689 	if (m_testConfig.depthTestEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
1690 	if (m_testConfig.depthWriteEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
1691 	if (m_testConfig.depthCompareOpConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
1692 	if (m_testConfig.depthBoundsTestEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
1693 	if (m_testConfig.stencilTestEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
1694 	if (m_testConfig.stencilOpConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
1695 	if (m_testConfig.vertexInputConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
1696 	if (m_testConfig.depthBiasEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
1697 	if (m_testConfig.rastDiscardEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
1698 	if (m_testConfig.primRestartEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
1699 	if (m_testConfig.logicOpConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
1700 	if (m_testConfig.patchControlPointsConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
1701 
1702 	const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
1703 	{
1704 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
1705 		nullptr,													//	const void*							pNext;
1706 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
1707 		static_cast<deUint32>(dynamicStates.size()),				//	deUint32							dynamicStateCount;
1708 		dynamicStates.data(),										//	const VkDynamicState*				pDynamicStates;
1709 	};
1710 
1711 	const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1712 	{
1713 		VK_FALSE,						// VkBool32                 blendEnable
1714 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            srcColorBlendFactor
1715 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            dstColorBlendFactor
1716 		vk::VK_BLEND_OP_ADD,			// VkBlendOp                colorBlendOp
1717 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            srcAlphaBlendFactor
1718 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            dstAlphaBlendFactor
1719 		vk::VK_BLEND_OP_ADD,			// VkBlendOp                alphaBlendOp
1720 		vk::VK_COLOR_COMPONENT_R_BIT	// VkColorComponentFlags    colorWriteMask
1721 		| vk::VK_COLOR_COMPONENT_G_BIT
1722 		| vk::VK_COLOR_COMPONENT_B_BIT
1723 		| vk::VK_COLOR_COMPONENT_A_BIT
1724 	};
1725 
1726 	const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
1727 	{
1728 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType                               sType
1729 		nullptr,														// const void*                                   pNext
1730 		0u,																// VkPipelineColorBlendStateCreateFlags          flags
1731 		m_testConfig.logicOpConfig.dynamicValue ? VK_TRUE : VK_FALSE,	// VkBool32                                      logicOpEnable
1732 		m_testConfig.logicOpConfig.staticValue,							// VkLogicOp                                     logicOp
1733 		1u,																// deUint32                                      attachmentCount
1734 		&colorBlendAttachmentState,										// const VkPipelineColorBlendAttachmentState*    pAttachments
1735 		{ 0.0f, 0.0f, 0.0f, 0.0f }										// float                                         blendConstants[4]
1736 	};
1737 
1738 	const vk::VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo =
1739 	{
1740 		vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,	// VkStructureType                               sType
1741 		nullptr,														// const void*                                   pNext
1742 		0u,																// VkPipelineTessellationStateCreateFlags        flags
1743 		m_testConfig.patchControlPointsConfig.staticValue,				// uint32_t										 patchControlPoints
1744 	};
1745 
1746 	const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
1747 	{
1748 		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	//	VkStructureType									sType;
1749 		nullptr,												//	const void*										pNext;
1750 		0u,														//	VkPipelineCreateFlags							flags;
1751 		static_cast<deUint32>(shaderStages.size()),				//	deUint32										stageCount;
1752 		shaderStages.data(),									//	const VkPipelineShaderStageCreateInfo*			pStages;
1753 		&vertexInputStateCreateInfo,							//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
1754 		&inputAssemblyStateCreateInfo,							//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
1755 		m_testConfig.useTessellation ? &pipelineTessellationStateCreateInfo : nullptr,	//	const VkPipelineTessellationStateCreateInfo*		pTessellationState;
1756 		nullptr,												//	const VkPipelineViewportStateCreateInfo *	pViewportState;
1757 		&rasterizationStateCreateInfo,							//	const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
1758 		&multisampleStateCreateInfo,							//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
1759 		&depthStencilStateCreateInfo,							//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
1760 		&colorBlendStateCreateInfo,								//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
1761 		nullptr,												//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
1762 		pipelineLayout.get(),									//	VkPipelineLayout								layout;
1763 		renderPass.get(),										//	VkRenderPass									renderPass;
1764 		0u,														//	deUint32										subpass;
1765 		DE_NULL,												//	VkPipeline										basePipelineHandle;
1766 		0,														//	deInt32											basePipelineIndex;
1767 	};
1768 
1769 	vk::Move<vk::VkPipeline>	staticPipeline;
1770 	const bool					bindStaticFirst		= (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES	||
1771 													   kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES	||
1772 													   kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
1773 	const bool					useStaticPipeline	= (bindStaticFirst || kReversed);
1774 
1775 	// Create static pipeline when needed.
1776 	if (useStaticPipeline)
1777 	{
1778 		auto staticPipelineCreateInfo			= graphicsPipelineCreateInfoTemplate;
1779 		staticPipelineCreateInfo.pViewportState	= &staticViewportStateCreateInfo;
1780 		staticPipeline							= vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
1781 	}
1782 
1783 	// Create dynamic pipeline.
1784 	vk::Move<vk::VkPipeline> graphicsPipeline;
1785 	{
1786 		auto dynamicPipelineCreateInfo				= graphicsPipelineCreateInfoTemplate;
1787 		dynamicPipelineCreateInfo.pDynamicState		= &dynamicStateCreateInfo;
1788 		dynamicPipelineCreateInfo.pViewportState	= &dynamicViewportStateCreateInfo;
1789 		graphicsPipeline							= vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
1790 	}
1791 
1792 	// Command buffer.
1793 	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
1794 	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1795 	const auto cmdBuffer	= cmdBufferPtr.get();
1796 
1797 	// Clear values, clear to green for dynamic logicOp
1798 	std::vector<vk::VkClearValue> clearValues;
1799 	if (m_testConfig.logicOpConfig.dynamicValue)
1800 		m_testConfig.clearColorValue = kGreenClearColor;
1801 	clearValues.push_back(vk::makeClearValueColor(m_testConfig.clearColorValue));
1802 	clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
1803 
1804 	// Record command buffer.
1805 	vk::beginCommandBuffer(vkd, cmdBuffer);
1806 
1807 	for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
1808 	{
1809 		// Track in-advance vertex buffer binding.
1810 		bool boundInAdvance = false;
1811 
1812 		// Maybe set extended dynamic state here.
1813 		if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
1814 		{
1815 			setDynamicStates(m_testConfig, vkd, cmdBuffer);
1816 			boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1817 		}
1818 
1819 		// Begin render pass.
1820 		vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
1821 
1822 			// Bind a static pipeline first if needed.
1823 			if (bindStaticFirst && iteration == 0u)
1824 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
1825 
1826 			// Maybe set extended dynamic state here.
1827 			if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
1828 			{
1829 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
1830 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1831 			}
1832 
1833 			// Bind dynamic pipeline.
1834 			if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
1835 				 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
1836 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
1837 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
1838 			{
1839 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
1840 			}
1841 
1842 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
1843 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
1844 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
1845 			{
1846 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
1847 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1848 			}
1849 
1850 			// Bind a static pipeline last if needed.
1851 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
1852 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
1853 			{
1854 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
1855 			}
1856 
1857 			const auto& viewportVec = m_testConfig.getActiveViewportVec();
1858 			for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
1859 			{
1860 				for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
1861 				{
1862 					// Push constants.
1863 					PushConstants pushConstants =
1864 					{
1865 						m_testConfig.meshParams[meshIdx].color,		//	tcu::Vec4	triangleColor;
1866 						m_testConfig.meshParams[meshIdx].depth,		//	float		meshDepth;
1867 						static_cast<deInt32>(viewportIdx),			//	deInt32		viewPortIndex;
1868 						m_testConfig.meshParams[meshIdx].scaleX,	//	float		scaleX;
1869 						m_testConfig.meshParams[meshIdx].scaleY,	//	float		scaleY;
1870 						m_testConfig.meshParams[meshIdx].offsetX,	//	float		offsetX;
1871 						m_testConfig.meshParams[meshIdx].offsetY,	//	float		offsetY;
1872 					};
1873 					vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
1874 
1875 					// Track vertex bounding state for this mesh.
1876 					bool boundBeforeDraw = false;
1877 
1878 					// Maybe set extended dynamic state here.
1879 					if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
1880 					{
1881 						setDynamicStates(m_testConfig, vkd, cmdBuffer);
1882 						boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1883 					}
1884 
1885 					// Bind vertex buffer with static stride if needed and draw.
1886 					if (!(boundInAdvance || boundBeforeDraw))
1887 					{
1888 						vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, (m_testConfig.meshParams[meshIdx].reversed ? &rvertBuffer.get() : &vertBuffer.get()), &m_testConfig.vertexDataOffset);
1889 						if (m_testConfig.useIndexBuffer)
1890 						{
1891 							vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0, vk::VK_INDEX_TYPE_UINT32);
1892 						}
1893 					}
1894 					// Draw mesh.
1895 					if (m_testConfig.useIndexBuffer) {
1896 						deUint32 numIndices = static_cast<deUint32>(indices.size());
1897 						// For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
1898 						// So, draw without using the invalid (0xFFFFFFFF) index, the second draw with primitive restart enabled will replace the results
1899 						// using all indices.
1900 						if (iteration == 0u &&
1901 							(m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
1902 							m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
1903 							numIndices = 3u;
1904 						vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
1905 					}
1906 					else
1907 						vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(vertexPtrs.size()), 1u, 0u, 0u);
1908 				}
1909 			}
1910 
1911 		vk::endRenderPass(vkd, cmdBuffer);
1912 	}
1913 
1914 	vk::endCommandBuffer(vkd, cmdBuffer);
1915 
1916 	// Submit commands.
1917 	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1918 
1919 	// Read result image aspects from the last used framebuffer.
1920 	const tcu::UVec2	renderSize		(kFramebufferWidth, kFramebufferHeight);
1921 	const auto			colorBuffer		= readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImages.back()->get(), colorFormat, renderSize);
1922 	const auto			depthBuffer		= readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
1923 	const auto			stencilBuffer	= readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1924 	const auto			colorAccess		= colorBuffer->getAccess();
1925 	const auto			depthAccess		= depthBuffer->getAccess();
1926 	const auto			stencilAccess	= stencilBuffer->getAccess();
1927 
1928 	const int kWidth	= static_cast<int>(kFramebufferWidth);
1929 	const int kHeight	= static_cast<int>(kFramebufferHeight);
1930 
1931 	// Generate reference color buffer.
1932 	const auto				tcuColorFormat			= vk::mapVkFormat(colorFormat);
1933 	tcu::TextureLevel		referenceColorLevel		(tcuColorFormat, kWidth, kHeight);
1934 	tcu::PixelBufferAccess	referenceColorAccess	= referenceColorLevel.getAccess();
1935 	m_testConfig.referenceColor(referenceColorAccess);
1936 
1937 	const tcu::TextureFormat	errorFormat			(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1938 	tcu::TextureLevel			colorError			(errorFormat, kWidth, kHeight);
1939 	tcu::TextureLevel			depthError			(errorFormat, kWidth, kHeight);
1940 	tcu::TextureLevel			stencilError		(errorFormat, kWidth, kHeight);
1941 	const auto					colorErrorAccess	= colorError.getAccess();
1942 	const auto					depthErrorAccess	= depthError.getAccess();
1943 	const auto					stencilErrorAccess	= stencilError.getAccess();
1944 	const tcu::Vec4				kGood				(0.0f, 1.0f, 0.0f, 1.0f);
1945 	const tcu::Vec4				kBad				(1.0f, 0.0f, 0.0f, 1.0f);
1946 
1947 	// Check expected values.
1948 	const auto	minDepth		= m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
1949 	const auto	maxDepth		= m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
1950 	bool		colorMatch		= true;
1951 	bool		depthMatch		= true;
1952 	bool		stencilMatch	= true;
1953 	bool		match;
1954 
1955 	for (int y = 0; y < kHeight; ++y)
1956 	for (int x = 0; x < kWidth; ++x)
1957 	{
1958 		auto colorPixel		= colorAccess.getPixel(x, y);
1959 		auto expectedPixel	= referenceColorAccess.getPixel(x, y);
1960 
1961 		// The logic OP must have ORed the colors to cyan
1962 		if (m_testConfig.logicOpConfig.dynamicValue)
1963 		{
1964 			// Multiply by 255.0f as the color is in R8G8B8A8 format
1965 			expectedPixel = kCyanColor * 255.0f;
1966 		}
1967 
1968 		match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kColorThreshold));
1969 		colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
1970 		if (!match)
1971 			colorMatch = false;
1972 
1973 		const auto depthPixel = depthAccess.getPixDepth(x, y);
1974 		match = de::inRange(depthPixel, minDepth, maxDepth);
1975 		depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
1976 		if (!match)
1977 			depthMatch = false;
1978 
1979 		const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
1980 		match = (stencilPixel == m_testConfig.expectedStencil);
1981 		stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
1982 		if (!match)
1983 			stencilMatch = false;
1984 	}
1985 
1986 	if (!(colorMatch && depthMatch && stencilMatch))
1987 	{
1988 		if (!colorMatch)
1989 			logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
1990 
1991 		if (!depthMatch)
1992 			logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
1993 
1994 		if (!stencilMatch)
1995 			logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
1996 
1997 		return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
1998 	}
1999 
2000 	return tcu::TestStatus::pass("Pass");
2001 }
2002 
stencilPasses(vk::VkCompareOp op,deUint8 storedValue,deUint8 referenceValue)2003 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
2004 {
2005 	switch (op)
2006 	{
2007 	case vk::VK_COMPARE_OP_NEVER:				return false;
2008 	case vk::VK_COMPARE_OP_LESS:				return (referenceValue <	storedValue);
2009 	case vk::VK_COMPARE_OP_EQUAL:				return (referenceValue ==	storedValue);
2010 	case vk::VK_COMPARE_OP_LESS_OR_EQUAL:		return (referenceValue <=	storedValue);
2011 	case vk::VK_COMPARE_OP_GREATER:				return (referenceValue >	storedValue);
2012 	case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:	return (referenceValue >=	storedValue);
2013 	case vk::VK_COMPARE_OP_ALWAYS:				return true;
2014 	default: DE_ASSERT(false); return false;
2015 	}
2016 
2017 	return false;	// Unreachable.
2018 }
2019 
stencilResult(vk::VkStencilOp op,deUint8 storedValue,deUint8 referenceValue,deUint8 min,deUint8 max)2020 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
2021 {
2022 	deUint8 result = storedValue;
2023 
2024 	switch (op)
2025 	{
2026 	case vk::VK_STENCIL_OP_KEEP:					break;
2027 	case vk::VK_STENCIL_OP_ZERO:					result = 0; break;
2028 	case vk::VK_STENCIL_OP_REPLACE:					result = referenceValue; break;
2029 	case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:		result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
2030 	case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:		result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
2031 	case vk::VK_STENCIL_OP_INVERT:					result = static_cast<deUint8>(~result); break;
2032 	case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:		result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
2033 	case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:		result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
2034 	default: DE_ASSERT(false); break;
2035 	}
2036 
2037 	return result;
2038 }
2039 
2040 } // anonymous namespace
2041 
createExtendedDynamicStateTests(tcu::TestContext & testCtx)2042 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
2043 {
2044 	de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
2045 
2046 	// Auxiliar constants.
2047 	const deUint32	kHalfWidthU	= kFramebufferWidth/2u;
2048 	const deInt32	kHalfWidthI	= static_cast<deInt32>(kHalfWidthU);
2049 	const float		kHalfWidthF	= static_cast<float>(kHalfWidthU);
2050 	const float		kHeightF	= static_cast<float>(kFramebufferHeight);
2051 
2052 	static const struct
2053 	{
2054 		SequenceOrdering	ordering;
2055 		std::string			name;
2056 		std::string			desc;
2057 	} kOrderingCases[] =
2058 	{
2059 		{ SequenceOrdering::CMD_BUFFER_START,	"cmd_buffer_start",		"Dynamic state set after command buffer start"																								},
2060 		{ SequenceOrdering::BEFORE_DRAW,		"before_draw",			"Dynamic state set just before drawing"																										},
2061 		{ SequenceOrdering::BETWEEN_PIPELINES,	"between_pipelines",	"Dynamic after a pipeline with static states has been bound and before a pipeline with dynamic states has been bound"						},
2062 		{ SequenceOrdering::AFTER_PIPELINES,	"after_pipelines",		"Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"									},
2063 		{ SequenceOrdering::BEFORE_GOOD_STATIC,	"before_good_static",	"Dynamic state set after a dynamic pipeline has been bound and before a second static-state pipeline with the right values has been bound"	},
2064 		{ SequenceOrdering::TWO_DRAWS_DYNAMIC,	"two_draws_dynamic",	"Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again"											},
2065 		{ SequenceOrdering::TWO_DRAWS_STATIC,	"two_draws_static",		"Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again"											},
2066 	};
2067 
2068 	for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
2069 	{
2070 		const auto& kOrderingCase	= kOrderingCases[orderingIdx];
2071 		const auto& kOrdering		= kOrderingCase.ordering;
2072 
2073 		de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
2074 
2075 		// Cull modes.
2076 		{
2077 			TestConfig config(kOrdering);
2078 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_BIT;
2079 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
2080 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
2081 		}
2082 		{
2083 			TestConfig config(kOrdering);
2084 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_AND_BACK;
2085 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
2086 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
2087 		}
2088 		{
2089 			TestConfig config(kOrdering);
2090 			// Make triangles look back.
2091 			config.meshParams[0].reversed		= true;
2092 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2093 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
2094 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
2095 		}
2096 		{
2097 			TestConfig config(kOrdering);
2098 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_NONE;
2099 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
2100 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2101 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
2102 		}
2103 
2104 		// Front face.
2105 		{
2106 			TestConfig config(kOrdering);
2107 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2108 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
2109 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2110 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
2111 		}
2112 		{
2113 			TestConfig config(kOrdering);
2114 			// Pass triangles in clockwise order.
2115 			config.meshParams[0].reversed		= true;
2116 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2117 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2118 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2119 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
2120 		}
2121 		{
2122 			TestConfig config(kOrdering);
2123 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2124 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2125 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2126 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2127 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
2128 		}
2129 		{
2130 			TestConfig config(kOrdering);
2131 			// Pass triangles in clockwise order.
2132 			config.meshParams[0].reversed		= true;
2133 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2134 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
2135 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2136 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2137 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
2138 		}
2139 
2140 		// Rasterizer discard
2141 		{
2142 			TestConfig config(kOrdering);
2143 			config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2144 			config.rastDiscardEnableConfig.staticValue = false;
2145 			config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
2146 			config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2147 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
2148 		}
2149 		{
2150 			TestConfig config(kOrdering);
2151 			config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2152 			config.rastDiscardEnableConfig.staticValue = true;
2153 			config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
2154 			config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2155 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
2156 		}
2157 
2158 		// Logic op
2159 		{
2160 			TestConfig config(kOrdering);
2161 			config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2162 			config.testExtendedDynamicState2LogicOp = true;
2163 			config.logicOpConfig.staticValue = vk::VK_LOGIC_OP_CLEAR;
2164 			config.logicOpConfig.dynamicValue = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
2165 			config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2166 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
2167 		}
2168 
2169 		// Dynamically enable primitive restart
2170 		{
2171 			TestConfig config(kOrdering);
2172 			config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2173 			config.useIndexBuffer = true;
2174 			config.primRestartEnableConfig.staticValue = false;
2175 			config.primRestartEnableConfig.dynamicValue = tcu::just(true);
2176 			config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2177 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "prim_restart_enable", "Dynamically enable primitiveRestart", config));
2178 		}
2179 
2180 		// Dynamically change the number of primitive control points
2181 		{
2182 			TestConfig config(kOrdering);
2183 			config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2184 			config.testExtendedDynamicState2PatchControlPoints = true;
2185 			config.useTessellation = true;
2186 			config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
2187 			config.patchControlPointsConfig.staticValue = 1;
2188 			config.patchControlPointsConfig.dynamicValue = 3;
2189 			config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2190 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points", "Dynamically change patch control points", config));
2191 		}
2192 
2193 		// Dynamic topology.
2194 		{
2195 			TestConfig baseConfig(kOrdering);
2196 
2197 			for (int i = 0; i < 2; ++i)
2198 			{
2199 				const bool forceGeometryShader = (i > 0);
2200 
2201 				static const struct
2202 				{
2203 					vk::VkPrimitiveTopology staticVal;
2204 					vk::VkPrimitiveTopology dynamicVal;
2205 				} kTopologyCases[] =
2206 				{
2207 					{ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN	},
2208 					{ vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP	},
2209 				};
2210 
2211 				for (int topoCaseIdx = 0; topoCaseIdx < DE_LENGTH_OF_ARRAY(kTopologyCases); ++topoCaseIdx)
2212 				{
2213 					TestConfig config(baseConfig);
2214 					config.forceGeometryShader			= forceGeometryShader;
2215 					config.topologyConfig.staticValue	= kTopologyCases[topoCaseIdx].staticVal;
2216 					config.topologyConfig.dynamicValue	= tcu::just<vk::VkPrimitiveTopology>(kTopologyCases[topoCaseIdx].dynamicVal);
2217 
2218 					const std::string	className	= topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
2219 					const std::string	name		= "topology_" + className + (forceGeometryShader ? "_geom" : "");
2220 					const std::string	desc		= "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "");
2221 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
2222 				}
2223 			}
2224 		}
2225 
2226 		// Viewport.
2227 		{
2228 			TestConfig config(kOrdering);
2229 			// 2 scissors, bad static single viewport.
2230 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2231 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2232 			config.viewportConfig.dynamicValue	= ViewportVec{
2233 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2234 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2235 			};
2236 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
2237 		}
2238 		{
2239 			TestConfig config(kOrdering);
2240 			// Bad static reduced viewport.
2241 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2242 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
2243 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
2244 		}
2245 		{
2246 			TestConfig config(kOrdering);
2247 			// 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
2248 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2249 			config.viewportConfig.staticValue	= ViewportVec{
2250 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
2251 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
2252 			};
2253 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2254 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
2255 		}
2256 		{
2257 			TestConfig config(kOrdering);
2258 			// 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
2259 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2260 			config.viewportConfig.staticValue	= ViewportVec{
2261 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
2262 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
2263 			};
2264 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2265 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2266 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
2267 		}
2268 
2269 		// Scissor.
2270 		{
2271 			TestConfig config(kOrdering);
2272 			// 2 viewports, bad static single scissor.
2273 			config.viewportConfig.staticValue	= ViewportVec{
2274 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2275 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2276 			};
2277 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2278 			config.scissorConfig.dynamicValue	= ScissorVec{
2279 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2280 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2281 			};
2282 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
2283 		}
2284 		{
2285 			TestConfig config(kOrdering);
2286 			// 1 viewport, bad static single scissor.
2287 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2288 			config.scissorConfig.dynamicValue	= ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
2289 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
2290 		}
2291 		{
2292 			TestConfig config(kOrdering);
2293 			// 2 viewports, 2 reversed scissors that need fixing.
2294 			config.viewportConfig.staticValue	= ViewportVec{
2295 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2296 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2297 			};
2298 			config.scissorConfig.staticValue	= ScissorVec{
2299 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2300 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2301 			};
2302 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2303 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
2304 		}
2305 		{
2306 			TestConfig config(kOrdering);
2307 			// 2 viewports, 2 scissors switched to prevent drawing.
2308 			config.viewportConfig.staticValue	= ViewportVec{
2309 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2310 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2311 			};
2312 			config.scissorConfig.staticValue	= ScissorVec{
2313 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2314 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2315 			};
2316 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2317 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2318 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
2319 		}
2320 
2321 		// Stride.
2322 		{
2323 			struct
2324 			{
2325 				VertexFactory		factory;
2326 				const std::string	prefix;
2327 			} strideCases[] =
2328 			{
2329 				{ getVertexWithPadding,			"stride"		},
2330 				{ getVertexWithExtraAttributes,	"large_stride"	},
2331 			};
2332 
2333 			for (int strideCaseIndex = 0; strideCaseIndex < DE_LENGTH_OF_ARRAY(strideCases); ++strideCaseIndex)
2334 			{
2335 				const auto	factory			= strideCases[strideCaseIndex].factory;
2336 				const auto&	prefix			= strideCases[strideCaseIndex].prefix;
2337 				const auto	dummyVertex		= factory(tcu::Vec2(0.0f, 0.0f));
2338 				const auto	vertexStride	= static_cast<vk::VkDeviceSize>(dummyVertex->getVertexDataSize());
2339 
2340 				if (factory == getVertexWithExtraAttributes && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
2341 				{
2342 					// This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
2343 					// stride being less than the extent of the binding for the second attribute.
2344 					continue;
2345 				}
2346 
2347 				{
2348 					TestConfig config(kOrdering, factory);
2349 					config.strideConfig.staticValue		= kCoordsSize;
2350 					config.strideConfig.dynamicValue	= vertexStride;
2351 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix, "Dynamically set stride", config));
2352 				}
2353 				{
2354 					TestConfig config(kOrdering, factory);
2355 					config.strideConfig.staticValue		= kCoordsSize;
2356 					config.strideConfig.dynamicValue	= vertexStride;
2357 					config.vertexDataOffset				= static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex));
2358 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset", "Dynamically set stride using a nonzero vertex data offset", config));
2359 				}
2360 				{
2361 					TestConfig config(kOrdering, factory);
2362 					config.strideConfig.staticValue		= kCoordsSize;
2363 					config.strideConfig.dynamicValue	= vertexStride;
2364 					config.vertexDataOffset				= static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex));
2365 					config.vertexDataExtraBytes			= config.vertexDataOffset;
2366 
2367 					// Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
2368 					// offscreen vertex and draw something in the bottom half.
2369 					config.referenceColor				= HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2370 					config.meshParams[0].scaleY			= 0.5f;
2371 					config.meshParams[0].offsetY		= -0.5f;
2372 
2373 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding", "Dynamically set stride using a nonzero vertex data offset and extra bytes", config));
2374 				}
2375 			}
2376 		}
2377 
2378 		// Depth test enable.
2379 		{
2380 			TestConfig config(kOrdering);
2381 			config.depthTestEnableConfig.staticValue	= false;
2382 			config.depthTestEnableConfig.dynamicValue	= tcu::just(true);
2383 			// By default, the depth test never passes when enabled.
2384 			config.referenceColor						= SingleColorGenerator(kDefaultClearColor);
2385 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
2386 		}
2387 		{
2388 			TestConfig config(kOrdering);
2389 			config.depthTestEnableConfig.staticValue	= true;
2390 			config.depthTestEnableConfig.dynamicValue	= tcu::just(false);
2391 			config.referenceColor						= SingleColorGenerator(kDefaultTriangleColor);
2392 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
2393 		}
2394 
2395 		// Depth write enable.
2396 		{
2397 			TestConfig config(kOrdering);
2398 
2399 			// Enable depth test and set values so it passes.
2400 			config.depthTestEnableConfig.staticValue	= true;
2401 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
2402 			config.clearDepthValue						= 0.5f;
2403 			config.meshParams[0].depth					= 0.25f;
2404 
2405 			// Enable writes and expect the mesh value.
2406 			config.depthWriteEnableConfig.staticValue	= false;
2407 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(true);
2408 			config.expectedDepth						= 0.25f;
2409 
2410 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
2411 		}
2412 		{
2413 			TestConfig config(kOrdering);
2414 
2415 			// Enable depth test and set values so it passes.
2416 			config.depthTestEnableConfig.staticValue	= true;
2417 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
2418 			config.clearDepthValue						= 0.5f;
2419 			config.meshParams[0].depth					= 0.25f;
2420 
2421 			// But disable writing dynamically and expect the clear value.
2422 			config.depthWriteEnableConfig.staticValue	= true;
2423 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(false);
2424 			config.expectedDepth						= 0.5f;
2425 
2426 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
2427 		}
2428 
2429 		// Depth bias enable.
2430 		{
2431 			{
2432 				TestConfig config(kOrdering);
2433 				config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2434 
2435 				// Enable depth test and write 1.0f
2436 				config.depthTestEnableConfig.staticValue = true;
2437 				config.depthWriteEnableConfig.staticValue = true;
2438 				config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2439 				// Clear depth buffer to 0.25f
2440 				config.clearDepthValue = 0.25f;
2441 				// Write depth to 0.5f
2442 				config.meshParams[0].depth = 0.5f;
2443 
2444 				// Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
2445 				config.depthBiasEnableConfig.staticValue = false;
2446 				config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
2447 				config.expectedDepth = 0.75f;
2448 
2449 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bias_enable", "Dynamically enable the depth bias", config));
2450 			}
2451 			{
2452 				TestConfig config(kOrdering);
2453 				config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2454 
2455 				// Enable depth test and write 1.0f
2456 				config.depthTestEnableConfig.staticValue = true;
2457 				config.depthWriteEnableConfig.staticValue = true;
2458 				config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2459 				// Clear depth buffer to 0.25f
2460 				config.clearDepthValue = 0.25f;
2461 				// Write depth to 0.5f
2462 				config.meshParams[0].depth = 0.5f;
2463 
2464 				// Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
2465 				config.depthBiasEnableConfig.staticValue = true;
2466 				config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
2467 				config.expectedDepth = 0.5f;
2468 
2469 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bias_disable", "Dynamically disable the depth bias", config));
2470 			}
2471 		}
2472 
2473 		// Depth compare op.
2474 		{
2475 			TestConfig baseConfig(kOrdering);
2476 			const tcu::Vec4 kAlternativeColor				(0.0f, 0.0f, 0.5f, 1.0f);
2477 			baseConfig.depthTestEnableConfig.staticValue	= true;
2478 			baseConfig.depthWriteEnableConfig.staticValue	= true;
2479 			baseConfig.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_NEVER;
2480 			baseConfig.clearDepthValue						= 0.5f;
2481 
2482 			{
2483 				TestConfig config = baseConfig;
2484 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_ALWAYS;
2485 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NEVER;
2486 				config.meshParams[0].depth					= 0.25f;
2487 				config.expectedDepth						= 0.5f;
2488 				config.referenceColor						= SingleColorGenerator(kDefaultClearColor);
2489 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
2490 			}
2491 			{
2492 				TestConfig config = baseConfig;
2493 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS;
2494 				config.meshParams[0].depth					= 0.25f;
2495 				config.expectedDepth						= 0.25f;
2496 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
2497 			}
2498 			{
2499 				TestConfig config = baseConfig;
2500 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER;
2501 				config.meshParams[0].depth					= 0.75f;
2502 				config.expectedDepth						= 0.75f;
2503 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
2504 			}
2505 			{
2506 				TestConfig config = baseConfig;
2507 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_EQUAL;
2508 				config.meshParams[0].depth					= 0.5f;
2509 				config.meshParams[0].color					= kAlternativeColor;
2510 				// Draw another mesh in front to verify it does not pass the equality test.
2511 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
2512 				config.expectedDepth						= 0.5f;
2513 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
2514 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
2515 			}
2516 			{
2517 				TestConfig config = baseConfig;
2518 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2519 				config.meshParams[0].depth					= 0.25f;
2520 				config.expectedDepth						= 0.25f;
2521 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with smaller depth", config));
2522 			}
2523 			{
2524 				TestConfig config = baseConfig;
2525 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2526 				config.meshParams[0].depth					= 0.5f;
2527 				config.expectedDepth						= 0.5f;
2528 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_equal", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with equal depth", config));
2529 			}
2530 			{
2531 				TestConfig config = baseConfig;
2532 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2533 				config.meshParams[0].depth					= 0.25f;
2534 				// Draw another mesh with the same depth in front of it.
2535 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
2536 				config.expectedDepth						= 0.25f;
2537 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
2538 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less_then_equal", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw two meshes with less and equal depth", config));
2539 			}
2540 			{
2541 				TestConfig config = baseConfig;
2542 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2543 				config.meshParams[0].depth					= 0.75f;
2544 				config.expectedDepth						= 0.75f;
2545 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_greater", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with greater depth", config));
2546 			}
2547 			{
2548 				TestConfig config = baseConfig;
2549 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2550 				config.meshParams[0].depth					= 0.5f;
2551 				config.expectedDepth						= 0.5f;
2552 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_equal", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with equal depth", config));
2553 			}
2554 			{
2555 				TestConfig config = baseConfig;
2556 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2557 				config.meshParams[0].depth					= 0.75f;
2558 				// Draw another mesh with the same depth in front of it.
2559 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
2560 				config.expectedDepth						= 0.75f;
2561 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
2562 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_greater_then_equal", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw two meshes with greater and equal depth", config));
2563 			}
2564 			{
2565 				TestConfig config = baseConfig;
2566 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NOT_EQUAL;
2567 
2568 				// Draw first mesh in front.
2569 				config.meshParams[0].depth					= 0.25f;
2570 				// Draw another mesh in the back, this should pass too.
2571 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
2572 				// Finally a new mesh with the same depth. This should not pass.
2573 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
2574 
2575 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
2576 				config.expectedDepth						= 0.5f;
2577 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
2578 			}
2579 			{
2580 				TestConfig config = baseConfig;
2581 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_ALWAYS;
2582 
2583 				config.meshParams[0].depth					= 0.5f;
2584 				config.expectedDepth						= 0.5f;
2585 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
2586 
2587 				config.meshParams[0].depth					= 0.25f;
2588 				config.expectedDepth						= 0.25f;
2589 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
2590 
2591 				config.meshParams[0].depth					= 0.75f;
2592 				config.expectedDepth						= 0.75f;
2593 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
2594 			}
2595 		}
2596 
2597 		// Depth bounds test.
2598 		{
2599 			TestConfig baseConfig(kOrdering);
2600 			baseConfig.minDepthBounds							= 0.25f;
2601 			baseConfig.maxDepthBounds							= 0.75f;
2602 			baseConfig.meshParams[0].depth						= 0.0f;
2603 
2604 			{
2605 				TestConfig config = baseConfig;
2606 				config.depthBoundsTestEnableConfig.staticValue	= false;
2607 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(true);
2608 				config.referenceColor							= SingleColorGenerator(kDefaultClearColor);
2609 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
2610 			}
2611 			{
2612 				TestConfig config = baseConfig;
2613 				config.depthBoundsTestEnableConfig.staticValue	= true;
2614 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(false);
2615 				config.referenceColor							= SingleColorGenerator(kDefaultTriangleColor);
2616 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
2617 			}
2618 		}
2619 
2620 		// Stencil test enable.
2621 		{
2622 			TestConfig config(kOrdering);
2623 			config.stencilTestEnableConfig.staticValue				= false;
2624 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(true);
2625 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
2626 			config.referenceColor									= SingleColorGenerator(kDefaultClearColor);
2627 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
2628 		}
2629 		{
2630 			TestConfig config(kOrdering);
2631 			config.stencilTestEnableConfig.staticValue				= true;
2632 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(false);
2633 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
2634 			config.referenceColor									= SingleColorGenerator(kDefaultTriangleColor);
2635 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
2636 		}
2637 
2638 		// Stencil operation. Many combinations are possible.
2639 		{
2640 			static const struct
2641 			{
2642 				vk::VkStencilFaceFlags	face;
2643 				std::string				name;
2644 			} kFaces[] =
2645 			{
2646 				{ vk::VK_STENCIL_FACE_FRONT_BIT,			"face_front"		},
2647 				{ vk::VK_STENCIL_FACE_BACK_BIT,				"face_back"			},
2648 				{ vk::VK_STENCIL_FRONT_AND_BACK,			"face_both_single"	},
2649 				{ vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM,	"face_both_dual"	},	// MAX_ENUM is a placeholder.
2650 			};
2651 
2652 			static const struct
2653 			{
2654 				vk::VkCompareOp		compareOp;
2655 				std::string			name;
2656 			} kCompare[] =
2657 			{
2658 				{ vk::VK_COMPARE_OP_NEVER,				"xf"		},
2659 				{ vk::VK_COMPARE_OP_LESS,				"lt"		},
2660 				{ vk::VK_COMPARE_OP_EQUAL,				"eq"		},
2661 				{ vk::VK_COMPARE_OP_LESS_OR_EQUAL,		"le"		},
2662 				{ vk::VK_COMPARE_OP_GREATER,			"gt"		},
2663 				{ vk::VK_COMPARE_OP_GREATER_OR_EQUAL,	"ge"		},
2664 				{ vk::VK_COMPARE_OP_ALWAYS,				"xt"		},
2665 			};
2666 
2667 			using u8vec = std::vector<deUint8>;
2668 
2669 			static const auto kMinVal	= std::numeric_limits<deUint8>::min();
2670 			static const auto kMaxVal	= std::numeric_limits<deUint8>::max();
2671 			static const auto kMidVal	= static_cast<deUint8>(kMaxVal * 2u / 5u);
2672 			static const auto kMinValI	= static_cast<int>(kMinVal);
2673 			static const auto kMaxValI	= static_cast<int>(kMaxVal);
2674 
2675 			static const struct
2676 			{
2677 				vk::VkStencilOp		stencilOp;
2678 				std::string			name;
2679 				u8vec				clearValues;	// One test per clear value interesting for this operation.
2680 				vk::VkStencilOp		incompatibleOp;	// Alternative operation giving incompatible results for the given values.
2681 			} kStencilOps[] =
2682 			{
2683 				{ vk::VK_STENCIL_OP_KEEP,					"keep",			u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
2684 				{ vk::VK_STENCIL_OP_ZERO,					"zero",			u8vec{kMidVal},					vk::VK_STENCIL_OP_KEEP					},
2685 				{ vk::VK_STENCIL_OP_REPLACE,				"replace",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
2686 				{ vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP,	"inc_clamp",	u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_ZERO					},
2687 				{ vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP,	"dec_clamp",	u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP	},
2688 				{ vk::VK_STENCIL_OP_INVERT,					"invert",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
2689 				{ vk::VK_STENCIL_OP_INCREMENT_AND_WRAP,		"inc_wrap",		u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_KEEP					},
2690 				{ vk::VK_STENCIL_OP_DECREMENT_AND_WRAP,		"dec_wrap",		u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_KEEP					},
2691 			};
2692 
2693 			for (int facesIdx	= 0; facesIdx	< DE_LENGTH_OF_ARRAY(kFaces);		++facesIdx)
2694 			for (int compareIdx	= 0; compareIdx	< DE_LENGTH_OF_ARRAY(kCompare);		++compareIdx)
2695 			for (int opIdx		= 0; opIdx		< DE_LENGTH_OF_ARRAY(kStencilOps);	++opIdx)
2696 			{
2697 				const auto& face	= kFaces[facesIdx];
2698 				const auto& compare	= kCompare[compareIdx];
2699 				const auto& op		= kStencilOps[opIdx];
2700 
2701 				// Try clearing the stencil value with different values.
2702 				for (const auto clearVal : op.clearValues)
2703 				{
2704 					// Use interesting values as the reference stencil value.
2705 					for (int delta = -1; delta <= 1; ++delta)
2706 					{
2707 						const int refVal = clearVal + delta;
2708 						if (refVal < kMinValI || refVal > kMaxValI)
2709 							continue;
2710 
2711 						const auto refValU8		= static_cast<deUint8>(refVal);
2712 						const auto refValU32	= static_cast<deUint32>(refVal);
2713 
2714 						// Calculate outcome of the stencil test itself.
2715 						const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
2716 
2717 						// If the test passes, use an additional variant for the depthFail operation.
2718 						const int subCases = (wouldPass ? 2 : 1);
2719 
2720 						for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
2721 						{
2722 							const bool depthFail	= (subCaseIdx > 0);				// depthFail would be the second variant.
2723 							const bool globalPass	= (wouldPass && !depthFail);	// Global result of the stencil+depth test.
2724 
2725 							// Start tuning test parameters.
2726 							TestConfig config(kOrdering);
2727 
2728 							// No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
2729 							if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
2730 							{
2731 								// Default parameters are OK.
2732 							}
2733 							else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
2734 							{
2735 								// Reverse the mesh so it applies the back operation.
2736 								config.meshParams[0].reversed = true;
2737 							}
2738 							else	// Front and back.
2739 							{
2740 								// Draw both a front and a back-facing mesh so both are applied.
2741 								// The first mesh will be drawn in the top half and the second mesh in the bottom half.
2742 
2743 								// Make the second mesh a reversed copy of the first mesh.
2744 								config.meshParams.push_back(config.meshParams.front());
2745 								config.meshParams.back().reversed = true;
2746 
2747 								// Apply scale and offset to the top mesh.
2748 								config.meshParams.front().scaleY = 0.5f;
2749 								config.meshParams.front().offsetY = -0.5f;
2750 
2751 								// Apply scale and offset to the bottom mesh.
2752 								config.meshParams.back().scaleY = 0.5f;
2753 								config.meshParams.back().offsetY = 0.5f;
2754 							}
2755 
2756 							// Enable the stencil test.
2757 							config.stencilTestEnableConfig.staticValue = true;
2758 
2759 							// Set dynamic configuration.
2760 							StencilOpParams dynamicStencilConfig;
2761 							dynamicStencilConfig.faceMask		= face.face;
2762 							dynamicStencilConfig.compareOp		= compare.compareOp;
2763 							dynamicStencilConfig.failOp			= vk::VK_STENCIL_OP_MAX_ENUM;
2764 							dynamicStencilConfig.passOp			= vk::VK_STENCIL_OP_MAX_ENUM;
2765 							dynamicStencilConfig.depthFailOp	= vk::VK_STENCIL_OP_MAX_ENUM;
2766 
2767 							// Set operations so only the appropriate operation for this case gives the right result.
2768 							vk::VkStencilOp* activeOp		= nullptr;
2769 							vk::VkStencilOp* inactiveOps[2]	= { nullptr, nullptr };
2770 							if (wouldPass)
2771 							{
2772 								if (depthFail)
2773 								{
2774 									activeOp		= &dynamicStencilConfig.depthFailOp;
2775 									inactiveOps[0]	= &dynamicStencilConfig.passOp;
2776 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
2777 								}
2778 								else
2779 								{
2780 									activeOp		= &dynamicStencilConfig.passOp;
2781 									inactiveOps[0]	= &dynamicStencilConfig.depthFailOp;
2782 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
2783 								}
2784 							}
2785 							else
2786 							{
2787 								activeOp		= &dynamicStencilConfig.failOp;
2788 								inactiveOps[0]	= &dynamicStencilConfig.passOp;
2789 								inactiveOps[1]	= &dynamicStencilConfig.depthFailOp;
2790 							}
2791 
2792 							*activeOp = op.stencilOp;
2793 							*inactiveOps[0] = op.incompatibleOp;
2794 							*inactiveOps[1] = op.incompatibleOp;
2795 
2796 							// Make sure all ops have been configured properly.
2797 							DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
2798 							DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
2799 							DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
2800 
2801 							// Set an incompatible static operation too.
2802 							auto& staticStencilConfig		= config.stencilOpConfig.staticValue.front();
2803 							staticStencilConfig.faceMask	= face.face;
2804 							staticStencilConfig.compareOp	= (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
2805 							staticStencilConfig.passOp		= op.incompatibleOp;
2806 							staticStencilConfig.failOp		= op.incompatibleOp;
2807 							staticStencilConfig.depthFailOp	= op.incompatibleOp;
2808 
2809 							// Set dynamic configuration.
2810 							StencilOpVec stencilOps;
2811 							stencilOps.push_back(dynamicStencilConfig);
2812 
2813 							if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
2814 							{
2815 								// This is the dual case. We will set the front and back face values with two separate calls.
2816 								stencilOps.push_back(stencilOps.front());
2817 								stencilOps.front().faceMask		= vk::VK_STENCIL_FACE_FRONT_BIT;
2818 								stencilOps.back().faceMask		= vk::VK_STENCIL_FACE_BACK_BIT;
2819 								staticStencilConfig.faceMask	= vk::VK_STENCIL_FACE_FRONT_AND_BACK;
2820 							}
2821 
2822 							config.stencilOpConfig.dynamicValue	= tcu::just(stencilOps);
2823 							config.clearStencilValue			= clearVal;
2824 							config.referenceStencil				= refValU32;
2825 
2826 							if (depthFail)
2827 							{
2828 								// Enable depth test and make it fail.
2829 								config.depthTestEnableConfig.staticValue	= true;
2830 								config.clearDepthValue						= 0.5f;
2831 								config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
2832 
2833 								for (auto& meshPar : config.meshParams)
2834 									meshPar.depth = 0.75f;
2835 							}
2836 
2837 							// Set expected outcome.
2838 							config.referenceColor	= SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor);
2839 							config.expectedDepth	= config.clearDepthValue; // No depth writing by default.
2840 							config.expectedStencil	= stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
2841 
2842 							const std::string testName = std::string("stencil_state")
2843 								+ "_" + face.name
2844 								+ "_" + compare.name
2845 								+ "_" + op.name
2846 								+ "_clear_" + de::toString(static_cast<int>(clearVal))
2847 								+ "_ref_" + de::toString(refVal)
2848 								+ "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
2849 
2850 							orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
2851 						}
2852 					}
2853 				}
2854 			}
2855 		}
2856 
2857 		// Vertex input.
2858 		{
2859 			const auto	dummyVertex		= getVertexWithPadding(tcu::Vec2(0.0f, 0.0f));
2860 
2861 			TestConfig config(kOrdering);
2862 			config.testExtendedDynamicStateVersion  = TEST_VERSION_vertex_input_dynamic_state;
2863 			config.vertexInputConfig.staticValue	= static_cast<deUint32>(dummyVertex->getPaddingOffset());
2864 			config.vertexInputConfig.dynamicValue	= static_cast<deUint32>(dummyVertex->getCoordsOffset());
2865 			config.strideConfig.staticValue			= kCoordsSize;
2866 			config.strideConfig.dynamicValue		= static_cast<vk::VkDeviceSize>(dummyVertex->getVertexDataSize());
2867 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input", "Dynamically set vertex input", config));
2868 		}
2869 
2870 		extendedDynamicStateGroup->addChild(orderingGroup.release());
2871 	}
2872 
2873 	return extendedDynamicStateGroup.release();
2874 }
2875 
2876 } // pipeline
2877 } // vkt
2878