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 #include "vktCustomInstancesDevices.hpp"
29 
30 #include "vkDefs.hpp"
31 #include "vkTypeUtil.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkObjUtil.hpp"
34 #include "vkBufferWithMemory.hpp"
35 #include "vkImageWithMemory.hpp"
36 #include "vkBuilderUtil.hpp"
37 #include "vkCmdUtil.hpp"
38 #include "vkImageUtil.hpp"
39 #include "vkBarrierUtil.hpp"
40 
41 #include "tcuVector.hpp"
42 #include "tcuMaybe.hpp"
43 #include "tcuTestLog.hpp"
44 #include "tcuVectorUtil.hpp"
45 #include "tcuStringTemplate.hpp"
46 #include "tcuTextureUtil.hpp"
47 #include "tcuCommandLine.hpp"
48 
49 #include "deUniquePtr.hpp"
50 #include "deStringUtil.hpp"
51 
52 #include <vector>
53 #include <sstream>
54 #include <algorithm>
55 #include <utility>
56 #include <iterator>
57 #include <string>
58 #include <limits>
59 #include <memory>
60 #include <functional>
61 #include <cstddef>
62 #include <set>
63 
64 namespace vkt
65 {
66 namespace pipeline
67 {
68 
69 namespace
70 {
71 
makeVkBool32(bool value)72 inline vk::VkBool32 makeVkBool32(bool value)
73 {
74 	return (value ? VK_TRUE : VK_FALSE);
75 }
76 
77 #ifndef CTS_USES_VULKANSC
makeProvokingVertexMode(bool lastVertex)78 vk::VkProvokingVertexModeEXT makeProvokingVertexMode (bool lastVertex)
79 {
80 	return (lastVertex ? vk::VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT : vk::VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT);
81 }
82 #endif // CTS_USES_VULKANSC
83 
84 // Framebuffer size.
85 constexpr deUint32	kFramebufferWidth	= 64u;
86 constexpr deUint32	kFramebufferHeight	= 64u;
87 const auto			kFramebufferExtent	= vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
88 
89 // Image formats.
90 constexpr	vk::VkFormat	kUnormColorFormat		= vk::VK_FORMAT_R8G8B8A8_UNORM;
91 constexpr	vk::VkFormat	kIntColorFormat			= vk::VK_FORMAT_R8G8B8A8_UINT;
92 constexpr	vk::VkFormat	kIntRedColorFormat		= vk::VK_FORMAT_R32_UINT;
93 const		tcu::Vec4		kUnormColorThreshold	(0.005f); // 1/255 < 0.005 < 2/255.
94 
95 // This sample count must be supported for all formats supporting VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT.
96 // See 44.1.1. Supported Sample Counts.
97 const auto kMultiSampleCount	= vk::VK_SAMPLE_COUNT_4_BIT;
98 const auto kSingleSampleCount	= vk::VK_SAMPLE_COUNT_1_BIT;
99 
100 // Image usage flags.
101 const vk::VkImageUsageFlags kColorUsage	= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
102 const vk::VkImageUsageFlags kDSUsage	= (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
103 
104 // Color components.
105 const auto CR = vk::VK_COLOR_COMPONENT_R_BIT;
106 const auto CG = vk::VK_COLOR_COMPONENT_G_BIT;
107 const auto CB = vk::VK_COLOR_COMPONENT_B_BIT;
108 const auto CA = vk::VK_COLOR_COMPONENT_A_BIT;
109 
componentCodes(vk::VkColorComponentFlags components)110 std::string componentCodes (vk::VkColorComponentFlags components)
111 {
112 	std::string name;
113 
114 	if ((components & CR) != 0u) name += "r";
115 	if ((components & CG) != 0u) name += "g";
116 	if ((components & CB) != 0u) name += "b";
117 	if ((components & CA) != 0u) name += "a";
118 
119 	if (name.empty())
120 		name = "0";
121 	return name;
122 }
123 
124 // Chooses clear or geometry color depending on the selected components.
filterColor(const tcu::Vec4& clearColor, const tcu::Vec4& color, vk::VkColorComponentFlags components)125 tcu::Vec4 filterColor (const tcu::Vec4& clearColor, const tcu::Vec4& color, vk::VkColorComponentFlags components)
126 {
127 	const tcu::Vec4 finalColor
128 	(
129 		(((components & CR) != 0u) ? color[0] : clearColor[0]),
130 		(((components & CG) != 0u) ? color[1] : clearColor[1]),
131 		(((components & CB) != 0u) ? color[2] : clearColor[2]),
132 		(((components & CA) != 0u) ? color[3] : clearColor[3])
133 	);
134 	return finalColor;
135 }
136 
137 struct DepthStencilFormat
138 {
139 	vk::VkFormat	imageFormat;
140 	float			depthThreshold;
141 };
142 
143 const DepthStencilFormat kDepthStencilFormats[] =
144 {
145 	{ vk::VK_FORMAT_D32_SFLOAT_S8_UINT,	0.0f		},
146 	{ vk::VK_FORMAT_D24_UNORM_S8_UINT,	1.0e-07f	},	// 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
147 };
148 
149 using StrideVec = std::vector<vk::VkDeviceSize>;
150 
151 // We will use several data types in vertex bindings. Each type will need to define a few things.
152 class VertexGenerator
153 {
154 public:
155 	// For GLSL.
156 
157 	// Vertex input/output attribute declarations in GLSL form. One sentence per element.
158 	virtual std::vector<std::string>								getAttributeDeclarations()	const = 0;
159 
160 	// Get statements to calculate a vec2 called "vertexCoords" using the vertex input attributes.
161 	virtual std::vector<std::string>								getVertexCoordCalc()		const = 0;
162 
163 	// Get vertex binding declarations as part of descriptor sets, used for mesh shading.
164 	virtual std::vector<std::string>								getDescriptorDeclarations()	const = 0;
165 
166 	// Get statements  to calculate a vec2 called "vertexCoords" using descriptor members.
167 	virtual std::vector<std::string>								getDescriptorCoordCalc()	const = 0;
168 
169 	// Get fragment input attribute declarations in GLSL form. One sentence per element.
getFragInputAttributes() const170 	virtual std::vector<std::string>								getFragInputAttributes()	const { return std::vector<std::string>(); }
171 
172 	// Get fragment output post-calculations, maybe altering the "color" output variable.
getFragOutputCalc() const173 	virtual std::vector<std::string>								getFragOutputCalc()			const { return std::vector<std::string>(); }
174 
175 
176 	// For the pipeline.
177 
178 	// Vertex attributes for VkPipelineVertexInputStateCreateInfo.
179 	virtual std::vector<vk::VkVertexInputAttributeDescription>		getAttributeDescriptions() const = 0;
180 
181 	// Vertex attributes for VK_EXT_vertex_input_dynamic_state.
182 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT>	getAttributeDescriptions2()	const = 0;
183 
184 	// Vertex bindings for VkPipelineVertexInputStateCreateInfo.
185 	virtual std::vector<vk::VkVertexInputBindingDescription>		getBindingDescriptions (const StrideVec& strides) const = 0;
186 
187 	// Vertex bindings for VK_EXT_vertex_input_dynamic_state.
188 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT>	getBindingDescriptions2 (const StrideVec& strides) const = 0;
189 
190 	// Create buffer data given an array of coordinates and an initial padding.
191 	virtual std::vector<std::vector<deUint8>>						createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const = 0;
192 
193 	// Stride of vertex data in each binding.
194 	virtual std::vector<vk::VkDeviceSize>							getVertexDataStrides() const = 0;
195 };
196 
197 // Auxiliar function to create these structs more easily.
makeVertexInputAttributeDescription2EXT(deUint32 location, deUint32 binding, vk::VkFormat format, deUint32 offset)198 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT (deUint32 location, deUint32 binding, vk::VkFormat format, deUint32 offset)
199 {
200 	vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
201 	desc.location = location;
202 	desc.binding = binding;
203 	desc.format = format;
204 	desc.offset = offset;
205 	return desc;
206 }
207 
makeVertexInputBindingDescription2EXT(deUint32 binding, deUint32 stride, vk::VkVertexInputRate inputRate)208 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT (deUint32 binding, deUint32 stride, vk::VkVertexInputRate inputRate)
209 {
210 	vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
211 	desc.binding = binding;
212 	desc.stride = stride;
213 	desc.inputRate = inputRate;
214 	desc.divisor = 1u;
215 	return desc;
216 }
217 
218 // Fill a section of the given buffer (from offset to offset+count) with repeating copies of the given data.
fillWithPattern(void* ptr_, size_t offset, size_t count, const void* src, size_t srcSize)219 void fillWithPattern(void* ptr_, size_t offset, size_t count, const void* src, size_t srcSize)
220 {
221 	auto	ptr		= reinterpret_cast<char*>(ptr_);
222 	size_t	done	= 0u;
223 	size_t	pending	= count;
224 
225 	while (pending > 0u)
226 	{
227 		const size_t stepSize = de::min(srcSize, pending);
228 		deMemcpy(ptr + offset + done, src, stepSize);
229 		done += stepSize;
230 		pending -= stepSize;
231 	}
232 }
233 
234 // Create a single binding vertex data vector given a type T for vertex data.
235 template<class T>
createSingleBindingVertexData(const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize)236 std::vector<deUint8> createSingleBindingVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize)
237 {
238 	DE_ASSERT(!coords.empty());
239 
240 	const auto dataOffsetSz			= static_cast<size_t>(dataOffset);
241 	const auto trailingPaddingSz	= static_cast<size_t>(trailingPadding);
242 
243 	std::vector<deUint8> buffer;
244 	buffer.resize(dataOffsetSz + coords.size() * sizeof(T) + trailingPaddingSz);
245 
246 	fillWithPattern(buffer.data(), 0u, dataOffsetSz, paddingPattern, patternSize);
247 
248 	auto pos = dataOffsetSz;
249 	for (const auto& coord : coords)
250 	{
251 		new (&buffer[pos]) T(coord);
252 		pos += sizeof(T);
253 	}
254 
255 	fillWithPattern(buffer.data(), pos, trailingPaddingSz, paddingPattern, patternSize);
256 
257 	return buffer;
258 }
259 
260 // Vertices in buffers will have 2 components and a padding to properly test the stride.
261 // This is the vertex type that will be used normally.
262 class VertexWithPadding : public VertexGenerator
263 {
264 protected:
265 	struct VertexData
266 	{
VertexDatavkt::pipeline::__anon29419::VertexWithPadding::VertexData267 		VertexData(const tcu::Vec2& coords_)
268 			: coords	(coords_)
269 			, padding	(0.0f, 0.0f)
270 		{}
271 
272 		tcu::Vec2 coords;
273 		tcu::Vec2 padding;
274 	};
275 
276 public:
277 	virtual std::vector<std::string> getAttributeDeclarations() const override
278 	{
279 		std::vector<std::string> declarations;
280 		declarations.push_back("layout(location=0) in vec2 position;");
281 		return declarations;
282 	}
283 
284 	virtual std::vector<std::string> getVertexCoordCalc() const override
285 	{
286 		std::vector<std::string> statements;
287 		statements.push_back("vec2 vertexCoords = position;");
288 		return statements;
289 	}
290 
291 	virtual std::vector<std::string> getDescriptorDeclarations() const override
292 	{
293 		std::vector<std::string> declarations;
294 		declarations.reserve(7u);
295 		declarations.push_back("struct VertexData {");
296 		declarations.push_back("    vec2 position;");
297 		declarations.push_back("    vec2 padding;");
298 		declarations.push_back("};");
299 		declarations.push_back("layout(set=0, binding=0, std430) readonly buffer S0B0Block {");
300 		declarations.push_back("    VertexData data[];");
301 		declarations.push_back("} s0b0buffer;");
302 		return declarations;
303 	}
304 
305 	virtual std::vector<std::string> getDescriptorCoordCalc() const override
306 	{
307 		std::vector<std::string> statements;
308 		statements.reserve(4u);
309 		statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
310 		statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
311 		statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
312 		statements.push_back("vec2 vertexCoords = s0b0buffer.data[invIndex].position;");
313 		return statements;
314 	}
315 
316 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
317 	{
318 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
319 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
320 		return descriptions;
321 	}
322 
323 	// Vertex attributes for VK_EXT_vertex_input_dynamic_state.
324 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
325 	{
326 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
327 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
328 		return descriptions;
329 	}
330 
331 	// Vertex bindings for VkPipelineVertexInputStateCreateInfo.
332 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
333 	{
334 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
335 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
336 		return descriptions;
337 	}
338 
339 	// Vertex bindings for VK_EXT_vertex_input_dynamic_state.
340 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
341 	{
342 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
343 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
344 		return descriptions;
345 	}
346 
347 	virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
348 	{
349 		return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
350 	}
351 
352 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
353 	{
354 		return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
355 	}
356 };
357 
358 // Vertex generator used when testing provoking vertices. It has an extra flat vertex output that's also a frag input. Note this
359 // generator only works with 3 vertices.
360 class ProvokingVertexWithPadding : public VertexWithPadding
361 {
362 protected:
363 	bool m_lastVertex;
364 
365 public:
ProvokingVertexWithPadding(bool lastVertex)366 	ProvokingVertexWithPadding (bool lastVertex)
367 		: m_lastVertex (lastVertex)
368 	{}
369 
370 	virtual std::vector<std::string> getAttributeDeclarations() const override
371 	{
372 		auto declarations = VertexWithPadding::getAttributeDeclarations();
373 		declarations.push_back("layout(location=0) flat out uint colorMultiplier;");
374 		return declarations;
375 	}
376 
377 	virtual std::vector<std::string> getDescriptorDeclarations() const override
378 	{
379 		auto declarations = VertexWithPadding::getDescriptorDeclarations();
380 		declarations.push_back("layout(location=0) flat out uint colorMultiplier[];");
381 		return declarations;
382 	}
383 
384 	virtual std::vector<std::string> getVertexCoordCalc() const override
385 	{
386 		auto statements = VertexWithPadding::getVertexCoordCalc();
387 		statements.push_back("const bool provokingLast = " + std::string(m_lastVertex ? "true" : "false") + ";");
388 		statements.push_back("colorMultiplier = (((!provokingLast && gl_VertexIndex == 0) || (provokingLast && gl_VertexIndex == 2)) ? 1 : 0);");
389 		return statements;
390 	}
391 
392 	virtual std::vector<std::string> getDescriptorCoordCalc() const override
393 	{
394 		auto statements = VertexWithPadding::getDescriptorCoordCalc();
395 		statements.push_back("const bool provokingLast = " + std::string(m_lastVertex ? "true" : "false") + ";");
396 		statements.push_back("colorMultiplier[gl_LocalInvocationIndex] = (((!provokingLast && gl_LocalInvocationIndex == 0) || (provokingLast && gl_LocalInvocationIndex == 2)) ? 1 : 0);");
397 		return statements;
398 	}
399 
400 	virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
401 	{
402 		static constexpr uint32_t kExpectecdCoordCount = 3u;
403 		DE_UNREF(kExpectecdCoordCount); // For release builds.
404 		DE_ASSERT(coords.size() == kExpectecdCoordCount);
405 		return VertexWithPadding::createVertexData(coords, dataOffset, trailingPadding, paddingPattern, patternSize);
406 	}
407 
408 	virtual std::vector<std::string> getFragInputAttributes() const override
409 	{
410 		std::vector<std::string> declarations;
411 		declarations.push_back("layout(location=0) flat in uint colorMultiplier;");
412 		return declarations;
413 	}
414 
415 	virtual std::vector<std::string> getFragOutputCalc() const override
416 	{
417 		std::vector<std::string> statements;
418 		statements.push_back("color = color * float(colorMultiplier);");
419 		return statements;
420 	}
421 };
422 
423 // Vertices with coordinates, padding and an extra constant field.
424 class VertexWithExtraAttributes : public VertexGenerator
425 {
426 protected:
427 	struct VertexData
428 	{
VertexDatavkt::pipeline::__anon29419::VertexWithExtraAttributes::VertexData429 		VertexData (const tcu::Vec2& coords_)
430 			: coords	(coords_)
431 			, ones		(1.0f, 1.0f)
432 		{
433 			deMemset(padding, 0, sizeof(padding));
434 		}
435 
436 		tcu::Vec2 coords;
437 		tcu::Vec2 padding[10];
438 		tcu::Vec2 ones;
439 	};
440 
441 public:
442 	virtual std::vector<std::string> getAttributeDeclarations() const override
443 	{
444 		std::vector<std::string> declarations;
445 		declarations.reserve(2u);
446 		declarations.push_back("layout(location=0) in vec2 position;");
447 		declarations.push_back("layout(location=1) in vec2 ones;");
448 		return declarations;
449 	}
450 
451 	virtual std::vector<std::string> getVertexCoordCalc() const override
452 	{
453 		std::vector<std::string> statements;
454 		statements.reserve(2u);
455 		statements.push_back("vec2 vertexCoords = position;");
456 		statements.push_back("vertexCoords = vertexCoords * ones;");
457 		return statements;
458 	}
459 
460 	virtual std::vector<std::string> getDescriptorDeclarations() const override
461 	{
462 		std::vector<std::string> declarations;
463 		declarations.reserve(8u);
464 		declarations.push_back("struct VertexData {");
465 		declarations.push_back("    vec2 coords;");
466 		declarations.push_back("    vec2 padding[10];");
467 		declarations.push_back("    vec2 ones;");
468 		declarations.push_back("};");
469 		declarations.push_back("layout(set=0, binding=0, std430) readonly buffer S0B0Block {");
470 		declarations.push_back("    VertexData data[];");
471 		declarations.push_back("} s0b0buffer;");
472 		return declarations;
473 	}
474 
475 	virtual std::vector<std::string> getDescriptorCoordCalc() const override
476 	{
477 		std::vector<std::string> statements;
478 		statements.reserve(6u);
479 		statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
480 		statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
481 		statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
482 		statements.push_back("vec2 auxPos = s0b0buffer.data[invIndex].coords;");
483 		statements.push_back("vec2 auxOnes = s0b0buffer.data[invIndex].ones;");
484 		statements.push_back("vec2 vertexCoords = auxPos * auxOnes;");
485 		return statements;
486 	}
487 
488 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
489 	{
490 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
491 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
492 		descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
493 		return descriptions;
494 	}
495 
496 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
497 	{
498 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
499 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
500 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
501 		return descriptions;
502 	}
503 
504 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
505 	{
506 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
507 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
508 		return descriptions;
509 	}
510 
511 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
512 	{
513 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
514 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
515 		return descriptions;
516 	}
517 
518 	virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
519 	{
520 		return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
521 	}
522 
523 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
524 	{
525 		return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
526 	}
527 };
528 
529 // Vertices using multiple bindings and constant fields.
530 // Binding 0: no data actually used.
531 // Binding 1: contains location 0, array of PaddingOnes.
532 // Binding 2: no data actually used.
533 // Binding 3: contains location 1, array of CoordsData.
534 // Binding 4: no data actually used.
535 // Binding 5: contains location 2, array of OneZeroPadding.
536 // See getAttributeDeclarations().
537 class MultipleBindingsVertex : public VertexGenerator
538 {
539 protected:
540 	struct CoordsData
541 	{
542 		tcu::Vec2 padding0;
543 		tcu::Vec2 coords;
544 		tcu::Vec2 padding1;
545 
CoordsDatavkt::pipeline::__anon29419::MultipleBindingsVertex::CoordsData546 		CoordsData (const tcu::Vec2& coords_)
547 			: padding0	(0.0f, 3.0f)
548 			, coords	(coords_)
549 			, padding1	(3.0f, 0.0f)
550 		{}
551 	};
552 
553 	struct PaddingOnes
554 	{
555 		tcu::Vec2 padding[4];
556 		tcu::Vec2 ones;
557 
PaddingOnesvkt::pipeline::__anon29419::MultipleBindingsVertex::PaddingOnes558 		PaddingOnes (const tcu::Vec2&)
559 			: ones	(1.0f, 1.0f)
560 		{
561 			deMemset(&padding, 0, sizeof(padding));
562 		}
563 	};
564 
565 	struct OneZeroPadding
566 	{
567 		tcu::Vec4 oneZero;
568 		tcu::Vec2 padding[3];
569 
OneZeroPaddingvkt::pipeline::__anon29419::MultipleBindingsVertex::OneZeroPadding570 		OneZeroPadding (const tcu::Vec2&)
571 			: oneZero	(1.0f, 1.0f, 0.0f, 0.0f)
572 		{
573 			deMemset(&padding, 0, sizeof(padding));
574 		}
575 	};
576 
577 	struct Zeros
578 	{
579 		tcu::Vec2 zeros;
580 
Zerosvkt::pipeline::__anon29419::MultipleBindingsVertex::Zeros581 		Zeros (const tcu::Vec2&)
582 			: zeros	(0.0f, 0.0f)
583 		{}
584 	};
585 
586 public:
587 	virtual std::vector<std::string> getAttributeDeclarations() const override
588 	{
589 		std::vector<std::string> declarations;
590 		declarations.reserve(3u);
591 
592 		declarations.push_back("layout(location=0) in vec2 ones;");
593 		declarations.push_back("layout(location=1) in vec2 position;");
594 		declarations.push_back("layout(location=2) in vec4 oneZero;");
595 
596 		return declarations;
597 	}
598 
599 	virtual std::vector<std::string> getVertexCoordCalc() const override
600 	{
601 		std::vector<std::string> statements;
602 		statements.reserve(2u);
603 
604 		statements.push_back("vec2 vertexCoords = position;");
605 		statements.push_back("vertexCoords = ((vertexCoords * ones) + oneZero.zw) * oneZero.xy;");
606 
607 		return statements;
608 	}
609 
610 	virtual std::vector<std::string> getDescriptorDeclarations() const override
611 	{
612 		std::vector<std::string> declarations;
613 		declarations.reserve(23u);
614 
615 		declarations.push_back("struct PaddingOnes {");
616 		declarations.push_back("    vec2 padding[4];");
617 		declarations.push_back("    vec2 ones;");
618 		declarations.push_back("};");
619 		declarations.push_back("struct CoordsData {");
620 		declarations.push_back("    vec2 padding0;");
621 		declarations.push_back("    vec2 coords;");
622 		declarations.push_back("    vec2 padding1;");
623 		declarations.push_back("};");
624 		declarations.push_back("struct OneZeroPadding {");
625 		declarations.push_back("    vec2 ones;");		// Note: we split the vec4 into two vec2s to match CPU-side alignment.
626 		declarations.push_back("    vec2 zeros;");
627 		declarations.push_back("    vec2 padding[3];");
628 		declarations.push_back("};");
629 		declarations.push_back("layout(set=0, binding=1, std430) readonly buffer S0B1Block {");
630 		declarations.push_back("    PaddingOnes data[];");
631 		declarations.push_back("} s0b1buffer;");
632 		declarations.push_back("layout(set=0, binding=3, std430) readonly buffer S0B3Block {");
633 		declarations.push_back("    CoordsData data[];");
634 		declarations.push_back("} s0b3buffer;");
635 		declarations.push_back("layout(set=0, binding=4, std430) readonly buffer S0B5Block {");
636 		declarations.push_back("    OneZeroPadding data[];");
637 		declarations.push_back("} s0b5buffer;");
638 
639 		return declarations;
640 	}
641 
642 	virtual std::vector<std::string> getDescriptorCoordCalc() const override
643 	{
644 		std::vector<std::string> statements;
645 		statements.reserve(8u);
646 		statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
647 		statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
648 		statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
649 		statements.push_back("vec2 auxOnes1 = s0b1buffer.data[invIndex].ones;");
650 		statements.push_back("vec2 auxCoords = s0b3buffer.data[invIndex].coords;");
651 		statements.push_back("vec2 auxOnes5 = s0b5buffer.data[invIndex].ones;");
652 		statements.push_back("vec2 auxZeros = s0b5buffer.data[invIndex].zeros;");
653 		statements.push_back("vec2 vertexCoords = ((auxCoords * auxOnes1) + auxZeros) * auxOnes5;");
654 		return statements;
655 	}
656 
657 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
658 	{
659 		// We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
660 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
661 		descriptions.reserve(3u);
662 
663 		descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
664 		descriptions.push_back(vk::makeVertexInputAttributeDescription(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
665 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
666 
667 		return descriptions;
668 	}
669 
670 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
671 	{
672 		// We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
673 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
674 		descriptions.reserve(3u);
675 
676 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
677 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
678 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
679 
680 		return descriptions;
681 	}
682 
683 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
684 	{
685 		// Provide descriptions out of order to make it more interesting.
686 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
687 		descriptions.reserve(6u);
688 
689 		descriptions.push_back(vk::makeVertexInputBindingDescription(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
690 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
691 		descriptions.push_back(vk::makeVertexInputBindingDescription(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
692 		descriptions.push_back(vk::makeVertexInputBindingDescription(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
693 		descriptions.push_back(vk::makeVertexInputBindingDescription(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
694 		descriptions.push_back(vk::makeVertexInputBindingDescription(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
695 
696 		return descriptions;
697 	}
698 
699 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
700 	{
701 		// Provide descriptions out of order to make it more interesting.
702 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
703 		descriptions.reserve(6u);
704 
705 		descriptions.push_back(makeVertexInputBindingDescription2EXT(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
706 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
707 		descriptions.push_back(makeVertexInputBindingDescription2EXT(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
708 		descriptions.push_back(makeVertexInputBindingDescription2EXT(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
709 		descriptions.push_back(makeVertexInputBindingDescription2EXT(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
710 		descriptions.push_back(makeVertexInputBindingDescription2EXT(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
711 
712 		return descriptions;
713 	}
714 
715 	virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
716 	{
717 		std::vector<std::vector<deUint8>> result;
718 		result.reserve(6u);
719 
720 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
721 		result.push_back(createSingleBindingVertexData<PaddingOnes>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));		// Binding 1 contains location=0 as PaddingOnes.
722 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
723 		result.push_back(createSingleBindingVertexData<CoordsData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));		// Binding 3 contains location=1 as CoordsData.
724 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
725 		result.push_back(createSingleBindingVertexData<OneZeroPadding>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));	// Binding 5 contains location=2 as OneZeroPadding.
726 
727 		return result;
728 	}
729 
730 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
731 	{
732 		std::vector<vk::VkDeviceSize> strides;
733 		strides.reserve(6u);
734 
735 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
736 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(PaddingOnes)));
737 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
738 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(CoordsData)));
739 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
740 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(OneZeroPadding)));
741 
742 		return strides;
743 	}
744 };
745 
746 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
747 struct StencilOpParams
748 {
749 	vk::VkStencilFaceFlags  faceMask;
750 	vk::VkStencilOp         failOp;
751 	vk::VkStencilOp         passOp;
752 	vk::VkStencilOp         depthFailOp;
753 	vk::VkCompareOp         compareOp;
754 };
755 
756 const StencilOpParams kDefaultStencilOpParams =
757 {
758 	vk::VK_STENCIL_FACE_FRONT_AND_BACK,
759 	vk::VK_STENCIL_OP_KEEP,
760 	vk::VK_STENCIL_OP_KEEP,
761 	vk::VK_STENCIL_OP_KEEP,
762 	vk::VK_COMPARE_OP_ALWAYS
763 };
764 
765 struct DepthBiasParams
766 {
767 	float constantFactor;
768 	float clamp;
769 };
770 
isAdvancedBlendOp(const vk::VkBlendOp blendOp)771 bool isAdvancedBlendOp (const vk::VkBlendOp blendOp)
772 {
773 	bool advanced = false;
774 
775 	switch (blendOp)
776 	{
777 	case vk::VK_BLEND_OP_ZERO_EXT:
778 	case vk::VK_BLEND_OP_SRC_EXT:
779 	case vk::VK_BLEND_OP_DST_EXT:
780 	case vk::VK_BLEND_OP_SRC_OVER_EXT:
781 	case vk::VK_BLEND_OP_DST_OVER_EXT:
782 	case vk::VK_BLEND_OP_SRC_IN_EXT:
783 	case vk::VK_BLEND_OP_DST_IN_EXT:
784 	case vk::VK_BLEND_OP_SRC_OUT_EXT:
785 	case vk::VK_BLEND_OP_DST_OUT_EXT:
786 	case vk::VK_BLEND_OP_SRC_ATOP_EXT:
787 	case vk::VK_BLEND_OP_DST_ATOP_EXT:
788 	case vk::VK_BLEND_OP_XOR_EXT:
789 	case vk::VK_BLEND_OP_MULTIPLY_EXT:
790 	case vk::VK_BLEND_OP_SCREEN_EXT:
791 	case vk::VK_BLEND_OP_OVERLAY_EXT:
792 	case vk::VK_BLEND_OP_DARKEN_EXT:
793 	case vk::VK_BLEND_OP_LIGHTEN_EXT:
794 	case vk::VK_BLEND_OP_COLORDODGE_EXT:
795 	case vk::VK_BLEND_OP_COLORBURN_EXT:
796 	case vk::VK_BLEND_OP_HARDLIGHT_EXT:
797 	case vk::VK_BLEND_OP_SOFTLIGHT_EXT:
798 	case vk::VK_BLEND_OP_DIFFERENCE_EXT:
799 	case vk::VK_BLEND_OP_EXCLUSION_EXT:
800 	case vk::VK_BLEND_OP_INVERT_EXT:
801 	case vk::VK_BLEND_OP_INVERT_RGB_EXT:
802 	case vk::VK_BLEND_OP_LINEARDODGE_EXT:
803 	case vk::VK_BLEND_OP_LINEARBURN_EXT:
804 	case vk::VK_BLEND_OP_VIVIDLIGHT_EXT:
805 	case vk::VK_BLEND_OP_LINEARLIGHT_EXT:
806 	case vk::VK_BLEND_OP_PINLIGHT_EXT:
807 	case vk::VK_BLEND_OP_HARDMIX_EXT:
808 	case vk::VK_BLEND_OP_HSL_HUE_EXT:
809 	case vk::VK_BLEND_OP_HSL_SATURATION_EXT:
810 	case vk::VK_BLEND_OP_HSL_COLOR_EXT:
811 	case vk::VK_BLEND_OP_HSL_LUMINOSITY_EXT:
812 	case vk::VK_BLEND_OP_PLUS_EXT:
813 	case vk::VK_BLEND_OP_PLUS_CLAMPED_EXT:
814 	case vk::VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT:
815 	case vk::VK_BLEND_OP_PLUS_DARKER_EXT:
816 	case vk::VK_BLEND_OP_MINUS_EXT:
817 	case vk::VK_BLEND_OP_MINUS_CLAMPED_EXT:
818 	case vk::VK_BLEND_OP_CONTRAST_EXT:
819 	case vk::VK_BLEND_OP_INVERT_OVG_EXT:
820 	case vk::VK_BLEND_OP_RED_EXT:
821 	case vk::VK_BLEND_OP_GREEN_EXT:
822 	case vk::VK_BLEND_OP_BLUE_EXT:
823 		advanced = true;
824 		break;
825 	default:
826 		advanced = false;
827 		break;
828 	}
829 
830 	return advanced;
831 }
832 
833 struct ColorBlendEq
834 {
835 	vk::VkBlendFactor	srcColorBlendFactor;
836 	vk::VkBlendFactor	dstColorBlendFactor;
837 	vk::VkBlendOp		colorBlendOp;
838 	vk::VkBlendFactor	srcAlphaBlendFactor;
839 	vk::VkBlendFactor	dstAlphaBlendFactor;
840 	vk::VkBlendOp		alphaBlendOp;
841 
ColorBlendEqvkt::pipeline::__anon29419::ColorBlendEq842 	ColorBlendEq ()
843 		: srcColorBlendFactor	(vk::VK_BLEND_FACTOR_ZERO)
844 		, dstColorBlendFactor	(vk::VK_BLEND_FACTOR_ZERO)
845 		, colorBlendOp			(vk::VK_BLEND_OP_ADD)
846 		, srcAlphaBlendFactor	(vk::VK_BLEND_FACTOR_ZERO)
847 		, dstAlphaBlendFactor	(vk::VK_BLEND_FACTOR_ZERO)
848 		, alphaBlendOp			(vk::VK_BLEND_OP_ADD)
849 	{}
850 
ColorBlendEqvkt::pipeline::__anon29419::ColorBlendEq851 	ColorBlendEq (vk::VkBlendFactor	srcColorBlendFactor_,
852 				  vk::VkBlendFactor	dstColorBlendFactor_,
853 				  vk::VkBlendOp		colorBlendOp_,
854 				  vk::VkBlendFactor	srcAlphaBlendFactor_,
855 				  vk::VkBlendFactor	dstAlphaBlendFactor_,
856 				  vk::VkBlendOp		alphaBlendOp_)
857 		: srcColorBlendFactor	(srcColorBlendFactor_)
858 		, dstColorBlendFactor	(dstColorBlendFactor_)
859 		, colorBlendOp			(colorBlendOp_)
860 		, srcAlphaBlendFactor	(srcAlphaBlendFactor_)
861 		, dstAlphaBlendFactor	(dstAlphaBlendFactor_)
862 		, alphaBlendOp			(alphaBlendOp_)
863 	{
864 		if (isAdvancedBlendOp(colorBlendOp))
865 			DE_ASSERT(colorBlendOp == alphaBlendOp);
866 	}
867 
isAdvancedvkt::pipeline::__anon29419::ColorBlendEq868 	bool isAdvanced () const
869 	{
870 		return isAdvancedBlendOp(colorBlendOp);
871 	}
872 };
873 
874 const DepthBiasParams kNoDepthBiasParams = { 0.0f, 0.0f };
875 
876 struct LineStippleParams
877 {
878 	uint32_t factor;
879 	uint16_t pattern;
880 };
881 
882 enum class LineRasterizationMode
883 {
884 	NONE = 0,
885 	RECTANGULAR,
886 	BRESENHAM,
887 	SMOOTH,
888 };
889 
890 using ViewportVec		= std::vector<vk::VkViewport>;
891 using ScissorVec		= std::vector<vk::VkRect2D>;
892 using StencilOpVec		= std::vector<StencilOpParams>;
893 using SampleMaskVec		= std::vector<vk::VkSampleMask>;
894 using OptRastStream		= tcu::Maybe<uint32_t>;
895 using OptBoolean		= tcu::Maybe<bool>;
896 using OptStippleParams	= tcu::Maybe<LineStippleParams>;
897 using OptLineRasterMode	= tcu::Maybe<LineRasterizationMode>;
898 using OptSampleCount	= tcu::Maybe<vk::VkSampleCountFlagBits>;
899 using CovModTableVec	= std::vector<float>;
900 #ifndef CTS_USES_VULKANSC
901 using ViewportSwzVec	= std::vector<vk::VkViewportSwizzleNV>;
902 #endif // CTS_USES_VULKANSC
903 
904 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
905 template<typename T>
906 struct StaticAndDynamicPair
907 {
908 	T				staticValue;
909 	tcu::Maybe<T>	dynamicValue;
910 
911 	// Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon29419::StaticAndDynamicPair912 	StaticAndDynamicPair (const T& value)
913 		: staticValue	(value)
914 		, dynamicValue	(tcu::Nothing)
915 	{
916 	}
917 
918 	// Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon29419::StaticAndDynamicPair919 	StaticAndDynamicPair (const T& sVal, const T& dVal)
920 		: staticValue	(sVal)
921 		, dynamicValue	(tcu::just<T>(dVal))
922 	{
923 	}
924 
925 	// If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon29419::StaticAndDynamicPair926 	void swapValues (void)
927 	{
928 		if (!dynamicValue)
929 			return;
930 		std::swap(staticValue, dynamicValue.get());
931 	}
932 };
933 
934 // For anything boolean, see below.
935 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
936 
937 // Configuration for every aspect of the extended dynamic state.
938 using CullModeConfig				= StaticAndDynamicPair<vk::VkCullModeFlags>;
939 using FrontFaceConfig				= StaticAndDynamicPair<vk::VkFrontFace>;
940 using TopologyConfig				= StaticAndDynamicPair<vk::VkPrimitiveTopology>;
941 using ViewportConfig				= StaticAndDynamicPair<ViewportVec>;	// At least one element.
942 using ScissorConfig					= StaticAndDynamicPair<ScissorVec>;		// At least one element.
943 using StrideConfig					= StaticAndDynamicPair<StrideVec>;		// At least one element.
944 using DepthTestEnableConfig			= BooleanFlagConfig;
945 using DepthWriteEnableConfig		= BooleanFlagConfig;
946 using DepthCompareOpConfig			= StaticAndDynamicPair<vk::VkCompareOp>;
947 using DepthBoundsTestEnableConfig	= BooleanFlagConfig;
948 using StencilTestEnableConfig		= BooleanFlagConfig;
949 using StencilOpConfig				= StaticAndDynamicPair<StencilOpVec>;	// At least one element.
950 using VertexGeneratorConfig			= StaticAndDynamicPair<const VertexGenerator*>;
951 using DepthBiasEnableConfig			= BooleanFlagConfig;
952 using RastDiscardEnableConfig		= BooleanFlagConfig;
953 using PrimRestartEnableConfig		= BooleanFlagConfig;
954 using LogicOpConfig					= StaticAndDynamicPair<vk::VkLogicOp>;
955 using PatchControlPointsConfig		= StaticAndDynamicPair<deUint8>;
956 using DepthBiasConfig				= StaticAndDynamicPair<DepthBiasParams>;
957 using TessDomainOriginConfig		= StaticAndDynamicPair<vk::VkTessellationDomainOrigin>;
958 using DepthClampEnableConfig		= BooleanFlagConfig;
959 using PolygonModeConfig				= StaticAndDynamicPair<vk::VkPolygonMode>;
960 using SampleMaskConfig				= StaticAndDynamicPair<SampleMaskVec>;
961 using AlphaToCoverageConfig			= BooleanFlagConfig;
962 using AlphaToOneConfig				= BooleanFlagConfig;
963 using ColorWriteMaskConfig			= StaticAndDynamicPair<vk::VkColorComponentFlags>;
964 using RasterizationStreamConfig		= StaticAndDynamicPair<OptRastStream>;
965 using LogicOpEnableConfig			= BooleanFlagConfig;
966 using ColorBlendEnableConfig		= BooleanFlagConfig;
967 using ColorBlendEquationConfig		= StaticAndDynamicPair<ColorBlendEq>;
968 using ProvokingVertexConfig			= StaticAndDynamicPair<OptBoolean>;	// First vertex boolean flag.
969 using NegativeOneToOneConfig		= StaticAndDynamicPair<OptBoolean>;
970 using DepthClipEnableConfig			= StaticAndDynamicPair<OptBoolean>;
971 using LineStippleEnableConfig		= BooleanFlagConfig;
972 using LineStippleParamsConfig		= StaticAndDynamicPair<OptStippleParams>;
973 using SampleLocationsEnableConfig	= BooleanFlagConfig;
974 using ConservativeRasterModeConfig	= StaticAndDynamicPair<vk::VkConservativeRasterizationModeEXT>;
975 using ExtraPrimitiveOverEstConfig	= StaticAndDynamicPair<float>; // Negative numbers will mean we're not interested in setting it.
976 using LineRasterModeConfig			= StaticAndDynamicPair<OptLineRasterMode>;
977 using CoverageToColorEnableConfig	= BooleanFlagConfig;
978 using CoverageToColorLocationConfig	= StaticAndDynamicPair<uint32_t>;
979 using RasterizationSamplesConfig	= StaticAndDynamicPair<vk::VkSampleCountFlagBits>;
980 #ifndef CTS_USES_VULKANSC
981 using CoverageModulationModeConfig	= StaticAndDynamicPair<vk::VkCoverageModulationModeNV>;
982 using CoverageModTableEnableConfig	= BooleanFlagConfig;
983 using CoverageModTableConfig		= StaticAndDynamicPair<CovModTableVec>;
984 using CoverageReductionModeConfig	= StaticAndDynamicPair<vk::VkCoverageReductionModeNV>;
985 using ViewportSwizzleConfig			= StaticAndDynamicPair<ViewportSwzVec>;
986 using ShadingRateImageEnableConfig	= BooleanFlagConfig;
987 using ViewportWScalingEnableConfig	= BooleanFlagConfig;
988 using ReprFragTestEnableConfig		= BooleanFlagConfig;
989 #endif // CTS_USES_VULKANSC
990 
991 const tcu::Vec4		kDefaultTriangleColor	(0.0f, 0.0f, 1.0f, 1.0f);	// Opaque blue.
992 const tcu::Vec4		kDefaultClearColor		(0.0f, 0.0f, 0.0f, 1.0f);	// Opaque black.
993 const tcu::Vec4		kTransparentColor		(0.0f, 0.0f, 1.0f, 0.0f);	// Transparent version of kDefaultTriangleColor.
994 const tcu::Vec4		kTransparentClearColor	(0.0f, 0.0f, 0.0f, 0.0f);	// Transparent version of kDefaultClearColor.
995 const tcu::Vec4		kOpaqueWhite			(1.0f, 1.0f, 1.0f, 1.0f);	// Opaque white, all components active.
996 
997 const tcu::UVec4	kLogicOpTriangleColor	(  0u,   0u, 255u, 255u);	// Opaque blue.
998 const tcu::UVec4	kGreenClearColor		(  0u, 255u,   0u, 255u);	// Opaque green, UINT.
999 const tcu::UVec4	kLogicOpFinalColor		(  0u, 255u, 255u, 255u);	// Opaque cyan, UINT.
1000 
1001 // Same as kLogicOpTriangleColor. Note: tcu::Vec4 and will be cast to the appropriate type in the shader.
1002 const tcu::Vec4 kLogicOpTriangleColorFl (static_cast<float>(kLogicOpTriangleColor.x()),
1003 										 static_cast<float>(kLogicOpTriangleColor.y()),
1004 										 static_cast<float>(kLogicOpTriangleColor.w()),
1005 										 static_cast<float>(kLogicOpTriangleColor.z()));
1006 
1007 struct MeshParams
1008 {
1009 	tcu::Vec4	color;
1010 	float		depth;
1011 	bool		reversed;
1012 	float		scaleX;
1013 	float		scaleY;
1014 	float		offsetX;
1015 	float		offsetY;
1016 	float		stripScale;
1017 
MeshParamsvkt::pipeline::__anon29419::MeshParams1018 	MeshParams (const tcu::Vec4&	color_		= kDefaultTriangleColor,
1019 				float				depth_		= 0.0f,
1020 				bool				reversed_	= false,
1021 				float				scaleX_		= 1.0f,
1022 				float				scaleY_		= 1.0f,
1023 				float				offsetX_	= 0.0f,
1024 				float				offsetY_	= 0.0f,
1025 				float				stripScale_	= 0.0f)
1026 		: color			(color_)
1027 		, depth			(depth_)
1028 		, reversed		(reversed_)
1029 		, scaleX		(scaleX_)
1030 		, scaleY		(scaleY_)
1031 		, offsetX		(offsetX_)
1032 		, offsetY		(offsetY_)
1033 		, stripScale	(stripScale_)
1034 	{}
1035 };
1036 
1037 enum class SequenceOrdering
1038 {
1039 	CMD_BUFFER_START	= 0,	// Set state at the start of the command buffer.
1040 	BEFORE_DRAW			= 1,	// After binding dynamic pipeline and just before drawing.
1041 	BETWEEN_PIPELINES	= 2,	// After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
1042 	AFTER_PIPELINES		= 3,	// After a static state pipeline and a second dynamic state pipeline have been bound.
1043 	BEFORE_GOOD_STATIC	= 4,	// Before a static state pipeline with the correct values has been bound.
1044 	TWO_DRAWS_DYNAMIC	= 5,	// Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
1045 	TWO_DRAWS_STATIC	= 6,	// Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
1046 };
1047 
1048 class ReferenceColorGenerator
1049 {
1050 public:
1051 	typedef std::unique_ptr<ReferenceColorGenerator> P;
1052 
1053 	virtual void	operator()	(tcu::PixelBufferAccess&)	const = 0;
1054 	virtual P		clone		()							const = 0;
1055 };
1056 
1057 using ColorVerificator = std::function<bool(const tcu::ConstPixelBufferAccess&/*result*/, const tcu::ConstPixelBufferAccess&/*reference*/, const tcu::PixelBufferAccess&/*errorMask*/)>;
1058 
1059 // Most tests expect a single output color in the whole image.
1060 class SingleColorGenerator : public ReferenceColorGenerator
1061 {
1062 public:
SingleColorGenerator(const tcu::Vec4& color)1063 	SingleColorGenerator (const tcu::Vec4& color)
1064 		: m_colorFloat	(color)
1065 		, m_colorUint	(0u)
1066 		, isUint		(false)
1067 	{}
1068 
SingleColorGenerator(const tcu::UVec4& color)1069 	SingleColorGenerator (const tcu::UVec4& color)
1070 		: m_colorFloat	(0.0f)
1071 		, m_colorUint	(color)
1072 		, isUint		(true)
1073 	{}
1074 
1075 	void operator()(tcu::PixelBufferAccess& access) const override
1076 	{
1077 		const auto kWidth	= access.getWidth();
1078 		const auto kHeight	= access.getHeight();
1079 
1080 		for (int y = 0; y < kHeight; ++y)
1081 			for (int x = 0; x < kWidth; ++x)
1082 			{
1083 				if (isUint)
1084 					access.setPixel(m_colorUint, x, y);
1085 				else
1086 					access.setPixel(m_colorFloat, x, y);
1087 			}
1088 	}
1089 
1090 	P clone() const override
1091 	{
1092 		return P(new SingleColorGenerator(*this));
1093 	}
1094 
1095 private:
1096 	const tcu::Vec4		m_colorFloat;
1097 	const tcu::UVec4	m_colorUint;
1098 	const bool			isUint;
1099 };
1100 
1101 // Some tests expect the upper half and the lower half having different color values.
1102 class HorizontalSplitGenerator : public ReferenceColorGenerator
1103 {
1104 public:
HorizontalSplitGenerator(const tcu::Vec4& top, const tcu::Vec4& bottom)1105 	HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
1106 		: m_top(top), m_bottom(bottom)
1107 	{}
1108 
1109 	void operator()(tcu::PixelBufferAccess& access) const override
1110 	{
1111 		const auto kWidth		= access.getWidth();
1112 		const auto kHeight		= access.getHeight();
1113 		const auto kHalfHeight	= kHeight / 2;
1114 
1115 		for (int y = 0; y < kHeight; ++y)
1116 			for (int x = 0; x < kWidth; ++x)
1117 			{
1118 				const auto& color = (y < kHalfHeight ? m_top : m_bottom);
1119 				access.setPixel(color, x, y);
1120 			}
1121 	}
1122 
1123 	P clone() const override
1124 	{
1125 		return P(new HorizontalSplitGenerator(*this));
1126 	}
1127 
1128 private:
1129 	const tcu::Vec4 m_top;
1130 	const tcu::Vec4 m_bottom;
1131 };
1132 
1133 // Primitive restart tests expect the last line to have some missing pixels.
1134 class LastSegmentMissingGenerator : public ReferenceColorGenerator
1135 {
1136 public:
LastSegmentMissingGenerator(const tcu::Vec4& geomColor, const tcu::Vec4& clearColor)1137 	LastSegmentMissingGenerator (const tcu::Vec4& geomColor, const tcu::Vec4& clearColor)
1138 		: m_geomColor	(geomColor)
1139 		, m_clearColor	(clearColor)
1140 	{}
1141 
1142 	void operator()(tcu::PixelBufferAccess& access) const override
1143 	{
1144 		constexpr auto kWidth				= static_cast<int>(kFramebufferWidth);
1145 		constexpr auto kHeight				= static_cast<int>(kFramebufferHeight);
1146 		constexpr auto kLastSegmentStart	= static_cast<int>(kWidth * 0.75f);
1147 
1148 		for (int y = 0; y < kHeight; ++y)
1149 		for (int x = 0; x < kWidth; ++x)
1150 		{
1151 			// The last segment of the last line has the background color.
1152 			const auto& color = ((y == kHeight - 1 && x >= kLastSegmentStart) ? m_clearColor : m_geomColor);
1153 			access.setPixel(color, x, y);
1154 		}
1155 	}
1156 
1157 	P clone() const override
1158 	{
1159 		return P(new LastSegmentMissingGenerator(*this));
1160 	}
1161 
1162 private:
1163 	const tcu::Vec4 m_geomColor;
1164 	const tcu::Vec4 m_clearColor;
1165 };
1166 
1167 // Some tests (like stippled line tests) expect vertical stripes of a given width.
1168 class VerticalStripesGenerator: public ReferenceColorGenerator
1169 {
1170 public:
VerticalStripesGenerator(const tcu::Vec4& left, const tcu::Vec4& right, uint32_t width)1171 	VerticalStripesGenerator (const tcu::Vec4& left, const tcu::Vec4& right, uint32_t width)
1172 		: m_left(left), m_right(right), m_width(width)
1173 	{
1174 		DE_ASSERT(width > 0 && width <= static_cast<uint32_t>(std::numeric_limits<int>::max()));
1175 	}
1176 
1177 	void operator()(tcu::PixelBufferAccess& access) const override
1178 	{
1179 		constexpr auto kWidth		= static_cast<int>(kFramebufferWidth);
1180 		constexpr auto kHeight		= static_cast<int>(kFramebufferHeight);
1181 
1182 		for (int y = 0; y < kHeight; ++y)
1183 			for (int x = 0; x < kWidth; ++x)
1184 			{
1185 				const int	stripeIdx	= x / static_cast<int>(m_width);
1186 				const auto&	color		= ((stripeIdx % 2 == 0) ? m_left : m_right);
1187 				access.setPixel(color, x, y);
1188 			}
1189 	}
1190 
1191 	P clone() const override
1192 	{
1193 		return P(new VerticalStripesGenerator(*this));
1194 	}
1195 
1196 private:
1197 	const tcu::Vec4	m_left;
1198 	const tcu::Vec4	m_right;
1199 	const uint32_t	m_width;
1200 };
1201 
1202 // Tests using an off-center triangle may want this generator: fill the image with a solid color but leave the top and left edges in
1203 // a different color.
1204 class TopLeftBorderGenerator : public ReferenceColorGenerator
1205 {
1206 public:
TopLeftBorderGenerator(const tcu::Vec4& mainColor, const tcu::Vec4& borderLeft, const tcu::Vec4& corner, const tcu::Vec4& borderTop)1207 	TopLeftBorderGenerator (const tcu::Vec4& mainColor, const tcu::Vec4& borderLeft, const tcu::Vec4& corner, const tcu::Vec4& borderTop)
1208 		: m_mainColor	(mainColor)
1209 		, m_borderLeft	(borderLeft)
1210 		, m_corner		(corner)
1211 		, m_borderTop	(borderTop)
1212 	{}
1213 
1214 	void operator()(tcu::PixelBufferAccess& access) const override
1215 	{
1216 		const auto kWidth		= access.getWidth();
1217 		const auto kHeight		= access.getHeight();
1218 
1219 		for (int y = 0; y < kHeight; ++y)
1220 			for (int x = 0; x < kWidth; ++x)
1221 			{
1222 				tcu::Vec4 color;
1223 
1224 				if (x == 0)
1225 				{
1226 					if (y == 0)
1227 						color = m_corner;
1228 					else
1229 						color = m_borderLeft;
1230 				}
1231 				else if (y == 0)
1232 					color = m_borderTop;
1233 				else
1234 					color = m_mainColor;
1235 
1236 				access.setPixel(color, x, y);
1237 			}
1238 	}
1239 
1240 	P clone() const override
1241 	{
1242 		return P(new TopLeftBorderGenerator(*this));
1243 	}
1244 
1245 private:
1246 	const tcu::Vec4 m_mainColor;
1247 	const tcu::Vec4 m_borderLeft;
1248 	const tcu::Vec4 m_corner;
1249 	const tcu::Vec4 m_borderTop;
1250 };
1251 
1252 // Verifies the top left pixel matches exactly.
verifyTopLeftCorner(const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference, const tcu::PixelBufferAccess& errorMask)1253 bool verifyTopLeftCorner (const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& reference, const tcu::PixelBufferAccess& errorMask)
1254 {
1255 	// Check corner.
1256 	const auto resultColor		= result.getPixel(0, 0);
1257 	const auto referenceColor	= reference.getPixel(0, 0);
1258 
1259 	const auto red		= tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1260 	const auto green	= tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1261 	const auto black	= tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1262 	const bool match	= (resultColor == referenceColor);
1263 
1264 	tcu::clear(errorMask, black);
1265 	errorMask.setPixel((match ? green : red), 0, 0);
1266 
1267 	return match;
1268 }
1269 
getVertexWithPaddingGenerator()1270 const VertexGenerator* getVertexWithPaddingGenerator ()
1271 {
1272 	static VertexWithPadding vertexWithPadding;
1273 	return &vertexWithPadding;
1274 }
1275 
getVertexWithExtraAttributesGenerator()1276 const VertexGenerator* getVertexWithExtraAttributesGenerator ()
1277 {
1278 	static VertexWithExtraAttributes vertexWithExtraAttributes;
1279 	return &vertexWithExtraAttributes;
1280 }
1281 
getVertexWithMultipleBindingsGenerator()1282 const VertexGenerator* getVertexWithMultipleBindingsGenerator ()
1283 {
1284 	static MultipleBindingsVertex multipleBindingsVertex;
1285 	return &multipleBindingsVertex;
1286 }
1287 
getProvokingVertexWithPaddingGenerator(bool lastVertex)1288 const VertexGenerator* getProvokingVertexWithPaddingGenerator (bool lastVertex)
1289 {
1290 	if (lastVertex)
1291 	{
1292 		static ProvokingVertexWithPadding provokingVertexGeneratorLastVtx (true);
1293 		return &provokingVertexGeneratorLastVtx;
1294 	}
1295 	static ProvokingVertexWithPadding provokingVertexGeneratorFirstVtx (false);
1296 	return &provokingVertexGeneratorFirstVtx;
1297 }
1298 
1299 // Create VertexGeneratorConfig varying constructor depending on having none, only the static or both.
makeVertexGeneratorConfig(const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)1300 VertexGeneratorConfig makeVertexGeneratorConfig (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
1301 {
1302 	DE_ASSERT(!(dynamicGen && !staticGen));
1303 	if (dynamicGen)
1304 		return VertexGeneratorConfig(staticGen, dynamicGen);
1305 	if (staticGen)
1306 		return VertexGeneratorConfig(staticGen);
1307 	return VertexGeneratorConfig(getVertexWithPaddingGenerator());	// Only static part with a default option.
1308 }
1309 
1310 // Similar to makeVertexGeneratorConfig, choosing the final value.
chooseVertexGenerator(const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)1311 const VertexGenerator* chooseVertexGenerator (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
1312 {
1313 	DE_ASSERT(!(dynamicGen && !staticGen));
1314 	if (dynamicGen)
1315 		return dynamicGen;
1316 	if (staticGen)
1317 		return staticGen;
1318 	return getVertexWithPaddingGenerator();
1319 }
1320 
1321 enum class TopologyClass
1322 {
1323 	POINT,
1324 	LINE,
1325 	TRIANGLE,
1326 	PATCH,
1327 	INVALID,
1328 };
1329 
topologyClassName(TopologyClass tclass)1330 std::string topologyClassName (TopologyClass tclass)
1331 {
1332 	switch (tclass)
1333 	{
1334 	case TopologyClass::POINT:		return "point";
1335 	case TopologyClass::LINE:		return "line";
1336 	case TopologyClass::TRIANGLE:	return "triangle";
1337 	case TopologyClass::PATCH:		return "patch";
1338 	default:
1339 		break;
1340 	}
1341 
1342 	DE_ASSERT(false);
1343 	return "";
1344 }
1345 
1346 #ifndef CTS_USES_VULKANSC
1347 // Is a particular dynamic state incompatible with mesh shading pipelines?
isMeshShadingPipelineIncompatible(vk::VkDynamicState state)1348 bool isMeshShadingPipelineIncompatible (vk::VkDynamicState state)
1349 {
1350 	switch (state)
1351 	{
1352 	case vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT:
1353 	case vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT:
1354 	case vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT:
1355 	case vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT:
1356 	case vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT:
1357 		return true;
1358 	default:
1359 		return false;
1360 	}
1361 
1362 	// Unreachable.
1363 	DE_ASSERT(false);
1364 	return false;
1365 }
1366 
1367 // Is a particular dynamic state compatible with mesh shading pipelines?
isMeshShadingPipelineCompatible(vk::VkDynamicState state)1368 bool isMeshShadingPipelineCompatible (vk::VkDynamicState state)
1369 {
1370 	return !isMeshShadingPipelineIncompatible(state);
1371 }
1372 #endif // CTS_USES_VULKANSC
1373 
getTopologyClass(vk::VkPrimitiveTopology topology)1374 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
1375 {
1376 	switch (topology)
1377 	{
1378 	case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1379 		return TopologyClass::POINT;
1380 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1381 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1382 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1383 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1384 		return TopologyClass::LINE;
1385 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1386 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1387 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1388 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1389 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1390 		return TopologyClass::TRIANGLE;
1391 	case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1392 		return TopologyClass::PATCH;
1393 	default:
1394 		break;
1395 	}
1396 
1397 	DE_ASSERT(false);
1398 	return TopologyClass::INVALID;
1399 }
1400 
selectLineRasterizationMode(const vk::VkPhysicalDeviceLineRasterizationFeaturesEXT& lineRasterFeatures, bool stippleRequired, const tcu::Maybe<LineRasterizationMode>& pref)1401 LineRasterizationMode selectLineRasterizationMode (const vk::VkPhysicalDeviceLineRasterizationFeaturesEXT& lineRasterFeatures, bool stippleRequired, const tcu::Maybe<LineRasterizationMode>& pref)
1402 {
1403 	LineRasterizationMode	selectedMode	= LineRasterizationMode::NONE;
1404 	const bool				hasPref			= static_cast<bool>(pref);
1405 
1406 	if ((!hasPref || pref.get() == LineRasterizationMode::RECTANGULAR) && lineRasterFeatures.rectangularLines && (!stippleRequired || lineRasterFeatures.stippledRectangularLines))
1407 		selectedMode = LineRasterizationMode::RECTANGULAR;
1408 	else if ((!hasPref || pref.get() == LineRasterizationMode::BRESENHAM) && lineRasterFeatures.bresenhamLines && (!stippleRequired || lineRasterFeatures.stippledBresenhamLines))
1409 		selectedMode = LineRasterizationMode::BRESENHAM;
1410 	else if ((!hasPref || pref.get() == LineRasterizationMode::SMOOTH) && lineRasterFeatures.smoothLines && (!stippleRequired || lineRasterFeatures.stippledSmoothLines))
1411 		selectedMode = LineRasterizationMode::SMOOTH;
1412 
1413 	return selectedMode;
1414 }
1415 
1416 #ifndef CTS_USES_VULKANSC
makeLineRasterizationMode(LineRasterizationMode mode)1417 vk::VkLineRasterizationModeEXT makeLineRasterizationMode (LineRasterizationMode mode)
1418 {
1419 	vk::VkLineRasterizationModeEXT modeEXT = vk::VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
1420 
1421 	switch (mode)
1422 	{
1423 	case LineRasterizationMode::RECTANGULAR:	modeEXT = vk::VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;			break;
1424 	case LineRasterizationMode::BRESENHAM:		modeEXT = vk::VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;				break;
1425 	case LineRasterizationMode::SMOOTH:			modeEXT = vk::VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;	break;
1426 	default:
1427 		DE_ASSERT(false);
1428 		break;
1429 	}
1430 
1431 	return modeEXT;
1432 }
1433 #endif // CTS_USES_VULKANSC
1434 
1435 struct TestConfig
1436 {
1437 	// Should we use pipeline_library to construct pipeline.
1438 	vk::PipelineConstructionType	pipelineConstructionType;
1439 
1440 	// Main sequence ordering.
1441 	SequenceOrdering				sequenceOrdering;
1442 
1443 	// Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
1444 	std::vector<MeshParams>			meshParams;			// Mesh parameters for each full-screen layer of geometry.
1445 	deUint32						referenceStencil;	// Reference stencil value.
1446 
1447 	// Clearing parameters for the framebuffer.
1448 	vk::VkClearValue				clearColorValue;
1449 	float							clearDepthValue;
1450 	deUint32						clearStencilValue;
1451 
1452 	// Expected output in the attachments.
1453 	ReferenceColorGenerator::P		referenceColor;
1454 	float							expectedDepth;
1455 	deUint32						expectedStencil;
1456 
1457 	// Optional verification routine.
1458 	tcu::Maybe<ColorVerificator>	colorVerificator;
1459 
1460 	// Depth bounds parameters for the pipeline.
1461 	float							minDepthBounds;
1462 	float							maxDepthBounds;
1463 
1464 	// Force inclusion of passthrough geometry shader or not.
1465 	bool							forceGeometryShader;
1466 
1467 	// Use mesh shaders instead of classic pipelines.
1468 	bool							useMeshShaders;
1469 
1470 	// Bind an unused mesh shading pipeline before binding the dynamic pipeline.
1471 	// This will only be used in the CMD_BUFFER_START sequence ordering, to minimize the number of cases.
1472 	bool							bindUnusedMeshShadingPipeline;
1473 
1474 	// Force single vertex in the VBO.
1475 	bool							singleVertex;
1476 	deUint32						singleVertexDrawCount;
1477 
1478 	// Force using an oversized triangle as the mesh.
1479 	bool							oversizedTriangle;
1480 
1481 	// Force using a single triangle with a small offset as the mesh.
1482 	bool							offCenterTriangle;
1483 	tcu::Vec2						offCenterProportion; // Relative to pixel size.
1484 
1485 	// Force using a single oblique line: this helps test line rasterization mode.
1486 	bool							obliqueLine;
1487 
1488 	// Offset and extra room after the vertex buffer data.
1489 	vk::VkDeviceSize				vertexDataOffset;
1490 	vk::VkDeviceSize				vertexDataExtraBytes;
1491 
1492 	// Bind and draw with a pipeline that uses dynamic patch control points but doesn't actually use a tessellation
1493 	// shader, before using the real pipelines being tested.
1494 	bool							useExtraDynPCPPipeline;
1495 
1496 	// Optional, to be used specifically for color attachments when testing coverage modulation and reduction.
1497 	bool							coverageModulation;
1498 	bool							coverageReduction;
1499 	OptSampleCount					colorSampleCount;
1500 
1501 	// Rasterization stream, if needed, used in the geometry shader.
1502 	OptRastStream					shaderRasterizationStream;
1503 
1504 	// Sample locations, which may be used if testing sample locations.
1505 	tcu::Vec2						sampleLocations;
1506 
1507 	// Optional maximum value for primitiveOverestimationSize so the test works properly.
1508 	tcu::Maybe<float>				maxPrimitiveOverestimationSize;
1509 
1510 	// Number of color attachments in the subpass. Note the fragment shader will only write to the last one.
1511 	uint32_t						colorAttachmentCount;
1512 
1513 	// Use viewport swizzle or not.
1514 	bool							viewportSwizzle;
1515 
1516 	// Use shading rate image configuration or not.
1517 	bool							shadingRateImage;
1518 
1519 	// Use viewport W scaling or not.
1520 	bool							viewportWScaling;
1521 
1522 	// Use representative fragment test or not.
1523 	bool							representativeFragmentTest;
1524 
1525 	// When setting the sample mask dynamically, we can use an alternative sample count specified here.
1526 	OptSampleCount					dynamicSampleMaskCount;
1527 
1528 	// Static and dynamic pipeline configuration.
1529 	VertexGeneratorConfig			vertexGenerator;
1530 	CullModeConfig					cullModeConfig;
1531 	FrontFaceConfig					frontFaceConfig;
1532 	TopologyConfig					topologyConfig;
1533 	ViewportConfig					viewportConfig;
1534 	ScissorConfig					scissorConfig;
1535 	StrideConfig					strideConfig;
1536 	DepthTestEnableConfig			depthTestEnableConfig;
1537 	DepthWriteEnableConfig			depthWriteEnableConfig;
1538 	DepthCompareOpConfig			depthCompareOpConfig;
1539 	DepthBoundsTestEnableConfig		depthBoundsTestEnableConfig;
1540 	StencilTestEnableConfig			stencilTestEnableConfig;
1541 	StencilOpConfig					stencilOpConfig;
1542 	DepthBiasEnableConfig			depthBiasEnableConfig;
1543 	RastDiscardEnableConfig			rastDiscardEnableConfig;
1544 	PrimRestartEnableConfig			primRestartEnableConfig;
1545 	LogicOpConfig					logicOpConfig;
1546 	PatchControlPointsConfig		patchControlPointsConfig;
1547 	DepthBiasConfig					depthBiasConfig;
1548 	TessDomainOriginConfig			tessDomainOriginConfig;
1549 	DepthClampEnableConfig			depthClampEnableConfig;
1550 	PolygonModeConfig				polygonModeConfig;
1551 	SampleMaskConfig				sampleMaskConfig;
1552 	AlphaToCoverageConfig			alphaToCoverageConfig;
1553 	AlphaToOneConfig				alphaToOneConfig;
1554 	ColorWriteMaskConfig			colorWriteMaskConfig;
1555 	RasterizationStreamConfig		rasterizationStreamConfig;
1556 	LogicOpEnableConfig				logicOpEnableConfig;
1557 	ColorBlendEnableConfig			colorBlendEnableConfig;
1558 	ColorBlendEquationConfig		colorBlendEquationConfig;
1559 	ProvokingVertexConfig			provokingVertexConfig;
1560 	NegativeOneToOneConfig			negativeOneToOneConfig;
1561 	DepthClipEnableConfig			depthClipEnableConfig;
1562 	LineStippleEnableConfig			lineStippleEnableConfig;
1563 	LineStippleParamsConfig			lineStippleParamsConfig;
1564 	SampleLocationsEnableConfig		sampleLocationsEnableConfig;
1565 	ConservativeRasterModeConfig	conservativeRasterModeConfig;
1566 	ExtraPrimitiveOverEstConfig		extraPrimitiveOverEstConfig;
1567 	LineRasterModeConfig			lineRasterModeConfig;
1568 	CoverageToColorEnableConfig		coverageToColorEnableConfig;
1569 	CoverageToColorLocationConfig	coverageToColorLocationConfig;
1570 	RasterizationSamplesConfig		rasterizationSamplesConfig;
1571 #ifndef CTS_USES_VULKANSC
1572 	CoverageModulationModeConfig	coverageModulationModeConfig;
1573 	CoverageModTableEnableConfig	coverageModTableEnableConfig;
1574 	CoverageModTableConfig			coverageModTableConfig;
1575 	CoverageReductionModeConfig		coverageReductionModeConfig;
1576 	ViewportSwizzleConfig			viewportSwizzleConfig;
1577 	ShadingRateImageEnableConfig	shadingRateImageEnableConfig;
1578 	ViewportWScalingEnableConfig	viewportWScalingEnableConfig;
1579 	ReprFragTestEnableConfig		reprFragTestEnableConfig;
1580 #endif // CTS_USES_VULKANSC
1581 
1582 	// Sane defaults.
TestConfigvkt::pipeline::__anon29419::TestConfig1583 	TestConfig (vk::PipelineConstructionType pipelineType, SequenceOrdering ordering, bool useMeshShaders_, const VertexGenerator* staticVertexGenerator = nullptr, const VertexGenerator* dynamicVertexGenerator = nullptr)
1584 		: pipelineConstructionType		(pipelineType)
1585 		, sequenceOrdering				(ordering)
1586 		, meshParams					(1u, MeshParams())
1587 		, referenceStencil				(0u)
1588 		, clearColorValue				(vk::makeClearValueColor(kDefaultClearColor))
1589 		, clearDepthValue				(1.0f)
1590 		, clearStencilValue				(0u)
1591 		, referenceColor				(new SingleColorGenerator(kDefaultTriangleColor))
1592 		, expectedDepth					(1.0f)
1593 		, expectedStencil				(0u)
1594 		, colorVerificator				(tcu::Nothing)
1595 		, minDepthBounds				(0.0f)
1596 		, maxDepthBounds				(1.0f)
1597 		, forceGeometryShader			(false)
1598 		, useMeshShaders				(useMeshShaders_)
1599 		, bindUnusedMeshShadingPipeline	(false)
1600 		, singleVertex					(false)
1601 		, singleVertexDrawCount			(0)
1602 		, oversizedTriangle				(false)
1603 		, offCenterTriangle				(false)
1604 		, offCenterProportion			(0.0f, 0.0f)
1605 		, obliqueLine					(false)
1606 		, vertexDataOffset				(0ull)
1607 		, vertexDataExtraBytes			(0ull)
1608 		, useExtraDynPCPPipeline		(false)
1609 		, coverageModulation			(false)
1610 		, coverageReduction				(false)
1611 		, colorSampleCount				(tcu::Nothing)
1612 		, shaderRasterizationStream		(tcu::Nothing)
1613 		, sampleLocations				(0.5f, 0.5f)
1614 		, colorAttachmentCount			(1u)
1615 		, viewportSwizzle				(false)
1616 		, shadingRateImage				(false)
1617 		, viewportWScaling				(false)
1618 		, representativeFragmentTest	(false)
1619 		, dynamicSampleMaskCount		(tcu::Nothing)
1620 		, vertexGenerator				(makeVertexGeneratorConfig(staticVertexGenerator, dynamicVertexGenerator))
1621 		, cullModeConfig				(static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
1622 		, frontFaceConfig				(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
1623 		// By default we will use a triangle strip with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
1624 		, topologyConfig				(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
1625 		, viewportConfig				(ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
1626 		, scissorConfig					(ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
1627 		// By default, the vertex stride is the size of a vertex according to the chosen vertex type.
1628 		, strideConfig					(chooseVertexGenerator(staticVertexGenerator, dynamicVertexGenerator)->getVertexDataStrides())
1629 		, depthTestEnableConfig			(false)
1630 		, depthWriteEnableConfig		(false)
1631 		, depthCompareOpConfig			(vk::VK_COMPARE_OP_NEVER)
1632 		, depthBoundsTestEnableConfig	(false)
1633 		, stencilTestEnableConfig		(false)
1634 		, stencilOpConfig				(StencilOpVec(1u, kDefaultStencilOpParams))
1635 		, depthBiasEnableConfig			(false)
1636 		, rastDiscardEnableConfig		(false)
1637 		, primRestartEnableConfig		(false)
1638 		, logicOpConfig					(vk::VK_LOGIC_OP_CLEAR)
1639 		, patchControlPointsConfig		(1u)
1640 		, depthBiasConfig				(kNoDepthBiasParams)
1641 		, tessDomainOriginConfig		(vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
1642 		, depthClampEnableConfig		(false)
1643 		, polygonModeConfig				(vk::VK_POLYGON_MODE_FILL)
1644 		, sampleMaskConfig				(SampleMaskVec())
1645 		, alphaToCoverageConfig			(false)
1646 		, alphaToOneConfig				(false)
1647 		, colorWriteMaskConfig			(CR | CG | CB | CA)
1648 		, rasterizationStreamConfig		(tcu::Nothing)
1649 		, logicOpEnableConfig			(false)
1650 		, colorBlendEnableConfig		(false)
1651 		, colorBlendEquationConfig		(ColorBlendEq())
1652 		, provokingVertexConfig			(tcu::Nothing)
1653 		, negativeOneToOneConfig		(tcu::Nothing)
1654 		, depthClipEnableConfig			(tcu::Nothing)
1655 		, lineStippleEnableConfig		(false)
1656 		, lineStippleParamsConfig		(tcu::Nothing)
1657 		, sampleLocationsEnableConfig	(false)
1658 		, conservativeRasterModeConfig	(vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT)
1659 		, extraPrimitiveOverEstConfig	(-1.0f)
1660 		, lineRasterModeConfig			(tcu::Nothing)
1661 		, coverageToColorEnableConfig	(false)
1662 		, coverageToColorLocationConfig	(0u)
1663 		, rasterizationSamplesConfig	(kSingleSampleCount)
1664 #ifndef CTS_USES_VULKANSC
1665 		, coverageModulationModeConfig	(vk::VK_COVERAGE_MODULATION_MODE_NONE_NV)
1666 		, coverageModTableEnableConfig	(false)
1667 		, coverageModTableConfig		(CovModTableVec())
1668 		, coverageReductionModeConfig	(vk::VK_COVERAGE_REDUCTION_MODE_MERGE_NV)
1669 		, viewportSwizzleConfig			(ViewportSwzVec())
1670 		, shadingRateImageEnableConfig	(false)
1671 		, viewportWScalingEnableConfig	(false)
1672 		, reprFragTestEnableConfig		(false)
1673 #endif // CTS_USES_VULKANSC
1674 		, m_swappedValues				(false)
1675 	{
1676 	}
1677 
TestConfigvkt::pipeline::__anon29419::TestConfig1678 	TestConfig (const TestConfig& other)
1679 		: pipelineConstructionType		(other.pipelineConstructionType)
1680 		, sequenceOrdering				(other.sequenceOrdering)
1681 		, meshParams					(other.meshParams)
1682 		, referenceStencil				(other.referenceStencil)
1683 		, clearColorValue				(other.clearColorValue)
1684 		, clearDepthValue				(other.clearDepthValue)
1685 		, clearStencilValue				(other.clearStencilValue)
1686 		, referenceColor				(other.referenceColor->clone())
1687 		, expectedDepth					(other.expectedDepth)
1688 		, expectedStencil				(other.expectedStencil)
1689 		, colorVerificator				(other.colorVerificator)
1690 		, minDepthBounds				(other.minDepthBounds)
1691 		, maxDepthBounds				(other.maxDepthBounds)
1692 		, forceGeometryShader			(other.forceGeometryShader)
1693 		, useMeshShaders				(other.useMeshShaders)
1694 		, bindUnusedMeshShadingPipeline	(other.bindUnusedMeshShadingPipeline)
1695 		, singleVertex					(other.singleVertex)
1696 		, singleVertexDrawCount			(other.singleVertexDrawCount)
1697 		, oversizedTriangle				(other.oversizedTriangle)
1698 		, offCenterTriangle				(other.offCenterTriangle)
1699 		, offCenterProportion			(other.offCenterProportion)
1700 		, obliqueLine					(other.obliqueLine)
1701 		, vertexDataOffset				(other.vertexDataOffset)
1702 		, vertexDataExtraBytes			(other.vertexDataExtraBytes)
1703 		, useExtraDynPCPPipeline		(other.useExtraDynPCPPipeline)
1704 		, coverageModulation			(other.coverageModulation)
1705 		, coverageReduction				(other.coverageReduction)
1706 		, colorSampleCount				(other.colorSampleCount)
1707 		, shaderRasterizationStream		(other.shaderRasterizationStream)
1708 		, sampleLocations				(other.sampleLocations)
1709 		, colorAttachmentCount			(other.colorAttachmentCount)
1710 		, viewportSwizzle				(other.viewportSwizzle)
1711 		, shadingRateImage				(other.shadingRateImage)
1712 		, viewportWScaling				(other.viewportWScaling)
1713 		, representativeFragmentTest	(other.representativeFragmentTest)
1714 		, dynamicSampleMaskCount		(other.dynamicSampleMaskCount)
1715 		, vertexGenerator				(other.vertexGenerator)
1716 		, cullModeConfig				(other.cullModeConfig)
1717 		, frontFaceConfig				(other.frontFaceConfig)
1718 		, topologyConfig				(other.topologyConfig)
1719 		, viewportConfig				(other.viewportConfig)
1720 		, scissorConfig					(other.scissorConfig)
1721 		, strideConfig					(other.strideConfig)
1722 		, depthTestEnableConfig			(other.depthTestEnableConfig)
1723 		, depthWriteEnableConfig		(other.depthWriteEnableConfig)
1724 		, depthCompareOpConfig			(other.depthCompareOpConfig)
1725 		, depthBoundsTestEnableConfig	(other.depthBoundsTestEnableConfig)
1726 		, stencilTestEnableConfig		(other.stencilTestEnableConfig)
1727 		, stencilOpConfig				(other.stencilOpConfig)
1728 		, depthBiasEnableConfig			(other.depthBiasEnableConfig)
1729 		, rastDiscardEnableConfig		(other.rastDiscardEnableConfig)
1730 		, primRestartEnableConfig		(other.primRestartEnableConfig)
1731 		, logicOpConfig					(other.logicOpConfig)
1732 		, patchControlPointsConfig		(other.patchControlPointsConfig)
1733 		, depthBiasConfig				(other.depthBiasConfig)
1734 		, tessDomainOriginConfig		(other.tessDomainOriginConfig)
1735 		, depthClampEnableConfig		(other.depthClampEnableConfig)
1736 		, polygonModeConfig				(other.polygonModeConfig)
1737 		, sampleMaskConfig				(other.sampleMaskConfig)
1738 		, alphaToCoverageConfig			(other.alphaToCoverageConfig)
1739 		, alphaToOneConfig				(other.alphaToOneConfig)
1740 		, colorWriteMaskConfig			(other.colorWriteMaskConfig)
1741 		, rasterizationStreamConfig		(other.rasterizationStreamConfig)
1742 		, logicOpEnableConfig			(other.logicOpEnableConfig)
1743 		, colorBlendEnableConfig		(other.colorBlendEnableConfig)
1744 		, colorBlendEquationConfig		(other.colorBlendEquationConfig)
1745 		, provokingVertexConfig			(other.provokingVertexConfig)
1746 		, negativeOneToOneConfig		(other.negativeOneToOneConfig)
1747 		, depthClipEnableConfig			(other.depthClipEnableConfig)
1748 		, lineStippleEnableConfig		(other.lineStippleEnableConfig)
1749 		, lineStippleParamsConfig		(other.lineStippleParamsConfig)
1750 		, sampleLocationsEnableConfig	(other.sampleLocationsEnableConfig)
1751 		, conservativeRasterModeConfig	(other.conservativeRasterModeConfig)
1752 		, extraPrimitiveOverEstConfig	(other.extraPrimitiveOverEstConfig)
1753 		, lineRasterModeConfig			(other.lineRasterModeConfig)
1754 		, coverageToColorEnableConfig	(other.coverageToColorEnableConfig)
1755 		, coverageToColorLocationConfig	(other.coverageToColorLocationConfig)
1756 		, rasterizationSamplesConfig	(other.rasterizationSamplesConfig)
1757 #ifndef CTS_USES_VULKANSC
1758 		, coverageModulationModeConfig	(other.coverageModulationModeConfig)
1759 		, coverageModTableEnableConfig	(other.coverageModTableEnableConfig)
1760 		, coverageModTableConfig		(other.coverageModTableConfig)
1761 		, coverageReductionModeConfig	(other.coverageReductionModeConfig)
1762 		, viewportSwizzleConfig			(other.viewportSwizzleConfig)
1763 		, shadingRateImageEnableConfig	(other.shadingRateImageEnableConfig)
1764 		, viewportWScalingEnableConfig	(other.viewportWScalingEnableConfig)
1765 		, reprFragTestEnableConfig		(other.reprFragTestEnableConfig)
1766 #endif // CTS_USES_VULKANSC
1767 		, m_swappedValues				(other.m_swappedValues)
1768 	{
1769 	}
1770 
1771 	// Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anon29419::TestConfig1772 	const ViewportVec& getActiveViewportVec () const
1773 	{
1774 		return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() : viewportConfig.staticValue);
1775 	}
1776 
1777 	// Gets the proper vertex generator according to the test config.
getActiveVertexGeneratorvkt::pipeline::__anon29419::TestConfig1778 	const VertexGenerator* getActiveVertexGenerator () const
1779 	{
1780 		return ((vertexGenerator.dynamicValue && !m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
1781 	}
1782 
1783 	// Gets the inactive vertex generator according to the test config. If there's only one, return that.
getInactiveVertexGeneratorvkt::pipeline::__anon29419::TestConfig1784 	const VertexGenerator* getInactiveVertexGenerator () const
1785 	{
1786 		return ((vertexGenerator.dynamicValue && m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
1787 	}
1788 
1789 	// Get the active number of patch control points according to the test config.
getActivePatchControlPointsvkt::pipeline::__anon29419::TestConfig1790 	deUint32 getActivePatchControlPoints () const
1791 	{
1792 		return ((patchControlPointsConfig.dynamicValue && !m_swappedValues) ? patchControlPointsConfig.dynamicValue.get() : patchControlPointsConfig.staticValue);
1793 	}
1794 
1795 	// Get the active depth bias parameters.
getActiveDepthBiasParamsvkt::pipeline::__anon29419::TestConfig1796 	DepthBiasParams getActiveDepthBiasParams () const
1797 	{
1798 		return ((depthBiasConfig.dynamicValue && !m_swappedValues) ? depthBiasConfig.dynamicValue.get() : depthBiasConfig.staticValue);
1799 	}
1800 
1801 	// Get the active primitive restart enable value.
getActivePrimitiveRestartEnablevkt::pipeline::__anon29419::TestConfig1802 	bool getActivePrimitiveRestartEnable () const
1803 	{
1804 		return ((primRestartEnableConfig.dynamicValue && !m_swappedValues) ? primRestartEnableConfig.dynamicValue.get() : primRestartEnableConfig.staticValue);
1805 	}
1806 
getActiveTessellationDomainOriginvkt::pipeline::__anon29419::TestConfig1807 	vk::VkTessellationDomainOrigin getActiveTessellationDomainOrigin () const
1808 	{
1809 		return ((tessDomainOriginConfig.dynamicValue && !m_swappedValues) ? tessDomainOriginConfig.dynamicValue.get() : tessDomainOriginConfig.staticValue);
1810 	}
1811 
getActivePolygonModevkt::pipeline::__anon29419::TestConfig1812 	vk::VkPolygonMode getActivePolygonMode () const
1813 	{
1814 		return ((polygonModeConfig.dynamicValue && !m_swappedValues) ? polygonModeConfig.dynamicValue.get() : polygonModeConfig.staticValue);
1815 	}
1816 
getActiveSampleCountvkt::pipeline::__anon29419::TestConfig1817 	vk::VkSampleCountFlagBits getActiveSampleCount () const
1818 	{
1819 		return ((rasterizationSamplesConfig.dynamicValue && !m_swappedValues) ? rasterizationSamplesConfig.dynamicValue.get() : rasterizationSamplesConfig.staticValue);
1820 	}
1821 
getActiveAlphaToOnevkt::pipeline::__anon29419::TestConfig1822 	bool getActiveAlphaToOne () const
1823 	{
1824 		return ((alphaToOneConfig.dynamicValue && !m_swappedValues) ? alphaToOneConfig.dynamicValue.get() : alphaToOneConfig.staticValue);
1825 	}
1826 
rasterizationStreamStructvkt::pipeline::__anon29419::TestConfig1827 	bool rasterizationStreamStruct () const
1828 	{
1829 		return (static_cast<bool>(rasterizationStreamConfig.staticValue)
1830 				|| (static_cast<bool>(rasterizationStreamConfig.dynamicValue) && static_cast<bool>(rasterizationStreamConfig.dynamicValue.get())));
1831 	}
1832 
provokingVertexStructvkt::pipeline::__anon29419::TestConfig1833 	bool provokingVertexStruct () const
1834 	{
1835 		return (static_cast<bool>(provokingVertexConfig.staticValue)
1836 				|| (static_cast<bool>(provokingVertexConfig.dynamicValue) && static_cast<bool>(provokingVertexConfig.dynamicValue.get())));
1837 	}
1838 
negativeOneToOneStructvkt::pipeline::__anon29419::TestConfig1839 	bool negativeOneToOneStruct () const
1840 	{
1841 		return (static_cast<bool>(negativeOneToOneConfig.staticValue)
1842 				|| (static_cast<bool>(negativeOneToOneConfig.dynamicValue) && static_cast<bool>(negativeOneToOneConfig.dynamicValue.get())));
1843 	}
1844 
depthClipEnableStructvkt::pipeline::__anon29419::TestConfig1845 	bool depthClipEnableStruct () const
1846 	{
1847 		return (static_cast<bool>(depthClipEnableConfig.staticValue)
1848 				|| (static_cast<bool>(depthClipEnableConfig.dynamicValue) && static_cast<bool>(depthClipEnableConfig.dynamicValue.get())));
1849 	}
1850 
hasStaticLineStippleParamsvkt::pipeline::__anon29419::TestConfig1851 	bool hasStaticLineStippleParams () const
1852 	{
1853 		return (static_cast<bool>(lineStippleParamsConfig.staticValue));
1854 	}
1855 
hasStaticLineRasterModevkt::pipeline::__anon29419::TestConfig1856 	bool hasStaticLineRasterMode () const
1857 	{
1858 		return (static_cast<bool>(lineRasterModeConfig.staticValue));
1859 	}
1860 
hasLineStippleParamsvkt::pipeline::__anon29419::TestConfig1861 	bool hasLineStippleParams () const
1862 	{
1863 		return (hasStaticLineStippleParams()
1864 				|| (static_cast<bool>(lineStippleParamsConfig.dynamicValue) && static_cast<bool>(lineStippleParamsConfig.dynamicValue.get())));
1865 	}
1866 
hasLineRasterModevkt::pipeline::__anon29419::TestConfig1867 	bool hasLineRasterMode () const
1868 	{
1869 		return (hasStaticLineRasterMode()
1870 				|| (static_cast<bool>(lineRasterModeConfig.dynamicValue) && static_cast<bool>(lineRasterModeConfig.dynamicValue.get())));
1871 	}
1872 
lineStippleSupportRequiredvkt::pipeline::__anon29419::TestConfig1873 	bool lineStippleSupportRequired () const
1874 	{
1875 		return (lineStippleEnableConfig.staticValue || (static_cast<bool>(lineStippleEnableConfig.dynamicValue) && lineStippleEnableConfig.dynamicValue.get()));
1876 	}
1877 
lineRasterStructvkt::pipeline::__anon29419::TestConfig1878 	bool lineRasterStruct () const
1879 	{
1880 		return (static_cast<bool>(lineStippleEnableConfig.dynamicValue) || lineStippleEnableConfig.staticValue || hasStaticLineStippleParams() || hasStaticLineRasterMode());
1881 	}
1882 
lineRasterizationExtvkt::pipeline::__anon29419::TestConfig1883 	bool lineRasterizationExt () const
1884 	{
1885 		return (lineRasterStruct() || hasLineStippleParams() || hasLineRasterMode());
1886 	}
1887 
sampleLocationsStructvkt::pipeline::__anon29419::TestConfig1888 	bool sampleLocationsStruct () const
1889 	{
1890 		return (static_cast<bool>(sampleLocationsEnableConfig.dynamicValue) || sampleLocationsEnableConfig.staticValue);
1891 	}
1892 
coverageToColorStructvkt::pipeline::__anon29419::TestConfig1893 	bool coverageToColorStruct () const
1894 	{
1895 		return (static_cast<bool>(coverageToColorEnableConfig.dynamicValue) || coverageToColorEnableConfig.staticValue);
1896 	}
1897 
conservativeRasterStructvkt::pipeline::__anon29419::TestConfig1898 	bool conservativeRasterStruct () const
1899 	{
1900 		return (static_cast<bool>(conservativeRasterModeConfig.dynamicValue) || conservativeRasterModeConfig.staticValue != vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT
1901 				|| static_cast<bool>(extraPrimitiveOverEstConfig.dynamicValue) || extraPrimitiveOverEstConfig.staticValue >= 0.0f);
1902 	}
1903 
getActiveConservativeRasterModevkt::pipeline::__anon29419::TestConfig1904 	vk::VkConservativeRasterizationModeEXT getActiveConservativeRasterMode () const
1905 	{
1906 		return ((static_cast<bool>(conservativeRasterModeConfig.dynamicValue) && !m_swappedValues) ? conservativeRasterModeConfig.dynamicValue.get() : conservativeRasterModeConfig.staticValue);
1907 	}
1908 
getActiveExtraPrimitiveOverEstSizevkt::pipeline::__anon29419::TestConfig1909 	float getActiveExtraPrimitiveOverEstSize () const
1910 	{
1911 		return ((static_cast<bool>(extraPrimitiveOverEstConfig.dynamicValue) && !m_swappedValues) ? extraPrimitiveOverEstConfig.dynamicValue.get() : extraPrimitiveOverEstConfig.staticValue);
1912 	}
1913 
getActiveLogicOpEnablevkt::pipeline::__anon29419::TestConfig1914 	bool getActiveLogicOpEnable () const
1915 	{
1916 		return ((logicOpEnableConfig.dynamicValue && !m_swappedValues) ? logicOpEnableConfig.dynamicValue.get() : logicOpEnableConfig.staticValue);
1917 	}
1918 
getActiveNegativeOneToOneValuevkt::pipeline::__anon29419::TestConfig1919 	bool getActiveNegativeOneToOneValue () const
1920 	{
1921 		const bool				staticValue		= (static_cast<bool>(negativeOneToOneConfig.staticValue) ? negativeOneToOneConfig.staticValue.get() : false);
1922 		const bool				hasDynamicValue	= (static_cast<bool>(negativeOneToOneConfig.dynamicValue) && static_cast<bool>(negativeOneToOneConfig.dynamicValue.get()));
1923 		const tcu::Maybe<bool>	dynamicValue	= (hasDynamicValue ? tcu::just(negativeOneToOneConfig.dynamicValue->get()) : tcu::nothing<bool>());
1924 
1925 		return ((hasDynamicValue && !m_swappedValues) ? dynamicValue.get() : staticValue);
1926 	}
1927 
getActiveDepthClipEnablevkt::pipeline::__anon29419::TestConfig1928 	bool getActiveDepthClipEnable () const
1929 	{
1930 		const bool				staticValue		= (static_cast<bool>(depthClipEnableConfig.staticValue) ? depthClipEnableConfig.staticValue.get() : true);
1931 		const bool				hasDynamicValue	= (static_cast<bool>(depthClipEnableConfig.dynamicValue) && static_cast<bool>(depthClipEnableConfig.dynamicValue.get()));
1932 		const tcu::Maybe<bool>	dynamicValue	= (hasDynamicValue ? tcu::just(depthClipEnableConfig.dynamicValue->get()) : tcu::nothing<bool>());
1933 
1934 		return ((hasDynamicValue && !m_swappedValues) ? dynamicValue.get() : staticValue);
1935 	}
1936 
1937 	// Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anon29419::TestConfig1938 	bool isMultiViewport () const
1939 	{
1940 		return (getActiveViewportVec().size() > 1);
1941 	}
1942 
1943 	// Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anon29419::TestConfig1944 	bool needsGeometryShader () const
1945 	{
1946 		// Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
1947 		// commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
1948 		return ((isMultiViewport() && (!useMeshShaders)) || forceGeometryShader || static_cast<bool>(shaderRasterizationStream));
1949 	}
1950 
1951 	// Returns true if we should use the static and dynamic values exchanged.
1952 	// This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon29419::TestConfig1953 	bool isReversed () const
1954 	{
1955 		return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
1956 				sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
1957 	}
1958 
1959 	// Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon29419::TestConfig1960 	void swapValues ()
1961 	{
1962 		vertexGenerator.swapValues();
1963 		cullModeConfig.swapValues();
1964 		frontFaceConfig.swapValues();
1965 		topologyConfig.swapValues();
1966 		viewportConfig.swapValues();
1967 		scissorConfig.swapValues();
1968 		strideConfig.swapValues();
1969 		depthTestEnableConfig.swapValues();
1970 		depthWriteEnableConfig.swapValues();
1971 		depthCompareOpConfig.swapValues();
1972 		depthBoundsTestEnableConfig.swapValues();
1973 		stencilTestEnableConfig.swapValues();
1974 		stencilOpConfig.swapValues();
1975 		depthBiasEnableConfig.swapValues();
1976 		rastDiscardEnableConfig.swapValues();
1977 		primRestartEnableConfig.swapValues();
1978 		logicOpConfig.swapValues();
1979 		patchControlPointsConfig.swapValues();
1980 		depthBiasConfig.swapValues();
1981 		tessDomainOriginConfig.swapValues();
1982 		depthClampEnableConfig.swapValues();
1983 		polygonModeConfig.swapValues();
1984 		sampleMaskConfig.swapValues();
1985 		alphaToCoverageConfig.swapValues();
1986 		alphaToOneConfig.swapValues();
1987 		colorWriteMaskConfig.swapValues();
1988 		rasterizationStreamConfig.swapValues();
1989 		logicOpEnableConfig.swapValues();
1990 		colorBlendEnableConfig.swapValues();
1991 		colorBlendEquationConfig.swapValues();
1992 		provokingVertexConfig.swapValues();
1993 		negativeOneToOneConfig.swapValues();
1994 		depthClipEnableConfig.swapValues();
1995 		lineStippleEnableConfig.swapValues();
1996 		lineStippleParamsConfig.swapValues();
1997 		sampleLocationsEnableConfig.swapValues();
1998 		conservativeRasterModeConfig.swapValues();
1999 		extraPrimitiveOverEstConfig.swapValues();
2000 		lineRasterModeConfig.swapValues();
2001 		coverageToColorEnableConfig.swapValues();
2002 		coverageToColorLocationConfig.swapValues();
2003 		rasterizationSamplesConfig.swapValues();
2004 #ifndef CTS_USES_VULKANSC
2005 		coverageModulationModeConfig.swapValues();
2006 		coverageModTableEnableConfig.swapValues();
2007 		coverageModTableConfig.swapValues();
2008 		coverageReductionModeConfig.swapValues();
2009 		viewportSwizzleConfig.swapValues();
2010 		shadingRateImageEnableConfig.swapValues();
2011 		viewportWScalingEnableConfig.swapValues();
2012 		reprFragTestEnableConfig.swapValues();
2013 #endif // CTS_USES_VULKANSC
2014 
2015 		m_swappedValues = !m_swappedValues;
2016 	}
2017 
2018 	// Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon29419::TestConfig2019 	deUint32 numIterations () const
2020 	{
2021 		deUint32 iterations = 0u;
2022 
2023 		switch (sequenceOrdering)
2024 		{
2025 		case SequenceOrdering::TWO_DRAWS_DYNAMIC:
2026 		case SequenceOrdering::TWO_DRAWS_STATIC:
2027 			iterations = 2u;
2028 			break;
2029 		default:
2030 			iterations = 1u;
2031 			break;
2032 		}
2033 
2034 		return iterations;
2035 	}
2036 
2037 	// Returns true if we're testing the logic op.
testLogicOpvkt::pipeline::__anon29419::TestConfig2038 	bool testLogicOp () const
2039 	{
2040 		return static_cast<bool>(logicOpConfig.dynamicValue);
2041 	}
2042 
2043 	// Returns true if we're testing the logic op enable state.
testLogicOpEnablevkt::pipeline::__anon29419::TestConfig2044 	bool testLogicOpEnable () const
2045 	{
2046 		return static_cast<bool>(logicOpEnableConfig.dynamicValue);
2047 	}
2048 
2049 	// Returns true if we're testing the patch control points.
testPatchControlPointsvkt::pipeline::__anon29419::TestConfig2050 	bool testPatchControlPoints () const
2051 	{
2052 		return static_cast<bool>(patchControlPointsConfig.dynamicValue);
2053 	}
2054 
2055 	// Returns true if we're testing tessellation domain origin.
testTessellationDomainOriginvkt::pipeline::__anon29419::TestConfig2056 	bool testTessellationDomainOrigin () const
2057 	{
2058 		return static_cast<bool>(tessDomainOriginConfig.dynamicValue);
2059 	}
2060 
2061 	// Returns true if we're testing primitive restart enable.
testPrimRestartEnablevkt::pipeline::__anon29419::TestConfig2062 	bool testPrimRestartEnable () const
2063 	{
2064 		return static_cast<bool>(primRestartEnableConfig.dynamicValue);
2065 	}
2066 
2067 	// Returns true if the topology class is patches for tessellation.
patchesTopologyvkt::pipeline::__anon29419::TestConfig2068 	bool patchesTopology () const
2069 	{
2070 		return (getTopologyClass(topologyConfig.staticValue) == TopologyClass::PATCH);
2071 	}
2072 
2073 	// Returns true if the test needs tessellation shaders.
needsTessellationvkt::pipeline::__anon29419::TestConfig2074 	bool needsTessellation () const
2075 	{
2076 		return (testPatchControlPoints() || patchesTopology() || testTessellationDomainOrigin());
2077 	}
2078 
2079 	// Returns the active line stipple enablement flag.
getActiveLineStippleEnablevkt::pipeline::__anon29419::TestConfig2080 	bool getActiveLineStippleEnable () const
2081 	{
2082 		return ((static_cast<bool>(lineStippleEnableConfig.dynamicValue) && !m_swappedValues) ? lineStippleEnableConfig.dynamicValue.get() : lineStippleEnableConfig.staticValue);
2083 	}
2084 
2085 	// Returns the active primitive restart enablement flag.
getActivePrimRestartEnablevkt::pipeline::__anon29419::TestConfig2086 	bool getActivePrimRestartEnable () const
2087 	{
2088 		return ((static_cast<bool>(primRestartEnableConfig.dynamicValue) && !m_swappedValues) ? primRestartEnableConfig.dynamicValue.get() : primRestartEnableConfig.staticValue);
2089 	}
2090 
2091 	// Returns the active representative fragment test enablement flag.
getActiveReprFragTestEnablevkt::pipeline::__anon29419::TestConfig2092 	bool getActiveReprFragTestEnable () const
2093 	{
2094 #ifndef CTS_USES_VULKANSC
2095 		return ((static_cast<bool>(reprFragTestEnableConfig.dynamicValue) && !m_swappedValues) ? reprFragTestEnableConfig.dynamicValue.get() : reprFragTestEnableConfig.staticValue);
2096 #else
2097 		return false;
2098 #endif // CTS_USES_VULKANSC
2099 	}
2100 
2101 	// Returns true if the test needs an index buffer.
needsIndexBuffervkt::pipeline::__anon29419::TestConfig2102 	bool needsIndexBuffer () const
2103 	{
2104 		return (testPrimRestartEnable() || getActiveLineStippleEnable());
2105 	}
2106 
2107 	// Returns true if the test needs the depth bias clamp feature.
needsDepthBiasClampFeaturevkt::pipeline::__anon29419::TestConfig2108 	bool needsDepthBiasClampFeature () const
2109 	{
2110 		return (getActiveDepthBiasParams().clamp != 0.0f);
2111 	}
2112 
2113 	// Returns true if the configuration needs VK_EXT_extended_dynamic_state3.
needsEDS3vkt::pipeline::__anon29419::TestConfig2114 	bool needsEDS3 () const
2115 	{
2116 		return	(	(!!tessDomainOriginConfig.dynamicValue)
2117 				||	(!!depthClampEnableConfig.dynamicValue)
2118 				||	(!!polygonModeConfig.dynamicValue)
2119 				||	(!!sampleMaskConfig.dynamicValue)
2120 				||	(!!alphaToCoverageConfig.dynamicValue)
2121 				||	(!!alphaToOneConfig.dynamicValue)
2122 				||	(!!colorWriteMaskConfig.dynamicValue)
2123 				||	(!!rasterizationStreamConfig.dynamicValue)
2124 				||	(!!logicOpEnableConfig.dynamicValue)
2125 				||	(!!colorBlendEnableConfig.dynamicValue)
2126 				||	(!!colorBlendEquationConfig.dynamicValue)
2127 				||	(!!provokingVertexConfig.dynamicValue)
2128 				||	(!!negativeOneToOneConfig.dynamicValue)
2129 				||	(!!depthClipEnableConfig.dynamicValue)
2130 				||	(!!lineStippleEnableConfig.dynamicValue)
2131 				||	(!!sampleLocationsEnableConfig.dynamicValue)
2132 				||	(!!conservativeRasterModeConfig.dynamicValue)
2133 				||	(!!extraPrimitiveOverEstConfig.dynamicValue)
2134 				||	(!!lineRasterModeConfig.dynamicValue)
2135 				||	(!!coverageToColorEnableConfig.dynamicValue)
2136 				||	(!!coverageToColorLocationConfig.dynamicValue)
2137 				||	(!!rasterizationSamplesConfig.dynamicValue)
2138 #ifndef CTS_USES_VULKANSC
2139 				||	(!!coverageModulationModeConfig.dynamicValue)
2140 				||	(!!coverageModTableEnableConfig.dynamicValue)
2141 				||	(!!coverageModTableConfig.dynamicValue)
2142 				||	(!!coverageReductionModeConfig.dynamicValue)
2143 				||	(!!viewportSwizzleConfig.dynamicValue)
2144 				||	(!!shadingRateImageEnableConfig.dynamicValue)
2145 				||	(!!viewportWScalingEnableConfig.dynamicValue)
2146 				||	(!!reprFragTestEnableConfig.dynamicValue)
2147 #endif // CTS_USES_VULKANSC
2148 				);
2149 	}
2150 
2151 	// Returns the appropriate color image format for the test.
colorFormatvkt::pipeline::__anon29419::TestConfig2152 	vk::VkFormat colorFormat () const
2153 	{
2154 		// Pick int color format when testing logic op dynamic states.
2155 		if (testLogicOp() || testLogicOpEnable())
2156 			return kIntColorFormat;
2157 
2158 		// Pick special color format for coverage to color.
2159 		if (coverageToColorStruct())
2160 			return kIntRedColorFormat;
2161 
2162 		return kUnormColorFormat;
2163 	}
2164 
2165 	// Get used color sample count.
getColorSampleCountvkt::pipeline::__anon29419::TestConfig2166 	vk::VkSampleCountFlagBits getColorSampleCount () const
2167 	{
2168 		const auto usedColorSampleCount	= ((coverageModulation || coverageReduction)
2169 										? colorSampleCount.get()
2170 										: getActiveSampleCount());
2171 		return usedColorSampleCount;
2172 	}
2173 
2174 	// Returns the list of dynamic states affected by this config.
getDynamicStatesvkt::pipeline::__anon29419::TestConfig2175 	std::vector<vk::VkDynamicState> getDynamicStates () const
2176 	{
2177 		std::vector<vk::VkDynamicState> dynamicStates;
2178 
2179 		if (depthBiasConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS);
2180 		if (cullModeConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
2181 		if (frontFaceConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
2182 		if (topologyConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
2183 		if (viewportConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
2184 		if (scissorConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
2185 		if (strideConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
2186 		if (depthTestEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
2187 		if (depthWriteEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
2188 		if (depthCompareOpConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
2189 		if (depthBoundsTestEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
2190 		if (stencilTestEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
2191 		if (stencilOpConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
2192 		if (vertexGenerator.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
2193 		if (patchControlPointsConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
2194 		if (rastDiscardEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
2195 		if (depthBiasEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
2196 		if (logicOpConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
2197 		if (primRestartEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
2198 #ifndef CTS_USES_VULKANSC
2199 		if (tessDomainOriginConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT);
2200 		if (depthClampEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
2201 		if (polygonModeConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
2202 		if (sampleMaskConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_MASK_EXT);
2203 		if (alphaToCoverageConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
2204 		if (alphaToOneConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
2205 		if (colorWriteMaskConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT);
2206 		if (rasterizationStreamConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT);
2207 		if (logicOpEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
2208 		if (colorBlendEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
2209 		if (colorBlendEquationConfig.dynamicValue)		dynamicStates.push_back(colorBlendEquationConfig.staticValue.isAdvanced()
2210 															? vk::VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT
2211 															: vk::VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
2212 		if (provokingVertexConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT);
2213 		if (negativeOneToOneConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT);
2214 		if (depthClipEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT);
2215 		if (lineStippleEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
2216 		if (lineStippleParamsConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
2217 		if (sampleLocationsEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT);
2218 		if (conservativeRasterModeConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
2219 		if (extraPrimitiveOverEstConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT);
2220 		if (lineRasterModeConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
2221 		if (rasterizationSamplesConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
2222 		if (coverageToColorEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV);
2223 		if (coverageToColorLocationConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV);
2224 		if (coverageModulationModeConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV);
2225 		if (coverageModTableEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV);
2226 		if (coverageModTableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV);
2227 		if (coverageReductionModeConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV);
2228 		if (viewportSwizzleConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV);
2229 		if (shadingRateImageEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV);
2230 		if (viewportWScalingEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV);
2231 		if (reprFragTestEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV);
2232 #else
2233 		DE_ASSERT(false);
2234 #endif // CTS_USES_VULKANSC
2235 
2236 		return dynamicStates;
2237 	}
2238 
2239 #ifndef CTS_USES_VULKANSC
2240 	// Returns true if the test configuration uses dynamic states which are incompatible with mesh shading pipelines.
badMeshShadingPipelineDynStatevkt::pipeline::__anon29419::TestConfig2241 	bool badMeshShadingPipelineDynState () const
2242 	{
2243 		const auto states = getDynamicStates();
2244 		return std::any_of(begin(states), end(states), isMeshShadingPipelineIncompatible);
2245 	}
2246 #endif // CTS_USES_VULKANSC
2247 
testEDSvkt::pipeline::__anon29419::TestConfig2248 	bool testEDS() const
2249 	{
2250 		return (cullModeConfig.dynamicValue
2251 			|| frontFaceConfig.dynamicValue
2252 			|| topologyConfig.dynamicValue
2253 			|| viewportConfig.dynamicValue
2254 			|| scissorConfig.dynamicValue
2255 			|| strideConfig.dynamicValue
2256 			|| depthTestEnableConfig.dynamicValue
2257 			|| depthWriteEnableConfig.dynamicValue
2258 			|| depthCompareOpConfig.dynamicValue
2259 			|| depthBoundsTestEnableConfig.dynamicValue
2260 			|| stencilTestEnableConfig.dynamicValue
2261 			|| stencilOpConfig.dynamicValue);
2262 	}
2263 
testEDS2vkt::pipeline::__anon29419::TestConfig2264 	bool testEDS2() const
2265 	{
2266 		return (rastDiscardEnableConfig.dynamicValue
2267 			|| depthBiasEnableConfig.dynamicValue
2268 			|| primRestartEnableConfig.dynamicValue
2269 			|| useExtraDynPCPPipeline);
2270 	}
2271 
testVertexDynamicvkt::pipeline::__anon29419::TestConfig2272 	bool testVertexDynamic() const
2273 	{
2274 		return static_cast<bool>(vertexGenerator.dynamicValue);
2275 	}
2276 
2277 	// Returns the list of extensions needed by this config. Note some other
2278 	// requirements are checked with feature structs, which is particularly
2279 	// important for extensions which have been partially promoted, like EDS
2280 	// and EDS2. Extensions requested here have not been partially promoted.
getRequiredExtensionsvkt::pipeline::__anon29419::TestConfig2281 	std::vector<std::string> getRequiredExtensions () const
2282 	{
2283 		std::vector<std::string> extensions;
2284 
2285 		if (needsEDS3())
2286 		{
2287 			extensions.push_back("VK_EXT_extended_dynamic_state3");
2288 		}
2289 
2290 		if (testTessellationDomainOrigin() || getActiveTessellationDomainOrigin() != vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
2291 		{
2292 			extensions.push_back("VK_KHR_maintenance2");
2293 		}
2294 
2295 		if (rasterizationStreamStruct())
2296 		{
2297 			extensions.push_back("VK_EXT_transform_feedback");
2298 		}
2299 
2300 		if (provokingVertexStruct())
2301 		{
2302 			extensions.push_back("VK_EXT_provoking_vertex");
2303 		}
2304 
2305 		if (negativeOneToOneStruct())
2306 		{
2307 			extensions.push_back("VK_EXT_depth_clip_control");
2308 		}
2309 
2310 		if (depthClipEnableStruct())
2311 		{
2312 			extensions.push_back("VK_EXT_depth_clip_enable");
2313 		}
2314 
2315 		if (lineRasterizationExt())
2316 		{
2317 			extensions.push_back("VK_EXT_line_rasterization");
2318 		}
2319 
2320 		if (colorBlendEquationConfig.staticValue.isAdvanced())
2321 		{
2322 			extensions.push_back("VK_EXT_blend_operation_advanced");
2323 		}
2324 
2325 		if (sampleLocationsStruct())
2326 		{
2327 			extensions.push_back("VK_EXT_sample_locations");
2328 		}
2329 
2330 		if (coverageToColorStruct())
2331 		{
2332 			extensions.push_back("VK_NV_fragment_coverage_to_color");
2333 		}
2334 
2335 		if (conservativeRasterStruct() || static_cast<bool>(maxPrimitiveOverestimationSize))
2336 		{
2337 			extensions.push_back("VK_EXT_conservative_rasterization");
2338 		}
2339 
2340 		if (coverageModulation)
2341 		{
2342 			extensions.push_back("VK_NV_framebuffer_mixed_samples");
2343 		}
2344 
2345 		if (coverageReduction)
2346 		{
2347 			extensions.push_back("VK_NV_coverage_reduction_mode");
2348 		}
2349 
2350 		if (viewportSwizzle)
2351 		{
2352 			extensions.push_back("VK_NV_viewport_swizzle");
2353 		}
2354 
2355 		if (shadingRateImage)
2356 		{
2357 			extensions.push_back("VK_NV_shading_rate_image");
2358 		}
2359 
2360 		if (viewportWScaling)
2361 		{
2362 			extensions.push_back("VK_NV_clip_space_w_scaling");
2363 		}
2364 
2365 		if (representativeFragmentTest)
2366 		{
2367 			extensions.push_back("VK_NV_representative_fragment_test");
2368 		}
2369 
2370 		return extensions;
2371 	}
2372 
getFragDescriptorSetIndexvkt::pipeline::__anon29419::TestConfig2373 	uint32_t getFragDescriptorSetIndex () const
2374 	{
2375 		return (useMeshShaders ? 1u : 0u);
2376 	}
2377 
2378 private:
2379 	// Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
2380 	// has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
2381 	// expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
2382 	// pipeline with wrong values and a static one with good values.
2383 	//
2384 	// Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
2385 	// 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
2386 	// given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
2387 	bool m_swappedValues;
2388 };
2389 
2390 struct PushConstants
2391 {
2392 	tcu::Vec4	triangleColor;
2393 	float		meshDepth;
2394 	deInt32		viewPortIndex;
2395 	float		scaleX;
2396 	float		scaleY;
2397 	float		offsetX;
2398 	float		offsetY;
2399 	float		stripScale;
2400 };
2401 
copy(vk::VkStencilOpState& dst, const StencilOpParams& src)2402 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
2403 {
2404 	dst.failOp		= src.failOp;
2405 	dst.passOp		= src.passOp;
2406 	dst.depthFailOp	= src.depthFailOp;
2407 	dst.compareOp	= src.compareOp;
2408 }
2409 
makeImageCreateInfo(vk::VkFormat format, vk::VkExtent3D extent, vk::VkSampleCountFlagBits sampleCount, vk::VkImageUsageFlags usage, vk::VkImageCreateFlags createFlags)2410 vk::VkImageCreateInfo makeImageCreateInfo (vk::VkFormat format, vk::VkExtent3D extent, vk::VkSampleCountFlagBits sampleCount, vk::VkImageUsageFlags usage, vk::VkImageCreateFlags createFlags)
2411 {
2412 	const vk::VkImageCreateInfo imageCreateInfo =
2413 	{
2414 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
2415 		nullptr,									//	const void*				pNext;
2416 		createFlags,								//	VkImageCreateFlags		flags;
2417 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
2418 		format,										//	VkFormat				format;
2419 		extent,										//	VkExtent3D				extent;
2420 		1u,											//	deUint32				mipLevels;
2421 		1u,											//	deUint32				arrayLayers;
2422 		sampleCount,								//	VkSampleCountFlagBits	samples;
2423 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
2424 		usage,										//	VkImageUsageFlags		usage;
2425 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
2426 		0u,											//	deUint32				queueFamilyIndexCount;
2427 		nullptr,									//	const deUint32*			pQueueFamilyIndices;
2428 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
2429 	};
2430 
2431 	return imageCreateInfo;
2432 }
2433 
2434 class ExtendedDynamicStateTest : public vkt::TestCase
2435 {
2436 public:
2437 							ExtendedDynamicStateTest		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ExtendedDynamicStateTest(void)2438 	virtual					~ExtendedDynamicStateTest		(void) {}
2439 
2440 	virtual void			checkSupport					(Context& context) const;
2441 	virtual void			initPrograms					(vk::SourceCollections& programCollection) const;
2442 	virtual TestInstance*	createInstance					(Context& context) const;
2443 
2444 private:
2445 	TestConfig				m_testConfig;
2446 };
2447 
2448 class ExtendedDynamicStateInstance : public vkt::TestInstance
2449 {
2450 public:
2451 								ExtendedDynamicStateInstance	(Context& context, const TestConfig& testConfig);
~ExtendedDynamicStateInstance(void)2452 	virtual						~ExtendedDynamicStateInstance	(void) {}
2453 
2454 	virtual tcu::TestStatus		iterate							(void);
2455 
2456 private:
2457 	TestConfig					m_testConfig;
2458 };
2459 
ExtendedDynamicStateTest(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)2460 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
2461 	: vkt::TestCase	(testCtx, name, description)
2462 	, m_testConfig	(testConfig)
2463 {
2464 	const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
2465 	DE_UNREF(staticTopologyClass); // For release builds.
2466 
2467 	// Matching topology classes.
2468 	DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
2469 			  staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
2470 
2471 	// Supported topology classes for these tests.
2472 	DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE
2473 		|| staticTopologyClass == TopologyClass::PATCH);
2474 
2475 	// Make sure these are consistent.
2476 	DE_ASSERT(!(m_testConfig.testPatchControlPoints() && !m_testConfig.patchesTopology()));
2477 	DE_ASSERT(!(m_testConfig.patchesTopology() && m_testConfig.getActivePatchControlPoints() <= 1u));
2478 
2479 	// Do not use an extra dynamic patch control points pipeline if we're not testing them.
2480 	DE_ASSERT(!m_testConfig.useExtraDynPCPPipeline || m_testConfig.testPatchControlPoints());
2481 }
2482 
checkSupport(Context& context) const2483 void ExtendedDynamicStateTest::checkSupport (Context& context) const
2484 {
2485 	const auto&	vki				= context.getInstanceInterface();
2486 	const auto	physicalDevice	= context.getPhysicalDevice();
2487 
2488 	// Check feature support.
2489 	const auto& edsFeatures		= context.getExtendedDynamicStateFeaturesEXT();
2490 	const auto& eds2Features	= context.getExtendedDynamicState2FeaturesEXT();
2491 	const auto& viFeatures		= context.getVertexInputDynamicStateFeaturesEXT();
2492 #ifndef CTS_USES_VULKANSC
2493 	const auto& meshFeatures	= context.getMeshShaderFeaturesEXT();
2494 #endif // CTS_USES_VULKANSC
2495 
2496 	if (m_testConfig.testEDS() && !edsFeatures.extendedDynamicState)
2497 		TCU_THROW(NotSupportedError, "extendedDynamicState is not supported");
2498 
2499 	if (m_testConfig.testEDS2() && !eds2Features.extendedDynamicState2)
2500 		TCU_THROW(NotSupportedError, "extendedDynamicState2 is not supported");
2501 
2502 	if (m_testConfig.testLogicOp() && !eds2Features.extendedDynamicState2LogicOp)
2503 		TCU_THROW(NotSupportedError, "extendedDynamicState2LogicOp is not supported");
2504 
2505 	if ((m_testConfig.testPatchControlPoints() || m_testConfig.useExtraDynPCPPipeline) && !eds2Features.extendedDynamicState2PatchControlPoints)
2506 		TCU_THROW(NotSupportedError, "extendedDynamicState2PatchControlPoints is not supported");
2507 
2508 	if (m_testConfig.testVertexDynamic() && !viFeatures.vertexInputDynamicState)
2509 		TCU_THROW(NotSupportedError, "vertexInputDynamicState is not supported");
2510 
2511 #ifndef CTS_USES_VULKANSC
2512 	if ((m_testConfig.useMeshShaders || m_testConfig.bindUnusedMeshShadingPipeline) && !meshFeatures.meshShader)
2513 		TCU_THROW(NotSupportedError, "meshShader is not supported");
2514 #endif // CTS_USES_VULKANSC
2515 
2516 	// Check extension support.
2517 	const auto requiredExtensions = m_testConfig.getRequiredExtensions();
2518 	for (const auto& extension : requiredExtensions)
2519 		context.requireDeviceFunctionality(extension);
2520 
2521 	// Special requirement for rasterizationSamples tests.
2522 	// The first iteration of these tests puts the pipeline in a mixed samples state,
2523 	// where colorCount != rasterizationSamples.
2524 	if (m_testConfig.rasterizationSamplesConfig.dynamicValue &&
2525 		(m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
2526 		 m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC) &&
2527 		!context.isDeviceFunctionalitySupported("VK_AMD_mixed_attachment_samples") &&
2528 		!context.isDeviceFunctionalitySupported("VK_NV_framebuffer_mixed_samples"))
2529 
2530 		TCU_THROW(NotSupportedError, "VK_AMD_mixed_attachment_samples or VK_NV_framebuffer_mixed_samples are not supported");
2531 
2532 	// Check the number of viewports needed and the corresponding limits.
2533 	const auto&	viewportConfig	= m_testConfig.viewportConfig;
2534 	auto		numViewports	= viewportConfig.staticValue.size();
2535 
2536 	if (viewportConfig.dynamicValue)
2537 		numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
2538 
2539 	if (numViewports > 1)
2540 	{
2541 		const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
2542 		if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
2543 			TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
2544 	}
2545 
2546 	const auto&	dbTestEnable	= m_testConfig.depthBoundsTestEnableConfig;
2547 	const bool	useDepthBounds	= (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
2548 
2549 	if (useDepthBounds || m_testConfig.needsGeometryShader() || m_testConfig.needsTessellation() || m_testConfig.needsDepthBiasClampFeature())
2550 	{
2551 		const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
2552 
2553 		// Check depth bounds test support.
2554 		if (useDepthBounds && !features.depthBounds)
2555 			TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
2556 
2557 		// Check geometry shader support.
2558 		if (m_testConfig.needsGeometryShader() && !features.geometryShader)
2559 			TCU_THROW(NotSupportedError, "Geometry shader not supported");
2560 
2561 		// Check tessellation support
2562 		if (m_testConfig.needsTessellation() && !features.tessellationShader)
2563 			TCU_THROW(NotSupportedError, "Tessellation feature not supported");
2564 
2565 		// Check depth bias clamp feature.
2566 		if (m_testConfig.needsDepthBiasClampFeature() && !features.depthBiasClamp)
2567 			TCU_THROW(NotSupportedError, "Depth bias clamp not supported");
2568 	}
2569 
2570 	// Check color image format support (depth/stencil will be chosen and checked at runtime).
2571 	{
2572 		const auto colorFormat		= m_testConfig.colorFormat();
2573 		const auto colorSampleCount	= m_testConfig.getColorSampleCount();
2574 		const auto colorImageInfo	= makeImageCreateInfo(colorFormat, kFramebufferExtent, colorSampleCount, kColorUsage, 0u);
2575 
2576 		vk::VkImageFormatProperties formatProps;
2577 		const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, colorImageInfo.format, colorImageInfo.imageType, colorImageInfo.tiling, colorImageInfo.usage, colorImageInfo.flags, &formatProps);
2578 
2579 		if (result != vk::VK_SUCCESS)
2580 			TCU_THROW(NotSupportedError, "Required color image features not supported");
2581 
2582 		if ((formatProps.sampleCounts & colorSampleCount) != colorSampleCount)
2583 			TCU_THROW(NotSupportedError, "Required color sample count not supported");
2584 	}
2585 
2586 	// Extended dynamic state 3 features.
2587 	if (m_testConfig.needsEDS3())
2588 	{
2589 #ifndef CTS_USES_VULKANSC
2590 		const auto& eds3Features = context.getExtendedDynamicState3FeaturesEXT();
2591 
2592 		if (m_testConfig.testTessellationDomainOrigin() && !eds3Features.extendedDynamicState3TessellationDomainOrigin)
2593 			TCU_THROW(NotSupportedError, "extendedDynamicState3TessellationDomainOrigin not supported");
2594 
2595 		if (m_testConfig.depthClampEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3DepthClampEnable)
2596 			TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClampEnable not supported");
2597 
2598 		if (m_testConfig.polygonModeConfig.dynamicValue && !eds3Features.extendedDynamicState3PolygonMode)
2599 			TCU_THROW(NotSupportedError, "extendedDynamicState3PolygonMode not supported");
2600 
2601 		if (m_testConfig.sampleMaskConfig.dynamicValue && !eds3Features.extendedDynamicState3SampleMask)
2602 			TCU_THROW(NotSupportedError, "extendedDynamicState3SampleMask not supported");
2603 
2604 		if (m_testConfig.alphaToCoverageConfig.dynamicValue && !eds3Features.extendedDynamicState3AlphaToCoverageEnable)
2605 			TCU_THROW(NotSupportedError, "extendedDynamicState3AlphaToCoverageEnable not supported");
2606 
2607 		if (m_testConfig.alphaToOneConfig.dynamicValue && !eds3Features.extendedDynamicState3AlphaToOneEnable)
2608 			TCU_THROW(NotSupportedError, "extendedDynamicState3AlphaToOneEnable not supported");
2609 
2610 		if (m_testConfig.colorWriteMaskConfig.dynamicValue && !eds3Features.extendedDynamicState3ColorWriteMask)
2611 			TCU_THROW(NotSupportedError, "extendedDynamicState3ColorWriteMask not supported");
2612 
2613 		if (m_testConfig.rasterizationStreamConfig.dynamicValue && !eds3Features.extendedDynamicState3RasterizationStream)
2614 			TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationStream not supported");
2615 
2616 		if (m_testConfig.logicOpEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3LogicOpEnable)
2617 			TCU_THROW(NotSupportedError, "extendedDynamicState3LogicOpEnable not supported");
2618 
2619 		if (m_testConfig.colorBlendEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3ColorBlendEnable)
2620 			TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendEnable not supported");
2621 
2622 		if (m_testConfig.colorBlendEquationConfig.dynamicValue)
2623 		{
2624 			if (m_testConfig.colorBlendEquationConfig.staticValue.isAdvanced())
2625 			{
2626 				if (!eds3Features.extendedDynamicState3ColorBlendAdvanced)
2627 					TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendAdvanced not supported");
2628 			}
2629 			else
2630 			{
2631 				if (!eds3Features.extendedDynamicState3ColorBlendEquation)
2632 					TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendEquation not supported");
2633 			}
2634 		}
2635 
2636 		if (m_testConfig.provokingVertexConfig.dynamicValue && !eds3Features.extendedDynamicState3ProvokingVertexMode)
2637 			TCU_THROW(NotSupportedError, "extendedDynamicState3ProvokingVertexMode not supported");
2638 
2639 		if (m_testConfig.negativeOneToOneConfig.dynamicValue && !eds3Features.extendedDynamicState3DepthClipNegativeOneToOne)
2640 			TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClipNegativeOneToOne not supported");
2641 
2642 		if (m_testConfig.depthClipEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3DepthClipEnable)
2643 			TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClipEnable not supported");
2644 
2645 		if (m_testConfig.lineStippleEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3LineStippleEnable)
2646 			TCU_THROW(NotSupportedError, "extendedDynamicState3LineStippleEnable not supported");
2647 
2648 		if (m_testConfig.sampleLocationsEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3SampleLocationsEnable)
2649 			TCU_THROW(NotSupportedError, "extendedDynamicState3SampleLocationsEnable not supported");
2650 
2651 		if (m_testConfig.conservativeRasterModeConfig.dynamicValue && !eds3Features.extendedDynamicState3ConservativeRasterizationMode)
2652 			TCU_THROW(NotSupportedError, "extendedDynamicState3ConservativeRasterizationMode not supported");
2653 
2654 		if (m_testConfig.extraPrimitiveOverEstConfig.dynamicValue && !eds3Features.extendedDynamicState3ExtraPrimitiveOverestimationSize)
2655 			TCU_THROW(NotSupportedError, "extendedDynamicState3ExtraPrimitiveOverestimationSize not supported");
2656 
2657 		if (m_testConfig.lineRasterModeConfig.dynamicValue && !eds3Features.extendedDynamicState3LineRasterizationMode)
2658 			TCU_THROW(NotSupportedError, "extendedDynamicState3LineRasterizationMode not supported");
2659 
2660 		if (m_testConfig.coverageToColorEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3CoverageToColorEnable)
2661 			TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageToColorEnable not supported");
2662 
2663 		if (m_testConfig.coverageToColorLocationConfig.dynamicValue && !eds3Features.extendedDynamicState3CoverageToColorLocation)
2664 			TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageToColorLocation not supported");
2665 
2666 		if (m_testConfig.coverageModulationModeConfig.dynamicValue && !eds3Features.extendedDynamicState3CoverageModulationMode)
2667 			TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationMode not supported");
2668 
2669 		if (m_testConfig.coverageModTableEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3CoverageModulationTableEnable)
2670 			TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationTableEnable not supported");
2671 
2672 		if (m_testConfig.coverageModTableConfig.dynamicValue && !eds3Features.extendedDynamicState3CoverageModulationTable)
2673 			TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationTable not supported");
2674 
2675 		if (m_testConfig.coverageReductionModeConfig.dynamicValue)
2676 		{
2677 			if (!eds3Features.extendedDynamicState3CoverageReductionMode)
2678 				TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageReductionMode not supported");
2679 
2680 			uint32_t combinationCount = 0U;
2681 			auto result = vki.getPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(physicalDevice, &combinationCount, nullptr);
2682 			if (result != vk::VK_SUCCESS || combinationCount == 0U)
2683 				TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV supported no combinations");
2684 
2685 			std::vector<vk::VkFramebufferMixedSamplesCombinationNV> combinations(combinationCount);
2686 			result = vki.getPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(physicalDevice, &combinationCount, combinations.data());
2687 			if (result != vk::VK_SUCCESS)
2688 				TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV supported no combinations");
2689 
2690 			auto findCombination = [&](vk::VkCoverageReductionModeNV const coverageReductionMode) -> bool {
2691 				for (uint32_t i = 0U; i < combinationCount; ++i) {
2692 					if (combinations[i].rasterizationSamples == m_testConfig.rasterizationSamplesConfig.staticValue &&
2693 						combinations[i].colorSamples == m_testConfig.getColorSampleCount() &&
2694 						combinations[i].coverageReductionMode == coverageReductionMode) {
2695 
2696 						return true;
2697 					}
2698 				}
2699 				return false;
2700 			};
2701 			if (!findCombination(m_testConfig.coverageReductionModeConfig.staticValue) || !findCombination(m_testConfig.coverageReductionModeConfig.dynamicValue.get()))
2702 				TCU_THROW(NotSupportedError, "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV no matching combination found");
2703 		}
2704 
2705 		if (m_testConfig.viewportSwizzleConfig.dynamicValue && !eds3Features.extendedDynamicState3ViewportSwizzle)
2706 			TCU_THROW(NotSupportedError, "extendedDynamicState3ViewportSwizzle not supported");
2707 
2708 		if (m_testConfig.shadingRateImageEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3ShadingRateImageEnable)
2709 			TCU_THROW(NotSupportedError, "extendedDynamicState3ShadingRateImageEnable not supported");
2710 
2711 		if (m_testConfig.viewportWScalingEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3ViewportWScalingEnable)
2712 			TCU_THROW(NotSupportedError, "extendedDynamicState3ViewportWScalingEnable not supported");
2713 
2714 		if (m_testConfig.reprFragTestEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3RepresentativeFragmentTestEnable)
2715 			TCU_THROW(NotSupportedError, "extendedDynamicState3RepresentativeFragmentTestEnable not supported");
2716 
2717 		if (m_testConfig.rasterizationSamplesConfig.dynamicValue && !eds3Features.extendedDynamicState3RasterizationSamples)
2718 			TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationSamples not supported");
2719 #else
2720 		TCU_THROW(NotSupportedError, "VulkanSC does not support extended dynamic state 3");
2721 #endif // CTS_USES_VULKANSC
2722 	}
2723 
2724 	if (m_testConfig.getActivePolygonMode() != vk::VK_POLYGON_MODE_FILL)
2725 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FILL_MODE_NON_SOLID);
2726 
2727 	if (m_testConfig.getActiveAlphaToOne())
2728 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_ALPHA_TO_ONE);
2729 
2730 	if (m_testConfig.rasterizationStreamStruct() || static_cast<bool>(m_testConfig.shaderRasterizationStream))
2731 	{
2732 #ifndef CTS_USES_VULKANSC
2733 		const auto& xfProperties = context.getTransformFeedbackPropertiesEXT();
2734 		if (!xfProperties.transformFeedbackRasterizationStreamSelect)
2735 			TCU_THROW(NotSupportedError, "transformFeedbackRasterizationStreamSelect not supported");
2736 
2737 		// VUID-RuntimeSpirv-Stream-06312
2738 		if (static_cast<bool>(m_testConfig.shaderRasterizationStream))
2739 		{
2740 			const auto shaderStreamId = m_testConfig.shaderRasterizationStream.get();
2741 			if (shaderStreamId >= xfProperties.maxTransformFeedbackStreams)
2742 				TCU_THROW(NotSupportedError, "Geometry shader rasterization stream above maxTransformFeedbackStreams limit");
2743 		}
2744 
2745 		// VUID-VkPipelineRasterizationStateStreamCreateInfoEXT-rasterizationStream-02325
2746 		if (static_cast<bool>(m_testConfig.rasterizationStreamConfig.staticValue))
2747 		{
2748 			const auto staticStreamId = m_testConfig.rasterizationStreamConfig.staticValue.get();
2749 			if (staticStreamId >= xfProperties.maxTransformFeedbackStreams)
2750 				TCU_THROW(NotSupportedError, "Static stream number above maxTransformFeedbackStreams limit");
2751 		}
2752 		if (static_cast<bool>(m_testConfig.rasterizationStreamConfig.dynamicValue && static_cast<bool>(m_testConfig.rasterizationStreamConfig.dynamicValue.get())))
2753 		{
2754 			const auto dynamicStreamId = m_testConfig.rasterizationStreamConfig.dynamicValue->get();
2755 			if (dynamicStreamId >= xfProperties.maxTransformFeedbackStreams)
2756 				TCU_THROW(NotSupportedError, "Dynamic stream number above maxTransformFeedbackStreams limit");
2757 		}
2758 #else
2759 		TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_transform_feedback");
2760 #endif // CTS_USES_VULKANSC
2761 	}
2762 
2763 	if (m_testConfig.lineRasterizationExt())
2764 	{
2765 		// Check the implementation supports some type of stippled line.
2766 		const auto&	lineRastFeatures	= context.getLineRasterizationFeaturesEXT();
2767 		const auto	rasterMode			= selectLineRasterizationMode(lineRastFeatures, m_testConfig.lineStippleSupportRequired(), m_testConfig.lineRasterModeConfig.staticValue);
2768 
2769 		if (rasterMode == LineRasterizationMode::NONE)
2770 			TCU_THROW(NotSupportedError, "Wanted static line rasterization mode not supported");
2771 
2772 		if (static_cast<bool>(m_testConfig.lineRasterModeConfig.dynamicValue) && static_cast<bool>(m_testConfig.lineRasterModeConfig.dynamicValue.get()))
2773 		{
2774 			const auto dynRasterMode = selectLineRasterizationMode(lineRastFeatures, m_testConfig.lineStippleSupportRequired(), m_testConfig.lineRasterModeConfig.dynamicValue.get());
2775 
2776 			if (dynRasterMode == LineRasterizationMode::NONE)
2777 				TCU_THROW(NotSupportedError, "Wanted dynamic line rasterization mode not supported");
2778 		}
2779 	}
2780 
2781 	const auto hasMaxPrimitiveOverestimationSize = static_cast<bool>(m_testConfig.maxPrimitiveOverestimationSize);
2782 
2783 	if (m_testConfig.conservativeRasterStruct() || hasMaxPrimitiveOverestimationSize)
2784 	{
2785 		const auto& conservativeRasterModeProps = context.getConservativeRasterizationPropertiesEXT();
2786 
2787 		if (m_testConfig.getActiveConservativeRasterMode() == vk::VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT && !conservativeRasterModeProps.primitiveUnderestimation)
2788 			TCU_THROW(NotSupportedError, "primitiveUnderestimation not supported");
2789 
2790 		const auto	extraSize	= m_testConfig.getActiveExtraPrimitiveOverEstSize();
2791 		const auto&	maxExtra	= conservativeRasterModeProps.maxExtraPrimitiveOverestimationSize;
2792 
2793 		if (extraSize >= 0.0f && extraSize > maxExtra)
2794 		{
2795 			std::ostringstream msg;
2796 			msg << "Extra primitive overestimation size (" << extraSize << ") above maxExtraPrimitiveOverestimationSize (" << maxExtra << ")";
2797 			TCU_THROW(NotSupportedError, msg.str());
2798 		}
2799 
2800 		if (hasMaxPrimitiveOverestimationSize)
2801 		{
2802 			const auto maxPrimitiveOverestimationSizeVal = m_testConfig.maxPrimitiveOverestimationSize.get();
2803 			if (conservativeRasterModeProps.primitiveOverestimationSize > maxPrimitiveOverestimationSizeVal)
2804 			{
2805 				std::ostringstream msg;
2806 				msg << "primitiveOverestimationSize (" << conservativeRasterModeProps.primitiveOverestimationSize
2807 					<< ") too big for this test (max " << maxPrimitiveOverestimationSizeVal << ")";
2808 				TCU_THROW(NotSupportedError, msg.str());
2809 			}
2810 		}
2811 	}
2812 
2813 	if (m_testConfig.representativeFragmentTest)
2814 		context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
2815 
2816 	checkPipelineLibraryRequirements(vki, physicalDevice, m_testConfig.pipelineConstructionType);
2817 }
2818 
initPrograms(vk::SourceCollections& programCollection) const2819 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
2820 {
2821 	const vk::ShaderBuildOptions meshBuildOptions (programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
2822 
2823 	std::ostringstream pushSource;
2824 	std::ostringstream fragOutputLocationStream;
2825 	std::ostringstream vertSourceTemplateStream;
2826 	std::ostringstream fragSourceTemplateStream;
2827 	std::ostringstream geomSource;
2828 	std::ostringstream tescSource;
2829 	std::ostringstream teseSource;
2830 	std::ostringstream meshSource;
2831 
2832 	pushSource
2833 		<< "layout(push_constant, std430) uniform PushConstantsBlock {\n"
2834 		<< "    vec4  triangleColor;\n"
2835 		<< "    float depthValue;\n"
2836 		<< "    int   viewPortIndex;\n"
2837 		<< "    float scaleX;\n"
2838 		<< "    float scaleY;\n"
2839 		<< "    float offsetX;\n"
2840 		<< "    float offsetY;\n"
2841 		<< "    float stripScale;\n"
2842 		<< "} pushConstants;\n"
2843 		;
2844 	const auto pushConstants = pushSource.str();
2845 
2846 	for (uint32_t refIdx = 0; refIdx < m_testConfig.colorAttachmentCount; ++refIdx)
2847 	{
2848 		const bool used = (refIdx == m_testConfig.colorAttachmentCount - 1u);
2849 		const std::string attName = (used ? "color" : "unused" + std::to_string(refIdx));
2850 		fragOutputLocationStream << "layout(location=" << refIdx << ") out ${OUT_COLOR_VTYPE} " << attName << ";\n";
2851 	}
2852 	const auto fragOutputLocations = fragOutputLocationStream.str();
2853 
2854 	// The actual generator, attributes and calculations.
2855 	const auto			activeGen	= m_testConfig.getActiveVertexGenerator();
2856 	const auto			attribDecls	= activeGen->getAttributeDeclarations();
2857 	const auto			coordCalcs	= activeGen->getVertexCoordCalc();
2858 	const auto			descDeclsV	= activeGen->getDescriptorDeclarations();
2859 	const auto			descCalcsV	= activeGen->getDescriptorCoordCalc();
2860 	const auto			fragInputs	= activeGen->getFragInputAttributes();
2861 	const auto			fragCalcs	= activeGen->getFragOutputCalc();
2862 
2863 	// The static generator, attributes and calculations, for the static pipeline, if needed.
2864 	const auto			inactiveGen			= m_testConfig.getInactiveVertexGenerator();
2865 	const auto			staticAttribDec		= inactiveGen->getAttributeDeclarations();
2866 	const auto			staticCoordCalc		= inactiveGen->getVertexCoordCalc();
2867 	const auto			staticFragInputs	= inactiveGen->getFragInputAttributes();
2868 	const auto			staticFragCalcs		= inactiveGen->getFragOutputCalc();
2869 
2870 	std::ostringstream	activeAttribs;
2871 	std::ostringstream	activeCalcs;
2872 	std::ostringstream	activeFragInputs;
2873 	std::ostringstream	activeFragCalcs;
2874 	std::ostringstream	inactiveAttribs;
2875 	std::ostringstream	inactiveCalcs;
2876 	std::ostringstream	descDecls;
2877 	std::ostringstream	descCalcs;
2878 	std::ostringstream	inactiveFragInputs;
2879 	std::ostringstream	inactiveFragCalcs;
2880 
2881 	for (const auto& decl : attribDecls)
2882 		activeAttribs << decl << "\n";
2883 
2884 	for (const auto& statement : coordCalcs)
2885 		activeCalcs << "    " << statement << "\n";
2886 
2887 	for (const auto& decl : staticAttribDec)
2888 		inactiveAttribs << decl << "\n";
2889 
2890 	for (const auto& statement : staticCoordCalc)
2891 		inactiveCalcs << "    " << statement << "\n";
2892 
2893 	for (const auto& decl : descDeclsV)
2894 		descDecls << decl << "\n";
2895 
2896 	for (const auto& calc : descCalcsV)
2897 		descCalcs << "    " << calc << "\n";
2898 
2899 	for (const auto& decl : fragInputs)
2900 		activeFragInputs << decl << "\n";
2901 
2902 	for (const auto& statement : fragCalcs)
2903 		activeFragCalcs << "    " << statement << "\n";
2904 
2905 	for (const auto& decl : staticFragInputs)
2906 		inactiveFragInputs << decl << "\n";
2907 
2908 	for (const auto& statement : staticFragCalcs)
2909 		inactiveFragCalcs << "    " << statement << "\n";
2910 
2911 	vertSourceTemplateStream
2912 		<< "#version 450\n"
2913 		<< pushConstants
2914 		<< "${ATTRIBUTES}"
2915 		<< "out gl_PerVertex\n"
2916 		<< "{\n"
2917 		<< "    vec4 gl_Position;\n"
2918 		<< "};\n"
2919 		<< "void main() {\n"
2920 		<< "${CALCULATIONS}"
2921 		<< "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
2922 		<< "    vec2 stripOffset;\n"
2923 		<< "    switch (gl_VertexIndex) {\n"
2924 		<< "    case 0: stripOffset = vec2(0.0, 0.0); break;\n"
2925 		<< "    case 1: stripOffset = vec2(0.0, 1.0); break;\n"
2926 		<< "    case 2: stripOffset = vec2(1.0, 0.0); break;\n"
2927 		<< "    case 3: stripOffset = vec2(1.0, 1.0); break;\n"
2928 		<< "    case 4: stripOffset = vec2(2.0, 0.0); break;\n"
2929 		<< "    case 5: stripOffset = vec2(2.0, 1.0); break;\n"
2930 		<< "    default: stripOffset = vec2(-1000.0); break;\n"
2931 		<< "    }\n"
2932 		<< "    gl_Position.xy += pushConstants.stripScale * stripOffset;\n"
2933 		<< "}\n"
2934 		;
2935 
2936 	tcu::StringTemplate vertSourceTemplate (vertSourceTemplateStream.str());
2937 
2938 	const auto colorFormat	= m_testConfig.colorFormat();
2939 	const auto vecType		= (vk::isUnormFormat(colorFormat) ? "vec4" : "uvec4");
2940 	const auto fragSetIndex	= std::to_string(m_testConfig.getFragDescriptorSetIndex());
2941 
2942 	fragSourceTemplateStream
2943 		<< "#version 450\n"
2944 		<< (m_testConfig.representativeFragmentTest ? "layout(early_fragment_tests) in;\n" : "")
2945 		<< (m_testConfig.representativeFragmentTest ? "layout(set=" + fragSetIndex + ", binding=0, std430) buffer AtomicBlock { uint fragCounter; } counterBuffer;\n" : "")
2946 		<< pushConstants
2947 		<< fragOutputLocations
2948 		<< "${FRAG_INPUTS}"
2949 		<< "void main() {\n"
2950 		<< "    color = ${OUT_COLOR_VTYPE}(pushConstants.triangleColor);\n"
2951 		<< "${FRAG_CALCULATIONS}"
2952 		<< (m_testConfig.representativeFragmentTest ? "    atomicAdd(counterBuffer.fragCounter, 1u);\n" : "")
2953 		<< "}\n"
2954 		;
2955 
2956 	tcu::StringTemplate fragSourceTemplate (fragSourceTemplateStream.str());
2957 
2958 	std::map<std::string, std::string> activeMap;
2959 	std::map<std::string, std::string> inactiveMap;
2960 
2961 	activeMap["ATTRIBUTES"]			= activeAttribs.str();
2962 	activeMap["CALCULATIONS"]		= activeCalcs.str();
2963 	activeMap["FRAG_INPUTS"]		= activeFragInputs.str();
2964 	activeMap["FRAG_CALCULATIONS"]	= activeFragCalcs.str();
2965 	activeMap["OUT_COLOR_VTYPE"]	= vecType;
2966 
2967 	inactiveMap["ATTRIBUTES"]			= inactiveAttribs.str();
2968 	inactiveMap["CALCULATIONS"]			= inactiveCalcs.str();
2969 	inactiveMap["FRAG_INPUTS"]			= inactiveFragInputs.str();
2970 	inactiveMap["FRAG_CALCULATIONS"]	= inactiveFragCalcs.str();
2971 	inactiveMap["OUT_COLOR_VTYPE"]		= vecType;
2972 
2973 	const auto activeVertSource		= vertSourceTemplate.specialize(activeMap);
2974 	const auto activeFragSource		= fragSourceTemplate.specialize(activeMap);
2975 	const auto inactiveVertSource	= vertSourceTemplate.specialize(inactiveMap);
2976 	const auto inactiveFragSource	= fragSourceTemplate.specialize(inactiveMap);
2977 
2978 	if (m_testConfig.needsGeometryShader())
2979 	{
2980 		const auto			topologyClass	= getTopologyClass(m_testConfig.topologyConfig.staticValue);
2981 		const std::string	inputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
2982 		const deUint32		vertexCount		= ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
2983 		const std::string	outputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
2984 		const auto			selectStream	= static_cast<bool>(m_testConfig.shaderRasterizationStream);
2985 		const auto			streamNumber	= (selectStream ? m_testConfig.shaderRasterizationStream.get() : 0u);
2986 		const auto			streamNumberStr	= de::toString(streamNumber);
2987 
2988 		geomSource
2989 			<< "#version 450\n"
2990 			<< "layout (" << inputPrimitive << ") in;\n"
2991 			<< "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
2992 			<< (m_testConfig.isMultiViewport() ? pushConstants : "")
2993 			<< (selectStream ? "layout (stream=" + streamNumberStr + ") out;\n" : "")
2994 			<< "in gl_PerVertex\n"
2995 			<< "{\n"
2996 			<< "    vec4 gl_Position;\n"
2997 			<< "} gl_in[" << vertexCount << "];\n"
2998 			<< "out gl_PerVertex\n"
2999 			<< "{\n"
3000 			<< "    vec4 gl_Position;\n"
3001 			<< "};\n"
3002 			<< "void main() {\n"
3003 			<< (m_testConfig.isMultiViewport() ? "    gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "")
3004 			;
3005 
3006 		for (deUint32 i = 0; i < vertexCount; ++i)
3007 		{
3008 			geomSource
3009 				<< "    gl_Position = gl_in[" << i << "].gl_Position;\n"
3010 				<< "    " << (selectStream ? ("EmitStreamVertex(" + streamNumberStr + ")") : "EmitVertex()") << ";\n"
3011 				;
3012 		}
3013 
3014 		geomSource
3015 			<< "}\n"
3016 			;
3017 	}
3018 
3019 	if (m_testConfig.needsTessellation())
3020 	{
3021 		tescSource
3022 			<< "#version 450\n"
3023 			<< "#extension GL_EXT_tessellation_shader : require\n"
3024 			<< "layout(vertices=3) out;\n"
3025 			<< "in gl_PerVertex\n"
3026 			<< "{\n"
3027 			<< "    vec4 gl_Position;\n"
3028 			<< "} gl_in[gl_MaxPatchVertices];\n"
3029 			<< "out gl_PerVertex\n"
3030 			<< "{\n"
3031 			<< "  vec4 gl_Position;\n"
3032 			<< "} gl_out[];\n"
3033 			<< "void main() {\n"
3034 			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3035 			<< "  gl_TessLevelOuter[0] = 3.0;\n"
3036 			<< "  gl_TessLevelOuter[1] = 3.0;\n"
3037 			<< "  gl_TessLevelOuter[2] = 3.0;\n"
3038 			<< "  gl_TessLevelInner[0] = 3.0;\n"
3039 			<< "}\n"
3040 			;
3041 		teseSource
3042 			<< "#version 450\n"
3043 			<< "#extension GL_EXT_tessellation_shader : require\n"
3044 			<< "layout(triangles) in;\n"
3045 			<< "in gl_PerVertex\n"
3046 			<< "{\n"
3047 			<< "  vec4 gl_Position;\n"
3048 			<< "} gl_in[gl_MaxPatchVertices];\n"
3049 			<< "out gl_PerVertex\n"
3050 			<< "{\n"
3051 			<< "  vec4 gl_Position;\n"
3052 			<< "};\n"
3053 			<< "void main() {\n"
3054 			<< "  gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
3055 			<< "                 gl_in[1].gl_Position * gl_TessCoord.y + \n"
3056 			<< "                 gl_in[2].gl_Position * gl_TessCoord.z);\n"
3057 			<< "}\n"
3058 			;
3059 	}
3060 
3061 #ifndef CTS_USES_VULKANSC
3062 	if (m_testConfig.useMeshShaders)
3063 	{
3064 		DE_ASSERT(!m_testConfig.needsGeometryShader());
3065 		DE_ASSERT(!m_testConfig.needsTessellation());
3066 		DE_ASSERT(!m_testConfig.needsIndexBuffer());
3067 
3068 		// Make sure no dynamic states incompatible with mesh shading pipelines are used.
3069 		DE_ASSERT(!m_testConfig.badMeshShadingPipelineDynState());
3070 
3071 		// Shader below is designed to work with vertex buffers containing triangle strips as used by default.
3072 		DE_ASSERT(m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
3073 		DE_ASSERT(!m_testConfig.singleVertex);
3074 
3075 		meshSource
3076 			<< "#version 450\n"
3077 			<< "#extension GL_EXT_mesh_shader : enable\n"
3078 			<< "layout(local_size_x=3, local_size_y=1, local_size_z=1) in;\n"
3079 			<< "layout(triangles) out;\n"
3080 			<< "layout(max_vertices=3, max_primitives=1) out;\n"
3081 			<< pushConstants
3082 			<< (m_testConfig.isMultiViewport()
3083 				? "perprimitiveEXT out gl_MeshPerPrimitiveEXT { int gl_ViewportIndex; } gl_MeshPrimitivesEXT[];\n"
3084 				: "")
3085 			<< descDecls.str()
3086 			<< "void main() {\n"
3087 			<< descCalcs.str()
3088 			<< "    SetMeshOutputsEXT(3u, 1u);\n"
3089 			<< "    gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
3090 			<< "    if (gl_LocalInvocationIndex == 0u) {\n"
3091 			<< "        gl_PrimitiveTriangleIndicesEXT[0] = uvec3(0, 1, 2);\n"
3092 			<< (m_testConfig.isMultiViewport()
3093 				? "        gl_MeshPrimitivesEXT[0].gl_ViewportIndex = pushConstants.viewPortIndex;\n"
3094 				: "")
3095 			<< "    }\n"
3096 			<< "}\n"
3097 			;
3098 	}
3099 #endif // CTS_USES_VULKANSC
3100 
3101 	// In reversed test configurations, the pipeline with dynamic state needs to have the inactive shader.
3102 	const auto kReversed = m_testConfig.isReversed();
3103 	programCollection.glslSources.add("dynamicVert")	<< glu::VertexSource(kReversed ? inactiveVertSource : activeVertSource);
3104 	programCollection.glslSources.add("staticVert")		<< glu::VertexSource(kReversed ? activeVertSource : inactiveVertSource);
3105 	programCollection.glslSources.add("dynamicFrag")	<< glu::FragmentSource(kReversed ? inactiveFragSource : activeFragSource);
3106 	programCollection.glslSources.add("staticFrag")		<< glu::FragmentSource(kReversed ? activeFragSource : inactiveFragSource);
3107 
3108 	if (m_testConfig.needsGeometryShader())
3109 		programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
3110 	if (m_testConfig.needsTessellation())
3111 	{
3112 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
3113 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
3114 	}
3115 	if (m_testConfig.useMeshShaders)
3116 		programCollection.glslSources.add("mesh") << glu::MeshSource(meshSource.str()) << meshBuildOptions;
3117 
3118 	if (m_testConfig.bindUnusedMeshShadingPipeline)
3119 	{
3120 		std::ostringstream meshNoOut;
3121 		meshNoOut
3122 			<< "#version 450\n"
3123 			<< "#extension GL_EXT_mesh_shader : enable\n"
3124 			<< "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
3125 			<< "layout(triangles) out;\n"
3126 			<< "layout(max_vertices=3, max_primitives=1) out;\n"
3127 			<< "void main() {\n"
3128 			<< "    SetMeshOutputsEXT(0u, 0u);\n"
3129 			<< "}\n"
3130 			;
3131 		programCollection.glslSources.add("meshNoOut") << glu::MeshSource(meshNoOut.str()) << meshBuildOptions;
3132 	}
3133 
3134 	// Extra vert and frag shaders for the extra patch control points pipeline. These draw offscreen.
3135 	if (m_testConfig.useExtraDynPCPPipeline)
3136 	{
3137 		std::ostringstream vertDPCP;
3138 		vertDPCP
3139 			<< "#version 450\n"
3140 			<< "\n"
3141 			<< "vec2 positions[3] = vec2[](\n"
3142 			<< "    vec2(-1.0, -1.0),\n"
3143 			<< "    vec2( 3.0, -1.0),\n"
3144 			<< "    vec2(-1.0,  3.0)\n"
3145 			<< ");\n"
3146 			<< "\n"
3147 			<< "void main() {\n"
3148 			<< "    gl_Position = vec4(positions[gl_VertexIndex] + 10.0 + 1.0 * float(gl_VertexIndex), 0.0, 1.0);\n"
3149 			<< "}\n"
3150 			;
3151 		programCollection.glslSources.add("vertDPCP") << glu::VertexSource(vertDPCP.str());
3152 
3153 		std::ostringstream fragDPCP;
3154 		fragDPCP
3155 			<< "#version 450\n"
3156 			<< "layout(location=0) out " << vecType << " color;\n"
3157 			<< "void main() {\n"
3158 			<< "    color = " << vecType << "(1.0, 1.0, 1.0, 1.0);\n"
3159 			<< "}\n"
3160 			;
3161 		programCollection.glslSources.add("fragDPCP") << glu::FragmentSource(fragDPCP.str());
3162 	}
3163 }
3164 
createInstance(Context& context) const3165 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
3166 {
3167 	return new ExtendedDynamicStateInstance(context, m_testConfig);
3168 }
3169 
ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)3170 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
3171 	: vkt::TestInstance	(context)
3172 	, m_testConfig		(testConfig)
3173 {
3174 }
3175 
3176 using BufferWithMemoryPtr = de::MovePtr<vk::BufferWithMemory>;
3177 
3178 struct VertexBufferInfo
3179 {
VertexBufferInfovkt::pipeline::__anon29419::VertexBufferInfo3180 	VertexBufferInfo ()
3181 		: buffer	()
3182 		, offset	(0ull)
3183 		, dataSize	(0ull)
3184 	{}
3185 
VertexBufferInfovkt::pipeline::__anon29419::VertexBufferInfo3186 	VertexBufferInfo (VertexBufferInfo&& other)
3187 		: buffer	(other.buffer.release())
3188 		, offset	(other.offset)
3189 		, dataSize	(other.dataSize)
3190 	{}
3191 
3192 	BufferWithMemoryPtr	buffer;
3193 	vk::VkDeviceSize	offset;
3194 	vk::VkDeviceSize	dataSize;
3195 };
3196 
logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)3197 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
3198 {
3199 	log << tcu::TestLog::ImageSet(setName, setDesc)
3200 		<< tcu::TestLog::Image(setName + "Result", "Result image", result)
3201 		<< tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
3202 		<< tcu::TestLog::EndImageSet;
3203 }
3204 
copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)3205 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
3206 {
3207 	auto&	alloc	= buffer.getAllocation();
3208 	auto	dst		= reinterpret_cast<char*>(alloc.getHostPtr());
3209 
3210 	deMemcpy(dst + offset, src, size);
3211 	vk::flushAlloc(vkd, device, alloc);
3212 }
3213 
3214 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)3215 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
3216 {
3217 	if (testConfig.cullModeConfig.dynamicValue)
3218 #ifndef CTS_USES_VULKANSC
3219 		vkd.cmdSetCullMode(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
3220 #else
3221 		vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
3222 #endif // CTS_USES_VULKANSC
3223 
3224 	if (testConfig.frontFaceConfig.dynamicValue)
3225 #ifndef CTS_USES_VULKANSC
3226 		vkd.cmdSetFrontFace(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
3227 #else
3228 		vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
3229 #endif // CTS_USES_VULKANSC
3230 
3231 	if (testConfig.topologyConfig.dynamicValue)
3232 #ifndef CTS_USES_VULKANSC
3233 		vkd.cmdSetPrimitiveTopology(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
3234 #else
3235 		vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
3236 #endif // CTS_USES_VULKANSC
3237 
3238 	if (testConfig.viewportConfig.dynamicValue)
3239 	{
3240 		const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
3241 #ifndef CTS_USES_VULKANSC
3242 		vkd.cmdSetViewportWithCount(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
3243 #else
3244 		vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
3245 #endif // CTS_USES_VULKANSC
3246 	}
3247 
3248 	if (testConfig.scissorConfig.dynamicValue)
3249 	{
3250 		const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
3251 #ifndef CTS_USES_VULKANSC
3252 		vkd.cmdSetScissorWithCount(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
3253 #else
3254 		vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
3255 #endif // CTS_USES_VULKANSC
3256 	}
3257 
3258 	if (testConfig.depthTestEnableConfig.dynamicValue)
3259 #ifndef CTS_USES_VULKANSC
3260 		vkd.cmdSetDepthTestEnable(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
3261 #else
3262 		vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
3263 #endif // CTS_USES_VULKANSC
3264 
3265 	if (testConfig.depthWriteEnableConfig.dynamicValue)
3266 #ifndef CTS_USES_VULKANSC
3267 		vkd.cmdSetDepthWriteEnable(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
3268 #else
3269 		vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
3270 #endif // CTS_USES_VULKANSC
3271 
3272 	if (testConfig.depthCompareOpConfig.dynamicValue)
3273 #ifndef CTS_USES_VULKANSC
3274 		vkd.cmdSetDepthCompareOp(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
3275 #else
3276 		vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
3277 #endif // CTS_USES_VULKANSC
3278 
3279 	if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
3280 #ifndef CTS_USES_VULKANSC
3281 		vkd.cmdSetDepthBoundsTestEnable(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
3282 #else
3283 		vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
3284 #endif // CTS_USES_VULKANSC
3285 
3286 	if (testConfig.stencilTestEnableConfig.dynamicValue)
3287 #ifndef CTS_USES_VULKANSC
3288 		vkd.cmdSetStencilTestEnable(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
3289 #else
3290 		vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
3291 #endif // CTS_USES_VULKANSC
3292 
3293 	if (testConfig.depthBiasEnableConfig.dynamicValue)
3294 #ifndef CTS_USES_VULKANSC
3295 		vkd.cmdSetDepthBiasEnable(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
3296 #else
3297 		vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
3298 #endif // CTS_USES_VULKANSC
3299 
3300 	if (testConfig.depthBiasConfig.dynamicValue)
3301 	{
3302 		const auto& bias = testConfig.depthBiasConfig.dynamicValue.get();
3303 		vkd.cmdSetDepthBias(cmdBuffer, bias.constantFactor, bias.clamp, 0.0f);
3304 	}
3305 
3306 	if (testConfig.rastDiscardEnableConfig.dynamicValue)
3307 #ifndef CTS_USES_VULKANSC
3308 		vkd.cmdSetRasterizerDiscardEnable(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
3309 #else
3310 		vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
3311 #endif // CTS_USES_VULKANSC
3312 
3313 	if (testConfig.primRestartEnableConfig.dynamicValue)
3314 #ifndef CTS_USES_VULKANSC
3315 		vkd.cmdSetPrimitiveRestartEnable(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
3316 #else
3317 		vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
3318 #endif // CTS_USES_VULKANSC
3319 
3320 	if (testConfig.logicOpConfig.dynamicValue)
3321 		vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
3322 
3323 	if (testConfig.patchControlPointsConfig.dynamicValue)
3324 		vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
3325 
3326 	if (testConfig.stencilOpConfig.dynamicValue)
3327 	{
3328 		for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
3329 #ifndef CTS_USES_VULKANSC
3330 			vkd.cmdSetStencilOp(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
3331 #else
3332 			vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
3333 #endif // CTS_USES_VULKANSC
3334 	}
3335 
3336 	if (testConfig.vertexGenerator.dynamicValue)
3337 	{
3338 		const auto generator	= testConfig.vertexGenerator.dynamicValue.get();
3339 		const auto bindings		= generator->getBindingDescriptions2(testConfig.strideConfig.staticValue);
3340 		const auto attributes	= generator->getAttributeDescriptions2();
3341 
3342 		vkd.cmdSetVertexInputEXT(cmdBuffer,
3343 			static_cast<deUint32>(bindings.size()), de::dataOrNull(bindings),
3344 			static_cast<deUint32>(attributes.size()), de::dataOrNull(attributes));
3345 	}
3346 
3347 #ifndef CTS_USES_VULKANSC
3348 	if (testConfig.tessDomainOriginConfig.dynamicValue)
3349 		vkd.cmdSetTessellationDomainOriginEXT(cmdBuffer, testConfig.tessDomainOriginConfig.dynamicValue.get());
3350 
3351 	if (testConfig.depthClampEnableConfig.dynamicValue)
3352 		vkd.cmdSetDepthClampEnableEXT(cmdBuffer, testConfig.depthClampEnableConfig.dynamicValue.get());
3353 
3354 	if (testConfig.polygonModeConfig.dynamicValue)
3355 		vkd.cmdSetPolygonModeEXT(cmdBuffer, testConfig.polygonModeConfig.dynamicValue.get());
3356 
3357 	if (testConfig.rasterizationSamplesConfig.dynamicValue)
3358 		vkd.cmdSetRasterizationSamplesEXT(cmdBuffer, testConfig.rasterizationSamplesConfig.dynamicValue.get());
3359 
3360 	if (testConfig.sampleMaskConfig.dynamicValue)
3361 	{
3362 		const auto sampleCount	= (static_cast<bool>(testConfig.dynamicSampleMaskCount)
3363 								? testConfig.dynamicSampleMaskCount.get()
3364 								: testConfig.getActiveSampleCount());
3365 		vkd.cmdSetSampleMaskEXT(cmdBuffer, sampleCount, testConfig.sampleMaskConfig.dynamicValue.get().data());
3366 	}
3367 
3368 	if (testConfig.alphaToCoverageConfig.dynamicValue)
3369 		vkd.cmdSetAlphaToCoverageEnableEXT(cmdBuffer, makeVkBool32(testConfig.alphaToCoverageConfig.dynamicValue.get()));
3370 
3371 	if (testConfig.alphaToOneConfig.dynamicValue)
3372 		vkd.cmdSetAlphaToOneEnableEXT(cmdBuffer, makeVkBool32(testConfig.alphaToOneConfig.dynamicValue.get()));
3373 
3374 	if (testConfig.colorWriteMaskConfig.dynamicValue)
3375 		vkd.cmdSetColorWriteMaskEXT(cmdBuffer, 0u, 1u, &testConfig.colorWriteMaskConfig.dynamicValue.get());
3376 
3377 	if (testConfig.rasterizationStreamConfig.dynamicValue && static_cast<bool>(testConfig.rasterizationStreamConfig.dynamicValue.get()))
3378 		vkd.cmdSetRasterizationStreamEXT(cmdBuffer, testConfig.rasterizationStreamConfig.dynamicValue->get());
3379 
3380 	if (testConfig.logicOpEnableConfig.dynamicValue)
3381 		vkd.cmdSetLogicOpEnableEXT(cmdBuffer, makeVkBool32(testConfig.logicOpEnableConfig.dynamicValue.get()));
3382 
3383 	if (testConfig.colorBlendEnableConfig.dynamicValue)
3384 	{
3385 		const auto colorBlendEnableFlag = makeVkBool32(testConfig.colorBlendEnableConfig.dynamicValue.get());
3386 		vkd.cmdSetColorBlendEnableEXT(cmdBuffer, 0u, 1u, &colorBlendEnableFlag);
3387 	}
3388 
3389 	if (testConfig.colorBlendEquationConfig.dynamicValue)
3390 	{
3391 		const auto& configEq = testConfig.colorBlendEquationConfig.dynamicValue.get();
3392 
3393 		if (testConfig.colorBlendEquationConfig.staticValue.isAdvanced())
3394 		{
3395 			const vk::VkColorBlendAdvancedEXT advanced =
3396 			{
3397 				configEq.colorBlendOp,					//	VkBlendOp			advancedBlendOp;
3398 				VK_TRUE,								//	VkBool32			srcPremultiplied;
3399 				VK_TRUE,								//	VkBool32			dstPremultiplied;
3400 				vk::VK_BLEND_OVERLAP_UNCORRELATED_EXT,	//	VkBlendOverlapEXT	blendOverlap;
3401 				VK_FALSE,								//	VkBool32			clampResults;
3402 			};
3403 			vkd.cmdSetColorBlendAdvancedEXT(cmdBuffer, 0u, 1u, &advanced);
3404 		}
3405 		else
3406 		{
3407 			const vk::VkColorBlendEquationEXT equation =
3408 			{
3409 				configEq.srcColorBlendFactor,	//	VkBlendFactor	srcColorBlendFactor;
3410 				configEq.dstColorBlendFactor,	//	VkBlendFactor	dstColorBlendFactor;
3411 				configEq.colorBlendOp,			//	VkBlendOp		colorBlendOp;
3412 				configEq.srcAlphaBlendFactor,	//	VkBlendFactor	srcAlphaBlendFactor;
3413 				configEq.dstAlphaBlendFactor,	//	VkBlendFactor	dstAlphaBlendFactor;
3414 				configEq.alphaBlendOp,			//	VkBlendOp		alphaBlendOp;
3415 			};
3416 			vkd.cmdSetColorBlendEquationEXT(cmdBuffer, 0u, 1u, &equation);
3417 		}
3418 	}
3419 
3420 	if (testConfig.provokingVertexConfig.dynamicValue && static_cast<bool>(testConfig.provokingVertexConfig.dynamicValue.get()))
3421 	{
3422 		const auto provokingVertexMode = makeProvokingVertexMode(testConfig.provokingVertexConfig.dynamicValue->get());
3423 		vkd.cmdSetProvokingVertexModeEXT(cmdBuffer, provokingVertexMode);
3424 	}
3425 
3426 	if (testConfig.negativeOneToOneConfig.dynamicValue && static_cast<bool>(testConfig.negativeOneToOneConfig.dynamicValue.get()))
3427 		vkd.cmdSetDepthClipNegativeOneToOneEXT(cmdBuffer, makeVkBool32(testConfig.negativeOneToOneConfig.dynamicValue->get()));
3428 
3429 	if (testConfig.depthClipEnableConfig.dynamicValue && static_cast<bool>(testConfig.depthClipEnableConfig.dynamicValue.get()))
3430 		vkd.cmdSetDepthClipEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthClipEnableConfig.dynamicValue->get()));
3431 
3432 	if (testConfig.lineStippleEnableConfig.dynamicValue)
3433 		vkd.cmdSetLineStippleEnableEXT(cmdBuffer, makeVkBool32(testConfig.lineStippleEnableConfig.dynamicValue.get()));
3434 
3435 	if (testConfig.lineStippleParamsConfig.dynamicValue && static_cast<bool>(testConfig.lineStippleParamsConfig.dynamicValue.get()))
3436 	{
3437 		const auto& stippleParams = testConfig.lineStippleParamsConfig.dynamicValue->get();
3438 		vkd.cmdSetLineStippleEXT(cmdBuffer, stippleParams.factor, stippleParams.pattern);
3439 	}
3440 
3441 	if (testConfig.sampleLocationsEnableConfig.dynamicValue)
3442 		vkd.cmdSetSampleLocationsEnableEXT(cmdBuffer, makeVkBool32(testConfig.sampleLocationsEnableConfig.dynamicValue.get()));
3443 
3444 	if (testConfig.conservativeRasterModeConfig.dynamicValue)
3445 		vkd.cmdSetConservativeRasterizationModeEXT(cmdBuffer, testConfig.conservativeRasterModeConfig.dynamicValue.get());
3446 
3447 	if (testConfig.extraPrimitiveOverEstConfig.dynamicValue)
3448 		vkd.cmdSetExtraPrimitiveOverestimationSizeEXT(cmdBuffer, testConfig.extraPrimitiveOverEstConfig.dynamicValue.get());
3449 
3450 	if (testConfig.lineRasterModeConfig.dynamicValue && static_cast<bool>(testConfig.lineRasterModeConfig.dynamicValue.get()))
3451 		vkd.cmdSetLineRasterizationModeEXT(cmdBuffer, makeLineRasterizationMode(testConfig.lineRasterModeConfig.dynamicValue->get()));
3452 
3453 	if (testConfig.coverageToColorEnableConfig.dynamicValue)
3454 		vkd.cmdSetCoverageToColorEnableNV(cmdBuffer, makeVkBool32(testConfig.coverageToColorEnableConfig.dynamicValue.get()));
3455 
3456 	if (testConfig.coverageToColorLocationConfig.dynamicValue)
3457 		vkd.cmdSetCoverageToColorLocationNV(cmdBuffer, testConfig.coverageToColorLocationConfig.dynamicValue.get());
3458 
3459 	if (testConfig.coverageModulationModeConfig.dynamicValue)
3460 		vkd.cmdSetCoverageModulationModeNV(cmdBuffer, testConfig.coverageModulationModeConfig.dynamicValue.get());
3461 
3462 	if (testConfig.coverageModTableEnableConfig.dynamicValue)
3463 		vkd.cmdSetCoverageModulationTableEnableNV(cmdBuffer, makeVkBool32(testConfig.coverageModTableEnableConfig.dynamicValue.get()));
3464 
3465 	if (testConfig.coverageModTableConfig.dynamicValue)
3466 	{
3467 		const auto& tableVec = testConfig.coverageModTableConfig.dynamicValue.get();
3468 		vkd.cmdSetCoverageModulationTableNV(cmdBuffer, static_cast<uint32_t>(tableVec.size()), de::dataOrNull(tableVec));
3469 	}
3470 
3471 	if (testConfig.coverageReductionModeConfig.dynamicValue)
3472 		vkd.cmdSetCoverageReductionModeNV(cmdBuffer, testConfig.coverageReductionModeConfig.dynamicValue.get());
3473 
3474 	if (testConfig.viewportSwizzleConfig.dynamicValue)
3475 	{
3476 		const auto& viewportSwizzleVec = testConfig.viewportSwizzleConfig.dynamicValue.get();
3477 		vkd.cmdSetViewportSwizzleNV(cmdBuffer, 0u, static_cast<uint32_t>(viewportSwizzleVec.size()), de::dataOrNull(viewportSwizzleVec));
3478 	}
3479 
3480 	if (testConfig.shadingRateImageEnableConfig.dynamicValue)
3481 		vkd.cmdSetShadingRateImageEnableNV(cmdBuffer, makeVkBool32(testConfig.shadingRateImageEnableConfig.dynamicValue.get()));
3482 
3483 	if (testConfig.viewportWScalingEnableConfig.dynamicValue)
3484 		vkd.cmdSetViewportWScalingEnableNV(cmdBuffer, makeVkBool32(testConfig.viewportWScalingEnableConfig.dynamicValue.get()));
3485 
3486 	if (testConfig.reprFragTestEnableConfig.dynamicValue)
3487 		vkd.cmdSetRepresentativeFragmentTestEnableNV(cmdBuffer, makeVkBool32(testConfig.reprFragTestEnableConfig.dynamicValue.get()));
3488 #else
3489 	DE_ASSERT(false);
3490 #endif // CTS_USES_VULKANSC
3491 }
3492 
3493 // Bind the appropriate vertex buffers using dynamic strides if the test configuration needs a dynamic stride.
3494 // Return true if the vertex buffer was bound.
maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, const std::vector<VertexBufferInfo>& vertBuffers, const std::vector<VertexBufferInfo>& rvertBuffers)3495 bool maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, const std::vector<VertexBufferInfo>& vertBuffers, const std::vector<VertexBufferInfo>& rvertBuffers)
3496 {
3497 	if (!testConfig.strideConfig.dynamicValue)
3498 		return false;
3499 
3500 	DE_ASSERT(!testConfig.useMeshShaders);
3501 
3502 	const auto& viewportVec = testConfig.getActiveViewportVec();
3503 	DE_UNREF(viewportVec); // For release builds.
3504 
3505 	// When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
3506 	// orderings if we have several viewports or meshes.
3507 	DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
3508 				|| testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
3509 				|| testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
3510 
3511 	// Split buffers, offsets, sizes and strides into their own vectors for the call.
3512 	std::vector<vk::VkBuffer>		buffers;
3513 	std::vector<vk::VkDeviceSize>	offsets;
3514 	std::vector<vk::VkDeviceSize>	sizes;
3515 	const auto						strides = testConfig.strideConfig.dynamicValue.get();
3516 
3517 	const auto& chosenBuffers = (testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers);
3518 
3519 	buffers.reserve	(chosenBuffers.size());
3520 	offsets.reserve	(chosenBuffers.size());
3521 	sizes.reserve	(chosenBuffers.size());
3522 	DE_ASSERT(chosenBuffers.size() == strides.size());
3523 
3524 	for (const auto& vertBuffer : chosenBuffers)
3525 	{
3526 		buffers.push_back	(vertBuffer.buffer->get());
3527 		offsets.push_back	(vertBuffer.offset);
3528 		sizes.push_back		(vertBuffer.dataSize);
3529 	}
3530 
3531 #ifndef CTS_USES_VULKANSC
3532 	vkd.cmdBindVertexBuffers2(cmdBuffer, 0u, static_cast<deUint32>(chosenBuffers.size()), buffers.data(), offsets.data(), sizes.data(), strides.data());
3533 #else
3534 	vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, static_cast<deUint32>(chosenBuffers.size()), buffers.data(), offsets.data(), sizes.data(), strides.data());
3535 #endif // CTS_USES_VULKANSC
3536 
3537 	return true;
3538 }
3539 
3540 // Bind the given vertex buffers with the non-dynamic call. Similar to maybeBindVertexBufferDynStride but simpler.
bindVertexBuffers(const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, const std::vector<VertexBufferInfo>& vertexBuffers)3541 void bindVertexBuffers (const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, const std::vector<VertexBufferInfo>& vertexBuffers)
3542 {
3543 	std::vector<vk::VkBuffer>		buffers;
3544 	std::vector<vk::VkDeviceSize>	offsets;
3545 
3546 	buffers.reserve	(vertexBuffers.size());
3547 	offsets.reserve	(vertexBuffers.size());
3548 
3549 	for (const auto& vertBuffer : vertexBuffers)
3550 	{
3551 		buffers.push_back	(vertBuffer.buffer->get());
3552 		offsets.push_back	(vertBuffer.offset);
3553 	}
3554 
3555 	vkd.cmdBindVertexBuffers(cmdBuffer, 0u, static_cast<deUint32>(vertexBuffers.size()), buffers.data(), offsets.data());
3556 }
3557 
3558 // Create a vector of VertexBufferInfo elements using the given vertex generator and set of vertices.
prepareVertexBuffers( std::vector<VertexBufferInfo>& buffers, const vk::DeviceInterface& vkd, vk::VkDevice device, vk::Allocator& allocator, const VertexGenerator* generator, const std::vector<tcu::Vec2>& vertices, deUint32 dataOffset, deUint32 trailingSize, bool ssbos)3559 void prepareVertexBuffers (	std::vector<VertexBufferInfo>&	buffers,
3560 							const vk::DeviceInterface&		vkd,
3561 							vk::VkDevice					device,
3562 							vk::Allocator&					allocator,
3563 							const VertexGenerator*			generator,
3564 							const std::vector<tcu::Vec2>&	vertices,
3565 							deUint32						dataOffset,
3566 							deUint32						trailingSize,
3567 							bool							ssbos)
3568 {
3569 	const deUint32	paddingBytes	= 0xDEADBEEFu;
3570 	const auto		vertexData		= generator->createVertexData(vertices, dataOffset, trailingSize, &paddingBytes, sizeof(paddingBytes));
3571 
3572 	for (const auto& bufferBytes : vertexData)
3573 	{
3574 		const auto bufferSize	= static_cast<vk::VkDeviceSize>(de::dataSize(bufferBytes));
3575 		const auto extraSize	= static_cast<vk::VkDeviceSize>(dataOffset + trailingSize);
3576 		DE_ASSERT(bufferSize > extraSize);
3577 		const auto dataSize		= bufferSize - extraSize;
3578 
3579 		// Create a full-size buffer but remember the data size and offset for it.
3580 		const auto createInfo = vk::makeBufferCreateInfo(bufferSize, (ssbos ? vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
3581 
3582 		VertexBufferInfo bufferInfo;
3583 		bufferInfo.buffer	= BufferWithMemoryPtr(new vk::BufferWithMemory(vkd, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
3584 		bufferInfo.offset	= static_cast<vk::VkDeviceSize>(dataOffset);
3585 		bufferInfo.dataSize	= dataSize;
3586 		buffers.emplace_back(std::move(bufferInfo));
3587 
3588 		// Copy the whole contents to the full buffer.
3589 		copyAndFlush(vkd, device, *buffers.back().buffer, 0, bufferBytes.data(), de::dataSize(bufferBytes));
3590 	}
3591 }
3592 
3593 // Device helper: this is needed in some tests when we create custom devices.
3594 class DeviceHelper
3595 {
3596 public:
~DeviceHelper()3597 	virtual ~DeviceHelper () {}
3598 	virtual const vk::DeviceInterface&	getDeviceInterface	(void) const = 0;
3599 	virtual vk::VkDevice				getDevice			(void) const = 0;
3600 	virtual uint32_t					getQueueFamilyIndex	(void) const = 0;
3601 	virtual vk::VkQueue					getQueue			(void) const = 0;
3602 	virtual vk::Allocator&				getAllocator		(void) const = 0;
3603 };
3604 
3605 // This one just reuses the default device from the context.
3606 class ContextDeviceHelper : public DeviceHelper
3607 {
3608 public:
ContextDeviceHelper(Context& context)3609 	ContextDeviceHelper (Context& context)
3610 		: m_deviceInterface		(context.getDeviceInterface())
3611 		, m_device				(context.getDevice())
3612 		, m_queueFamilyIndex	(context.getUniversalQueueFamilyIndex())
3613 		, m_queue				(context.getUniversalQueue())
3614 		, m_allocator			(context.getDefaultAllocator())
3615 		{}
3616 
~ContextDeviceHelper()3617 	virtual ~ContextDeviceHelper () {}
3618 
3619 	const vk::DeviceInterface&	getDeviceInterface	(void) const override	{ return m_deviceInterface;		}
3620 	vk::VkDevice				getDevice			(void) const override	{ return m_device;				}
3621 	uint32_t					getQueueFamilyIndex	(void) const override	{ return m_queueFamilyIndex;	}
3622 	vk::VkQueue					getQueue			(void) const override	{ return m_queue;				}
3623 	vk::Allocator&				getAllocator		(void) const override	{ return m_allocator;			}
3624 
3625 protected:
3626 	const vk::DeviceInterface&	m_deviceInterface;
3627 	const vk::VkDevice			m_device;
3628 	const uint32_t				m_queueFamilyIndex;
3629 	const vk::VkQueue			m_queue;
3630 	vk::Allocator&				m_allocator;
3631 };
3632 
3633 // This one creates a new device with VK_NV_shading_rate_image and VK_EXT_extended_dynamic_state3.
3634 // It also enables VK_EXT_mesh_shader if supported, as some tests need it.
3635 class ShadingRateImageDeviceHelper : public DeviceHelper
3636 {
3637 public:
ShadingRateImageDeviceHelper(Context& context)3638 	ShadingRateImageDeviceHelper (Context& context)
3639 	{
3640 		const auto&	vkp				= context.getPlatformInterface();
3641 		const auto&	vki				= context.getInstanceInterface();
3642 		const auto	instance		= context.getInstance();
3643 		const auto	physicalDevice	= context.getPhysicalDevice();
3644 		const auto	queuePriority	= 1.0f;
3645 
3646 		// Queue index first.
3647 		m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
3648 
3649 		// Create a universal queue that supports graphics and compute.
3650 		const vk::VkDeviceQueueCreateInfo queueParams =
3651 		{
3652 			vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,	// VkStructureType				sType;
3653 			DE_NULL,										// const void*					pNext;
3654 			0u,												// VkDeviceQueueCreateFlags		flags;
3655 			m_queueFamilyIndex,								// deUint32						queueFamilyIndex;
3656 			1u,												// deUint32						queueCount;
3657 			&queuePriority									// const float*					pQueuePriorities;
3658 		};
3659 
3660 #ifndef CTS_USES_VULKANSC
3661 		const auto&	contextMeshFeatures	= context.getMeshShaderFeaturesEXT();
3662 		const bool	meshShaderSupport	= contextMeshFeatures.meshShader;
3663 
3664 		vk::VkPhysicalDeviceMeshShaderFeaturesEXT				meshFeatures				= vk::initVulkanStructure();
3665 		vk::VkPhysicalDeviceExtendedDynamicState2FeaturesEXT	eds3Features				= vk::initVulkanStructure(meshShaderSupport ? &meshFeatures : nullptr);
3666 		vk::VkPhysicalDeviceShadingRateImageFeaturesNV			shadingRateImageFeatures	= vk::initVulkanStructure(&eds3Features);
3667 		vk::VkPhysicalDeviceFeatures2							features2					= vk::initVulkanStructure(&shadingRateImageFeatures);
3668 
3669 		vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
3670 #endif // CTS_USES_VULKANSC
3671 
3672 		std::vector<const char*> extensions
3673 		{
3674 			"VK_EXT_extended_dynamic_state3",
3675 			"VK_NV_shading_rate_image",
3676 		};
3677 #ifndef CTS_USES_VULKANSC
3678 		if (meshShaderSupport)
3679 			extensions.push_back("VK_EXT_mesh_shader");
3680 #endif // CTS_USES_VULKANSC
3681 
3682 		const vk::VkDeviceCreateInfo deviceCreateInfo =
3683 		{
3684 			vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,				//sType;
3685 #ifndef CTS_USES_VULKANSC
3686 			&features2,												//pNext;
3687 #else
3688 			nullptr,
3689 #endif // CTS_USES_VULKANSC
3690 			0u,														//flags
3691 			1u,														//queueRecordCount;
3692 			&queueParams,											//pRequestedQueues;
3693 			0u,														//layerCount;
3694 			nullptr,												//ppEnabledLayerNames;
3695 			de::sizeU32(extensions),								// deUint32							enabledExtensionCount;
3696 			de::dataOrNull(extensions),								// const char* const*				ppEnabledExtensionNames;
3697 			nullptr,												//pEnabledFeatures;
3698 		};
3699 
3700 		m_device	= createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance, vki, physicalDevice, &deviceCreateInfo);
3701 		m_vkd		.reset(new vk::DeviceDriver(vkp, instance, m_device.get()));
3702 		m_queue		= getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
3703 		m_allocator	.reset(new vk::SimpleAllocator(*m_vkd, m_device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
3704 	}
3705 
~ShadingRateImageDeviceHelper()3706 	virtual ~ShadingRateImageDeviceHelper () {}
3707 
3708 	const vk::DeviceInterface&	getDeviceInterface	(void) const override	{ return *m_vkd;				}
3709 	vk::VkDevice				getDevice			(void) const override	{ return m_device.get();		}
3710 	uint32_t					getQueueFamilyIndex	(void) const override	{ return m_queueFamilyIndex;	}
3711 	vk::VkQueue					getQueue			(void) const override	{ return m_queue;				}
3712 	vk::Allocator&				getAllocator		(void) const override	{ return *m_allocator;			}
3713 
3714 protected:
3715 	vk::Move<vk::VkDevice>					m_device;
3716 	std::unique_ptr<vk::DeviceDriver>		m_vkd;
3717 	deUint32								m_queueFamilyIndex;
3718 	vk::VkQueue								m_queue;
3719 	std::unique_ptr<vk::SimpleAllocator>	m_allocator;
3720 };
3721 
3722 std::unique_ptr<DeviceHelper> g_shadingRateDeviceHelper;
3723 std::unique_ptr<DeviceHelper> g_contextDeviceHelper;
3724 
getDeviceHelper(Context& context, const TestConfig& testConfig)3725 DeviceHelper& getDeviceHelper(Context& context, const TestConfig& testConfig)
3726 {
3727 	if (testConfig.shadingRateImage)
3728 	{
3729 		if (!g_shadingRateDeviceHelper)
3730 			g_shadingRateDeviceHelper.reset(new ShadingRateImageDeviceHelper(context));
3731 		return *g_shadingRateDeviceHelper;
3732 	}
3733 
3734 	if (!g_contextDeviceHelper)
3735 		g_contextDeviceHelper.reset(new ContextDeviceHelper(context));
3736 	return *g_contextDeviceHelper;
3737 }
3738 
cleanupDevices()3739 void cleanupDevices()
3740 {
3741 	g_shadingRateDeviceHelper.reset(nullptr);
3742 	g_contextDeviceHelper.reset(nullptr);
3743 }
3744 
iterate(void)3745 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
3746 {
3747 	using ImageWithMemoryVec	= std::vector<std::unique_ptr<vk::ImageWithMemory>>;
3748 	using ImageViewVec			= std::vector<vk::Move<vk::VkImageView>>;
3749 	using FramebufferVec		= std::vector<vk::Move<vk::VkFramebuffer>>;
3750 
3751 	const auto&	vki					= m_context.getInstanceInterface();
3752 	const auto	physicalDevice		= m_context.getPhysicalDevice();
3753 	const auto& deviceHelper		= getDeviceHelper(m_context, m_testConfig);
3754 	const auto&	vkd					= deviceHelper.getDeviceInterface();
3755 	const auto	device				= deviceHelper.getDevice();
3756 	auto&		allocator			= deviceHelper.getAllocator();
3757 	const auto	queue				= deviceHelper.getQueue();
3758 	const auto	queueIndex			= deviceHelper.getQueueFamilyIndex();
3759 	auto&		log					= m_context.getTestContext().getLog();
3760 
3761 	const auto	kReversed			= m_testConfig.isReversed();
3762 	const auto	kNumIterations		= m_testConfig.numIterations();
3763 	const auto	kColorAttCount		= m_testConfig.colorAttachmentCount;
3764 	const auto	kSequenceOrdering	= m_testConfig.sequenceOrdering;
3765 
3766 	const auto	kDSCreateFlags		= (m_testConfig.sampleLocationsStruct() ? static_cast<vk::VkImageCreateFlags>(vk::VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT) : 0u);
3767 	const auto	colorFormat			= m_testConfig.colorFormat();
3768 	const auto	colorSampleCount	= m_testConfig.getColorSampleCount();
3769 	const auto	activeSampleCount	= m_testConfig.getActiveSampleCount();
3770 	const bool	vertDataAsSSBO		= m_testConfig.useMeshShaders;
3771 	const auto	pipelineBindPoint	= vk::VK_PIPELINE_BIND_POINT_GRAPHICS;
3772 	const bool	kUseResolveAtt		= (colorSampleCount != kSingleSampleCount);
3773 	const bool	kMultisampleDS		= (activeSampleCount != kSingleSampleCount);
3774 
3775 	// Choose depth/stencil format.
3776 	const DepthStencilFormat* dsFormatInfo = nullptr;
3777 
3778 	for (const auto& kDepthStencilFormat : kDepthStencilFormats)
3779 	{
3780 		// This is how we'll attempt to create images later.
3781 		const auto dsImageInfo = makeImageCreateInfo(kDepthStencilFormat.imageFormat, kFramebufferExtent, activeSampleCount, kDSUsage, kDSCreateFlags);
3782 
3783 		vk::VkImageFormatProperties formatProps;
3784 		const auto result = vki.getPhysicalDeviceImageFormatProperties(physicalDevice, dsImageInfo.format, dsImageInfo.imageType, dsImageInfo.tiling, dsImageInfo.usage, dsImageInfo.flags, &formatProps);
3785 
3786 		// Format not supported.
3787 		if (result != vk::VK_SUCCESS)
3788 			continue;
3789 
3790 		// Extent not big enough.
3791 		const auto& maxExtent = formatProps.maxExtent;
3792 		if (maxExtent.width < kFramebufferExtent.width || maxExtent.height < kFramebufferExtent.height || maxExtent.depth < kFramebufferExtent.depth)
3793 			continue;
3794 
3795 		// Sample count not supported.
3796 		if ((formatProps.sampleCounts & activeSampleCount) != activeSampleCount)
3797 			continue;
3798 
3799 		dsFormatInfo = &kDepthStencilFormat;
3800 		break;
3801 	}
3802 
3803 	// Note: Not Supported insted of Fail because some features are not mandatory.
3804 	if (!dsFormatInfo)
3805 		TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
3806 	log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
3807 
3808 	// Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
3809 	// where we will bind the static pipeline last before drawing.
3810 	if (kReversed)
3811 		m_testConfig.swapValues();
3812 
3813 	// Create color and depth/stencil images.
3814 	ImageWithMemoryVec colorImages;
3815 	ImageWithMemoryVec dsImages;
3816 	ImageWithMemoryVec resolveImages;
3817 
3818 	const auto colorImageInfo = makeImageCreateInfo(colorFormat, kFramebufferExtent, colorSampleCount, kColorUsage, 0u);
3819 	for (deUint32 i = 0u; i < kNumIterations * kColorAttCount; ++i)
3820 		colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
3821 
3822 	const auto dsImageInfo = makeImageCreateInfo(dsFormatInfo->imageFormat, kFramebufferExtent, activeSampleCount, kDSUsage, kDSCreateFlags);
3823 	for (deUint32 i = 0u; i < kNumIterations; ++i)
3824 		dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
3825 
3826 	if (kUseResolveAtt)
3827 	{
3828 		const auto resolveImageInfo = makeImageCreateInfo(colorFormat, kFramebufferExtent, kSingleSampleCount, kColorUsage, 0u);
3829 		for (uint32_t i = 0u; i < kNumIterations * kColorAttCount; ++i)
3830 			resolveImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, resolveImageInfo, vk::MemoryRequirement::Any));
3831 	}
3832 
3833 	const auto colorSubresourceRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
3834 	const auto dsSubresourceRange		= vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
3835 
3836 	ImageViewVec colorImageViews;
3837 	ImageViewVec dsImageViews;
3838 	ImageViewVec resolveImageViews;
3839 
3840 	for (const auto& img : colorImages)
3841 		colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
3842 
3843 	for (const auto& img : dsImages)
3844 		dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
3845 
3846 	for (const auto& img : resolveImages)
3847 		resolveImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
3848 
3849 	// Vertex buffer.
3850 	const auto				topologyClass	= getTopologyClass(m_testConfig.topologyConfig.staticValue);
3851 	std::vector<uint32_t>	indices;
3852 	std::vector<tcu::Vec2>	vertices;
3853 
3854 	if (m_testConfig.oversizedTriangle || m_testConfig.offCenterTriangle)
3855 	{
3856 		DE_ASSERT(topologyClass == TopologyClass::TRIANGLE);
3857 		DE_ASSERT(!m_testConfig.singleVertex);
3858 	}
3859 
3860 	if (m_testConfig.obliqueLine)
3861 		DE_ASSERT(topologyClass == TopologyClass::LINE);
3862 
3863 	if (topologyClass == TopologyClass::TRIANGLE)
3864 	{
3865 		// These indices are used for a subset of cases.
3866 		DE_ASSERT(!m_testConfig.needsIndexBuffer());
3867 
3868 		if (m_testConfig.oversizedTriangle)
3869 		{
3870 			vertices.reserve(3u);
3871 			vertices.push_back(tcu::Vec2(-2.0f, -2.0f));
3872 			vertices.push_back(tcu::Vec2(-2.0f,  6.0f));
3873 			vertices.push_back(tcu::Vec2( 6.0f, -2.0f));
3874 		}
3875 		else if (m_testConfig.offCenterTriangle)
3876 		{
3877 			// Triangle covering the whole screen, except for the first row and column, which may not be covered by all samples.
3878 			const float horOffset	= 2.0f / static_cast<float>(kFramebufferWidth) * m_testConfig.offCenterProportion.x();
3879 			const float vertOffset	= 2.0f / static_cast<float>(kFramebufferHeight) * m_testConfig.offCenterProportion.y();
3880 
3881 			vertices.reserve(3u);
3882 			vertices.push_back(tcu::Vec2(-1.0f + horOffset, -1.0f + vertOffset));
3883 			vertices.push_back(tcu::Vec2(-1.0f + horOffset,               4.0f));
3884 			vertices.push_back(tcu::Vec2(             4.0f, -1.0f + vertOffset));
3885 		}
3886 		else
3887 		{
3888 			// Full-screen triangle strip with 6 vertices.
3889 			//
3890 			// 0        2        4
3891 			//  +-------+-------+
3892 			//  |      XX      X|
3893 			//  |     X X     X |
3894 			//  |    X  X    X  |
3895 			//  |   X   X   X   |
3896 			//  |  X    X  X    |
3897 			//  | X     X X     |
3898 			//  |X      XX      |
3899 			//  +-------+-------+
3900 			// 1        3       5
3901 			vertices.reserve(6u);
3902 			vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
3903 			vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
3904 			vertices.push_back(tcu::Vec2( 0.0f, -1.0f));
3905 			vertices.push_back(tcu::Vec2( 0.0f,  1.0f));
3906 			vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
3907 			vertices.push_back(tcu::Vec2( 1.0f,  1.0f));
3908 		}
3909 	}
3910 	else if (topologyClass == TopologyClass::PATCH)
3911 	{
3912 		DE_ASSERT(!m_testConfig.needsIndexBuffer());
3913 		DE_ASSERT(m_testConfig.getActivePatchControlPoints() > 1u);
3914 
3915 		// 2 triangles making a quad
3916 		vertices.reserve(6u);
3917 		vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
3918 		vertices.push_back(tcu::Vec2( 1.0f,  1.0f));
3919 		vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
3920 		vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
3921 		vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
3922 		vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
3923 	}
3924 	else // TopologyClass::LINE
3925 	{
3926 		const float pixelHeight	= 2.0f / static_cast<float>(kFramebufferHeight);
3927 		const float pixelWidth	= 2.0f / static_cast<float>(kFramebufferWidth);
3928 
3929 		if (m_testConfig.obliqueLine)
3930 		{
3931 			// The starting point of the oblique line is located in the top left pixel, in a position below and slightly to the left
3932 			// of the pixel center. The ending point is in the middle of the right side of the framebuffer. Those coordinates make
3933 			// sure that a bresenham-style line covers the center of the top left pixel, because the left edge of the line goes up
3934 			// vertically from that point. However, a rectangular line misses it by a small delta because its edge goes up and to
3935 			// the right, leaving the pixel center to its left. So the top left pixel itself may be covered or not depending on the
3936 			// active line rasterization mode.
3937 			//
3938 			// Note: results may also be affected by multisample and sample locations if those are used.
3939 			vertices.reserve(2u);
3940 			vertices.push_back(tcu::Vec2(pixelWidth * 7.0f / 16.0f - 1.0f, pixelHeight * 12.0f / 16.0f - 1.0f));
3941 			vertices.push_back(tcu::Vec2(1.0f, 0.0f));
3942 		}
3943 		else
3944 		{
3945 			DE_ASSERT(m_testConfig.getActivePrimRestartEnable());
3946 
3947 			// 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.
3948 			vertices.reserve(kFramebufferHeight * 4u);
3949 
3950 			if (m_testConfig.needsIndexBuffer())
3951 				indices.reserve(kFramebufferHeight * 5u);
3952 
3953 			for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
3954 			{
3955 				// Offset of 0.5 pixels + one pixel per row, from -1 to 1.
3956 				const float yCoord = (pixelHeight / 2.0f) + pixelHeight * static_cast<float>(rowIdx) - 1.0f;
3957 				vertices.push_back(tcu::Vec2(-1.0f, yCoord));
3958 				vertices.push_back(tcu::Vec2(-0.5f, yCoord));
3959 				vertices.push_back(tcu::Vec2( 0.5f, yCoord));
3960 				vertices.push_back(tcu::Vec2( 1.0f, yCoord));
3961 
3962 				if (m_testConfig.needsIndexBuffer())
3963 				{
3964 					indices.push_back(4u * rowIdx + 0u);
3965 					indices.push_back(4u * rowIdx + 1u);
3966 					indices.push_back(4u * rowIdx + 2u);
3967 					indices.push_back(4u * rowIdx + 3u);
3968 					indices.push_back(0xFFFFFFFFu); // Restart line strip.
3969 				}
3970 			}
3971 		}
3972 	}
3973 
3974 	if (m_testConfig.singleVertex)
3975 	{
3976 		DE_ASSERT(!m_testConfig.needsIndexBuffer());
3977 		vertices.resize(1);
3978 	}
3979 
3980 	// Reversed vertices order in triangle strip (1, 0, 3, 2, 5, 4)
3981 	std::vector<tcu::Vec2> rvertices;
3982 	if (topologyClass == TopologyClass::TRIANGLE)
3983 	{
3984 		DE_ASSERT(!vertices.empty());
3985 		if (m_testConfig.singleVertex)
3986 			rvertices.push_back(vertices[0]);
3987 		else if (m_testConfig.oversizedTriangle || m_testConfig.offCenterTriangle)
3988 		{
3989 			rvertices.reserve(3u);
3990 			rvertices.push_back(vertices[0]);
3991 			rvertices.push_back(vertices[2]);
3992 			rvertices.push_back(vertices[1]);
3993 		}
3994 		else
3995 		{
3996 			rvertices.reserve(6u);
3997 			rvertices.push_back(vertices[1]);
3998 			rvertices.push_back(vertices[0]);
3999 			rvertices.push_back(vertices[3]);
4000 			rvertices.push_back(vertices[2]);
4001 			rvertices.push_back(vertices[5]);
4002 			rvertices.push_back(vertices[4]);
4003 		}
4004 	}
4005 
4006 	if (topologyClass != TopologyClass::TRIANGLE)
4007 	{
4008 		for (const auto& mesh : m_testConfig.meshParams)
4009 		{
4010 			DE_UNREF(mesh); // For release builds.
4011 			DE_ASSERT(!mesh.reversed);
4012 		}
4013 	}
4014 
4015 	// Buffers with vertex data for the different bindings.
4016 	std::vector<VertexBufferInfo> vertBuffers;
4017 	std::vector<VertexBufferInfo> rvertBuffers;
4018 
4019 	{
4020 		const auto dataOffset	= static_cast<deUint32>(m_testConfig.vertexDataOffset);
4021 		const auto trailingSize	= static_cast<deUint32>(m_testConfig.vertexDataExtraBytes);
4022 		const auto generator	= m_testConfig.getActiveVertexGenerator();
4023 		prepareVertexBuffers(vertBuffers, vkd, device, allocator, generator, vertices, dataOffset, trailingSize, vertDataAsSSBO);
4024 		if (topologyClass == TopologyClass::TRIANGLE)
4025 			prepareVertexBuffers(rvertBuffers, vkd, device, allocator, generator, rvertices, dataOffset, trailingSize, vertDataAsSSBO);
4026 	}
4027 
4028 	// Index buffer.
4029 	BufferWithMemoryPtr indexBuffer;
4030 	if (!indices.empty())
4031 	{
4032 		const auto indexDataSize	= static_cast<vk::VkDeviceSize>(de::dataSize(indices));
4033 		const auto indexBufferInfo	= vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
4034 
4035 		indexBuffer = BufferWithMemoryPtr(new vk::BufferWithMemory(vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible));
4036 		copyAndFlush(vkd, device, *indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
4037 	}
4038 
4039 	// Fragment counter buffer.
4040 	BufferWithMemoryPtr	counterBuffer;
4041 	const auto			counterBufferSize	= static_cast<vk::VkDeviceSize>(sizeof(uint32_t));
4042 
4043 	if (m_testConfig.representativeFragmentTest)
4044 	{
4045 		const auto		counterBufferInfo	= vk::makeBufferCreateInfo(counterBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
4046 		const uint32_t	initialValue		= 0u;
4047 
4048 		counterBuffer = BufferWithMemoryPtr(new vk::BufferWithMemory(vkd, device, allocator, counterBufferInfo, vk::MemoryRequirement::HostVisible));
4049 		copyAndFlush(vkd, device, *counterBuffer, 0u, &initialValue, static_cast<size_t>(counterBufferSize));
4050 	}
4051 
4052 	// Frag shader descriptor set layout.
4053 	vk::Move<vk::VkDescriptorSetLayout> fragSetLayout;
4054 	{
4055 		vk::DescriptorSetLayoutBuilder layoutBuilder;
4056 		if (m_testConfig.representativeFragmentTest)
4057 			layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
4058 		fragSetLayout = layoutBuilder.build(vkd, device);
4059 	}
4060 
4061 	// Descriptor pool and set.
4062 	vk::Move<vk::VkDescriptorPool>	fragDescriptorPool;
4063 	vk::Move<vk::VkDescriptorSet>	fragDescriptorSet;
4064 
4065 	if (m_testConfig.representativeFragmentTest)
4066 	{
4067 		vk::DescriptorPoolBuilder poolBuilder;
4068 		poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
4069 		fragDescriptorPool	= poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
4070 		fragDescriptorSet	= vk::makeDescriptorSet(vkd, device, fragDescriptorPool.get(), fragSetLayout.get());
4071 
4072 		vk::DescriptorSetUpdateBuilder updateBuilder;
4073 		const auto location = vk::DescriptorSetUpdateBuilder::Location::binding(0u);
4074 		const auto descInfo = vk::makeDescriptorBufferInfo(counterBuffer->get(), 0ull, counterBufferSize);
4075 		updateBuilder.writeSingle(fragDescriptorSet.get(), location, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descInfo);
4076 		updateBuilder.update(vkd, device);
4077 	}
4078 
4079 	// Push constant stages (matches SSBO stages if used).
4080 	vk::VkShaderStageFlags pushConstantStageFlags = (
4081 		(m_testConfig.useMeshShaders
4082 #ifndef CTS_USES_VULKANSC
4083 		 ? vk::VK_SHADER_STAGE_MESH_BIT_EXT
4084 #else
4085 		 ? 0
4086 #endif // CTS_USES_VULKANSC
4087 		 : vk::VK_SHADER_STAGE_VERTEX_BIT)
4088 		| vk::VK_SHADER_STAGE_FRAGMENT_BIT);
4089 
4090 	if (m_testConfig.needsGeometryShader())
4091 		pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
4092 
4093 	// Mesh descriptor set layout.
4094 	vk::Move<vk::VkDescriptorSetLayout> meshSetLayout;
4095 	if (vertDataAsSSBO)
4096 	{
4097 		vk::DescriptorSetLayoutBuilder layoutBuilder;
4098 		for (size_t i = 0; i < vertBuffers.size(); ++i)
4099 			layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, pushConstantStageFlags);
4100 		meshSetLayout = layoutBuilder.build(vkd, device);
4101 	}
4102 
4103 	// Descriptor pool and set if needed.
4104 	vk::Move<vk::VkDescriptorPool>	meshDescriptorPool;
4105 	vk::Move<vk::VkDescriptorSet>	meshDescriptorSet;
4106 	vk::Move<vk::VkDescriptorSet>	meshDescriptorSetRev;
4107 
4108 	if (vertDataAsSSBO)
4109 	{
4110 		const auto					descType		= vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
4111 		vk::DescriptorPoolBuilder	poolBuilder;
4112 		poolBuilder.addType(descType, static_cast<uint32_t>(vertBuffers.size()) * 2u);
4113 
4114 		meshDescriptorPool		= poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
4115 		meshDescriptorSet		= vk::makeDescriptorSet(vkd, device, meshDescriptorPool.get(), meshSetLayout.get());
4116 		meshDescriptorSetRev	= vk::makeDescriptorSet(vkd, device, meshDescriptorPool.get(), meshSetLayout.get());
4117 
4118 		std::vector<vk::VkDescriptorBufferInfo> descBufferInfos;
4119 		std::vector<vk::VkDescriptorBufferInfo> descBufferInfosRev;
4120 		descBufferInfos.reserve(vertBuffers.size());
4121 		descBufferInfosRev.reserve(rvertBuffers.size());
4122 
4123 		vk::DescriptorSetUpdateBuilder updateBuilder;
4124 
4125 		DE_ASSERT(vertBuffers.size() == rvertBuffers.size());
4126 		for (size_t i = 0; i < vertBuffers.size(); ++i)
4127 		{
4128 			descBufferInfos.push_back(vk::makeDescriptorBufferInfo(vertBuffers[i].buffer->get(), vertBuffers[i].offset, vertBuffers[i].dataSize));
4129 			descBufferInfosRev.push_back(vk::makeDescriptorBufferInfo(rvertBuffers[i].buffer->get(), rvertBuffers[i].offset, rvertBuffers[i].dataSize));
4130 
4131 			const auto binding = vk::DescriptorSetUpdateBuilder::Location::binding(static_cast<uint32_t>(i));
4132 
4133 			updateBuilder.writeSingle(meshDescriptorSet.get(), binding, descType, &descBufferInfos.back());
4134 			updateBuilder.writeSingle(meshDescriptorSetRev.get(), binding, descType, &descBufferInfosRev.back());
4135 		}
4136 
4137 		updateBuilder.update(vkd, device);
4138 	}
4139 
4140 	// The frag shader descriptor set is the second one if both exist. See getFragDescriptorSetIndex().
4141 	std::vector<vk::VkDescriptorSetLayout> rawSetLayouts;
4142 
4143 	if (meshSetLayout.get() != VK_NULL_HANDLE)
4144 		rawSetLayouts.push_back(meshSetLayout.get());
4145 
4146 	if (fragSetLayout.get() != VK_NULL_HANDLE)
4147 		rawSetLayouts.push_back(fragSetLayout.get());
4148 
4149 	// Pipeline layout.
4150 	const vk::VkPushConstantRange pushConstantRange =
4151 	{
4152 		pushConstantStageFlags,							//	VkShaderStageFlags	stageFlags;
4153 		0u,												//	deUint32			offset;
4154 		static_cast<deUint32>(sizeof(PushConstants)),	//	deUint32			size;
4155 	};
4156 
4157 	const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
4158 	{
4159 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//	VkStructureType					sType;
4160 		nullptr,											//	const void*						pNext;
4161 		0u,													//	VkPipelineLayoutCreateFlags		flags;
4162 		de::sizeU32(rawSetLayouts),							//	deUint32						setLayoutCount;
4163 		de::dataOrNull(rawSetLayouts),						//	const VkDescriptorSetLayout*	pSetLayouts;
4164 		1u,													//	deUint32						pushConstantRangeCount;
4165 		&pushConstantRange,									//	const VkPushConstantRange*		pPushConstantRanges;
4166 	};
4167 	const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
4168 
4169 	// Render pass with single subpass. Attachment order:
4170 	// 1) Color attachments (kColorAttCount items).
4171 	// 2) DS attachment.
4172 	// 3) [optional] Resolve attachments (kColorAttCount).
4173 
4174 	DE_ASSERT(kColorAttCount > 0u);
4175 
4176 	std::vector<vk::VkAttachmentReference> colorAttachments;
4177 	std::vector<vk::VkAttachmentReference> resolveAttachments;
4178 
4179 	for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
4180 	{
4181 		colorAttachments.push_back(vk::makeAttachmentReference(colorAttIdx, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
4182 		if (kUseResolveAtt)
4183 			resolveAttachments.push_back(vk::makeAttachmentReference(kColorAttCount + 1u + colorAttIdx, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
4184 	}
4185 
4186 	const vk::VkAttachmentReference dsAttachmentReference =
4187 	{
4188 		kColorAttCount,											//	deUint32		attachment;
4189 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
4190 	};
4191 
4192 	const vk::VkSubpassDescription subpassDescription =
4193 	{
4194 		0u,										//	VkSubpassDescriptionFlags		flags;
4195 		pipelineBindPoint,						//	VkPipelineBindPoint				pipelineBindPoint;
4196 		0u,										//	deUint32						inputAttachmentCount;
4197 		nullptr,								//	const VkAttachmentReference*	pInputAttachments;
4198 		kColorAttCount,							//	deUint32						colorAttachmentCount;
4199 		de::dataOrNull(colorAttachments),		//	const VkAttachmentReference*	pColorAttachments;
4200 		de::dataOrNull(resolveAttachments),		//	const VkAttachmentReference*	pResolveAttachments;
4201 		&dsAttachmentReference,					//	const VkAttachmentReference*	pDepthStencilAttachment;
4202 		0u,										//	deUint32						preserveAttachmentCount;
4203 		nullptr,								//	const deUint32*					pPreserveAttachments;
4204 	};
4205 
4206 	std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
4207 
4208 	// For multisample, we care about the resolve attachment, not the color one.
4209 	const auto colorAttachmentStoreOp = (kUseResolveAtt ? vk::VK_ATTACHMENT_STORE_OP_DONT_CARE : vk::VK_ATTACHMENT_STORE_OP_STORE);
4210 
4211 	for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
4212 	{
4213 		attachmentDescriptions.push_back(vk::VkAttachmentDescription
4214 		{
4215 			0u,												//	VkAttachmentDescriptionFlags	flags;
4216 			colorFormat,									//	VkFormat						format;
4217 			colorSampleCount,								//	VkSampleCountFlagBits			samples;
4218 			vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
4219 			colorAttachmentStoreOp,							//	VkAttachmentStoreOp				storeOp;
4220 			vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
4221 			vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
4222 			vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
4223 			vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
4224 		});
4225 	}
4226 
4227 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
4228 	{
4229 		0u,														//	VkAttachmentDescriptionFlags	flags;
4230 		dsFormatInfo->imageFormat,								//	VkFormat						format;
4231 		activeSampleCount,										//	VkSampleCountFlagBits			samples;
4232 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				loadOp;
4233 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				storeOp;
4234 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				stencilLoadOp;
4235 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				stencilStoreOp;
4236 		vk::VK_IMAGE_LAYOUT_UNDEFINED,							//	VkImageLayout					initialLayout;
4237 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
4238 	});
4239 
4240 	if (kUseResolveAtt)
4241 	{
4242 		// Resolve attachments.
4243 		for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
4244 		{
4245 			attachmentDescriptions.push_back(vk::VkAttachmentDescription
4246 			{
4247 				0u,												//	VkAttachmentDescriptionFlags	flags;
4248 				colorFormat,									//	VkFormat						format;
4249 				kSingleSampleCount,								//	VkSampleCountFlagBits			samples;
4250 				vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				loadOp;
4251 				vk::VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
4252 				vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
4253 				vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
4254 				vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
4255 				vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
4256 			});
4257 		}
4258 	}
4259 
4260 	const vk::VkRenderPassCreateInfo renderPassCreateInfo =
4261 	{
4262 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			//	VkStructureType					sType;
4263 		nullptr,												//	const void*						pNext;
4264 		0u,														//	VkRenderPassCreateFlags			flags;
4265 		static_cast<deUint32>(attachmentDescriptions.size()),	//	deUint32						attachmentCount;
4266 		attachmentDescriptions.data(),							//	const VkAttachmentDescription*	pAttachments;
4267 		1u,														//	deUint32						subpassCount;
4268 		&subpassDescription,									//	const VkSubpassDescription*		pSubpasses;
4269 		0u,														//	deUint32						dependencyCount;
4270 		nullptr,												//	const VkSubpassDependency*		pDependencies;
4271 	};
4272 	const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
4273 
4274 	// Framebuffers.
4275 	FramebufferVec framebuffers;
4276 
4277 	DE_ASSERT(colorImageViews.size() == dsImageViews.size() * kColorAttCount);
4278 
4279 	if (kUseResolveAtt)
4280 		DE_ASSERT(colorImageViews.size() == resolveImageViews.size());
4281 
4282 	for (size_t iterIdx = 0; iterIdx < dsImageViews.size(); ++iterIdx)
4283 	{
4284 		std::vector<vk::VkImageView> attachments;
4285 
4286 		for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
4287 		{
4288 			const auto colorViewIdx = iterIdx * kColorAttCount + colorAttIdx;
4289 			attachments.push_back(colorImageViews[colorViewIdx].get());
4290 		}
4291 
4292 		attachments.push_back(dsImageViews[iterIdx].get());
4293 
4294 		if (kUseResolveAtt)
4295 		{
4296 			for (uint32_t resolveAttIdx = 0u; resolveAttIdx < kColorAttCount; ++resolveAttIdx)
4297 			{
4298 				const auto resolveViewIdx = iterIdx * kColorAttCount + resolveAttIdx;
4299 				attachments.push_back(resolveImageViews[resolveViewIdx].get());
4300 			}
4301 		}
4302 
4303 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
4304 		{
4305 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	//	VkStructureType				sType;
4306 			nullptr,										//	const void*					pNext;
4307 			0u,												//	VkFramebufferCreateFlags	flags;
4308 			renderPass.get(),								//	VkRenderPass				renderPass;
4309 			static_cast<deUint32>(attachments.size()),		//	deUint32					attachmentCount;
4310 			attachments.data(),								//	const VkImageView*			pAttachments;
4311 			kFramebufferWidth,								//	deUint32					width;
4312 			kFramebufferHeight,								//	deUint32					height;
4313 			1u,												//	deUint32					layers;
4314 		};
4315 
4316 		framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
4317 	}
4318 
4319 	// Shader modules.
4320 	const auto&	binaries			= m_context.getBinaryCollection();
4321 	const auto	dynamicVertModule	= vk::createShaderModule(vkd, device, binaries.get("dynamicVert"));
4322 	const auto	staticVertModule	= vk::createShaderModule(vkd, device, binaries.get("staticVert"));
4323 	const auto	dynamicFragModule	= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("dynamicFrag"), 0u);
4324 	const auto	staticFragModule	= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("staticFrag"), 0u);
4325 	const auto	geomModule			= (m_testConfig.needsGeometryShader() ? vk::createShaderModule(vkd, device, binaries.get("geom")) : vk::Move<vk::VkShaderModule>());
4326 	const auto	tescModule			= (m_testConfig.needsTessellation() ? vk::createShaderModule(vkd, device, binaries.get("tesc")) : vk::Move<vk::VkShaderModule>());
4327 	const auto	teseModule			= (m_testConfig.needsTessellation() ? vk::createShaderModule(vkd, device, binaries.get("tese")) : vk::Move<vk::VkShaderModule>());
4328 	const auto	meshModule			= (m_testConfig.useMeshShaders ? vk::createShaderModule(vkd, device, binaries.get("mesh")) : vk::Move<vk::VkShaderModule>());
4329 	const auto	meshNoOutModule		= (m_testConfig.bindUnusedMeshShadingPipeline ? vk::createShaderModule(vkd, device, binaries.get("meshNoOut")) : vk::Move<vk::VkShaderModule>());
4330 
4331 	vk::Move<vk::VkShaderModule>	vertDPCPModule;
4332 	vk::Move<vk::VkShaderModule>	fragDPCPModule;
4333 
4334 	// Input state.
4335 	const auto vertexBindings	= m_testConfig.vertexGenerator.staticValue->getBindingDescriptions(m_testConfig.strideConfig.staticValue);
4336 	const auto vertexAttributes	= m_testConfig.vertexGenerator.staticValue->getAttributeDescriptions();
4337 
4338 	const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
4339 	{
4340 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
4341 		nullptr,														//	const void*									pNext;
4342 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
4343 		static_cast<deUint32>(vertexBindings.size()),					//	deUint32									vertexBindingDescriptionCount;
4344 		vertexBindings.data(),											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
4345 		static_cast<deUint32>(vertexAttributes.size()),					//	deUint32									vertexAttributeDescriptionCount;
4346 		vertexAttributes.data(),										//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
4347 	};
4348 
4349 	// Input assembly.
4350 	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
4351 	{
4352 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
4353 		nullptr,															//	const void*								pNext;
4354 		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
4355 		m_testConfig.topologyConfig.staticValue,							//	VkPrimitiveTopology						topology;
4356 		makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue),		//	VkBool32								primitiveRestartEnable;
4357 	};
4358 
4359 	// Viewport state.
4360 	if (m_testConfig.viewportConfig.dynamicValue)
4361 		DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
4362 	else
4363 		DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
4364 
4365 	if (m_testConfig.scissorConfig.dynamicValue)
4366 		DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
4367 	else
4368 		DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
4369 
4370 	// Rasterization state.
4371 	void* multisamplePnext		= nullptr;
4372 	void* rasterizationPnext	= nullptr;
4373 	void* viewportPnext			= nullptr;
4374 
4375 #ifndef CTS_USES_VULKANSC
4376 	using RastStreamInfoPtr		= de::MovePtr<vk::VkPipelineRasterizationStateStreamCreateInfoEXT>;
4377 	using ProvokingVtxModePtr	= de::MovePtr<vk::VkPipelineRasterizationProvokingVertexStateCreateInfoEXT>;
4378 	using DepthClipControlPtr	= de::MovePtr<vk::VkPipelineViewportDepthClipControlCreateInfoEXT>;
4379 	using DepthClipEnablePtr	= de::MovePtr<vk::VkPipelineRasterizationDepthClipStateCreateInfoEXT>;
4380 	using LineRasterModePtr		= de::MovePtr<vk::VkPipelineRasterizationLineStateCreateInfoEXT>;
4381 	using ConservativeRastPtr	= de::MovePtr<vk::VkPipelineRasterizationConservativeStateCreateInfoEXT>;
4382 
4383 	RastStreamInfoPtr	pRasterizationStreamInfo;
4384 	const bool			staticStreamInfo			= static_cast<bool>(m_testConfig.rasterizationStreamConfig.staticValue);
4385 
4386 	if (staticStreamInfo)
4387 	{
4388 		pRasterizationStreamInfo = RastStreamInfoPtr(new vk::VkPipelineRasterizationStateStreamCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
4389 		pRasterizationStreamInfo->rasterizationStream = m_testConfig.rasterizationStreamConfig.staticValue.get();
4390 		rasterizationPnext = pRasterizationStreamInfo.get();
4391 	}
4392 
4393 	ProvokingVtxModePtr	pProvokingVertexModeInfo;
4394 	const bool			staticProvokingVtxInfo		= static_cast<bool>(m_testConfig.provokingVertexConfig.staticValue);
4395 
4396 	if (staticProvokingVtxInfo)
4397 	{
4398 		pProvokingVertexModeInfo = ProvokingVtxModePtr(new vk::VkPipelineRasterizationProvokingVertexStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
4399 		pProvokingVertexModeInfo->provokingVertexMode = makeProvokingVertexMode(m_testConfig.provokingVertexConfig.staticValue.get());
4400 		rasterizationPnext = pProvokingVertexModeInfo.get();
4401 	}
4402 
4403 	DepthClipEnablePtr	pDepthClipEnableInfo;
4404 	const bool			staticDepthClipEnableInfo	= static_cast<bool>(m_testConfig.depthClipEnableConfig.staticValue);
4405 
4406 	if (staticDepthClipEnableInfo)
4407 	{
4408 		pDepthClipEnableInfo = DepthClipEnablePtr(new vk::VkPipelineRasterizationDepthClipStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
4409 		pDepthClipEnableInfo->depthClipEnable = makeVkBool32(m_testConfig.depthClipEnableConfig.staticValue.get());
4410 		rasterizationPnext = pDepthClipEnableInfo.get();
4411 	}
4412 
4413 	DepthClipControlPtr	pDepthClipControlInfo;
4414 	const bool			staticDepthClipControlInfo	= static_cast<bool>(m_testConfig.negativeOneToOneConfig.staticValue);
4415 
4416 	if (staticDepthClipControlInfo)
4417 	{
4418 		pDepthClipControlInfo = DepthClipControlPtr(new vk::VkPipelineViewportDepthClipControlCreateInfoEXT(vk::initVulkanStructure(viewportPnext)));
4419 		pDepthClipControlInfo->negativeOneToOne = makeVkBool32(m_testConfig.negativeOneToOneConfig.staticValue.get());
4420 		viewportPnext = pDepthClipControlInfo.get();
4421 	}
4422 
4423 	LineRasterModePtr	pLineRasterModeInfo;
4424 
4425 	if (m_testConfig.lineRasterStruct())
4426 	{
4427 		DE_ASSERT(static_cast<bool>(m_testConfig.lineStippleParamsConfig.staticValue));
4428 
4429 		pLineRasterModeInfo = LineRasterModePtr(new vk::VkPipelineRasterizationLineStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
4430 		rasterizationPnext = pLineRasterModeInfo.get();
4431 
4432 		const auto&	lineRasterFeatures	= m_context.getLineRasterizationFeaturesEXT();
4433 		const auto	lineRasterMode		= selectLineRasterizationMode(lineRasterFeatures, m_testConfig.lineStippleSupportRequired(), m_testConfig.lineRasterModeConfig.staticValue);
4434 		const auto&	staticParams		= m_testConfig.lineStippleParamsConfig.staticValue.get();
4435 
4436 		pLineRasterModeInfo->stippledLineEnable		= m_testConfig.lineStippleEnableConfig.staticValue;
4437 		pLineRasterModeInfo->lineRasterizationMode	= makeLineRasterizationMode(lineRasterMode);
4438 		pLineRasterModeInfo->lineStippleFactor		= staticParams.factor;
4439 		pLineRasterModeInfo->lineStipplePattern		= staticParams.pattern;
4440 	}
4441 
4442 	ConservativeRastPtr	pConservativeRasterModeInfo;
4443 
4444 	if (m_testConfig.conservativeRasterStruct())
4445 	{
4446 		pConservativeRasterModeInfo = ConservativeRastPtr(new vk::VkPipelineRasterizationConservativeStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
4447 		rasterizationPnext = pConservativeRasterModeInfo.get();
4448 
4449 		pConservativeRasterModeInfo->conservativeRasterizationMode		= m_testConfig.conservativeRasterModeConfig.staticValue;
4450 		pConservativeRasterModeInfo->extraPrimitiveOverestimationSize	= m_testConfig.extraPrimitiveOverEstConfig.staticValue;
4451 	}
4452 #else
4453 	DE_ASSERT(false);
4454 #endif // CTS_USES_VULKANSC
4455 
4456 	const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
4457 	{
4458 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
4459 		rasterizationPnext,												//	const void*								pNext;
4460 		0u,																//	VkPipelineRasterizationStateCreateFlags	flags;
4461 		makeVkBool32(m_testConfig.depthClampEnableConfig.staticValue),	//	VkBool32								depthClampEnable;
4462 		makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue),	//	VkBool32								rasterizerDiscardEnable;
4463 		m_testConfig.polygonModeConfig.staticValue,						//	VkPolygonMode							polygonMode;
4464 		m_testConfig.cullModeConfig.staticValue,						//	VkCullModeFlags							cullMode;
4465 		m_testConfig.frontFaceConfig.staticValue,						//	VkFrontFace								frontFace;
4466 		makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue),	//	VkBool32								depthBiasEnable;
4467 		m_testConfig.depthBiasConfig.staticValue.constantFactor,		//	float									depthBiasConstantFactor;
4468 		m_testConfig.depthBiasConfig.staticValue.clamp,					//	float									depthBiasClamp;
4469 		0.0f,															//	float									depthBiasSlopeFactor;
4470 		1.0f,															//	float									lineWidth;
4471 	};
4472 
4473 	using SampleLocationsPtr = de::MovePtr<vk::VkPipelineSampleLocationsStateCreateInfoEXT>;
4474 	SampleLocationsPtr						pSampleLocations;
4475 	std::vector<vk::VkSampleLocationEXT>	sampleLocationCoords;
4476 
4477 #ifndef CTS_USES_VULKANSC
4478 	using CoverageToColorPtr = de::MovePtr<vk::VkPipelineCoverageToColorStateCreateInfoNV>;
4479 	CoverageToColorPtr						pCoverageToColor;
4480 
4481 	using CoverageModulationPtr = de::MovePtr<vk::VkPipelineCoverageModulationStateCreateInfoNV>;
4482 	CoverageModulationPtr					pCoverageModulation;
4483 
4484 	using CoverageReductionPtr = de::MovePtr<vk::VkPipelineCoverageReductionStateCreateInfoNV>;
4485 	CoverageReductionPtr					pCoverageReduction;
4486 
4487 	using ViewportSwizzlePtr = de::MovePtr<vk::VkPipelineViewportSwizzleStateCreateInfoNV>;
4488 	ViewportSwizzlePtr						pViewportSwizzle;
4489 
4490 	using ShadingRateImagePtr = de::MovePtr<vk::VkPipelineViewportShadingRateImageStateCreateInfoNV>;
4491 	ShadingRateImagePtr						pShadingRateImage;
4492 
4493 	using ViewportWScalingPtr = de::MovePtr<vk::VkPipelineViewportWScalingStateCreateInfoNV>;
4494 	ViewportWScalingPtr						pViewportWScaling;
4495 
4496 	using ReprFragmentPtr = de::MovePtr<vk::VkPipelineRepresentativeFragmentTestStateCreateInfoNV>;
4497 	ReprFragmentPtr							pReprFragment;
4498 #endif // CTS_USES_VULKANSC
4499 
4500 	if (m_testConfig.sampleLocationsStruct())
4501 	{
4502 		pSampleLocations = SampleLocationsPtr(new vk::VkPipelineSampleLocationsStateCreateInfoEXT(vk::initVulkanStructure(multisamplePnext)));
4503 		multisamplePnext = pSampleLocations.get();
4504 
4505 		pSampleLocations->sampleLocationsEnable							= makeVkBool32(m_testConfig.sampleLocationsEnableConfig.staticValue);
4506 		pSampleLocations->sampleLocationsInfo							= vk::initVulkanStructure();
4507 		pSampleLocations->sampleLocationsInfo.sampleLocationsPerPixel	= activeSampleCount;
4508 		pSampleLocations->sampleLocationsInfo.sampleLocationGridSize	= vk::makeExtent2D(1u, 1u);
4509 		pSampleLocations->sampleLocationsInfo.sampleLocationsCount		= static_cast<uint32_t>(activeSampleCount);
4510 
4511 		sampleLocationCoords.reserve(pSampleLocations->sampleLocationsInfo.sampleLocationsCount);
4512 		for (uint32_t i = 0; i < pSampleLocations->sampleLocationsInfo.sampleLocationsCount; ++i)
4513 			sampleLocationCoords.push_back(vk::VkSampleLocationEXT{m_testConfig.sampleLocations.x(), m_testConfig.sampleLocations.y()});
4514 
4515 		pSampleLocations->sampleLocationsInfo.pSampleLocations = sampleLocationCoords.data();
4516 	}
4517 
4518 #ifndef CTS_USES_VULKANSC
4519 	if (m_testConfig.coverageToColorStruct())
4520 	{
4521 		pCoverageToColor = CoverageToColorPtr(new vk::VkPipelineCoverageToColorStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
4522 		multisamplePnext = pCoverageToColor.get();
4523 
4524 		pCoverageToColor->coverageToColorEnable		= makeVkBool32(m_testConfig.coverageToColorEnableConfig.staticValue);
4525 		pCoverageToColor->coverageToColorLocation	= m_testConfig.coverageToColorLocationConfig.staticValue;
4526 	}
4527 
4528 	if (m_testConfig.coverageModulation)
4529 	{
4530 		pCoverageModulation	= CoverageModulationPtr(new vk::VkPipelineCoverageModulationStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
4531 		multisamplePnext	= pCoverageModulation.get();
4532 
4533 		pCoverageModulation->coverageModulationMode			= m_testConfig.coverageModulationModeConfig.staticValue;
4534 		pCoverageModulation->coverageModulationTableEnable	= makeVkBool32(m_testConfig.coverageModTableEnableConfig.staticValue);
4535 		pCoverageModulation->coverageModulationTableCount	= static_cast<uint32_t>(m_testConfig.coverageModTableConfig.staticValue.size());
4536 		pCoverageModulation->pCoverageModulationTable		= de::dataOrNull(m_testConfig.coverageModTableConfig.staticValue);
4537 	}
4538 
4539 	if (m_testConfig.coverageReduction)
4540 	{
4541 		pCoverageReduction	= CoverageReductionPtr(new vk::VkPipelineCoverageReductionStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
4542 		multisamplePnext	= pCoverageReduction.get();
4543 
4544 		pCoverageReduction->coverageReductionMode = m_testConfig.coverageReductionModeConfig.staticValue;
4545 	}
4546 
4547 	if (m_testConfig.viewportSwizzle)
4548 	{
4549 		pViewportSwizzle	= ViewportSwizzlePtr(new vk::VkPipelineViewportSwizzleStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
4550 		viewportPnext		= pViewportSwizzle.get();
4551 
4552 		const auto& swizzleVec				= m_testConfig.viewportSwizzleConfig.staticValue;
4553 		pViewportSwizzle->viewportCount		= static_cast<uint32_t>(swizzleVec.size());
4554 		pViewportSwizzle->pViewportSwizzles	= de::dataOrNull(swizzleVec);
4555 	}
4556 
4557 	const vk::VkShadingRatePaletteEntryNV	defaultShadingRatePaletteEntry	= vk::VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV;
4558 	const auto								defaultShadingRatePalette		= vk::makeShadingRatePaletteNV(1u, &defaultShadingRatePaletteEntry);
4559 	std::vector<vk::VkShadingRatePaletteNV>	shadingRatePaletteVec;
4560 
4561 	const auto								defaultViewportWScalingFactors	= vk::makeViewportWScalingNV(-1.0f, -1.0f);
4562 	std::vector<vk::VkViewportWScalingNV>	viewportWScalingVec;
4563 
4564 	if (m_testConfig.shadingRateImage)
4565 	{
4566 		pShadingRateImage	= ShadingRateImagePtr(new vk::VkPipelineViewportShadingRateImageStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
4567 		viewportPnext		= pShadingRateImage.get();
4568 
4569 		const auto& viewportVec						= m_testConfig.getActiveViewportVec();
4570 		pShadingRateImage->shadingRateImageEnable	= makeVkBool32(m_testConfig.shadingRateImageEnableConfig.staticValue);
4571 		pShadingRateImage->viewportCount			= de::sizeU32(viewportVec);
4572 
4573 		shadingRatePaletteVec.resize(viewportVec.size(), defaultShadingRatePalette);
4574 		pShadingRateImage->pShadingRatePalettes = shadingRatePaletteVec.data();
4575 	}
4576 
4577 	if (m_testConfig.viewportWScaling)
4578 	{
4579 		pViewportWScaling	= ViewportWScalingPtr(new vk::VkPipelineViewportWScalingStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
4580 		viewportPnext		= pViewportWScaling.get();
4581 
4582 		const auto& viewportVec						= m_testConfig.getActiveViewportVec();
4583 		pViewportWScaling->viewportWScalingEnable	= makeVkBool32(m_testConfig.viewportWScalingEnableConfig.staticValue);
4584 		pViewportWScaling->viewportCount			= de::sizeU32(viewportVec);
4585 
4586 		viewportWScalingVec.resize(viewportVec.size(), defaultViewportWScalingFactors);
4587 		pViewportWScaling->pViewportWScalings = viewportWScalingVec.data();
4588 	}
4589 
4590 	if (m_testConfig.representativeFragmentTest)
4591 	{
4592 		pReprFragment = ReprFragmentPtr(new vk::VkPipelineRepresentativeFragmentTestStateCreateInfoNV(vk::initVulkanStructure()));
4593 		pReprFragment->representativeFragmentTestEnable = makeVkBool32(m_testConfig.reprFragTestEnableConfig.staticValue);
4594 	}
4595 #endif // CTS_USES_VULKANSC
4596 
4597 	// Multisample state.
4598 	const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo
4599 	{
4600 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
4601 		multisamplePnext,												//	const void*								pNext;
4602 		0u,																//	VkPipelineMultisampleStateCreateFlags	flags;
4603 		m_testConfig.rasterizationSamplesConfig.staticValue,			//	VkSampleCountFlagBits					rasterizationSamples;
4604 		VK_FALSE,														//	VkBool32								sampleShadingEnable;
4605 		0.0f,															//	float									minSampleShading;
4606 		de::dataOrNull(m_testConfig.sampleMaskConfig.staticValue),		//	const VkSampleMask*						pSampleMask;
4607 		makeVkBool32(m_testConfig.alphaToCoverageConfig.staticValue),	//	VkBool32								alphaToCoverageEnable;
4608 		makeVkBool32(m_testConfig.alphaToOneConfig.staticValue),		//	VkBool32								alphaToOneEnable;
4609 	};
4610 
4611 	// Depth/stencil state.
4612 	vk::VkStencilOpState	staticFrontStencil;
4613 	vk::VkStencilOpState	staticBackStencil;
4614 	bool					staticFrontStencilSet	= false;
4615 	bool					staticBackStencilSet	= false;
4616 
4617 	// Common setup for the front and back operations.
4618 	staticFrontStencil.compareMask	= 0xFFu;
4619 	staticFrontStencil.writeMask	= 0xFFu;
4620 	staticFrontStencil.reference	= m_testConfig.referenceStencil;
4621 	staticBackStencil				= staticFrontStencil;
4622 
4623 	for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
4624 	{
4625 		if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
4626 		{
4627 			copy(staticFrontStencil, op);
4628 			staticFrontStencilSet = true;
4629 		}
4630 		if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
4631 		{
4632 			copy(staticBackStencil, op);
4633 			staticBackStencilSet = true;
4634 		}
4635 	}
4636 
4637 	// Default values for the static part.
4638 	if (!staticFrontStencilSet)
4639 		copy(staticFrontStencil, kDefaultStencilOpParams);
4640 	if (!staticBackStencilSet)
4641 		copy(staticBackStencil, kDefaultStencilOpParams);
4642 
4643 	const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
4644 	{
4645 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		//	VkStructureType							sType;
4646 		nullptr,															//	const void*								pNext;
4647 		0u,																	//	VkPipelineDepthStencilStateCreateFlags	flags;
4648 		makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),		//	VkBool32								depthTestEnable;
4649 		makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),		//	VkBool32								depthWriteEnable;
4650 		m_testConfig.depthCompareOpConfig.staticValue,						//	VkCompareOp								depthCompareOp;
4651 		makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue),	//	VkBool32								depthBoundsTestEnable;
4652 		makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),		//	VkBool32								stencilTestEnable;
4653 		staticFrontStencil,													//	VkStencilOpState						front;
4654 		staticBackStencil,													//	VkStencilOpState						back;
4655 		m_testConfig.minDepthBounds,										//	float									minDepthBounds;
4656 		m_testConfig.maxDepthBounds,										//	float									maxDepthBounds;
4657 	};
4658 
4659 	// Dynamic state. Here we will set all states which have a dynamic value.
4660 	const auto dynamicStates = m_testConfig.getDynamicStates();
4661 
4662 	const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
4663 	{
4664 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
4665 		nullptr,													//	const void*							pNext;
4666 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
4667 		static_cast<deUint32>(dynamicStates.size()),				//	deUint32							dynamicStateCount;
4668 		de::dataOrNull(dynamicStates),								//	const VkDynamicState*				pDynamicStates;
4669 	};
4670 
4671 	const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
4672 	{
4673 		makeVkBool32(m_testConfig.colorBlendEnableConfig.staticValue),			// VkBool32                 blendEnable
4674 		m_testConfig.colorBlendEquationConfig.staticValue.srcColorBlendFactor,	// VkBlendFactor            srcColorBlendFactor
4675 		m_testConfig.colorBlendEquationConfig.staticValue.dstColorBlendFactor,	// VkBlendFactor            dstColorBlendFactor
4676 		m_testConfig.colorBlendEquationConfig.staticValue.colorBlendOp,			// VkBlendOp                colorBlendOp
4677 		m_testConfig.colorBlendEquationConfig.staticValue.srcAlphaBlendFactor,	// VkBlendFactor            srcAlphaBlendFactor
4678 		m_testConfig.colorBlendEquationConfig.staticValue.dstAlphaBlendFactor,	// VkBlendFactor            dstAlphaBlendFactor
4679 		m_testConfig.colorBlendEquationConfig.staticValue.alphaBlendOp,			// VkBlendOp                alphaBlendOp
4680 		m_testConfig.colorWriteMaskConfig.staticValue,							// VkColorComponentFlags    colorWriteMask
4681 	};
4682 	const std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentStateVec (kColorAttCount, colorBlendAttachmentState);
4683 
4684 	using ColorBlendAdvancedPtr = de::MovePtr<vk::VkPipelineColorBlendAdvancedStateCreateInfoEXT>;
4685 	ColorBlendAdvancedPtr pColorBlendAdvanced;
4686 
4687 	if (m_testConfig.colorBlendEquationConfig.staticValue.isAdvanced())
4688 	{
4689 		pColorBlendAdvanced = ColorBlendAdvancedPtr(new vk::VkPipelineColorBlendAdvancedStateCreateInfoEXT(vk::initVulkanStructure()));
4690 		pColorBlendAdvanced->srcPremultiplied	= VK_TRUE;
4691 		pColorBlendAdvanced->dstPremultiplied	= VK_TRUE;
4692 		pColorBlendAdvanced->blendOverlap		= vk::VK_BLEND_OVERLAP_UNCORRELATED_EXT;
4693 	}
4694 
4695 	const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
4696 	{
4697 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType                               sType
4698 		pColorBlendAdvanced.get(),										// const void*                                   pNext
4699 		0u,																// VkPipelineColorBlendStateCreateFlags          flags
4700 		m_testConfig.logicOpEnableConfig.staticValue,					// VkBool32                                      logicOpEnable
4701 		m_testConfig.logicOpConfig.staticValue,							// VkLogicOp                                     logicOp
4702 		static_cast<uint32_t>(colorBlendAttachmentStateVec.size()),		// deUint32                                      attachmentCount
4703 		de::dataOrNull(colorBlendAttachmentStateVec),					// const VkPipelineColorBlendAttachmentState*    pAttachments
4704 		{ 0.0f, 0.0f, 0.0f, 0.0f }										// float                                         blendConstants[4]
4705 	};
4706 
4707 	vk::GraphicsPipelineWrapper	staticPipeline		(vkd, device, m_testConfig.pipelineConstructionType);
4708 	const bool					bindStaticFirst		= (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES	||
4709 													   kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES	||
4710 													   kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
4711 	const bool					useStaticPipeline	= (bindStaticFirst || kReversed);
4712 
4713 	// Create extra dynamic patch control points pipeline if needed.
4714 	vk::Move<vk::VkPipeline> extraDynPCPPipeline;
4715 
4716 	if (m_testConfig.useExtraDynPCPPipeline)
4717 	{
4718 		vertDPCPModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vertDPCP"));
4719 		fragDPCPModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("fragDPCP"));
4720 
4721 		const vk::VkPipelineVertexInputStateCreateInfo	extraDPCPInputState		= vk::initVulkanStructure();
4722 		const vk::VkDynamicState						extraDynamicState		= vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT;
4723 		const vk::VkPipelineDynamicStateCreateInfo		extraDynamicStateInfo	=
4724 		{
4725 			vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
4726 			nullptr,													//	const void*							pNext;
4727 			0u,															//	VkPipelineDynamicStateCreateFlags	flags;
4728 			1u,															//	uint32_t							dynamicStateCount;
4729 			&extraDynamicState,												//	const VkDynamicState*				pDynamicStates;
4730 		};
4731 
4732 		const auto extraPipelineLayout = vk::makePipelineLayout(vkd, device);
4733 
4734 		const auto viewports	= m_testConfig.viewportConfig.staticValue;
4735 		const auto scissors		= m_testConfig.scissorConfig.staticValue;
4736 
4737 		extraDynPCPPipeline = vk::makeGraphicsPipeline(
4738 			vkd, device, *extraPipelineLayout,
4739 			vertDPCPModule.get(), DE_NULL, DE_NULL, DE_NULL, fragDPCPModule.get(),
4740 			renderPass.get(), viewports, scissors, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0u, 0u,
4741 			&extraDPCPInputState, nullptr, nullptr, nullptr, nullptr, &extraDynamicStateInfo);
4742 	}
4743 
4744 	// Create static pipeline when needed.
4745 	if (useStaticPipeline)
4746 	{
4747 		auto viewports	= m_testConfig.viewportConfig.staticValue;
4748 		auto scissors	= m_testConfig.scissorConfig.staticValue;
4749 
4750 		// The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
4751 		const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
4752 		viewports.resize(minStaticCount);
4753 		scissors.resize(minStaticCount);
4754 
4755 		staticPipeline.setDefaultPatchControlPoints(m_testConfig.patchControlPointsConfig.staticValue)
4756 					  .setViewportStatePnext(viewportPnext)
4757 					  .setDefaultTessellationDomainOrigin(m_testConfig.tessDomainOriginConfig.staticValue);
4758 
4759 
4760 #ifndef CTS_USES_VULKANSC
4761 		if (m_testConfig.useMeshShaders)
4762 		{
4763 			staticPipeline.setupPreRasterizationMeshShaderState(
4764 												viewports,
4765 												scissors,
4766 												*pipelineLayout,
4767 												*renderPass,
4768 												0u,
4769 												VK_NULL_HANDLE,
4770 												*meshModule,
4771 												&rasterizationStateCreateInfo);
4772 		}
4773 		else
4774 #endif // CTS_USES_VULKANSC
4775 		{
4776 			staticPipeline.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
4777 						  .setupPreRasterizationShaderState(
4778 												viewports,
4779 												scissors,
4780 												*pipelineLayout,
4781 												*renderPass,
4782 												0u,
4783 												*staticVertModule,
4784 												&rasterizationStateCreateInfo,
4785 												*tescModule,
4786 												*teseModule,
4787 												*geomModule);
4788 		}
4789 
4790 		staticPipeline
4791 #ifndef CTS_USES_VULKANSC
4792 					  .setRepresentativeFragmentTestState(pReprFragment.get())
4793 #endif // CTS_USES_VULKANSC
4794 					  .setupFragmentShaderState(*pipelineLayout, *renderPass, 0u, *staticFragModule, &depthStencilStateCreateInfo, &multisampleStateCreateInfo)
4795 					  .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
4796 					  .setMonolithicPipelineLayout(*pipelineLayout)
4797 					  .buildPipeline();
4798 	}
4799 
4800 	// Create dynamic pipeline.
4801 	vk::GraphicsPipelineWrapper graphicsPipeline(vkd, device, m_testConfig.pipelineConstructionType);
4802 	{
4803 		auto viewports	= m_testConfig.viewportConfig.staticValue;
4804 		auto scissors	= m_testConfig.scissorConfig.staticValue;
4805 
4806 		const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
4807 			? m_testConfig.viewportConfig.dynamicValue.get().size()
4808 			: m_testConfig.viewportConfig.staticValue.size());
4809 
4810 		const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
4811 			? m_testConfig.scissorConfig.dynamicValue.get().size()
4812 			: m_testConfig.scissorConfig.staticValue.size());
4813 
4814 		const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
4815 
4816 		// The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
4817 		if (m_testConfig.viewportConfig.dynamicValue)
4818 		{
4819 			graphicsPipeline.setDefaultViewportsCount();
4820 			viewports = std::vector<vk::VkViewport>();
4821 		}
4822 		else
4823 			viewports.resize(minDynamicCount);
4824 
4825 		if (m_testConfig.scissorConfig.dynamicValue)
4826 		{
4827 			graphicsPipeline.setDefaultScissorsCount();
4828 			scissors = std::vector<vk::VkRect2D>();
4829 		}
4830 		else
4831 			scissors.resize(minDynamicCount);
4832 
4833 		graphicsPipeline.setDynamicState(&dynamicStateCreateInfo)
4834 						.setDefaultPatchControlPoints(m_testConfig.patchControlPointsConfig.staticValue)
4835 						.setViewportStatePnext(viewportPnext)
4836 						.setDefaultTessellationDomainOrigin(m_testConfig.tessDomainOriginConfig.staticValue);
4837 
4838 #ifndef CTS_USES_VULKANSC
4839 		if (m_testConfig.useMeshShaders)
4840 		{
4841 			graphicsPipeline.setupPreRasterizationMeshShaderState(
4842 												viewports,
4843 												scissors,
4844 												*pipelineLayout,
4845 												*renderPass,
4846 												0u,
4847 												DE_NULL,
4848 												*meshModule,
4849 												&rasterizationStateCreateInfo);
4850 		}
4851 		else
4852 #endif // CTS_USES_VULKANSC
4853 		{
4854 			graphicsPipeline.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
4855 							.setupPreRasterizationShaderState(
4856 												viewports,
4857 												scissors,
4858 												*pipelineLayout,
4859 												*renderPass,
4860 												0u,
4861 												*dynamicVertModule,
4862 												&rasterizationStateCreateInfo,
4863 												*tescModule,
4864 												*teseModule,
4865 												*geomModule);
4866 		}
4867 
4868 		graphicsPipeline
4869 #ifndef CTS_USES_VULKANSC
4870 						.setRepresentativeFragmentTestState(pReprFragment.get())
4871 #endif // CTS_USES_VULKANSC
4872 						.setupFragmentShaderState(*pipelineLayout, *renderPass, 0u, *dynamicFragModule, &depthStencilStateCreateInfo, &multisampleStateCreateInfo)
4873 						.setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
4874 						.setMonolithicPipelineLayout(*pipelineLayout)
4875 						.buildPipeline();
4876 	}
4877 
4878 	vk::GraphicsPipelineWrapper meshNoOutPipeline(vkd, device, m_testConfig.pipelineConstructionType);
4879 
4880 #ifndef CTS_USES_VULKANSC
4881 	if (m_testConfig.bindUnusedMeshShadingPipeline)
4882 	{
4883 		// Remove dynamic states which are not compatible with mesh shading pipelines.
4884 		std::vector<vk::VkDynamicState> meshNoOutDynamicStates;
4885 		std::copy_if(begin(dynamicStates), end(dynamicStates), std::back_inserter(meshNoOutDynamicStates), isMeshShadingPipelineCompatible);
4886 
4887 		const vk::VkPipelineDynamicStateCreateInfo meshNoOutDynamicStateInfo =
4888 		{
4889 			vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
4890 			nullptr,													//	const void*							pNext;
4891 			0u,															//	VkPipelineDynamicStateCreateFlags	flags;
4892 			de::sizeU32(meshNoOutDynamicStates),						//	uint32_t							dynamicStateCount;
4893 			de::dataOrNull(meshNoOutDynamicStates),						//	const VkDynamicState*				pDynamicStates;
4894 		};
4895 
4896 		// Provide a viewport state similar to the static pipeline.
4897 		auto viewports	= m_testConfig.viewportConfig.staticValue;
4898 		auto scissors	= m_testConfig.scissorConfig.staticValue;
4899 
4900 		const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
4901 		viewports.resize(minStaticCount);
4902 		scissors.resize(minStaticCount);
4903 
4904 		meshNoOutPipeline.setDynamicState(&meshNoOutDynamicStateInfo)
4905 						 .setDefaultPatchControlPoints(m_testConfig.patchControlPointsConfig.staticValue)
4906 						 .setupPreRasterizationMeshShaderState(
4907 											viewports,
4908 											scissors,
4909 											*pipelineLayout,
4910 											*renderPass,
4911 											0u,
4912 											VK_NULL_HANDLE,
4913 											*meshNoOutModule,
4914 											&rasterizationStateCreateInfo)
4915 						 .setupFragmentShaderState(*pipelineLayout, *renderPass, 0u, VK_NULL_HANDLE, &depthStencilStateCreateInfo, &multisampleStateCreateInfo)
4916 						 .setupFragmentOutputState(*renderPass, 0u, &colorBlendStateCreateInfo, &multisampleStateCreateInfo)
4917 						 .setMonolithicPipelineLayout(*pipelineLayout)
4918 						 .buildPipeline();
4919 	}
4920 #endif // CTS_USES_VULKANSC
4921 
4922 	// Command buffer.
4923 	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
4924 	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
4925 	const auto cmdBuffer	= cmdBufferPtr.get();
4926 
4927 	// Clear values, clear to green for dynamic logicOp
4928 	std::vector<vk::VkClearValue> clearValues (kColorAttCount, m_testConfig.clearColorValue);
4929 	clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
4930 
4931 	// Record command buffer.
4932 	vk::beginCommandBuffer(vkd, cmdBuffer);
4933 
4934 	for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
4935 	{
4936 		// Track in-advance vertex buffer binding.
4937 		bool boundInAdvance = false;
4938 
4939 		// Maybe set extended dynamic state here.
4940 		if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
4941 		{
4942 			setDynamicStates(m_testConfig, vkd, cmdBuffer);
4943 			boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
4944 		}
4945 
4946 		// Begin render pass.
4947 		vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
4948 
4949 			// Bind a static pipeline first if needed.
4950 			if (bindStaticFirst && iteration == 0u)
4951 				vkd.cmdBindPipeline(cmdBuffer, pipelineBindPoint, staticPipeline.getPipeline());
4952 
4953 			// Maybe set extended dynamic state here.
4954 			if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
4955 			{
4956 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
4957 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
4958 			}
4959 
4960 			// Bind dynamic pipeline.
4961 			if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
4962 				 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
4963 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
4964 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
4965 			{
4966 				if (m_testConfig.bindUnusedMeshShadingPipeline)
4967 				{
4968 					DE_ASSERT(kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START);
4969 					vkd.cmdBindPipeline(cmdBuffer, pipelineBindPoint, meshNoOutPipeline.getPipeline());
4970 				}
4971 
4972 				if (m_testConfig.useExtraDynPCPPipeline)
4973 				{
4974 					vkd.cmdBindPipeline(cmdBuffer, pipelineBindPoint, extraDynPCPPipeline.get());
4975 
4976 					// In these two sequence orderings, the right dynamic state value will have been set before and we would be
4977 					// setting it to a wrong value here, resulting in test failures. We keep the right value instead.
4978 					if (kSequenceOrdering != SequenceOrdering::CMD_BUFFER_START && kSequenceOrdering != SequenceOrdering::BETWEEN_PIPELINES)
4979 						vkd.cmdSetPatchControlPointsEXT(cmdBuffer, m_testConfig.patchControlPointsConfig.staticValue);
4980 
4981 					vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
4982 				}
4983 
4984 				vkd.cmdBindPipeline(cmdBuffer, pipelineBindPoint, graphicsPipeline.getPipeline());
4985 			}
4986 
4987 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
4988 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
4989 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
4990 			{
4991 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
4992 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
4993 			}
4994 
4995 			// Bind a static pipeline last if needed.
4996 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
4997 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
4998 			{
4999 				vkd.cmdBindPipeline(cmdBuffer, pipelineBindPoint, staticPipeline.getPipeline());
5000 			}
5001 
5002 			const auto& viewportVec = m_testConfig.getActiveViewportVec();
5003 			for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
5004 			{
5005 				for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
5006 				{
5007 					// Push constants.
5008 					PushConstants pushConstants =
5009 					{
5010 						m_testConfig.meshParams[meshIdx].color,			//	tcu::Vec4	triangleColor;
5011 						m_testConfig.meshParams[meshIdx].depth,			//	float		meshDepth;
5012 						static_cast<deInt32>(viewportIdx),				//	deInt32		viewPortIndex;
5013 						m_testConfig.meshParams[meshIdx].scaleX,		//	float		scaleX;
5014 						m_testConfig.meshParams[meshIdx].scaleY,		//	float		scaleY;
5015 						m_testConfig.meshParams[meshIdx].offsetX,		//	float		offsetX;
5016 						m_testConfig.meshParams[meshIdx].offsetY,		//	float		offsetY;
5017 						m_testConfig.meshParams[meshIdx].stripScale,	//	float		stripScale;
5018 					};
5019 					vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
5020 
5021 					// Track vertex bounding state for this mesh.
5022 					bool boundBeforeDraw = false;
5023 
5024 					// Maybe set extended dynamic state here.
5025 					if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
5026 					{
5027 						setDynamicStates(m_testConfig, vkd, cmdBuffer);
5028 						boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffers, rvertBuffers);
5029 					}
5030 
5031 					// Bind vertex buffer with static stride if needed and draw.
5032 					if (!(boundInAdvance || boundBeforeDraw) && !m_testConfig.useMeshShaders)
5033 					{
5034 						bindVertexBuffers(vkd, cmdBuffer, (m_testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers));
5035 						if (m_testConfig.needsIndexBuffer())
5036 						{
5037 							const auto indexType = vk::VK_INDEX_TYPE_UINT32;
5038 							vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer->get(), 0, indexType);
5039 						}
5040 					}
5041 
5042 					if (vertDataAsSSBO)
5043 					{
5044 						const auto boundSet = (m_testConfig.meshParams[meshIdx].reversed ? meshDescriptorSetRev.get() : meshDescriptorSet.get());
5045 						vkd.cmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, pipelineLayout.get(), 0u, 1u, &boundSet, 0u, nullptr);
5046 					}
5047 
5048 #ifndef CTS_USES_VULKANSC
5049 					// Shading rate image if enabled (we'll use a null handle to simplify, which is valid).
5050 					if (m_testConfig.shadingRateImage)
5051 						vkd.cmdBindShadingRateImageNV(cmdBuffer, VK_NULL_HANDLE, vk::VK_IMAGE_LAYOUT_GENERAL);
5052 #endif // CTS_USES_VULKANSC
5053 
5054 					if (m_testConfig.representativeFragmentTest)
5055 						vkd.cmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, pipelineLayout.get(), m_testConfig.getFragDescriptorSetIndex(), 1u, &fragDescriptorSet.get(), 0u, nullptr);
5056 
5057 					// Draw mesh.
5058 					if (m_testConfig.needsIndexBuffer())
5059 					{
5060 						deUint32 numIndices = static_cast<deUint32>(indices.size());
5061 						// For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
5062 						// So, draw without using the invalid index, the second draw with primitive restart enabled will replace the results
5063 						// using all indices.
5064 						if (iteration == 0u && m_testConfig.testPrimRestartEnable() &&
5065 							(m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
5066 							m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
5067 						{
5068 							numIndices = 3u;
5069 						}
5070 						vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
5071 					}
5072 #ifndef CTS_USES_VULKANSC
5073 					else if (m_testConfig.useMeshShaders)
5074 					{
5075 						// Make sure drawing this way makes sense.
5076 						DE_ASSERT(vertices.size() > 2u);
5077 						DE_ASSERT(!m_testConfig.topologyConfig.dynamicValue);
5078 						DE_ASSERT(m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
5079 
5080 						const auto numPrimitives = static_cast<uint32_t>(vertices.size()) - 2u;
5081 						vkd.cmdDrawMeshTasksEXT(cmdBuffer, numPrimitives, 1u, 1u);
5082 					}
5083 #endif // CTS_USES_VULKANSC
5084 					else
5085 					{
5086 						deUint32 vertex_count = static_cast<deUint32>(vertices.size());
5087 						if (m_testConfig.singleVertex)
5088 							vertex_count = m_testConfig.singleVertexDrawCount;
5089 						vkd.cmdDraw(cmdBuffer, vertex_count, 1u, 0u, 0u);
5090 					}
5091 				}
5092 			}
5093 
5094 		vk::endRenderPass(vkd, cmdBuffer);
5095 	}
5096 
5097 	if (m_testConfig.representativeFragmentTest)
5098 	{
5099 		const auto bufferBarrier = vk::makeMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT);
5100 		vk::cmdPipelineMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, vk::VK_PIPELINE_STAGE_HOST_BIT, &bufferBarrier);
5101 	}
5102 
5103 	vk::endCommandBuffer(vkd, cmdBuffer);
5104 
5105 	// Submit commands.
5106 	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
5107 
5108 	// Read result image aspects from the last used framebuffer.
5109 	using LevelPtr = de::MovePtr<tcu::TextureLevel>;
5110 
5111 	const tcu::UVec2	renderSize		(kFramebufferWidth, kFramebufferHeight);
5112 
5113 	const auto			colorResultImg	= (kUseResolveAtt ? resolveImages.back()->get() : colorImages.back()->get());
5114 	const auto			colorBuffer		= readColorAttachment(vkd, device, queue, queueIndex, allocator, colorResultImg, colorFormat, renderSize);
5115 	const auto			colorAccess		= colorBuffer->getAccess();
5116 
5117 	LevelPtr				depthBuffer;
5118 	LevelPtr				stencilBuffer;
5119 	tcu::PixelBufferAccess	depthAccess;
5120 	tcu::PixelBufferAccess	stencilAccess;
5121 
5122 	if (!kMultisampleDS)
5123 	{
5124 		depthBuffer		= readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
5125 		stencilBuffer	= readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
5126 		depthAccess		= depthBuffer->getAccess();
5127 		stencilAccess	= stencilBuffer->getAccess();
5128 	}
5129 
5130 	const int kWidth	= static_cast<int>(kFramebufferWidth);
5131 	const int kHeight	= static_cast<int>(kFramebufferHeight);
5132 
5133 	// Generate reference color buffer.
5134 	const auto				tcuColorFormat			= vk::mapVkFormat(colorFormat);
5135 	tcu::TextureLevel		referenceColorLevel		(tcuColorFormat, kWidth, kHeight);
5136 	tcu::PixelBufferAccess	referenceColorAccess	= referenceColorLevel.getAccess();
5137 	(*m_testConfig.referenceColor)(referenceColorAccess);
5138 
5139 	const tcu::TextureFormat	errorFormat			(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
5140 	tcu::TextureLevel			colorError			(errorFormat, kWidth, kHeight);
5141 	tcu::TextureLevel			depthError			(errorFormat, kWidth, kHeight);
5142 	tcu::TextureLevel			stencilError		(errorFormat, kWidth, kHeight);
5143 	const auto					colorErrorAccess	= colorError.getAccess();
5144 	const auto					depthErrorAccess	= depthError.getAccess();
5145 	const auto					stencilErrorAccess	= stencilError.getAccess();
5146 	const tcu::Vec4				kGood				(0.0f, 1.0f, 0.0f, 1.0f);
5147 	const tcu::Vec4				kBad				(1.0f, 0.0f, 0.0f, 1.0f);
5148 
5149 	// Check expected values.
5150 	const bool	hasCustomVerif	= static_cast<bool>(m_testConfig.colorVerificator);
5151 	const auto	minDepth		= m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
5152 	const auto	maxDepth		= m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
5153 	bool		colorMatch		= true;
5154 	bool		depthMatch		= true;
5155 	bool		stencilMatch	= true;
5156 	bool		match;
5157 
5158 	if (hasCustomVerif)
5159 		colorMatch = (*m_testConfig.colorVerificator)(colorAccess, referenceColorAccess, colorErrorAccess);
5160 
5161 	for (int y = 0; y < kHeight; ++y)
5162 		for (int x = 0; x < kWidth; ++x)
5163 		{
5164 			if (!hasCustomVerif)
5165 			{
5166 				if (vk::isUnormFormat(colorFormat))
5167 				{
5168 					const auto colorPixel		= colorAccess.getPixel(x, y);
5169 					const auto expectedPixel	= referenceColorAccess.getPixel(x, y);
5170 					match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kUnormColorThreshold));
5171 				}
5172 				else
5173 				{
5174 					DE_ASSERT(vk::isUintFormat(colorFormat));
5175 					const auto colorPixel		= colorAccess.getPixelUint(x, y);
5176 					const auto expectedPixel	= referenceColorAccess.getPixelUint(x, y);
5177 					match = (colorPixel == expectedPixel);
5178 				}
5179 
5180 				colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
5181 				if (!match)
5182 					colorMatch = false;
5183 			}
5184 
5185 			if (!kMultisampleDS)
5186 			{
5187 				const auto depthPixel = depthAccess.getPixDepth(x, y);
5188 				match = de::inRange(depthPixel, minDepth, maxDepth);
5189 				depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
5190 				if (!match)
5191 					depthMatch = false;
5192 
5193 				const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
5194 				match = (stencilPixel == m_testConfig.expectedStencil);
5195 				stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
5196 				if (!match)
5197 					stencilMatch = false;
5198 			}
5199 		}
5200 
5201 	if (!colorMatch)
5202 		logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
5203 
5204 	if (!depthMatch)
5205 		logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
5206 
5207 	if (!stencilMatch)
5208 		logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
5209 
5210 	if (!(colorMatch && depthMatch && stencilMatch))
5211 	{
5212 		if (!colorMatch)
5213 			logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
5214 
5215 		if (!depthMatch)
5216 			logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
5217 
5218 		if (!stencilMatch)
5219 			logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
5220 
5221 		if (!(colorMatch && depthMatch && stencilMatch))
5222 			return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
5223 	}
5224 
5225 	// Check storage buffer if used.
5226 	if (m_testConfig.representativeFragmentTest)
5227 	{
5228 		DE_ASSERT(m_testConfig.oversizedTriangle);
5229 		DE_ASSERT(m_testConfig.meshParams.size() == 1u);
5230 		DE_ASSERT(!m_testConfig.depthWriteEnableConfig.dynamicValue);	// No dynamic value for depth writes.
5231 		DE_ASSERT(!m_testConfig.depthWriteEnableConfig.staticValue);	// No depth writes.
5232 
5233 		// The expected number of invocations depends on how many draws are performed with the test enabled.
5234 		// Draws with the test disabled should always result in kFramebufferHeight * kFramebufferWidth invocations.
5235 		// Draws with the test enabled should result in at least 1 invocation, maybe more.
5236 		uint32_t minValue = 0u;
5237 
5238 		const uint32_t minInvocations[] = { (kFramebufferHeight * kFramebufferWidth), 1u };
5239 
5240 		if (kNumIterations == 1u)
5241 		{
5242 			const auto testEnabled	= m_testConfig.getActiveReprFragTestEnable();
5243 			minValue += minInvocations[testEnabled];
5244 		}
5245 		else if (kNumIterations == 2u)
5246 		{
5247 
5248 			for (uint32_t i = 0u; i < kNumIterations; ++i)
5249 			{
5250 				bool testEnabled = false;
5251 
5252 #ifndef CTS_USES_VULKANSC
5253 				// Actually varies depending on TWO_DRAWS_STATIC/_DYNAMIC, but does not affect results.
5254 				const bool staticDraw = (i == 0u);
5255 
5256 				if (staticDraw)
5257 					testEnabled = m_testConfig.reprFragTestEnableConfig.staticValue;
5258 				else
5259 				{
5260 					testEnabled	= (m_testConfig.reprFragTestEnableConfig.dynamicValue
5261 								? m_testConfig.reprFragTestEnableConfig.dynamicValue.get()
5262 								: m_testConfig.reprFragTestEnableConfig.staticValue);
5263 				}
5264 #endif // CTS_USES_VULKANSC
5265 
5266 				minValue += minInvocations[testEnabled];
5267 			}
5268 		}
5269 		else
5270 		{
5271 			DE_ASSERT(false);
5272 		}
5273 
5274 		auto& counterBufferAlloc	= counterBuffer->getAllocation();
5275 		void* counterBufferData		= counterBufferAlloc.getHostPtr();
5276 		vk::invalidateAlloc(vkd, device, counterBufferAlloc);
5277 
5278 		uint32_t fragCounter;
5279 		deMemcpy(&fragCounter, counterBufferData, sizeof(fragCounter));
5280 
5281 		log << tcu::TestLog::Message << "Fragment counter minimum value: " << minValue << tcu::TestLog::EndMessage;
5282 		log << tcu::TestLog::Message << "Fragment counter: " << fragCounter << tcu::TestLog::EndMessage;
5283 
5284 		if (fragCounter < minValue)
5285 		{
5286 			std::ostringstream msg;
5287 			msg << "Fragment shader invocation counter lower than expected: found " << fragCounter << " and expected at least " << minValue;
5288 			return tcu::TestStatus::fail(msg.str());
5289 		}
5290 	}
5291 
5292 	return tcu::TestStatus::pass("Pass");
5293 }
5294 
stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)5295 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
5296 {
5297 	switch (op)
5298 	{
5299 	case vk::VK_COMPARE_OP_NEVER:				return false;
5300 	case vk::VK_COMPARE_OP_LESS:				return (referenceValue <	storedValue);
5301 	case vk::VK_COMPARE_OP_EQUAL:				return (referenceValue ==	storedValue);
5302 	case vk::VK_COMPARE_OP_LESS_OR_EQUAL:		return (referenceValue <=	storedValue);
5303 	case vk::VK_COMPARE_OP_GREATER:				return (referenceValue >	storedValue);
5304 	case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:	return (referenceValue >=	storedValue);
5305 	case vk::VK_COMPARE_OP_ALWAYS:				return true;
5306 	default: DE_ASSERT(false); return false;
5307 	}
5308 
5309 	return false;	// Unreachable.
5310 }
5311 
stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)5312 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
5313 {
5314 	deUint8 result = storedValue;
5315 
5316 	switch (op)
5317 	{
5318 	case vk::VK_STENCIL_OP_KEEP:					break;
5319 	case vk::VK_STENCIL_OP_ZERO:					result = 0; break;
5320 	case vk::VK_STENCIL_OP_REPLACE:					result = referenceValue; break;
5321 	case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:		result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
5322 	case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:		result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
5323 	case vk::VK_STENCIL_OP_INVERT:					result = static_cast<deUint8>(~result); break;
5324 	case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:		result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
5325 	case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:		result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
5326 	default: DE_ASSERT(false); break;
5327 	}
5328 
5329 	return result;
5330 }
5331 
5332 class TestGroupWithClean : public tcu::TestCaseGroup
5333 {
5334 public:
TestGroupWithClean(tcu::TestContext& testCtx, const char* name, const char* description)5335 			TestGroupWithClean	(tcu::TestContext& testCtx, const char* name, const char* description)
5336 				: tcu::TestCaseGroup(testCtx, name, description)
5337 				{}
5338 
~TestGroupWithClean(void)5339 	virtual	~TestGroupWithClean	(void) { cleanupDevices(); }
5340 };
5341 
5342 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
5343 
5344 } // anonymous namespace
5345 
createExtendedDynamicStateTests(tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)5346 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx, vk::PipelineConstructionType pipelineConstructionType)
5347 {
5348 	GroupPtr extendedDynamicStateGroup(new TestGroupWithClean(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
5349 	GroupPtr meshShaderGroup(new tcu::TestCaseGroup(testCtx, "mesh_shader", "Extended dynamic state with mesh shading pipelines"));
5350 
5351 	// Auxiliar constants.
5352 	const deUint32	kHalfWidthU	= kFramebufferWidth/2u;
5353 	const deInt32	kHalfWidthI	= static_cast<deInt32>(kHalfWidthU);
5354 	const float		kHalfWidthF	= static_cast<float>(kHalfWidthU);
5355 	const float		kWidthF		= static_cast<float>(kFramebufferWidth);
5356 	const float		kHeightF	= static_cast<float>(kFramebufferHeight);
5357 
5358 	static const struct
5359 	{
5360 		SequenceOrdering	ordering;
5361 		std::string			name;
5362 		std::string			desc;
5363 	} kOrderingCases[] =
5364 	{
5365 		{ SequenceOrdering::CMD_BUFFER_START,	"cmd_buffer_start",		"Dynamic state set after command buffer start"																								},
5366 		{ SequenceOrdering::BEFORE_DRAW,		"before_draw",			"Dynamic state set just before drawing"																										},
5367 		{ 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"						},
5368 		{ SequenceOrdering::AFTER_PIPELINES,	"after_pipelines",		"Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"									},
5369 		{ 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"	},
5370 		{ SequenceOrdering::TWO_DRAWS_DYNAMIC,	"two_draws_dynamic",	"Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again"											},
5371 		{ SequenceOrdering::TWO_DRAWS_STATIC,	"two_draws_static",		"Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again"											},
5372 	};
5373 
5374 	static const struct
5375 	{
5376 		bool			useMeshShaders;
5377 		std::string		groupName;
5378 	} kMeshShadingCases[] =
5379 	{
5380 		{ false,	""				},
5381 #ifndef CTS_USES_VULKANSC
5382 		{ true,		"mesh_shader"	},
5383 #endif // CTS_USES_VULKANSC
5384 	};
5385 
5386 	static const struct
5387 	{
5388 		bool			bindUnusedMeshShadingPipeline;
5389 		std::string		nameSuffix;
5390 		std::string		descSuffix;
5391 	} kBindUnusedCases[] =
5392 	{
5393 		{ false,	"",					""																},
5394 #ifndef CTS_USES_VULKANSC
5395 		{ true,		"_bind_unused_ms",	" and bind unused mesh shading pipeline before the dynamic one"	},
5396 #endif // CTS_USES_VULKANSC
5397 	};
5398 
5399 	for (const auto& kMeshShadingCase : kMeshShadingCases)
5400 	for (const auto& kOrderingCase : kOrderingCases)
5401 	{
5402 		const auto& kUseMeshShaders	= kMeshShadingCase.useMeshShaders;
5403 		const auto& kOrdering		= kOrderingCase.ordering;
5404 
5405 		GroupPtr orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
5406 
5407 		// Cull modes.
5408 		{
5409 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5410 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_BIT;
5411 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
5412 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
5413 		}
5414 		{
5415 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5416 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_AND_BACK;
5417 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
5418 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
5419 		}
5420 		{
5421 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5422 			// Make triangles look back.
5423 			config.meshParams[0].reversed		= true;
5424 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
5425 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
5426 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
5427 		}
5428 		{
5429 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5430 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_NONE;
5431 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
5432 			config.referenceColor.reset			(new SingleColorGenerator(kDefaultClearColor));
5433 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
5434 		}
5435 
5436 		// Front face.
5437 		{
5438 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5439 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
5440 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
5441 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
5442 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
5443 		}
5444 		{
5445 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5446 			// Pass triangles in clockwise order.
5447 			config.meshParams[0].reversed		= true;
5448 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
5449 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
5450 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
5451 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
5452 		}
5453 		{
5454 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5455 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
5456 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
5457 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
5458 			config.referenceColor.reset			(new SingleColorGenerator(kDefaultClearColor));
5459 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
5460 		}
5461 		{
5462 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5463 			// Pass triangles in clockwise order.
5464 			config.meshParams[0].reversed		= true;
5465 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
5466 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
5467 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
5468 			config.referenceColor.reset			(new SingleColorGenerator(kDefaultClearColor));
5469 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
5470 		}
5471 
5472 		// Rasterizer discard
5473 		{
5474 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5475 			config.rastDiscardEnableConfig.staticValue	= false;
5476 			config.rastDiscardEnableConfig.dynamicValue	= tcu::just(true);
5477 			config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
5478 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
5479 		}
5480 		{
5481 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5482 			config.rastDiscardEnableConfig.staticValue	= true;
5483 			config.rastDiscardEnableConfig.dynamicValue	= tcu::just(false);
5484 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
5485 		}
5486 
5487 		// Logic op
5488 		{
5489 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5490 
5491 			config.logicOpEnableConfig.staticValue	= true;
5492 			config.logicOpConfig.staticValue		= vk::VK_LOGIC_OP_CLEAR;
5493 			config.logicOpConfig.dynamicValue		= tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
5494 
5495 			// Clear to green, paint in blue, expect cyan due to logic op.
5496 			config.meshParams[0].color	= kLogicOpTriangleColorFl;
5497 			config.clearColorValue		= vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
5498 			config.referenceColor.reset	(new SingleColorGenerator(kLogicOpFinalColor));
5499 
5500 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
5501 		}
5502 
5503 		// Logic op enable.
5504 		{
5505 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5506 
5507 			config.logicOpEnableConfig.staticValue	= false;
5508 			config.logicOpEnableConfig.dynamicValue	= true;
5509 			config.logicOpConfig.staticValue		= vk::VK_LOGIC_OP_OR;
5510 
5511 			// Clear to green, paint in blue, expect cyan due to logic op.
5512 			config.meshParams[0].color	= kLogicOpTriangleColorFl;
5513 			config.clearColorValue		= vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
5514 			config.referenceColor.reset (new SingleColorGenerator(kLogicOpFinalColor));
5515 
5516 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_enable", "Dynamically enable logic OP", config));
5517 		}
5518 		{
5519 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5520 
5521 			config.logicOpEnableConfig.staticValue	= true;
5522 			config.logicOpEnableConfig.dynamicValue	= false;
5523 			config.logicOpConfig.staticValue		= vk::VK_LOGIC_OP_OR;
5524 
5525 			// Clear to green, paint in blue, expect cyan due to logic op.
5526 			config.meshParams[0].color	= kLogicOpTriangleColorFl;
5527 			config.clearColorValue		= vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
5528 			config.referenceColor.reset	(new SingleColorGenerator(kLogicOpTriangleColor));
5529 
5530 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_disable", "Dynamically disable logic OP", config));
5531 		}
5532 
5533 		// Color blend enable.
5534 		{
5535 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5536 
5537 			// The equation picks the old color instead of the new one if blending is enabled.
5538 			config.colorBlendEquationConfig.staticValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO,
5539 																	   vk::VK_BLEND_FACTOR_ONE,
5540 																	   vk::VK_BLEND_OP_ADD,
5541 																	   vk::VK_BLEND_FACTOR_ZERO,
5542 																	   vk::VK_BLEND_FACTOR_ONE,
5543 																	   vk::VK_BLEND_OP_ADD);
5544 
5545 			config.colorBlendEnableConfig.staticValue	= false;
5546 			config.colorBlendEnableConfig.dynamicValue	= true;
5547 			config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
5548 
5549 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_enable", "Dynamically enable color blending", config));
5550 		}
5551 		{
5552 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5553 
5554 			// The equation picks the old color instead of the new one if blending is enabled.
5555 			config.colorBlendEquationConfig.staticValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO,
5556 																	   vk::VK_BLEND_FACTOR_ONE,
5557 																	   vk::VK_BLEND_OP_ADD,
5558 																	   vk::VK_BLEND_FACTOR_ZERO,
5559 																	   vk::VK_BLEND_FACTOR_ONE,
5560 																	   vk::VK_BLEND_OP_ADD);
5561 
5562 			config.colorBlendEnableConfig.staticValue	= true;
5563 			config.colorBlendEnableConfig.dynamicValue	= false;
5564 
5565 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_disable", "Dynamically disable color blending", config));
5566 		}
5567 
5568 		// Color blend equation.
5569 		{
5570 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5571 
5572 			// The equation picks the old color instead of the new one if blending is enabled.
5573 			config.colorBlendEquationConfig.staticValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO,
5574 																	   vk::VK_BLEND_FACTOR_ONE,
5575 																	   vk::VK_BLEND_OP_ADD,
5576 																	   vk::VK_BLEND_FACTOR_ZERO,
5577 																	   vk::VK_BLEND_FACTOR_ONE,
5578 																	   vk::VK_BLEND_OP_ADD);
5579 
5580 			// The dynamic value picks the new color.
5581 			config.colorBlendEquationConfig.dynamicValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ONE,
5582 																		vk::VK_BLEND_FACTOR_ZERO,
5583 																		vk::VK_BLEND_OP_ADD,
5584 																		vk::VK_BLEND_FACTOR_ONE,
5585 																		vk::VK_BLEND_FACTOR_ZERO,
5586 																		vk::VK_BLEND_OP_ADD);
5587 
5588 			config.colorBlendEnableConfig.staticValue	= true;
5589 
5590 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_equation_new_color", "Dynamically set a color equation that picks the mesh color", config));
5591 
5592 			config.colorBlendEquationConfig.swapValues();
5593 			config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
5594 
5595 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_equation_old_color", "Dynamically set a color equation that picks the clear color", config));
5596 		}
5597 
5598 		// Color blend advanced.
5599 		{
5600 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5601 
5602 			// This static value picks the old color instead of the new one.
5603 			config.colorBlendEquationConfig.staticValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO,
5604 																	   vk::VK_BLEND_FACTOR_ONE,
5605 																	   vk::VK_BLEND_OP_DARKEN_EXT,
5606 																	   vk::VK_BLEND_FACTOR_ZERO,
5607 																	   vk::VK_BLEND_FACTOR_ONE,
5608 																	   vk::VK_BLEND_OP_DARKEN_EXT);
5609 
5610 			// The dynamic value picks the new color.
5611 			config.colorBlendEquationConfig.dynamicValue = ColorBlendEq(vk::VK_BLEND_FACTOR_ONE,
5612 																		vk::VK_BLEND_FACTOR_ZERO,
5613 																		vk::VK_BLEND_OP_LIGHTEN_EXT,
5614 																		vk::VK_BLEND_FACTOR_ONE,
5615 																		vk::VK_BLEND_FACTOR_ZERO,
5616 																		vk::VK_BLEND_OP_LIGHTEN_EXT);
5617 
5618 			config.colorBlendEnableConfig.staticValue	= true;
5619 
5620 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_equation_advanced_new_color", "Dynamically set an advanced color equation that picks the mesh color", config));
5621 
5622 			config.colorBlendEquationConfig.swapValues();
5623 			config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
5624 
5625 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_equation_advanced_old_color", "Dynamically set an advanced color equation that picks the clear color", config));
5626 		}
5627 
5628 		// Dynamically enable primitive restart
5629 		if (!kUseMeshShaders)
5630 		{
5631 			for (const auto& bindUnusedCase : kBindUnusedCases)
5632 			{
5633 				if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
5634 					continue;
5635 
5636 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5637 				config.primRestartEnableConfig.staticValue	= false;
5638 				config.primRestartEnableConfig.dynamicValue	= tcu::just(true);
5639 				config.topologyConfig.staticValue			= vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
5640 				config.bindUnusedMeshShadingPipeline		= bindUnusedCase.bindUnusedMeshShadingPipeline;
5641 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, std::string("prim_restart_enable") + bindUnusedCase.nameSuffix, "Dynamically enable primitiveRestart" + bindUnusedCase.descSuffix, config));
5642 			}
5643 		}
5644 
5645 		// Dynamically change the number of primitive control points
5646 		if (!kUseMeshShaders)
5647 		{
5648 			for (const auto& bindUnusedCase : kBindUnusedCases)
5649 			{
5650 				if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
5651 					continue;
5652 
5653 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5654 				config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
5655 				config.patchControlPointsConfig.staticValue = 1;
5656 				config.patchControlPointsConfig.dynamicValue = 3;
5657 				config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
5658 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points" + bindUnusedCase.nameSuffix, "Dynamically change patch control points" + bindUnusedCase.descSuffix, config));
5659 			}
5660 
5661 			{
5662 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5663 				config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
5664 				config.patchControlPointsConfig.staticValue = 1;
5665 				config.patchControlPointsConfig.dynamicValue = 3;
5666 				config.useExtraDynPCPPipeline = true;
5667 
5668 				const auto testName	= "patch_control_points_extra_pipeline";
5669 				const auto testDesc	= "Dynamically change patch control points and draw first with a pipeline using the state and no tessellation shaders";
5670 
5671 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, testDesc, config));
5672 			}
5673 		}
5674 
5675 		// Test tessellation domain origin.
5676 		if (!kUseMeshShaders)
5677 		{
5678 			{
5679 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5680 				config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
5681 				config.patchControlPointsConfig.staticValue = 3;
5682 				config.tessDomainOriginConfig.staticValue = vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT;
5683 				config.tessDomainOriginConfig.dynamicValue = vk::VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
5684 				config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
5685 
5686 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "tess_domain_origin_lower_left", "Dynamically set the right domain origin to lower left", config));
5687 			}
5688 			{
5689 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5690 				config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
5691 				config.patchControlPointsConfig.staticValue = 3;
5692 				config.tessDomainOriginConfig.staticValue = vk::VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
5693 				config.tessDomainOriginConfig.dynamicValue = vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT;
5694 				config.cullModeConfig.staticValue = vk::VK_CULL_MODE_FRONT_BIT;
5695 
5696 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "tess_domain_origin_upper_left", "Dynamically set the right domain origin to upper left", config));
5697 			}
5698 		}
5699 
5700 		// Dynamic topology.
5701 		if (!kUseMeshShaders)
5702 		{
5703 			TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
5704 
5705 			for (int i = 0; i < 2; ++i)
5706 			{
5707 				const bool forceGeometryShader = (i > 0);
5708 
5709 				static const struct
5710 				{
5711 					vk::VkPrimitiveTopology staticVal;
5712 					vk::VkPrimitiveTopology dynamicVal;
5713 				} kTopologyCases[] =
5714 				{
5715 					{ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP	},
5716 					{ vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP		},
5717 					{ vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,		vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST		},
5718 				};
5719 
5720 				for (const auto& kTopologyCase : kTopologyCases)
5721 				{
5722 					const auto topologyClass = getTopologyClass(kTopologyCase.staticVal);
5723 
5724 					for (const auto& bindUnusedCase : kBindUnusedCases)
5725 					{
5726 						if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
5727 							continue;
5728 
5729 						TestConfig config(baseConfig);
5730 						config.forceGeometryShader					= forceGeometryShader;
5731 						config.topologyConfig.staticValue			= kTopologyCase.staticVal;
5732 						config.topologyConfig.dynamicValue			= tcu::just<vk::VkPrimitiveTopology>(kTopologyCase.dynamicVal);
5733 						config.primRestartEnableConfig.staticValue	= (topologyClass == TopologyClass::LINE);
5734 						config.patchControlPointsConfig.staticValue	= (config.needsTessellation() ? 3u : 1u);
5735 						config.bindUnusedMeshShadingPipeline		= bindUnusedCase.bindUnusedMeshShadingPipeline;
5736 
5737 						const std::string	className	= topologyClassName(topologyClass);
5738 						const std::string	name		= "topology_" + className + (forceGeometryShader ? "_geom" : "") + bindUnusedCase.nameSuffix;
5739 						const std::string	desc		= "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "") + bindUnusedCase.descSuffix;
5740 						orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
5741 					}
5742 				}
5743 			}
5744 		}
5745 
5746 		// Line stipple enable.
5747 		if (!kUseMeshShaders)
5748 		{
5749 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5750 
5751 			config.primRestartEnableConfig.staticValue	= true;
5752 			config.topologyConfig.staticValue			= vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
5753 			config.lineStippleEnableConfig.staticValue	= true;
5754 			config.lineStippleEnableConfig.dynamicValue	= false;
5755 			config.lineStippleParamsConfig.staticValue	= LineStippleParams{1u, 0x5555u};
5756 
5757 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_disable", "Dynamically disable line stipple", config));
5758 
5759 			config.lineStippleEnableConfig.swapValues();
5760 			config.referenceColor.reset(new VerticalStripesGenerator(kDefaultTriangleColor, kDefaultClearColor, 1u));
5761 
5762 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_enable", "Dynamycally enable line stipple", config));
5763 		}
5764 
5765 		// Line stipple params.
5766 		if (!kUseMeshShaders)
5767 		{
5768 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5769 
5770 			config.primRestartEnableConfig.staticValue	= true;
5771 			config.topologyConfig.staticValue			= vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
5772 			config.lineStippleEnableConfig.staticValue	= true;
5773 			config.lineStippleParamsConfig.staticValue	= LineStippleParams{1u, 0x5555u};
5774 			config.lineStippleParamsConfig.dynamicValue	= LineStippleParams{2u, 0x3333u};
5775 			config.referenceColor.reset					(new VerticalStripesGenerator(kDefaultTriangleColor, kDefaultClearColor, 4u));
5776 
5777 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_params", "Dynamically change the line stipple parameters", config));
5778 		}
5779 
5780 		// Line rasterization mode.
5781 		if (!kUseMeshShaders)
5782 		{
5783 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5784 
5785 			config.topologyConfig.staticValue			= vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
5786 			config.obliqueLine							= true;
5787 			config.colorVerificator						= verifyTopLeftCorner;
5788 			config.lineStippleEnableConfig.staticValue	= false;
5789 			config.lineStippleParamsConfig.staticValue	= LineStippleParams{0u, 0u};
5790 			config.lineRasterModeConfig.staticValue		= LineRasterizationMode::RECTANGULAR;
5791 			config.lineRasterModeConfig.dynamicValue	= LineRasterizationMode::BRESENHAM;
5792 
5793 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_raster_mode_bresenham", "Dynamically set line rasterization mode to bresenham", config));
5794 
5795 			config.lineRasterModeConfig.swapValues();
5796 			config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
5797 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_raster_mode_rectangular", "Dynamically set line rasterization mode to rectangular", config));
5798 		}
5799 
5800 		// Viewport.
5801 		{
5802 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5803 			// 2 scissors, bad static single viewport.
5804 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
5805 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
5806 			config.viewportConfig.dynamicValue	= ViewportVec{
5807 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5808 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5809 			};
5810 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
5811 		}
5812 		{
5813 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5814 			// Bad static reduced viewport.
5815 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
5816 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
5817 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
5818 		}
5819 		{
5820 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5821 			// 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
5822 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
5823 			config.viewportConfig.staticValue	= ViewportVec{
5824 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
5825 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
5826 			};
5827 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
5828 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
5829 		}
5830 		{
5831 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5832 			// 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
5833 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
5834 			config.viewportConfig.staticValue	= ViewportVec{
5835 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
5836 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
5837 			};
5838 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
5839 			config.referenceColor.reset			(new SingleColorGenerator(kDefaultClearColor));
5840 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
5841 		}
5842 
5843 		// Scissor.
5844 		{
5845 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5846 			// 2 viewports, bad static single scissor.
5847 			config.viewportConfig.staticValue	= ViewportVec{
5848 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5849 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5850 			};
5851 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
5852 			config.scissorConfig.dynamicValue	= ScissorVec{
5853 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
5854 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
5855 			};
5856 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
5857 		}
5858 		{
5859 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5860 			// 1 viewport, bad static single scissor.
5861 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
5862 			config.scissorConfig.dynamicValue	= ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
5863 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
5864 		}
5865 		{
5866 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5867 			// 2 viewports, 2 reversed scissors that need fixing.
5868 			config.viewportConfig.staticValue	= ViewportVec{
5869 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5870 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5871 			};
5872 			config.scissorConfig.staticValue	= ScissorVec{
5873 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
5874 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
5875 			};
5876 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
5877 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
5878 		}
5879 		{
5880 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5881 			// 2 viewports, 2 scissors switched to prevent drawing.
5882 			config.viewportConfig.staticValue	= ViewportVec{
5883 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5884 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
5885 			};
5886 			config.scissorConfig.staticValue	= ScissorVec{
5887 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
5888 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
5889 			};
5890 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
5891 			config.referenceColor.reset			(new SingleColorGenerator(kDefaultClearColor));
5892 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
5893 		}
5894 
5895 		// Stride.
5896 		if (!kUseMeshShaders)
5897 		{
5898 			struct
5899 			{
5900 				const VertexGenerator*	factory;
5901 				const std::string		prefix;
5902 			} strideCases[] =
5903 			{
5904 				{ getVertexWithPaddingGenerator(),			"stride"		},
5905 				{ getVertexWithExtraAttributesGenerator(),	"large_stride"	},
5906 			};
5907 
5908 			for (const auto& strideCase : strideCases)
5909 			{
5910 				const auto	factory			= strideCase.factory;
5911 				const auto&	prefix			= strideCase.prefix;
5912 				const auto	vertexStrides	= factory->getVertexDataStrides();
5913 				StrideVec	halfStrides;
5914 
5915 				halfStrides.reserve(vertexStrides.size());
5916 				for (const auto& stride : vertexStrides)
5917 					halfStrides.push_back(stride / 2u);
5918 
5919 				if (factory == getVertexWithExtraAttributesGenerator() && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
5920 				{
5921 					// This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
5922 					// stride being less than the extent of the binding for the second attribute.
5923 					continue;
5924 				}
5925 
5926 				for (const auto& bindUnusedCase : kBindUnusedCases)
5927 				{
5928 					if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
5929 						continue;
5930 
5931 					{
5932 						TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
5933 						config.strideConfig.staticValue			= halfStrides;
5934 						config.strideConfig.dynamicValue		= vertexStrides;
5935 						config.bindUnusedMeshShadingPipeline	= bindUnusedCase.bindUnusedMeshShadingPipeline;
5936 						orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + bindUnusedCase.nameSuffix, "Dynamically set stride" + bindUnusedCase.descSuffix, config));
5937 					}
5938 					{
5939 						TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
5940 						config.strideConfig.staticValue			= halfStrides;
5941 						config.strideConfig.dynamicValue		= vertexStrides;
5942 						config.vertexDataOffset					= vertexStrides[0];
5943 						config.bindUnusedMeshShadingPipeline	= bindUnusedCase.bindUnusedMeshShadingPipeline;
5944 						orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset" + bindUnusedCase.nameSuffix, "Dynamically set stride using a nonzero vertex data offset" + bindUnusedCase.descSuffix, config));
5945 					}
5946 					{
5947 						TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
5948 						config.strideConfig.staticValue			= halfStrides;
5949 						config.strideConfig.dynamicValue		= vertexStrides;
5950 						config.vertexDataOffset					= vertexStrides[0];
5951 						config.vertexDataExtraBytes				= config.vertexDataOffset;
5952 						config.bindUnusedMeshShadingPipeline	= bindUnusedCase.bindUnusedMeshShadingPipeline;
5953 
5954 						// Make the mesh cover the top half only. If the implementation reads data outside the vertex values it may draw something to the bottom half.
5955 						config.referenceColor.reset				(new HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor));
5956 						config.meshParams[0].scaleY				= 0.5f;
5957 						config.meshParams[0].offsetY			= -0.5f;
5958 
5959 						orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding" + bindUnusedCase.nameSuffix, "Dynamically set stride using a nonzero vertex data offset and extra bytes" + bindUnusedCase.descSuffix, config));
5960 					}
5961 				}
5962 			}
5963 
5964 			// Dynamic stride of 0
5965 			//
5966 			// The "two_draws" variants are invalid because the non-zero vertex stride will cause out-of-bounds access
5967 			// when drawing more than one vertex.
5968 			if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC && kOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC)
5969 			{
5970 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, getVertexWithExtraAttributesGenerator());
5971 				config.strideConfig.staticValue		= config.getActiveVertexGenerator()->getVertexDataStrides();
5972 				config.strideConfig.dynamicValue	= { 0 };
5973 				config.vertexDataOffset				= 4;
5974 				config.singleVertex					= true;
5975 				config.singleVertexDrawCount		= 6;
5976 
5977 				// Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
5978 				// offscreen vertex and draw something in the bottom half.
5979 				config.referenceColor.reset		(new HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor));
5980 				config.meshParams[0].scaleY		= 0.5f;
5981 				config.meshParams[0].offsetY	= -0.5f;
5982 
5983 				// Use strip scale to synthesize a strip from a vertex attribute which remains constant over the draw call.
5984 				config.meshParams[0].stripScale = 1.0f;
5985 
5986 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "zero_stride_with_offset", "Dynamically set zero stride using a nonzero vertex data offset", config));
5987 			}
5988 		}
5989 
5990 		// Depth test enable.
5991 		{
5992 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
5993 			config.depthTestEnableConfig.staticValue	= false;
5994 			config.depthTestEnableConfig.dynamicValue	= tcu::just(true);
5995 			// By default, the depth test never passes when enabled.
5996 			config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
5997 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
5998 		}
5999 		{
6000 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6001 			config.depthTestEnableConfig.staticValue	= true;
6002 			config.depthTestEnableConfig.dynamicValue	= tcu::just(false);
6003 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
6004 		}
6005 
6006 		// Depth write enable.
6007 		{
6008 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6009 
6010 			// Enable depth test and set values so it passes.
6011 			config.depthTestEnableConfig.staticValue	= true;
6012 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6013 			config.clearDepthValue						= 0.5f;
6014 			config.meshParams[0].depth					= 0.25f;
6015 
6016 			// Enable writes and expect the mesh value.
6017 			config.depthWriteEnableConfig.staticValue	= false;
6018 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(true);
6019 			config.expectedDepth						= 0.25f;
6020 
6021 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
6022 		}
6023 		{
6024 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6025 
6026 			// Enable depth test and set values so it passes.
6027 			config.depthTestEnableConfig.staticValue	= true;
6028 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6029 			config.clearDepthValue						= 0.5f;
6030 			config.meshParams[0].depth					= 0.25f;
6031 
6032 			// But disable writing dynamically and expect the clear value.
6033 			config.depthWriteEnableConfig.staticValue	= true;
6034 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(false);
6035 			config.expectedDepth						= 0.5f;
6036 
6037 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
6038 		}
6039 
6040 		// Depth clamp enable.
6041 		{
6042 			// Without clamping, the mesh depth fails the depth test after applying the viewport transform.
6043 			// With clamping, it should pass thanks to the viewport.
6044 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6045 
6046 			config.meshParams[0].depth					= 1.5f;
6047 			config.clearDepthValue						= 0.625f;
6048 			config.depthTestEnableConfig.staticValue	= true;
6049 			config.depthWriteEnableConfig.staticValue	= true;
6050 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6051 			config.viewportConfig.staticValue			= ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.0f, 0.5f));
6052 			config.expectedDepth						= 0.5f;
6053 
6054 			config.depthClampEnableConfig.staticValue	= false;
6055 			config.depthClampEnableConfig.dynamicValue	= true;
6056 
6057 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_enable", "Dynamically enable depth clamp", config));
6058 		}
6059 		{
6060 			// Reverse situation.
6061 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6062 
6063 			config.meshParams[0].depth					= 1.5f;
6064 			config.clearDepthValue						= 0.625f;
6065 			config.depthTestEnableConfig.staticValue	= true;
6066 			config.depthWriteEnableConfig.staticValue	= true;
6067 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6068 			config.viewportConfig.staticValue			= ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.0f, 0.5f));
6069 			config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
6070 			config.expectedDepth						= 0.625f;
6071 
6072 			config.depthClampEnableConfig.staticValue	= true;
6073 			config.depthClampEnableConfig.dynamicValue	= false;
6074 
6075 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_disable", "Dynamically disable depth clamp", config));
6076 		}
6077 
6078 		// Polygon mode.
6079 		{
6080 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6081 
6082 			config.polygonModeConfig.staticValue	= vk::VK_POLYGON_MODE_FILL;
6083 			config.polygonModeConfig.dynamicValue	= vk::VK_POLYGON_MODE_POINT;
6084 			config.oversizedTriangle				= true;
6085 			config.referenceColor.reset				(new SingleColorGenerator(kDefaultClearColor));
6086 
6087 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "polygon_mode_point", "Dynamically set polygon draw mode to points", config));
6088 		}
6089 		{
6090 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6091 
6092 			config.polygonModeConfig.staticValue	= vk::VK_POLYGON_MODE_POINT;
6093 			config.polygonModeConfig.dynamicValue	= vk::VK_POLYGON_MODE_FILL;
6094 			config.oversizedTriangle				= true;
6095 
6096 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "polygon_mode_fill", "Dynamically set polygon draw mode to fill", config));
6097 		}
6098 
6099 		for (int i = 0; i < 2; ++i)
6100 		{
6101 			const bool			multisample			= (i > 0);
6102 			const auto			activeSampleCount	= (multisample ? kMultiSampleCount : kSingleSampleCount);
6103 			const auto			inactiveSampleCount	= (multisample ? kSingleSampleCount : kMultiSampleCount);
6104 			const std::string	namePrefix			= (multisample ? "multi_sample_" : "single_sample_");
6105 			const std::string	descSuffix			= (multisample ? " in multisample mode" : " in single sample mode");
6106 
6107 			// Sample count.
6108 			{
6109 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6110 				config.rasterizationSamplesConfig.staticValue	= inactiveSampleCount;
6111 				config.rasterizationSamplesConfig.dynamicValue	= activeSampleCount;
6112 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "rasterization_samples", "Dynamically set the rasterization sample count" + descSuffix, config));
6113 			}
6114 
6115 			// Sample mask
6116 			{
6117 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6118 				config.rasterizationSamplesConfig		= activeSampleCount;
6119 				config.sampleMaskConfig.staticValue		= SampleMaskVec(1u, 0u);
6120 				config.sampleMaskConfig.dynamicValue	= SampleMaskVec(1u, 0xFFu);
6121 
6122 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "sample_mask_enable", "Dynamically set a sample mask that allows drawing" + descSuffix, config));
6123 			}
6124 			{
6125 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6126 				config.rasterizationSamplesConfig		= activeSampleCount;
6127 				config.sampleMaskConfig.staticValue		= SampleMaskVec(1u, 0xFFu);
6128 				config.sampleMaskConfig.dynamicValue	= SampleMaskVec(1u, 0u);
6129 				config.referenceColor.reset				(new SingleColorGenerator(kDefaultClearColor));
6130 
6131 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "sample_mask_disable", "Dynamically set a sample mask that prevents drawing" + descSuffix, config));
6132 			}
6133 
6134 			// Alpha to coverage.
6135 			{
6136 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6137 
6138 				config.rasterizationSamplesConfig			= activeSampleCount;
6139 				config.meshParams[0].color					= kTransparentColor;
6140 				config.alphaToCoverageConfig.staticValue	= false;
6141 				config.alphaToCoverageConfig.dynamicValue	= true;
6142 				config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
6143 
6144 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_coverage_enable", "Dynamically enable alpha to coverage" + descSuffix, config));
6145 			}
6146 			{
6147 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6148 
6149 				config.rasterizationSamplesConfig			= activeSampleCount;
6150 				config.meshParams[0].color					= kTransparentColor;
6151 				config.alphaToCoverageConfig.staticValue	= true;
6152 				config.alphaToCoverageConfig.dynamicValue	= false;
6153 				config.referenceColor.reset					(new SingleColorGenerator(kTransparentColor));
6154 
6155 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_coverage_disable", "Dynamically disable alpha to coverage" + descSuffix, config));
6156 			}
6157 
6158 			// Alpha to one.
6159 			{
6160 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6161 
6162 				config.rasterizationSamplesConfig		= activeSampleCount;
6163 				config.meshParams[0].color				= kTransparentColor;
6164 				config.alphaToOneConfig.staticValue		= false;
6165 				config.alphaToOneConfig.dynamicValue	= true;
6166 				config.referenceColor.reset				(new SingleColorGenerator(kDefaultTriangleColor));
6167 
6168 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_one_enable", "Dynamically enable alpha to one" + descSuffix, config));
6169 			}
6170 			{
6171 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6172 
6173 				config.rasterizationSamplesConfig		= activeSampleCount;
6174 				config.meshParams[0].color				= kTransparentColor;
6175 				config.alphaToOneConfig.staticValue		= true;
6176 				config.alphaToOneConfig.dynamicValue	= false;
6177 				config.referenceColor.reset				(new SingleColorGenerator(kTransparentColor));
6178 
6179 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_one_disable", "Dynamically disable alpha to one" + descSuffix, config));
6180 			}
6181 		}
6182 
6183 		// Special sample mask case: make sure the dynamic sample mask count does not overwrite the actual sample mask.
6184 		{
6185 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6186 
6187 			// There's guaranteed support for 1 sample and 4 samples. So the official pipeline sample count will be 1 sample, and
6188 			// the one we'll use in the dynamic sample mask call will be 4.
6189 			//
6190 			// When using 4 samples, sample 3 uses a Y offset of 0.875 pixels, so we'll use an off-center triangle to try to trick
6191 			// the implementation into having that one covered by using a Y offset of 0.75.
6192 			config.dynamicSampleMaskCount			= tcu::just(kMultiSampleCount);
6193 			config.sampleMaskConfig.staticValue		= SampleMaskVec(1u, 0u);
6194 			config.sampleMaskConfig.dynamicValue	= SampleMaskVec(1u, 0xFFu);
6195 			config.offCenterTriangle				= true;
6196 			config.offCenterProportion				= tcu::Vec2(0.0f, 0.75f);
6197 			config.referenceColor.reset				(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor));
6198 
6199 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_mask_count", "Dynamically set sample mask with slightly different sample count", config));
6200 		}
6201 
6202 		// Color write mask.
6203 		{
6204 			const struct
6205 			{
6206 				vk::VkColorComponentFlags staticVal;
6207 				vk::VkColorComponentFlags dynamicVal;
6208 			} colorComponentCases[] =
6209 			{
6210 				{	(CR | CG | CB | CA),	(CR |  0 |  0 |  0)		},
6211 				{	(CR | CG | CB | CA),	( 0 | CG |  0 |  0)		},
6212 				{	(CR | CG | CB | CA),	( 0 |  0 | CB |  0)		},
6213 				{	(CR | CG | CB | CA),	( 0 |  0 |  0 | CA)		},
6214 				{	(CR | CG | CB | CA),	( 0 |  0 |  0 |  0)		},
6215 				{	( 0 |  0 |  0 |  0),	(CR |  0 |  0 |  0)		},
6216 				{	( 0 |  0 |  0 |  0),	( 0 | CG |  0 |  0)		},
6217 				{	( 0 |  0 |  0 |  0),	( 0 |  0 | CB |  0)		},
6218 				{	( 0 |  0 |  0 |  0),	( 0 |  0 |  0 | CA)		},
6219 				{	( 0 |  0 |  0 |  0),	(CR | CG | CB | CA)		},
6220 			};
6221 
6222 			for (const auto& colorCompCase : colorComponentCases)
6223 			{
6224 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6225 
6226 				config.clearColorValue						= vk::makeClearValueColor(kTransparentClearColor);
6227 				config.meshParams[0].color					= kOpaqueWhite;
6228 				config.colorWriteMaskConfig.staticValue		= colorCompCase.staticVal;
6229 				config.colorWriteMaskConfig.dynamicValue	= colorCompCase.dynamicVal;
6230 				config.referenceColor.reset					(new SingleColorGenerator(filterColor(kTransparentClearColor, kOpaqueWhite, colorCompCase.dynamicVal)));
6231 
6232 				const auto staticCode	= componentCodes(colorCompCase.staticVal);
6233 				const auto dynamicCode	= componentCodes(colorCompCase.dynamicVal);
6234 				const auto testName		= "color_write_mask_" + staticCode + "_to_" + dynamicCode;
6235 
6236 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically set color write mask to " + dynamicCode, config));
6237 			}
6238 		}
6239 
6240 		// Rasterization stream selection.
6241 		if (!kUseMeshShaders)
6242 		{
6243 			const struct
6244 			{
6245 				OptRastStream	shaderStream;	// Stream in the geometry shader.
6246 				OptRastStream	staticVal;		// Static value for the extension struct.
6247 				OptRastStream	dynamicVal;		// Dynamic value for the setter.
6248 				const bool		expectDraw;		// Match between actual stream and active selected value?
6249 				const char*		name;
6250 			} rastStreamCases[] =
6251 			{
6252 				{ tcu::just(1u),	tcu::Nothing,		tcu::just(1u),		true,	"none_to_one"						},
6253 				{ tcu::just(1u),	tcu::just(0u),		tcu::just(1u),		true,	"zero_to_one"						},
6254 				{ tcu::Nothing,		tcu::just(1u),		tcu::just(0u),		true,	"one_to_zero"						},
6255 				{ tcu::just(0u),	tcu::just(1u),		tcu::just(0u),		true,	"one_to_zero_explicit"				},
6256 				{ tcu::just(0u),	tcu::Nothing,		tcu::just(1u),		false,	"none_to_one_mismatch"				},
6257 				{ tcu::just(0u),	tcu::just(0u),		tcu::just(1u),		false,	"zero_to_one_mismatch"				},
6258 				{ tcu::Nothing,		tcu::Nothing,		tcu::just(1u),		false,	"none_to_one_mismatch_implicit"		},
6259 				{ tcu::Nothing,		tcu::just(0u),		tcu::just(1u),		false,	"zero_to_one_mismatch_implicit"		},
6260 			};
6261 
6262 			for (const auto& rastStreamCase : rastStreamCases)
6263 			{
6264 				// In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
6265 				// calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
6266 				// must be set if the used pipeline contains the dynamic state.
6267 				if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC && !static_cast<bool>(rastStreamCase.staticVal))
6268 					continue;
6269 
6270 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6271 
6272 				config.rasterizationStreamConfig.staticValue	= rastStreamCase.staticVal;
6273 				config.rasterizationStreamConfig.dynamicValue	= rastStreamCase.dynamicVal;
6274 				config.shaderRasterizationStream				= rastStreamCase.shaderStream;
6275 				config.referenceColor.reset						(new SingleColorGenerator(rastStreamCase.expectDraw ? kDefaultTriangleColor : kDefaultClearColor));
6276 
6277 				const auto testName = std::string("rasterization_stream_") + rastStreamCase.name;
6278 
6279 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically switch rasterization streams", config));
6280 			}
6281 		}
6282 
6283 		// Provoking vertex mode.
6284 		{
6285 			const struct
6286 			{
6287 				OptBoolean		staticVal;
6288 				OptBoolean		dynamicVal;
6289 				const char*		name;
6290 				const char*		desc;
6291 			} provokingVtxCases[] =
6292 			{
6293 				{ tcu::Nothing,		tcu::just(true),	"provoking_vertex_first_to_last_implicit",	"Dynamically switch provoking vertex mode from none (first) to last"	},
6294 				{ tcu::just(false),	tcu::just(true),	"provoking_vertex_first_to_last_explicit",	"Dynamically switch provoking vertex mode from first to last"			},
6295 				{ tcu::just(true),	tcu::just(false),	"provoking_vertex_last_to_first",			"Dynamically switch provoking vertex mode from last to first"			},
6296 			};
6297 
6298 			for (const auto& provokingVtxCase : provokingVtxCases)
6299 			{
6300 				// In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
6301 				// calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
6302 				// must be set if the used pipeline contains the dynamic state.
6303 				if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC && !static_cast<bool>(provokingVtxCase.staticVal))
6304 					continue;
6305 
6306 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, getProvokingVertexWithPaddingGenerator(provokingVtxCase.dynamicVal.get()));
6307 				config.provokingVertexConfig.staticValue	= provokingVtxCase.staticVal;
6308 				config.provokingVertexConfig.dynamicValue	= provokingVtxCase.dynamicVal;
6309 				config.oversizedTriangle					= true;
6310 
6311 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, provokingVtxCase.name, provokingVtxCase.desc, config));
6312 			}
6313 		}
6314 
6315 		// Depth clip negative one to one.
6316 		{
6317 			const struct
6318 			{
6319 				OptBoolean		staticVal;
6320 				OptBoolean		dynamicVal;
6321 				const char*		name;
6322 				const char*		desc;
6323 			} negativeOneToOneCases[] =
6324 			{
6325 				{ tcu::Nothing,		tcu::just(true),	"negative_one_to_one_false_to_true_implicit",	"Dynamically switch negative one to one mode from none (false) to true"	},
6326 				{ tcu::just(false),	tcu::just(true),	"negative_one_to_one_false_to_true_explicit",	"Dynamically switch negative one to one mode from false to true"		},
6327 				{ tcu::just(true),	tcu::just(false),	"negative_one_to_one_true_to_false",			"Dynamically switch negative one to one mode from true to false"		},
6328 			};
6329 
6330 			for (const auto& negOneToOneCase : negativeOneToOneCases)
6331 			{
6332 				// In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
6333 				// calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
6334 				// must be set if the used pipeline contains the dynamic state.
6335 				if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC && !static_cast<bool>(negOneToOneCase.staticVal))
6336 					continue;
6337 
6338 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6339 				config.negativeOneToOneConfig.staticValue	= negOneToOneCase.staticVal;
6340 				config.negativeOneToOneConfig.dynamicValue	= negOneToOneCase.dynamicVal;
6341 
6342 				// Enable depth test and set values so it passes.
6343 				config.depthTestEnableConfig.staticValue	= true;
6344 				config.depthWriteEnableConfig.staticValue	= true;
6345 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6346 				config.meshParams[0].depth					= 0.5f;
6347 				config.expectedDepth						= (config.getActiveNegativeOneToOneValue() ? 0.75f : 0.5f);
6348 
6349 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, negOneToOneCase.name, negOneToOneCase.desc, config));
6350 			}
6351 		}
6352 
6353 		// Depth clip enable.
6354 		{
6355 			const struct
6356 			{
6357 				OptBoolean		staticVal;
6358 				OptBoolean		dynamicVal;
6359 				const char*		name;
6360 				const char*		desc;
6361 			} depthClipEnableCases[] =
6362 			{
6363 				{ tcu::Nothing,		tcu::just(false),	"depth_clip_enable_true_to_false_implicit",	"Dynamically switch negative one to one mode from none (true) to false"	},
6364 				{ tcu::just(true),	tcu::just(false),	"depth_clip_enable_true_to_false_explicit",	"Dynamically switch negative one to one mode from true to false"		},
6365 				{ tcu::just(false),	tcu::just(true),	"depth_clip_enable_true_to_false",			"Dynamically switch negative one to one mode from false to true"		},
6366 			};
6367 
6368 			for (const auto& depthClipEnableCase : depthClipEnableCases)
6369 			{
6370 				// In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
6371 				// calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
6372 				// must be set if the used pipeline contains the dynamic state.
6373 				if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC && !static_cast<bool>(depthClipEnableCase.staticVal))
6374 					continue;
6375 
6376 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6377 				config.depthClipEnableConfig.staticValue	= depthClipEnableCase.staticVal;
6378 				config.depthClipEnableConfig.dynamicValue	= depthClipEnableCase.dynamicVal;
6379 
6380 				const bool depthClipActive = config.getActiveDepthClipEnable();
6381 
6382 				// Enable depth test and set values so it passes.
6383 				config.depthTestEnableConfig.staticValue	= true;
6384 				config.depthWriteEnableConfig.staticValue	= true;
6385 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6386 				config.meshParams[0].depth					= -0.5f;
6387 				config.viewportConfig.staticValue			= ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.5f, 1.0f));
6388 				config.expectedDepth						= (depthClipActive ? 1.0f : 0.25f);
6389 				config.referenceColor.reset					(new SingleColorGenerator(depthClipActive ? kDefaultClearColor : kDefaultTriangleColor));
6390 
6391 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, depthClipEnableCase.name, depthClipEnableCase.desc, config));
6392 			}
6393 		}
6394 
6395 		// Sample locations enablement.
6396 		{
6397 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6398 			config.rasterizationSamplesConfig	= kMultiSampleCount;
6399 			config.offCenterTriangle			= true;
6400 			config.offCenterProportion			= tcu::Vec2(0.90625f, 0.90625f);
6401 
6402 			// Push sample locations towards the bottom right corner so they're able to sample the off-center triangle.
6403 			config.sampleLocations				= tcu::Vec2(1.0f, 1.0f);
6404 
6405 			config.sampleLocationsEnableConfig.staticValue	= false;
6406 			config.sampleLocationsEnableConfig.dynamicValue	= true;
6407 
6408 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_locations_enable", "Dynamically enable sample locations", config));
6409 
6410 			config.sampleLocationsEnableConfig.swapValues();
6411 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor, kDefaultClearColor));
6412 
6413 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_locations_disable", "Dynamically disable sample locations", config));
6414 		}
6415 
6416 		// Coverage to color enable.
6417 		{
6418 			for (int i = 0; i < 2; ++i)
6419 			{
6420 				const bool multisample = (i > 0);
6421 
6422 				for (int j = 0; j < 2; ++j)
6423 				{
6424 					const bool		covToColor		= (j > 0);
6425 					const uint32_t	referenceRed	= ((covToColor ? (multisample ? 15u : 1u) : 48u/*matches meshParams[0].color*/));
6426 
6427 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6428 
6429 					config.oversizedTriangle						= true; // This avoids partial coverages in fragments.
6430 					config.rasterizationSamplesConfig				= (multisample ? kMultiSampleCount : kSingleSampleCount);
6431 					config.coverageToColorEnableConfig.staticValue	= !covToColor;
6432 					config.coverageToColorEnableConfig.dynamicValue	= covToColor;
6433 					config.meshParams[0].color						= tcu::Vec4(48.0f, 0.0f, 0.0f, 1.0f); // Distinct value, does not match any coverage mask.
6434 					config.referenceColor.reset						(new SingleColorGenerator(tcu::UVec4(referenceRed, 0u, 0u, 1u)));
6435 
6436 					const std::string	finalState	= (covToColor ? "enable" : "disable");
6437 					const auto			testName	= "coverage_to_color_" + finalState + "_" + (multisample ? "multisample" : "single_sample");
6438 					const auto			testDesc	= "Dynamically " + finalState + " coverage to color in " + (multisample ? "multisample" : "single sample") + " images";
6439 
6440 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, testDesc, config));
6441 				}
6442 			}
6443 		}
6444 
6445 		// Coverage to color location.
6446 		{
6447 			for (int i = 0; i < 2; ++i)
6448 			{
6449 				const bool multisample = (i > 0);
6450 
6451 				for (int j = 0; j < 2; ++j)
6452 				{
6453 					const bool		locationLast	= (j > 0);
6454 					const uint32_t	colorAttCount	= 4u;
6455 					const uint32_t	covToColorLoc	= (locationLast ? colorAttCount - 1u : 0u);
6456 					const uint32_t	referenceRed	= ((locationLast ? (multisample ? 15u : 1u) : 48u/*matches meshParams[0].color*/));
6457 
6458 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6459 
6460 					config.oversizedTriangle							= true; // This avoids partial coverages in fragments.
6461 					config.rasterizationSamplesConfig					= (multisample ? kMultiSampleCount : kSingleSampleCount);
6462 					config.colorAttachmentCount							= colorAttCount;
6463 					config.coverageToColorEnableConfig.staticValue		= true;
6464 					config.coverageToColorLocationConfig.staticValue	= (locationLast ? 0u : colorAttCount - 1u);
6465 					config.coverageToColorLocationConfig.dynamicValue	= covToColorLoc;
6466 					config.meshParams[0].color							= tcu::Vec4(48.0f, 0.0f, 0.0f, 1.0f); // Distinct value, does not match any coverage mask.
6467 					config.referenceColor.reset							(new SingleColorGenerator(tcu::UVec4(referenceRed, 0u, 0u, 1u)));
6468 
6469 					const auto	locName		= std::to_string(covToColorLoc);
6470 					const auto	testName	= "coverage_to_color_location_" + locName + "_" + (multisample ? "multisample" : "single_sample");
6471 					const auto	testDesc	= "Dynamically enable coverage to color in location " + locName + " using " + (multisample ? "multisample" : "single sample") + " images";
6472 
6473 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, testDesc, config));
6474 				}
6475 			}
6476 		}
6477 
6478 #ifndef CTS_USES_VULKANSC
6479 		// Coverage modulation mode.
6480 		{
6481 			const struct
6482 			{
6483 				vk::VkCoverageModulationModeNV	staticVal;
6484 				vk::VkCoverageModulationModeNV	dynamicVal;
6485 				tcu::Vec4						partialCovFactor; // This will match the expected coverage proportion. See below.
6486 				const char*						name;
6487 			} modulationModeCases[] =
6488 			{
6489 				{ vk::VK_COVERAGE_MODULATION_MODE_NONE_NV,	vk::VK_COVERAGE_MODULATION_MODE_RGB_NV,		tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f),	"rgb"	},
6490 				{ vk::VK_COVERAGE_MODULATION_MODE_NONE_NV,	vk::VK_COVERAGE_MODULATION_MODE_ALPHA_NV,	tcu::Vec4(1.0f, 1.0f, 1.0f, 0.25f),		"alpha"	},
6491 				{ vk::VK_COVERAGE_MODULATION_MODE_NONE_NV,	vk::VK_COVERAGE_MODULATION_MODE_RGBA_NV,	tcu::Vec4(0.25f, 0.25f, 0.25f, 0.25f),	"rgba"	},
6492 				{ vk::VK_COVERAGE_MODULATION_MODE_RGBA_NV,	vk::VK_COVERAGE_MODULATION_MODE_NONE_NV,	tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f),		"none"	},
6493 			};
6494 
6495 			for (const auto& modulationModeCase : modulationModeCases)
6496 			{
6497 				TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6498 
6499 				config.coverageModulation			= true;
6500 				config.rasterizationSamplesConfig	= kMultiSampleCount;
6501 				config.colorSampleCount				= kSingleSampleCount;
6502 
6503 				// With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
6504 				// * Leave the corner pixel uncovered.
6505 				// * Cover the top border with sample 3 (1/4 the samples = 0.25).
6506 				// * Cover the left border with sample 1 (1/4 the samples = 0.25).
6507 				config.offCenterProportion	= tcu::Vec2(0.6875f, 0.6875f);
6508 				config.offCenterTriangle	= true;
6509 
6510 				config.coverageModulationModeConfig.staticValue		= modulationModeCase.staticVal;
6511 				config.coverageModulationModeConfig.dynamicValue	= modulationModeCase.dynamicVal;
6512 
6513 				const auto& partialCoverageColor = kDefaultTriangleColor * modulationModeCase.partialCovFactor;
6514 				config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, partialCoverageColor, kDefaultClearColor, partialCoverageColor));
6515 
6516 				const auto testName = std::string("coverage_modulation_mode_") + modulationModeCase.name;
6517 				const auto testDesc = std::string("Dynamically set coverage modulation mode to ") + modulationModeCase.name;
6518 
6519 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, testDesc, config));
6520 			}
6521 		}
6522 
6523 		// Coverage modulation table enable.
6524 		{
6525 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6526 
6527 			config.coverageModulation			= true;
6528 			config.rasterizationSamplesConfig	= kMultiSampleCount;
6529 			config.colorSampleCount				= kSingleSampleCount;
6530 
6531 			// With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
6532 			// * Leave the corner pixel uncovered.
6533 			// * Cover the top border with sample 3 (1/4 the samples = 0.25).
6534 			// * Cover the left border with sample 1 (1/4 the samples = 0.25).
6535 			config.offCenterProportion	= tcu::Vec2(0.6875f, 0.6875f);
6536 			config.offCenterTriangle	= true;
6537 
6538 			const CovModTableVec table { 0.75f, 1.0f, 1.0f, 1.0f };
6539 			config.coverageModulationModeConfig.staticValue		= vk::VK_COVERAGE_MODULATION_MODE_RGB_NV;
6540 			config.coverageModTableConfig.staticValue			= table;
6541 
6542 			config.coverageModTableEnableConfig.staticValue		= false;
6543 			config.coverageModTableEnableConfig.dynamicValue	= true;
6544 
6545 			const auto	tableCoverFactor			= tcu::Vec4(0.75f, 0.75f, 0.75f, 1.0f);
6546 			const auto&	tablePartialCoverageColor	= kDefaultTriangleColor * tableCoverFactor;
6547 
6548 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, tablePartialCoverageColor, kDefaultClearColor, tablePartialCoverageColor));
6549 
6550 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_enable", "Dynamically enable coverage modulation table", config));
6551 
6552 			// Reverse situation, fall back to the default modulation factor.
6553 			config.coverageModTableEnableConfig.swapValues();
6554 			const auto	noTableCoverFactor			= tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f);
6555 			const auto&	noTablePartialCoverageColor	= kDefaultTriangleColor * noTableCoverFactor;
6556 			config.referenceColor.reset				(new TopLeftBorderGenerator(kDefaultTriangleColor, noTablePartialCoverageColor, kDefaultClearColor, noTablePartialCoverageColor));
6557 
6558 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_disable", "Dynamically disable coverage modulation table", config));
6559 		}
6560 
6561 		// Coverage modulation table.
6562 		{
6563 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6564 
6565 			config.coverageModulation			= true;
6566 			config.rasterizationSamplesConfig	= kMultiSampleCount;
6567 			config.colorSampleCount				= kSingleSampleCount;
6568 
6569 			// With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
6570 			// * Cover the corner pixel with 1 sample (0.25).
6571 			// * Cover the top border with 2 samples (0.5).
6572 			// * Cover the left border with 2 samples (0.5).
6573 			config.offCenterProportion	= tcu::Vec2(0.5f, 0.5f);
6574 			config.offCenterTriangle	= true;
6575 
6576 			config.coverageModulationModeConfig.staticValue		= vk::VK_COVERAGE_MODULATION_MODE_RGB_NV;
6577 			config.coverageModTableEnableConfig.staticValue		= true;
6578 
6579 			//									corner	border	unused		main
6580 			const CovModTableVec goodTable	{	0.75f,	0.25f,	0.0f,		0.5f	};
6581 			const CovModTableVec badTable	{	0.5f,	0.75f,	1.0f,		0.25f	};
6582 
6583 			config.coverageModTableConfig.staticValue	= badTable;
6584 			config.coverageModTableConfig.dynamicValue	= goodTable;
6585 
6586 			// VK_COVERAGE_MODULATION_MODE_RGB_NV, factors for RGB according to goodTable, alpha untouched.
6587 			const auto	cornerFactor	= tcu::Vec4(0.75f, 0.75f, 0.75f, 1.0f);
6588 			const auto	borderFactor	= tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f);
6589 			const auto	mainFactor		= tcu::Vec4(0.5f,  0.5f,  0.5f,  1.0f);
6590 
6591 			const auto&	cornerColor		= kDefaultTriangleColor * cornerFactor;
6592 			const auto&	borderColor		= kDefaultTriangleColor * borderFactor;
6593 			const auto&	mainColor		= kDefaultTriangleColor * mainFactor;
6594 
6595 			config.referenceColor.reset(new TopLeftBorderGenerator(mainColor, borderColor, cornerColor, borderColor));
6596 
6597 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_change", "Dynamically change coverage modulation table", config));
6598 		}
6599 
6600 		// Coverage reduction mode.
6601 		{
6602 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6603 
6604 			config.coverageReduction			= true;
6605 			config.rasterizationSamplesConfig	= kMultiSampleCount;
6606 			config.colorSampleCount				= kSingleSampleCount;
6607 
6608 			// With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
6609 			// * Leave the corner pixel uncovered.
6610 			// * Cover the top border with sample 3 (1/4 the samples = 0.25).
6611 			// * Cover the left border with sample 1 (1/4 the samples = 0.25).
6612 			config.offCenterProportion	= tcu::Vec2(0.6875f, 0.6875f);
6613 			config.offCenterTriangle	= true;
6614 
6615 			config.coverageReductionModeConfig.staticValue	= vk::VK_COVERAGE_REDUCTION_MODE_MERGE_NV;
6616 			config.coverageReductionModeConfig.dynamicValue	= vk::VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV;
6617 
6618 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor, kDefaultClearColor));
6619 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_reduction_truncate", "Dynamically set coverage reduction truncate mode", config));
6620 
6621 			// In merge mode, the only pixel without coverage should be the corner. However, the spec is a bit ambiguous in this
6622 			// case:
6623 			//
6624 			//    VK_COVERAGE_REDUCTION_MODE_MERGE_NV specifies that each color sample will be associated with an
6625 			//    implementation-dependent subset of samples in the pixel coverage. If any of those associated samples are covered,
6626 			//    the color sample is covered.
6627 			//
6628 			// We cannot be 100% sure the single color sample will be associated with the whole set of 4 rasterization samples, but
6629 			// the test appears to pass in existing HW.
6630 			config.coverageReductionModeConfig.swapValues();
6631 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultTriangleColor, kDefaultClearColor, kDefaultTriangleColor));
6632 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_reduction_merge", "Dynamically set coverage reduction merge mode", config));
6633 		}
6634 
6635 		// Viewport swizzle.
6636 		{
6637 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6638 
6639 			config.viewportSwizzle				= true;
6640 			config.oversizedTriangle			= true;
6641 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
6642 
6643 			const vk::VkViewportSwizzleNV idSwizzle
6644 			{
6645 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,
6646 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,
6647 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV,
6648 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV,
6649 			};
6650 
6651 			const vk::VkViewportSwizzleNV yxSwizzle // Switches Y and X coordinates, makes the oversized triangle clockwise.
6652 			{
6653 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV, // <--
6654 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, // <--
6655 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV,
6656 				vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV,
6657 			};
6658 
6659 			config.viewportSwizzleConfig.staticValue	= ViewportSwzVec(1u, idSwizzle);
6660 			config.viewportSwizzleConfig.dynamicValue	= ViewportSwzVec(1u, yxSwizzle);
6661 			config.frontFaceConfig.staticValue			= vk::VK_FRONT_FACE_CLOCKWISE;
6662 
6663 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "viewport_swizzle_yx", "Dynamically set a viewport swizzle with X and Y switched around", config));
6664 
6665 			config.viewportSwizzleConfig.swapValues();
6666 			config.frontFaceConfig.staticValue			= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
6667 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "viewport_swizzle_xy", "Dynamically set the viewport identity swizzle", config));
6668 		}
6669 
6670 		// Shading rate image enable.
6671 		{
6672 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6673 
6674 			for (int i = 0; i < 2; ++i)
6675 			{
6676 				const bool			sriEnable	= (i > 0);
6677 				const std::string	enableStr	= (sriEnable ? "enable" : "disable");
6678 
6679 				config.shadingRateImage = true;
6680 				config.shadingRateImageEnableConfig.staticValue = !sriEnable;
6681 				config.shadingRateImageEnableConfig.dynamicValue = sriEnable;
6682 				config.referenceColor.reset(new SingleColorGenerator(sriEnable ? kDefaultClearColor : kDefaultTriangleColor));
6683 
6684 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "shading_rate_image_" + enableStr, "Dynamically " + enableStr + " a shading rate image", config));
6685 			}
6686 		}
6687 
6688 		// Viewport W Scaling enable.
6689 		{
6690 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6691 
6692 			for (int i = 0; i < 2; ++i)
6693 			{
6694 				const bool			wScalingEnable	= (i > 0);
6695 				const std::string	enableStr		= (wScalingEnable ? "enable" : "disable");
6696 
6697 				config.colorVerificator = verifyTopLeftCorner;
6698 				config.viewportWScaling = true;
6699 				config.viewportWScalingEnableConfig.staticValue = !wScalingEnable;
6700 				config.viewportWScalingEnableConfig.dynamicValue = wScalingEnable;
6701 				config.referenceColor.reset(new SingleColorGenerator(wScalingEnable ? kDefaultClearColor : kDefaultTriangleColor));
6702 
6703 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "viewport_w_scaling_" + enableStr, "Dynamically " + enableStr + " viewport W scaling", config));
6704 			}
6705 		}
6706 
6707 		// Representative fragment test state.
6708 		{
6709 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6710 
6711 			for (int i = 0; i < 2; ++i)
6712 			{
6713 				const bool			reprFragTestEnable	= (i > 0);
6714 				const std::string	enableStr			= (reprFragTestEnable ? "enable" : "disable");
6715 
6716 				config.depthTestEnableConfig.staticValue	= true;
6717 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
6718 				config.colorWriteMaskConfig.staticValue		= 0u; // Disable color writes.
6719 				config.oversizedTriangle					= true;
6720 				config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
6721 
6722 				config.representativeFragmentTest				= true;
6723 				config.reprFragTestEnableConfig.staticValue		= !reprFragTestEnable;
6724 				config.reprFragTestEnableConfig.dynamicValue	= reprFragTestEnable;
6725 
6726 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "repr_frag_test_" + enableStr, "Dynamically " + enableStr + " representative frag test", config));
6727 			}
6728 		}
6729 #endif // CTS_USES_VULKANSC
6730 
6731 		// Conservative rasterization mode.
6732 		{
6733 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6734 			config.offCenterTriangle = true;
6735 
6736 			// Single-sampling at the pixel center should not cover this, but overestimation should result in coverage.
6737 			config.offCenterProportion							= tcu::Vec2(0.75f, 0.75f);
6738 			config.extraPrimitiveOverEstConfig.staticValue		= 0.0f;
6739 			config.conservativeRasterModeConfig.staticValue		= vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
6740 			config.conservativeRasterModeConfig.dynamicValue	= vk::VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
6741 
6742 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_overestimate", "Dynamically set conservative rasterization mode to overestimation", config));
6743 
6744 			config.conservativeRasterModeConfig.swapValues();
6745 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor, kDefaultClearColor));
6746 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_disabled", "Dynamically set conservative rasterization mode to disabled", config));
6747 		}
6748 		{
6749 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6750 			config.offCenterTriangle = true;
6751 
6752 			// Single-sampling at the pixel center should cover this, but underestimation should result in lack of coverage.
6753 			config.offCenterProportion							= tcu::Vec2(0.25f, 0.25f);
6754 			config.extraPrimitiveOverEstConfig.staticValue		= 0.0f;
6755 			config.conservativeRasterModeConfig.staticValue		= vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
6756 			config.conservativeRasterModeConfig.dynamicValue	= vk::VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT;
6757 			config.referenceColor.reset							(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor, kDefaultClearColor));
6758 
6759 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_underestimate", "Dynamically set conservative rasterization mode to underestimation", config));
6760 		}
6761 
6762 		// Extra primitive overestimation size.
6763 		// Notes as of 2022-08-12 and gpuinfo.org:
6764 		//    * primitiveOverestimationSize is typically 0.0, 0.001953125 or 0.00195313 (i.e. very small).
6765 		//    * maxExtraPrimitiveOverestimationSize is typically 0.0 or 0.75 (no other values).
6766 		//    * extraPrimitiveOverestimationSizeGranularity is typically 0.0 or 0.25 (no other values).
6767 		{
6768 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6769 			config.offCenterTriangle = true;
6770 
6771 			// Move the triangle by more than one pixel, then use an extra overestimation of 0.75 to cover the border pixels too.
6772 			config.offCenterProportion						= tcu::Vec2(1.125f, 1.125f);
6773 			config.maxPrimitiveOverestimationSize			= 0.5f; // Otherwise the base overestimation size will be enough. This should never trigger.
6774 			config.conservativeRasterModeConfig.staticValue	= vk::VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
6775 			config.extraPrimitiveOverEstConfig.staticValue	= 0.0f;
6776 			config.extraPrimitiveOverEstConfig.dynamicValue	= 0.75f; // Large enough to reach the center of the border pixel.
6777 
6778 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "extra_overestimation_size_large", "Dynamically set the extra overestimation size to a large value", config));
6779 
6780 			config.extraPrimitiveOverEstConfig.swapValues();
6781 			config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor, kDefaultClearColor, kDefaultClearColor));
6782 
6783 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "extra_overestimation_size_none", "Dynamically set the extra overestimation size to zero", config));
6784 		}
6785 
6786 		// Depth bias enable with static or dynamic depth bias parameters.
6787 		{
6788 			const DepthBiasParams kAlternativeDepthBiasParams = { 2e7f, 0.25f };
6789 
6790 			for (int dynamicBiasIter = 0; dynamicBiasIter < 2; ++dynamicBiasIter)
6791 			{
6792 				const bool useDynamicBias = (dynamicBiasIter > 0);
6793 
6794 				{
6795 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6796 
6797 					// Enable depth test and write 1.0f
6798 					config.depthTestEnableConfig.staticValue = true;
6799 					config.depthWriteEnableConfig.staticValue = true;
6800 					config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
6801 					// Clear depth buffer to 0.25f
6802 					config.clearDepthValue = 0.25f;
6803 					// Write depth to 0.5f
6804 					config.meshParams[0].depth = 0.5f;
6805 
6806 					// Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
6807 					if (useDynamicBias)
6808 					{
6809 						config.depthBiasConfig.staticValue	= kNoDepthBiasParams;
6810 						config.depthBiasConfig.dynamicValue	= kAlternativeDepthBiasParams;
6811 					}
6812 					else
6813 					{
6814 						config.depthBiasConfig.staticValue	= kAlternativeDepthBiasParams;
6815 					}
6816 
6817 					config.depthBiasEnableConfig.staticValue = false;
6818 					config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
6819 					config.expectedDepth = 0.75f;
6820 
6821 					std::string caseName = "depth_bias_enable";
6822 					std::string caseDesc = "Dynamically enable the depth bias";
6823 
6824 					if (useDynamicBias)
6825 					{
6826 						caseName += "_dynamic_bias_params";
6827 						caseDesc += " and set the bias params dynamically";
6828 					}
6829 
6830 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
6831 				}
6832 				{
6833 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6834 
6835 					// Enable depth test and write 1.0f
6836 					config.depthTestEnableConfig.staticValue = true;
6837 					config.depthWriteEnableConfig.staticValue = true;
6838 					config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
6839 					// Clear depth buffer to 0.25f
6840 					config.clearDepthValue = 0.25f;
6841 					// Write depth to 0.5f
6842 					config.meshParams[0].depth = 0.5f;
6843 
6844 					// Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
6845 					if (useDynamicBias)
6846 					{
6847 						config.depthBiasConfig.staticValue	= kNoDepthBiasParams;
6848 						config.depthBiasConfig.dynamicValue	= kAlternativeDepthBiasParams;
6849 					}
6850 					else
6851 					{
6852 						config.depthBiasConfig.staticValue	= kAlternativeDepthBiasParams;
6853 					}
6854 
6855 					config.depthBiasEnableConfig.staticValue = true;
6856 					config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
6857 					config.expectedDepth = 0.5f;
6858 
6859 					std::string caseName = "depth_bias_disable";
6860 					std::string caseDesc = "Dynamically disable the depth bias";
6861 
6862 					if (useDynamicBias)
6863 					{
6864 						caseName += "_dynamic_bias_params";
6865 						caseDesc += " and set the bias params dynamically";
6866 					}
6867 
6868 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
6869 				}
6870 			}
6871 		}
6872 
6873 		// Depth compare op.
6874 		{
6875 			TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
6876 			const tcu::Vec4 kAlternativeColor				(0.0f, 0.0f, 0.5f, 1.0f);
6877 			baseConfig.depthTestEnableConfig.staticValue	= true;
6878 			baseConfig.depthWriteEnableConfig.staticValue	= true;
6879 			baseConfig.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_NEVER;
6880 			baseConfig.clearDepthValue						= 0.5f;
6881 
6882 			{
6883 				TestConfig config = baseConfig;
6884 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_ALWAYS;
6885 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NEVER;
6886 				config.meshParams[0].depth					= 0.25f;
6887 				config.expectedDepth						= 0.5f;
6888 				config.referenceColor.reset					(new SingleColorGenerator(kDefaultClearColor));
6889 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
6890 			}
6891 			{
6892 				TestConfig config = baseConfig;
6893 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS;
6894 				config.meshParams[0].depth					= 0.25f;
6895 				config.expectedDepth						= 0.25f;
6896 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
6897 			}
6898 			{
6899 				TestConfig config = baseConfig;
6900 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER;
6901 				config.meshParams[0].depth					= 0.75f;
6902 				config.expectedDepth						= 0.75f;
6903 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
6904 			}
6905 			{
6906 				TestConfig config = baseConfig;
6907 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_EQUAL;
6908 				config.meshParams[0].depth					= 0.5f;
6909 				config.meshParams[0].color					= kAlternativeColor;
6910 				// Draw another mesh in front to verify it does not pass the equality test.
6911 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
6912 				config.expectedDepth						= 0.5f;
6913 				config.referenceColor.reset					(new SingleColorGenerator(kAlternativeColor));
6914 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
6915 			}
6916 			{
6917 				TestConfig config = baseConfig;
6918 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
6919 				config.meshParams[0].depth					= 0.25f;
6920 				config.expectedDepth						= 0.25f;
6921 				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));
6922 			}
6923 			{
6924 				TestConfig config = baseConfig;
6925 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
6926 				config.meshParams[0].depth					= 0.5f;
6927 				config.expectedDepth						= 0.5f;
6928 				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));
6929 			}
6930 			{
6931 				TestConfig config = baseConfig;
6932 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
6933 				config.meshParams[0].depth					= 0.25f;
6934 				// Draw another mesh with the same depth in front of it.
6935 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
6936 				config.expectedDepth						= 0.25f;
6937 				config.referenceColor.reset					(new SingleColorGenerator(kAlternativeColor));
6938 				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));
6939 			}
6940 			{
6941 				TestConfig config = baseConfig;
6942 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
6943 				config.meshParams[0].depth					= 0.75f;
6944 				config.expectedDepth						= 0.75f;
6945 				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));
6946 			}
6947 			{
6948 				TestConfig config = baseConfig;
6949 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
6950 				config.meshParams[0].depth					= 0.5f;
6951 				config.expectedDepth						= 0.5f;
6952 				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));
6953 			}
6954 			{
6955 				TestConfig config = baseConfig;
6956 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
6957 				config.meshParams[0].depth					= 0.75f;
6958 				// Draw another mesh with the same depth in front of it.
6959 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
6960 				config.expectedDepth						= 0.75f;
6961 				config.referenceColor.reset					(new SingleColorGenerator(kAlternativeColor));
6962 				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));
6963 			}
6964 			{
6965 				TestConfig config = baseConfig;
6966 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NOT_EQUAL;
6967 
6968 				// Draw first mesh in front.
6969 				config.meshParams[0].depth					= 0.25f;
6970 				// Draw another mesh in the back, this should pass too.
6971 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
6972 				// Finally a new mesh with the same depth. This should not pass.
6973 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
6974 
6975 				config.referenceColor.reset					(new SingleColorGenerator(kAlternativeColor));
6976 				config.expectedDepth						= 0.5f;
6977 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
6978 			}
6979 			{
6980 				TestConfig config = baseConfig;
6981 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_ALWAYS;
6982 
6983 				config.meshParams[0].depth					= 0.5f;
6984 				config.expectedDepth						= 0.5f;
6985 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
6986 
6987 				config.meshParams[0].depth					= 0.25f;
6988 				config.expectedDepth						= 0.25f;
6989 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
6990 
6991 				config.meshParams[0].depth					= 0.75f;
6992 				config.expectedDepth						= 0.75f;
6993 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
6994 			}
6995 		}
6996 
6997 		// Depth bounds test.
6998 		{
6999 			TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
7000 			baseConfig.minDepthBounds							= 0.25f;
7001 			baseConfig.maxDepthBounds							= 0.75f;
7002 			baseConfig.meshParams[0].depth						= 0.0f;
7003 
7004 			{
7005 				TestConfig config = baseConfig;
7006 				config.depthBoundsTestEnableConfig.staticValue	= false;
7007 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(true);
7008 				config.referenceColor.reset						(new SingleColorGenerator(kDefaultClearColor));
7009 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
7010 			}
7011 			{
7012 				TestConfig config = baseConfig;
7013 				config.depthBoundsTestEnableConfig.staticValue	= true;
7014 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(false);
7015 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
7016 			}
7017 		}
7018 
7019 		// Stencil test enable.
7020 		{
7021 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7022 			config.stencilTestEnableConfig.staticValue				= false;
7023 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(true);
7024 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
7025 			config.referenceColor.reset								(new SingleColorGenerator(kDefaultClearColor));
7026 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
7027 		}
7028 		{
7029 			TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7030 			config.stencilTestEnableConfig.staticValue				= true;
7031 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(false);
7032 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
7033 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
7034 		}
7035 
7036 		// Stencil operation. Many combinations are possible.
7037 		{
7038 			static const struct
7039 			{
7040 				vk::VkStencilFaceFlags	face;
7041 				std::string				name;
7042 			} kFaces[] =
7043 			{
7044 				{ vk::VK_STENCIL_FACE_FRONT_BIT,			"face_front"		},
7045 				{ vk::VK_STENCIL_FACE_BACK_BIT,				"face_back"			},
7046 				{ vk::VK_STENCIL_FACE_FRONT_AND_BACK,		"face_both_single"	},
7047 				{ vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM,	"face_both_dual"	},	// MAX_ENUM is a placeholder.
7048 			};
7049 
7050 			static const struct
7051 			{
7052 				vk::VkCompareOp		compareOp;
7053 				std::string			name;
7054 			} kCompare[] =
7055 			{
7056 				{ vk::VK_COMPARE_OP_NEVER,				"xf"		},
7057 				{ vk::VK_COMPARE_OP_LESS,				"lt"		},
7058 				{ vk::VK_COMPARE_OP_EQUAL,				"eq"		},
7059 				{ vk::VK_COMPARE_OP_LESS_OR_EQUAL,		"le"		},
7060 				{ vk::VK_COMPARE_OP_GREATER,			"gt"		},
7061 				{ vk::VK_COMPARE_OP_GREATER_OR_EQUAL,	"ge"		},
7062 				{ vk::VK_COMPARE_OP_ALWAYS,				"xt"		},
7063 			};
7064 
7065 			using u8vec = std::vector<deUint8>;
7066 
7067 			static const auto kMinVal	= std::numeric_limits<deUint8>::min();
7068 			static const auto kMaxVal	= std::numeric_limits<deUint8>::max();
7069 			static const auto kMidVal	= static_cast<deUint8>(kMaxVal * 2u / 5u);
7070 			static const auto kMinValI	= static_cast<int>(kMinVal);
7071 			static const auto kMaxValI	= static_cast<int>(kMaxVal);
7072 
7073 			static const struct
7074 			{
7075 				vk::VkStencilOp		stencilOp;
7076 				std::string			name;
7077 				u8vec				clearValues;	// One test per clear value interesting for this operation.
7078 				vk::VkStencilOp		incompatibleOp;	// Alternative operation giving incompatible results for the given values.
7079 			} kStencilOps[] =
7080 			{
7081 				{ vk::VK_STENCIL_OP_KEEP,					"keep",			u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
7082 				{ vk::VK_STENCIL_OP_ZERO,					"zero",			u8vec{kMidVal},					vk::VK_STENCIL_OP_KEEP					},
7083 				{ vk::VK_STENCIL_OP_REPLACE,				"replace",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
7084 				{ vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP,	"inc_clamp",	u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_ZERO					},
7085 				{ vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP,	"dec_clamp",	u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP	},
7086 				{ vk::VK_STENCIL_OP_INVERT,					"invert",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
7087 				{ vk::VK_STENCIL_OP_INCREMENT_AND_WRAP,		"inc_wrap",		u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_KEEP					},
7088 				{ vk::VK_STENCIL_OP_DECREMENT_AND_WRAP,		"dec_wrap",		u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_KEEP					},
7089 			};
7090 
7091 			for (const auto& face : kFaces)
7092 			for (const auto& compare : kCompare)
7093 			for (const auto& op : kStencilOps)
7094 			{
7095 				// Try clearing the stencil value with different values.
7096 				for (const auto clearVal : op.clearValues)
7097 				{
7098 					// Use interesting values as the reference stencil value.
7099 					for (int delta = -1; delta <= 1; ++delta)
7100 					{
7101 						const int refVal = clearVal + delta;
7102 						if (refVal < kMinValI || refVal > kMaxValI)
7103 							continue;
7104 
7105 						const auto refValU8		= static_cast<deUint8>(refVal);
7106 						const auto refValU32	= static_cast<deUint32>(refVal);
7107 
7108 						// Calculate outcome of the stencil test itself.
7109 						const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
7110 
7111 						// If the test passes, use an additional variant for the depthFail operation.
7112 						const int subCases = (wouldPass ? 2 : 1);
7113 
7114 						for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
7115 						{
7116 							const bool depthFail	= (subCaseIdx > 0);				// depthFail would be the second variant.
7117 							const bool globalPass	= (wouldPass && !depthFail);	// Global result of the stencil+depth test.
7118 
7119 							// Start tuning test parameters.
7120 							TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7121 
7122 							// No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
7123 							if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
7124 							{
7125 								// Default parameters are OK.
7126 							}
7127 							else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
7128 							{
7129 								// Reverse the mesh so it applies the back operation.
7130 								config.meshParams[0].reversed = true;
7131 							}
7132 							else	// Front and back.
7133 							{
7134 								// Draw both a front and a back-facing mesh so both are applied.
7135 								// The first mesh will be drawn in the top half and the second mesh in the bottom half.
7136 
7137 								// Make the second mesh a reversed copy of the first mesh.
7138 								config.meshParams.push_back(config.meshParams.front());
7139 								config.meshParams.back().reversed = true;
7140 
7141 								// Apply scale and offset to the top mesh.
7142 								config.meshParams.front().scaleY = 0.5f;
7143 								config.meshParams.front().offsetY = -0.5f;
7144 
7145 								// Apply scale and offset to the bottom mesh.
7146 								config.meshParams.back().scaleY = 0.5f;
7147 								config.meshParams.back().offsetY = 0.5f;
7148 							}
7149 
7150 							// Enable the stencil test.
7151 							config.stencilTestEnableConfig.staticValue = true;
7152 
7153 							// Set dynamic configuration.
7154 							StencilOpParams dynamicStencilConfig;
7155 							dynamicStencilConfig.faceMask		= face.face;
7156 							dynamicStencilConfig.compareOp		= compare.compareOp;
7157 							dynamicStencilConfig.failOp			= vk::VK_STENCIL_OP_MAX_ENUM;
7158 							dynamicStencilConfig.passOp			= vk::VK_STENCIL_OP_MAX_ENUM;
7159 							dynamicStencilConfig.depthFailOp	= vk::VK_STENCIL_OP_MAX_ENUM;
7160 
7161 							// Set operations so only the appropriate operation for this case gives the right result.
7162 							vk::VkStencilOp* activeOp		= nullptr;
7163 							vk::VkStencilOp* inactiveOps[2]	= { nullptr, nullptr };
7164 							if (wouldPass)
7165 							{
7166 								if (depthFail)
7167 								{
7168 									activeOp		= &dynamicStencilConfig.depthFailOp;
7169 									inactiveOps[0]	= &dynamicStencilConfig.passOp;
7170 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
7171 								}
7172 								else
7173 								{
7174 									activeOp		= &dynamicStencilConfig.passOp;
7175 									inactiveOps[0]	= &dynamicStencilConfig.depthFailOp;
7176 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
7177 								}
7178 							}
7179 							else
7180 							{
7181 								activeOp		= &dynamicStencilConfig.failOp;
7182 								inactiveOps[0]	= &dynamicStencilConfig.passOp;
7183 								inactiveOps[1]	= &dynamicStencilConfig.depthFailOp;
7184 							}
7185 
7186 							*activeOp = op.stencilOp;
7187 							*inactiveOps[0] = op.incompatibleOp;
7188 							*inactiveOps[1] = op.incompatibleOp;
7189 
7190 							// Make sure all ops have been configured properly.
7191 							DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
7192 							DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
7193 							DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
7194 
7195 							// Set an incompatible static operation too.
7196 							auto& staticStencilConfig		= config.stencilOpConfig.staticValue.front();
7197 							staticStencilConfig.faceMask	= face.face;
7198 							staticStencilConfig.compareOp	= (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
7199 							staticStencilConfig.passOp		= op.incompatibleOp;
7200 							staticStencilConfig.failOp		= op.incompatibleOp;
7201 							staticStencilConfig.depthFailOp	= op.incompatibleOp;
7202 
7203 							// Set dynamic configuration.
7204 							StencilOpVec stencilOps;
7205 							stencilOps.push_back(dynamicStencilConfig);
7206 
7207 							if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
7208 							{
7209 								// This is the dual case. We will set the front and back face values with two separate calls.
7210 								stencilOps.push_back(stencilOps.front());
7211 								stencilOps.front().faceMask		= vk::VK_STENCIL_FACE_FRONT_BIT;
7212 								stencilOps.back().faceMask		= vk::VK_STENCIL_FACE_BACK_BIT;
7213 								staticStencilConfig.faceMask	= vk::VK_STENCIL_FACE_FRONT_AND_BACK;
7214 							}
7215 
7216 							config.stencilOpConfig.dynamicValue	= tcu::just(stencilOps);
7217 							config.clearStencilValue			= clearVal;
7218 							config.referenceStencil				= refValU32;
7219 
7220 							if (depthFail)
7221 							{
7222 								// Enable depth test and make it fail.
7223 								config.depthTestEnableConfig.staticValue	= true;
7224 								config.clearDepthValue						= 0.5f;
7225 								config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
7226 
7227 								for (auto& meshPar : config.meshParams)
7228 									meshPar.depth = 0.75f;
7229 							}
7230 
7231 							// Set expected outcome.
7232 							config.referenceColor.reset	(new SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor));
7233 							config.expectedDepth		= config.clearDepthValue; // No depth writing by default.
7234 							config.expectedStencil		= stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
7235 
7236 							const std::string testName = std::string("stencil_state")
7237 								+ "_" + face.name
7238 								+ "_" + compare.name
7239 								+ "_" + op.name
7240 								+ "_clear_" + de::toString(static_cast<int>(clearVal))
7241 								+ "_ref_" + de::toString(refVal)
7242 								+ "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
7243 
7244 							orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
7245 						}
7246 					}
7247 				}
7248 			}
7249 		}
7250 
7251 		// Vertex input.
7252 		if (!kUseMeshShaders)
7253 		{
7254 			for (const auto& bindUnusedCase : kBindUnusedCases)
7255 			{
7256 				if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
7257 					continue;
7258 
7259 				// TWO_DRAWS_STATIC would be invalid because it violates VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the
7260 				// dynamic stride being less than the extent of the binding for the second attribute.
7261 				if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
7262 				{
7263 					const auto	staticGen	= getVertexWithPaddingGenerator();
7264 					const auto	dynamicGen	= getVertexWithExtraAttributesGenerator();
7265 					const auto	goodStrides	= dynamicGen->getVertexDataStrides();
7266 					StrideVec	badStrides;
7267 
7268 					badStrides.reserve(goodStrides.size());
7269 					for (const auto& stride : goodStrides)
7270 						badStrides.push_back(stride / 2u);
7271 
7272 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, staticGen, dynamicGen);
7273 					config.strideConfig.staticValue			= badStrides;
7274 					config.strideConfig.dynamicValue		= goodStrides;
7275 					config.bindUnusedMeshShadingPipeline	= bindUnusedCase.bindUnusedMeshShadingPipeline;
7276 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input" + bindUnusedCase.nameSuffix, "Dynamically set vertex input" + bindUnusedCase.descSuffix, config));
7277 				}
7278 
7279 				{
7280 					// Variant without mixing in the stride config.
7281 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, getVertexWithPaddingGenerator(), getVertexWithExtraAttributesGenerator());
7282 					config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
7283 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_no_dyn_stride" + bindUnusedCase.nameSuffix, "Dynamically set vertex input without using dynamic strides" + bindUnusedCase.descSuffix, config));
7284 				}
7285 
7286 				{
7287 					// Variant using multiple bindings.
7288 					TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, getVertexWithExtraAttributesGenerator(), getVertexWithMultipleBindingsGenerator());
7289 					config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
7290 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_multiple_bindings" + bindUnusedCase.nameSuffix, "Dynamically set vertex input with multiple bindings" + bindUnusedCase.descSuffix, config));
7291 				}
7292 			}
7293 		}
7294 
7295 		tcu::TestCaseGroup* group = (kUseMeshShaders ? meshShaderGroup.get() : extendedDynamicStateGroup.get());
7296 		group->addChild(orderingGroup.release());
7297 	}
7298 
7299 	extendedDynamicStateGroup->addChild(meshShaderGroup.release());
7300 	return extendedDynamicStateGroup.release();
7301 }
7302 
7303 } // pipeline
7304 } // vkt
7305