• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*
21  * \file
22  * \brief Extended dynamic state tests
23 *//*--------------------------------------------------------------------*/
24 
25 #include "vktPipelineExtendedDynamicStateTests.hpp"
26 #include "vktPipelineImageUtil.hpp"
27 #include "vktTestCase.hpp"
28 
29 #include "vkDefs.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38 
39 #include "tcuVector.hpp"
40 #include "tcuMaybe.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43 #include "tcuStringTemplate.hpp"
44 
45 #include "deUniquePtr.hpp"
46 #include "deStringUtil.hpp"
47 
48 #include <vector>
49 #include <sstream>
50 #include <algorithm>
51 #include <utility>
52 #include <iterator>
53 #include <string>
54 #include <limits>
55 #include <memory>
56 #include <functional>
57 #include <cstddef>
58 #include <set>
59 
60 namespace vkt
61 {
62 namespace pipeline
63 {
64 
65 namespace
66 {
67 
makeVkBool32(bool value)68 inline vk::VkBool32 makeVkBool32(bool value)
69 {
70 	return (value ? VK_TRUE : VK_FALSE);
71 }
72 
73 // Framebuffer size.
74 constexpr deUint32	kFramebufferWidth	= 64u;
75 constexpr deUint32	kFramebufferHeight	= 64u;
76 
77 // Image formats.
78 constexpr	vk::VkFormat	kUnormColorFormat		= vk::VK_FORMAT_R8G8B8A8_UNORM;
79 constexpr	vk::VkFormat	kIntColorFormat			= vk::VK_FORMAT_R8G8B8A8_UINT;
80 const		tcu::Vec4		kUnormColorThreshold	(0.005f); // 1/255 < 0.005 < 2/255.
81 
82 struct DepthStencilFormat
83 {
84 	vk::VkFormat	imageFormat;
85 	float			depthThreshold;
86 };
87 
88 const DepthStencilFormat kDepthStencilFormats[] =
89 {
90 	{ vk::VK_FORMAT_D32_SFLOAT_S8_UINT,	0.0f		},
91 	{ vk::VK_FORMAT_D24_UNORM_S8_UINT,	1.0e-07f	},	// 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
92 };
93 
94 using StrideVec = std::vector<vk::VkDeviceSize>;
95 
96 // We will use several data types in vertex bindings. Each type will need to define a few things.
97 class VertexGenerator
98 {
99 public:
100 	// For GLSL.
101 
102 	// Vertex input attribute declarations in GLSL form. One sentence per element.
103 	virtual std::vector<std::string>								getAttributeDeclarations()	const = 0;
104 
105 	// Get statements to calculate a vec2 called "vertexCoords" using the vertex input attributes.
106 	virtual std::vector<std::string>								getVertexCoordCalc()		const = 0;
107 
108 
109 	// For the pipeline.
110 
111 	// Vertex attributes for VkPipelineVertexInputStateCreateInfo.
112 	virtual std::vector<vk::VkVertexInputAttributeDescription>		getAttributeDescriptions()	const = 0;
113 
114 	// Vertex attributes for VK_EXT_vertex_input_dynamic_state.
115 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT>	getAttributeDescriptions2() const = 0;
116 
117 	// Vertex bindings for VkPipelineVertexInputStateCreateInfo.
118 	virtual std::vector<vk::VkVertexInputBindingDescription>		getBindingDescriptions (const StrideVec& strides) const = 0;
119 
120 	// Vertex bindings for VK_EXT_vertex_input_dynamic_state.
121 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT>	getBindingDescriptions2 (const StrideVec& strides) const = 0;
122 
123 	// Create buffer data given an array of coordinates and an initial padding.
124 	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;
125 
126 	// Stride of vertex data in each binding.
127 	virtual std::vector<vk::VkDeviceSize>							getVertexDataStrides()		const = 0;
128 };
129 
130 // Auxiliar function to create these structs more easily.
makeVertexInputAttributeDescription2EXT(deUint32 location,deUint32 binding,vk::VkFormat format,deUint32 offset)131 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT (deUint32 location, deUint32 binding, vk::VkFormat format, deUint32 offset)
132 {
133 	vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
134 	desc.location = location;
135 	desc.binding = binding;
136 	desc.format = format;
137 	desc.offset = offset;
138 	return desc;
139 }
140 
makeVertexInputBindingDescription2EXT(deUint32 binding,deUint32 stride,vk::VkVertexInputRate inputRate)141 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT (deUint32 binding, deUint32 stride, vk::VkVertexInputRate inputRate)
142 {
143 	vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
144 	desc.binding = binding;
145 	desc.stride = stride;
146 	desc.inputRate = inputRate;
147 	desc.divisor = 1u;
148 	return desc;
149 }
150 
151 // 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)152 void fillWithPattern(void* ptr_, size_t offset, size_t count, const void* src, size_t srcSize)
153 {
154 	auto	ptr		= reinterpret_cast<char*>(ptr_);
155 	size_t	done	= 0u;
156 	size_t	pending	= count;
157 
158 	while (pending > 0u)
159 	{
160 		const size_t stepSize = de::min(srcSize, pending);
161 		deMemcpy(ptr + offset + done, src, stepSize);
162 		done += stepSize;
163 		pending -= stepSize;
164 	}
165 }
166 
167 // Create a single binding vertex data vector given a type T for vertex data.
168 template<class T>
createSingleBindingVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize)169 std::vector<deUint8> createSingleBindingVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize)
170 {
171 	DE_ASSERT(!coords.empty());
172 
173 	const auto dataOffsetSz			= static_cast<size_t>(dataOffset);
174 	const auto trailingPaddingSz	= static_cast<size_t>(trailingPadding);
175 
176 	std::vector<deUint8> buffer;
177 	buffer.resize(dataOffsetSz + coords.size() * sizeof(T) + trailingPaddingSz);
178 
179 	fillWithPattern(buffer.data(), 0u, dataOffsetSz, paddingPattern, patternSize);
180 
181 	auto pos = dataOffsetSz;
182 	for (const auto& coord : coords)
183 	{
184 		new (&buffer[pos]) T(coord);
185 		pos += sizeof(T);
186 	}
187 
188 	fillWithPattern(buffer.data(), pos, trailingPaddingSz, paddingPattern, patternSize);
189 
190 	return buffer;
191 }
192 
193 // Vertices in buffers will have 2 components and a padding to properly test the stride.
194 // This is the vertex type that will be used normally.
195 class VertexWithPadding : public VertexGenerator
196 {
197 protected:
198 	struct VertexData
199 	{
VertexDatavkt::pipeline::__anon8f7ea4da0111::VertexWithPadding::VertexData200 		VertexData(const tcu::Vec2& coords_)
201 			: coords	(coords_)
202 			, padding	(0.0f, 0.0f)
203 		{}
204 
205 		tcu::Vec2 coords;
206 		tcu::Vec2 padding;
207 	};
208 
209 public:
getAttributeDeclarations() const210 	virtual std::vector<std::string> getAttributeDeclarations() const override
211 	{
212 		std::vector<std::string> declarations;
213 		declarations.push_back("layout(location=0) in vec2 position;");
214 		return declarations;
215 	}
216 
getVertexCoordCalc() const217 	virtual std::vector<std::string> getVertexCoordCalc() const override
218 	{
219 		std::vector<std::string> statements;
220 		statements.push_back("vec2 vertexCoords = position;");
221 		return statements;
222 	}
223 
getAttributeDescriptions() const224 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
225 	{
226 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
227 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
228 		return descriptions;
229 	}
230 
231 	// Vertex attributes for VK_EXT_vertex_input_dynamic_state.
getAttributeDescriptions2() const232 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
233 	{
234 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
235 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
236 		return descriptions;
237 	}
238 
239 	// Vertex bindings for VkPipelineVertexInputStateCreateInfo.
getBindingDescriptions(const StrideVec & strides) const240 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
241 	{
242 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
243 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
244 		return descriptions;
245 	}
246 
247 	// Vertex bindings for VK_EXT_vertex_input_dynamic_state.
getBindingDescriptions2(const StrideVec & strides) const248 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
249 	{
250 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
251 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
252 		return descriptions;
253 	}
254 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const255 	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
256 	{
257 		return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
258 	}
259 
getVertexDataStrides() const260 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
261 	{
262 		return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
263 	}
264 };
265 
266 // Vertices with coordinates, padding and an extra constant field.
267 class VertexWithExtraAttributes : public VertexGenerator
268 {
269 protected:
270 	struct VertexData
271 	{
VertexDatavkt::pipeline::__anon8f7ea4da0111::VertexWithExtraAttributes::VertexData272 		VertexData (const tcu::Vec2& coords_)
273 			: coords	(coords_)
274 			, ones		(1.0f, 1.0f)
275 		{
276 			deMemset(padding, 0, sizeof(padding));
277 		}
278 
279 		tcu::Vec2 coords;
280 		tcu::Vec2 padding[10];
281 		tcu::Vec2 ones;
282 	};
283 
284 public:
getAttributeDeclarations() const285 	virtual std::vector<std::string> getAttributeDeclarations() const override
286 	{
287 		std::vector<std::string> declarations;
288 		declarations.push_back("layout(location=0) in vec2 position;");
289 		declarations.push_back("layout(location=1) in vec2 ones;");
290 		return declarations;
291 	}
292 
getVertexCoordCalc() const293 	virtual std::vector<std::string> getVertexCoordCalc() const override
294 	{
295 		std::vector<std::string> statements;
296 		statements.push_back("vec2 vertexCoords = position;");
297 		statements.push_back("vertexCoords = vertexCoords * ones;");
298 		return statements;
299 	}
300 
getAttributeDescriptions() const301 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
302 	{
303 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
304 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
305 		descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
306 		return descriptions;
307 	}
308 
getAttributeDescriptions2() const309 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
310 	{
311 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
312 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
313 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
314 		return descriptions;
315 	}
316 
getBindingDescriptions(const StrideVec & strides) const317 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
318 	{
319 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
320 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
321 		return descriptions;
322 	}
323 
getBindingDescriptions2(const StrideVec & strides) const324 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
325 	{
326 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
327 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
328 		return descriptions;
329 	}
330 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const331 	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
332 	{
333 		return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
334 	}
335 
getVertexDataStrides() const336 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
337 	{
338 		return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
339 	}
340 };
341 
342 // Vertices using multiple bindings and constant fields.
343 // Binding 0: no data actually used.
344 // Binding 1: contains location 0, array of PaddingOnes.
345 // Binding 2: no data actually used.
346 // Binding 3: contains location 1, array of CoordsData.
347 // Binding 4: no data actually used.
348 // Binding 5: contains location 2, array of OneZeroPadding.
349 // See getAttributeDeclarations().
350 class MultipleBindingsVertex : public VertexGenerator
351 {
352 protected:
353 	struct CoordsData
354 	{
355 		tcu::Vec2 padding0;
356 		tcu::Vec2 coords;
357 		tcu::Vec2 padding1;
358 
CoordsDatavkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::CoordsData359 		CoordsData (const tcu::Vec2& coords_)
360 			: padding0	(0.0f, 3.0f)
361 			, coords	(coords_)
362 			, padding1	(3.0f, 0.0f)
363 		{}
364 	};
365 
366 	struct PaddingOnes
367 	{
368 		tcu::Vec2 padding[4];
369 		tcu::Vec2 ones;
370 
PaddingOnesvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::PaddingOnes371 		PaddingOnes (const tcu::Vec2&)
372 			: ones	(1.0f, 1.0f)
373 		{
374 			deMemset(&padding, 0, sizeof(padding));
375 		}
376 	};
377 
378 	struct OneZeroPadding
379 	{
380 		tcu::Vec4 oneZero;
381 		tcu::Vec2 padding[3];
382 
OneZeroPaddingvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::OneZeroPadding383 		OneZeroPadding (const tcu::Vec2&)
384 			: oneZero	(1.0f, 1.0f, 0.0f, 0.0f)
385 		{
386 			deMemset(&padding, 0, sizeof(padding));
387 		}
388 	};
389 
390 	struct Zeros
391 	{
392 		tcu::Vec2 zeros;
393 
Zerosvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::Zeros394 		Zeros (const tcu::Vec2&)
395 			: zeros	(0.0f, 0.0f)
396 		{}
397 	};
398 
399 public:
getAttributeDeclarations() const400 	virtual std::vector<std::string> getAttributeDeclarations() const override
401 	{
402 		std::vector<std::string> declarations;
403 		declarations.reserve(3u);
404 
405 		declarations.push_back("layout(location=0) in vec2 ones;");
406 		declarations.push_back("layout(location=1) in vec2 position;");
407 		declarations.push_back("layout(location=2) in vec4 oneZero;");
408 
409 		return declarations;
410 	}
411 
getVertexCoordCalc() const412 	virtual std::vector<std::string> getVertexCoordCalc() const override
413 	{
414 		std::vector<std::string> statements;
415 		statements.reserve(2u);
416 
417 		statements.push_back("vec2 vertexCoords = position;");
418 		statements.push_back("vertexCoords = ((vertexCoords * ones) + oneZero.zw) * oneZero.xy;");
419 
420 		return statements;
421 	}
422 
getAttributeDescriptions() const423 	virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
424 	{
425 		// We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
426 		std::vector<vk::VkVertexInputAttributeDescription> descriptions;
427 		descriptions.reserve(3u);
428 
429 		descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
430 		descriptions.push_back(vk::makeVertexInputAttributeDescription(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
431 		descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
432 
433 		return descriptions;
434 	}
435 
getAttributeDescriptions2() const436 	virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
437 	{
438 		// We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
439 		std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
440 		descriptions.reserve(3u);
441 
442 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
443 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
444 		descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
445 
446 		return descriptions;
447 	}
448 
getBindingDescriptions(const StrideVec & strides) const449 	virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
450 	{
451 		// Provide descriptions out of order to make it more interesting.
452 		std::vector<vk::VkVertexInputBindingDescription> descriptions;
453 		descriptions.reserve(6u);
454 
455 		descriptions.push_back(vk::makeVertexInputBindingDescription(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
456 		descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
457 		descriptions.push_back(vk::makeVertexInputBindingDescription(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
458 		descriptions.push_back(vk::makeVertexInputBindingDescription(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
459 		descriptions.push_back(vk::makeVertexInputBindingDescription(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
460 		descriptions.push_back(vk::makeVertexInputBindingDescription(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
461 
462 		return descriptions;
463 	}
464 
getBindingDescriptions2(const StrideVec & strides) const465 	virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
466 	{
467 		// Provide descriptions out of order to make it more interesting.
468 		std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
469 		descriptions.reserve(6u);
470 
471 		descriptions.push_back(makeVertexInputBindingDescription2EXT(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
472 		descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
473 		descriptions.push_back(makeVertexInputBindingDescription2EXT(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
474 		descriptions.push_back(makeVertexInputBindingDescription2EXT(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
475 		descriptions.push_back(makeVertexInputBindingDescription2EXT(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
476 		descriptions.push_back(makeVertexInputBindingDescription2EXT(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
477 
478 		return descriptions;
479 	}
480 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const481 	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
482 	{
483 		std::vector<std::vector<deUint8>> result;
484 		result.reserve(6u);
485 
486 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
487 		result.push_back(createSingleBindingVertexData<PaddingOnes>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));		// Binding 1 contains location=0 as PaddingOnes.
488 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
489 		result.push_back(createSingleBindingVertexData<CoordsData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));		// Binding 3 contains location=1 as CoordsData.
490 		result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));			// Not actually used.
491 		result.push_back(createSingleBindingVertexData<OneZeroPadding>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));	// Binding 5 contains location=2 as OneZeroPadding.
492 
493 		return result;
494 	}
495 
getVertexDataStrides() const496 	virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
497 	{
498 		std::vector<vk::VkDeviceSize> strides;
499 		strides.reserve(6u);
500 
501 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
502 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(PaddingOnes)));
503 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
504 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(CoordsData)));
505 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
506 		strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(OneZeroPadding)));
507 
508 		return strides;
509 	}
510 };
511 
512 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
513 struct StencilOpParams
514 {
515 	vk::VkStencilFaceFlags  faceMask;
516 	vk::VkStencilOp         failOp;
517 	vk::VkStencilOp         passOp;
518 	vk::VkStencilOp         depthFailOp;
519 	vk::VkCompareOp         compareOp;
520 };
521 
522 const StencilOpParams kDefaultStencilOpParams =
523 {
524 	vk::VK_STENCIL_FACE_FRONT_AND_BACK,
525 	vk::VK_STENCIL_OP_KEEP,
526 	vk::VK_STENCIL_OP_KEEP,
527 	vk::VK_STENCIL_OP_KEEP,
528 	vk::VK_COMPARE_OP_ALWAYS
529 };
530 
531 struct DepthBiasParams
532 {
533 	float constantFactor;
534 	float clamp;
535 };
536 
537 const DepthBiasParams kNoDepthBiasParams = { 0.0f, 0.0f };
538 
539 using ViewportVec	= std::vector<vk::VkViewport>;
540 using ScissorVec	= std::vector<vk::VkRect2D>;
541 using StencilOpVec	= std::vector<StencilOpParams>;
542 
543 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
544 template<typename T>
545 struct StaticAndDynamicPair
546 {
547 	T				staticValue;
548 	tcu::Maybe<T>	dynamicValue;
549 
550 	// Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair551 	StaticAndDynamicPair (const T& value)
552 		: staticValue	(value)
553 		, dynamicValue	(tcu::Nothing)
554 	{
555 	}
556 
557 	// Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair558 	StaticAndDynamicPair (const T& sVal, const T& dVal)
559 		: staticValue	(sVal)
560 		, dynamicValue	(tcu::just<T>(dVal))
561 	{
562 	}
563 
564 	// If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair565 	void swapValues (void)
566 	{
567 		if (!dynamicValue)
568 			return;
569 		std::swap(staticValue, dynamicValue.get());
570 	}
571 };
572 
573 // For anything boolean, see below.
574 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
575 
576 // Configuration for every aspect of the extended dynamic state.
577 using CullModeConfig				= StaticAndDynamicPair<vk::VkCullModeFlags>;
578 using FrontFaceConfig				= StaticAndDynamicPair<vk::VkFrontFace>;
579 using TopologyConfig				= StaticAndDynamicPair<vk::VkPrimitiveTopology>;
580 using ViewportConfig				= StaticAndDynamicPair<ViewportVec>;	// At least one element.
581 using ScissorConfig					= StaticAndDynamicPair<ScissorVec>;		// At least one element.
582 using StrideConfig					= StaticAndDynamicPair<StrideVec>;		// At least one element.
583 using DepthTestEnableConfig			= BooleanFlagConfig;
584 using DepthWriteEnableConfig		= BooleanFlagConfig;
585 using DepthCompareOpConfig			= StaticAndDynamicPair<vk::VkCompareOp>;
586 using DepthBoundsTestEnableConfig	= BooleanFlagConfig;
587 using StencilTestEnableConfig		= BooleanFlagConfig;
588 using StencilOpConfig				= StaticAndDynamicPair<StencilOpVec>;	// At least one element.
589 using VertexGeneratorConfig			= StaticAndDynamicPair<const VertexGenerator*>;
590 using DepthBiasEnableConfig			= BooleanFlagConfig;
591 using RastDiscardEnableConfig		= BooleanFlagConfig;
592 using PrimRestartEnableConfig		= BooleanFlagConfig;
593 using LogicOpConfig					= StaticAndDynamicPair<vk::VkLogicOp>;
594 using PatchControlPointsConfig		= StaticAndDynamicPair<deUint8>;
595 using DepthBiasConfig				= StaticAndDynamicPair<DepthBiasParams>;
596 
597 const tcu::Vec4		kDefaultTriangleColor	(0.0f, 0.0f, 1.0f, 1.0f);	// Opaque blue.
598 const tcu::Vec4		kDefaultClearColor		(0.0f, 0.0f, 0.0f, 1.0f);	// Opaque black.
599 
600 const tcu::Vec4		kLogicOpTriangleColor	(0.0f, 0.0f,255.f,255.f);	// Opaque blue. Note: tcu::Vec4 and will be cast to the appropriate type in the shader.
601 const tcu::UVec4	kGreenClearColor		(  0u, 255u,   0u, 255u);	// Opaque green, UINT.
602 const tcu::UVec4	kLogicOpFinalColor		(  0u, 255u, 255u, 255u);	// Opaque cyan, UINT.
603 
604 struct MeshParams
605 {
606 	tcu::Vec4	color;
607 	float		depth;
608 	bool		reversed;
609 	float		scaleX;
610 	float		scaleY;
611 	float		offsetX;
612 	float		offsetY;
613 	float		stripScale;
614 
MeshParamsvkt::pipeline::__anon8f7ea4da0111::MeshParams615 	MeshParams (const tcu::Vec4&	color_		= kDefaultTriangleColor,
616 				float				depth_		= 0.0f,
617 				bool				reversed_	= false,
618 				float				scaleX_		= 1.0f,
619 				float				scaleY_		= 1.0f,
620 				float				offsetX_	= 0.0f,
621 				float				offsetY_	= 0.0f,
622 				float				stripScale_	= 0.0f)
623 		: color			(color_)
624 		, depth			(depth_)
625 		, reversed		(reversed_)
626 		, scaleX		(scaleX_)
627 		, scaleY		(scaleY_)
628 		, offsetX		(offsetX_)
629 		, offsetY		(offsetY_)
630 		, stripScale	(stripScale_)
631 	{}
632 };
633 
634 enum class SequenceOrdering
635 {
636 	CMD_BUFFER_START	= 0,	// Set state at the start of the command buffer.
637 	BEFORE_DRAW			= 1,	// After binding dynamic pipeline and just before drawing.
638 	BETWEEN_PIPELINES	= 2,	// After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
639 	AFTER_PIPELINES		= 3,	// After a static state pipeline and a second dynamic state pipeline have been bound.
640 	BEFORE_GOOD_STATIC	= 4,	// Before a static state pipeline with the correct values has been bound.
641 	TWO_DRAWS_DYNAMIC	= 5,	// Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
642 	TWO_DRAWS_STATIC	= 6,	// Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
643 };
644 
645 using ReferenceColorGenerator = std::function<void(tcu::PixelBufferAccess&)>;
646 
647 // Most tests expect a single output color in the whole image.
648 class SingleColorGenerator
649 {
650 public:
SingleColorGenerator(const tcu::Vec4 & color)651 	SingleColorGenerator (const tcu::Vec4& color)
652 		: m_colorFloat	(color)
653 		, m_colorUint	(0u)
654 		, isUint		(false)
655 	{}
656 
SingleColorGenerator(const tcu::UVec4 & color)657 	SingleColorGenerator (const tcu::UVec4& color)
658 		: m_colorFloat	(0.0f)
659 		, m_colorUint	(color)
660 		, isUint		(true)
661 	{}
662 
operator ()(tcu::PixelBufferAccess & access)663 	void operator()(tcu::PixelBufferAccess& access)
664 	{
665 		constexpr auto kWidth	= static_cast<int>(kFramebufferWidth);
666 		constexpr auto kHeight	= static_cast<int>(kFramebufferHeight);
667 
668 		for (int y = 0; y < kHeight; ++y)
669 		for (int x = 0; x < kWidth; ++x)
670 		{
671 			if (isUint)
672 				access.setPixel(m_colorUint, x, y);
673 			else
674 				access.setPixel(m_colorFloat, x, y);
675 		}
676 	}
677 
678 private:
679 	const tcu::Vec4		m_colorFloat;
680 	const tcu::UVec4	m_colorUint;
681 	const bool			isUint;
682 };
683 
684 // Some tests expect the upper half and the lower half having different color values.
685 class HorizontalSplitGenerator
686 {
687 public:
HorizontalSplitGenerator(const tcu::Vec4 & top,const tcu::Vec4 & bottom)688 	HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
689 		: m_top(top), m_bottom(bottom)
690 	{}
691 
operator ()(tcu::PixelBufferAccess & access)692 	void operator()(tcu::PixelBufferAccess& access)
693 	{
694 		constexpr auto kWidth		= static_cast<int>(kFramebufferWidth);
695 		constexpr auto kHeight		= static_cast<int>(kFramebufferHeight);
696 		constexpr auto kHalfHeight	= kHeight / 2;
697 
698 		for (int y = 0; y < kHeight; ++y)
699 		for (int x = 0; x < kWidth; ++x)
700 		{
701 			const auto& color = (y < kHalfHeight ? m_top : m_bottom);
702 			access.setPixel(color, x, y);
703 		}
704 	}
705 
706 private:
707 	const tcu::Vec4 m_top;
708 	const tcu::Vec4 m_bottom;
709 };
710 
getVertexWithPaddingGenerator()711 const VertexGenerator* getVertexWithPaddingGenerator ()
712 {
713 	static const VertexWithPadding vertexWithPadding;
714 	return &vertexWithPadding;
715 }
716 
getVertexWithExtraAttributesGenerator()717 const VertexGenerator* getVertexWithExtraAttributesGenerator ()
718 {
719 	static const VertexWithExtraAttributes vertexWithExtraAttributes;
720 	return &vertexWithExtraAttributes;
721 }
722 
getVertexWithMultipleBindingsGenerator()723 const VertexGenerator* getVertexWithMultipleBindingsGenerator ()
724 {
725 	static const MultipleBindingsVertex multipleBindingsVertex;
726 	return &multipleBindingsVertex;
727 }
728 
729 // Create VertexGeneratorConfig varying constructor depending on having none, only the static or both.
makeVertexGeneratorConfig(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)730 VertexGeneratorConfig makeVertexGeneratorConfig (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
731 {
732 	DE_ASSERT(!(dynamicGen && !staticGen));
733 	if (dynamicGen)
734 		return VertexGeneratorConfig(staticGen, dynamicGen);
735 	if (staticGen)
736 		return VertexGeneratorConfig(staticGen);
737 	return VertexGeneratorConfig(getVertexWithPaddingGenerator());	// Only static part with a default option.c
738 }
739 
740 // Similar to makeVertexGeneratorConfig, choosing the final value.
chooseVertexGenerator(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)741 const VertexGenerator* chooseVertexGenerator (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
742 {
743 	DE_ASSERT(!(dynamicGen && !staticGen));
744 	if (dynamicGen)
745 		return dynamicGen;
746 	if (staticGen)
747 		return staticGen;
748 	return getVertexWithPaddingGenerator();
749 }
750 
751 enum class TopologyClass
752 {
753 	POINT,
754 	LINE,
755 	TRIANGLE,
756 	PATCH,
757 	INVALID,
758 };
759 
topologyClassName(TopologyClass tclass)760 std::string topologyClassName (TopologyClass tclass)
761 {
762 	switch (tclass)
763 	{
764 	case TopologyClass::POINT:		return "point";
765 	case TopologyClass::LINE:		return "line";
766 	case TopologyClass::TRIANGLE:	return "triangle";
767 	case TopologyClass::PATCH:		return "patch";
768 	default:
769 		break;
770 	}
771 
772 	DE_ASSERT(false);
773 	return "";
774 }
775 
getTopologyClass(vk::VkPrimitiveTopology topology)776 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
777 {
778 	switch (topology)
779 	{
780 	case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
781 		return TopologyClass::POINT;
782 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
783 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
784 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
785 	case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
786 		return TopologyClass::LINE;
787 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
788 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
789 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
790 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
791 	case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
792 		return TopologyClass::TRIANGLE;
793 	case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
794 		return TopologyClass::PATCH;
795 	default:
796 		break;
797 	}
798 
799 	DE_ASSERT(false);
800 	return TopologyClass::INVALID;
801 }
802 
803 struct TestConfig
804 {
805 	// Main sequence ordering.
806 	SequenceOrdering			sequenceOrdering;
807 
808 	// Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
809 	std::vector<MeshParams>		meshParams;			// Mesh parameters for each full-screen layer of geometry.
810 	deUint32					referenceStencil;	// Reference stencil value.
811 
812 	// Clearing parameters for the framebuffer.
813 	vk::VkClearValue			clearColorValue;
814 	float						clearDepthValue;
815 	deUint32					clearStencilValue;
816 
817 	// Expected output in the attachments.
818 	ReferenceColorGenerator		referenceColor;
819 	float						expectedDepth;
820 	deUint32					expectedStencil;
821 
822 	// Depth bounds parameters for the pipeline.
823 	float						minDepthBounds;
824 	float						maxDepthBounds;
825 
826 	// Force inclusion of passthrough geometry shader or not.
827 	bool						forceGeometryShader;
828 
829 	// Force single vertex in the VBO.
830 	bool						singleVertex;
831 	deUint32					singleVertexDrawCount;
832 
833 	// Offset and extra room after the vertex buffer data.
834 	vk::VkDeviceSize			vertexDataOffset;
835 	vk::VkDeviceSize			vertexDataExtraBytes;
836 
837 	// Static and dynamic pipeline configuration.
838 	VertexGeneratorConfig		vertexGenerator;
839 	CullModeConfig				cullModeConfig;
840 	FrontFaceConfig				frontFaceConfig;
841 	TopologyConfig				topologyConfig;
842 	ViewportConfig				viewportConfig;
843 	ScissorConfig				scissorConfig;
844 	StrideConfig				strideConfig;
845 	DepthTestEnableConfig		depthTestEnableConfig;
846 	DepthWriteEnableConfig		depthWriteEnableConfig;
847 	DepthCompareOpConfig		depthCompareOpConfig;
848 	DepthBoundsTestEnableConfig	depthBoundsTestEnableConfig;
849 	StencilTestEnableConfig		stencilTestEnableConfig;
850 	StencilOpConfig				stencilOpConfig;
851 	DepthBiasEnableConfig		depthBiasEnableConfig;
852 	RastDiscardEnableConfig		rastDiscardEnableConfig;
853 	PrimRestartEnableConfig		primRestartEnableConfig;
854 	LogicOpConfig				logicOpConfig;
855 	PatchControlPointsConfig	patchControlPointsConfig;
856 	DepthBiasConfig				depthBiasConfig;
857 
858 	// Sane defaults.
TestConfigvkt::pipeline::__anon8f7ea4da0111::TestConfig859 	TestConfig (SequenceOrdering ordering, const VertexGenerator* staticVertexGenerator = nullptr, const VertexGenerator* dynamicVertexGenerator = nullptr)
860 		: sequenceOrdering				(ordering)
861 		, meshParams					(1u, MeshParams())
862 		, referenceStencil				(0u)
863 		, clearColorValue				(vk::makeClearValueColor(kDefaultClearColor))
864 		, clearDepthValue				(1.0f)
865 		, clearStencilValue				(0u)
866 		, referenceColor				(SingleColorGenerator(kDefaultTriangleColor))
867 		, expectedDepth					(1.0f)
868 		, expectedStencil				(0u)
869 		, minDepthBounds				(0.0f)
870 		, maxDepthBounds				(1.0f)
871 		, forceGeometryShader			(false)
872 		, singleVertex					(false)
873 		, singleVertexDrawCount			(0)
874 		, vertexDataOffset				(0ull)
875 		, vertexDataExtraBytes			(0ull)
876 		, vertexGenerator				(makeVertexGeneratorConfig(staticVertexGenerator, dynamicVertexGenerator))
877 		, cullModeConfig				(static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
878 		, frontFaceConfig				(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
879 		// By default we will use a triangle strip with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
880 		, topologyConfig				(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
881 		, viewportConfig				(ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
882 		, scissorConfig					(ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
883 		// By default, the vertex stride is the size of a vertex according to the chosen vertex type.
884 		, strideConfig					(chooseVertexGenerator(staticVertexGenerator, dynamicVertexGenerator)->getVertexDataStrides())
885 		, depthTestEnableConfig			(false)
886 		, depthWriteEnableConfig		(false)
887 		, depthCompareOpConfig			(vk::VK_COMPARE_OP_NEVER)
888 		, depthBoundsTestEnableConfig	(false)
889 		, stencilTestEnableConfig		(false)
890 		, stencilOpConfig				(StencilOpVec(1u, kDefaultStencilOpParams))
891 		, depthBiasEnableConfig			(false)
892 		, rastDiscardEnableConfig		(false)
893 		, primRestartEnableConfig		(false)
894 		, logicOpConfig					(vk::VK_LOGIC_OP_CLEAR)
895 		, patchControlPointsConfig		(1u)
896 		, depthBiasConfig				(kNoDepthBiasParams)
897 		, m_swappedValues				(false)
898 	{
899 	}
900 
901 	// Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anon8f7ea4da0111::TestConfig902 	const ViewportVec& getActiveViewportVec () const
903 	{
904 		return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() : viewportConfig.staticValue);
905 	}
906 
907 	// Gets the proper vertex generator according to the test config.
getActiveVertexGeneratorvkt::pipeline::__anon8f7ea4da0111::TestConfig908 	const VertexGenerator* getActiveVertexGenerator () const
909 	{
910 		return ((vertexGenerator.dynamicValue && !m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
911 	}
912 
913 	// Gets the inactive vertex generator according to the test config. If there's only one, return that.
getInactiveVertexGeneratorvkt::pipeline::__anon8f7ea4da0111::TestConfig914 	const VertexGenerator* getInactiveVertexGenerator () const
915 	{
916 		return ((vertexGenerator.dynamicValue && m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
917 	}
918 
919 	// Get the active number of patch control points according to the test config.
getActivePatchControlPointsvkt::pipeline::__anon8f7ea4da0111::TestConfig920 	deUint32 getActivePatchControlPoints () const
921 	{
922 		return ((patchControlPointsConfig.dynamicValue && !m_swappedValues) ? patchControlPointsConfig.dynamicValue.get() : patchControlPointsConfig.staticValue);
923 	}
924 
925 	// Get the active depth bias parameters.
getActiveDepthBiasParamsvkt::pipeline::__anon8f7ea4da0111::TestConfig926 	DepthBiasParams getActiveDepthBiasParams () const
927 	{
928 		return ((depthBiasConfig.dynamicValue && !m_swappedValues) ? depthBiasConfig.dynamicValue.get() : depthBiasConfig.staticValue);
929 	}
930 
931 	// Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anon8f7ea4da0111::TestConfig932 	bool isMultiViewport () const
933 	{
934 		return (getActiveViewportVec().size() > 1);
935 	}
936 
937 	// Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anon8f7ea4da0111::TestConfig938 	bool needsGeometryShader () const
939 	{
940 		// Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
941 		// commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
942 		return (isMultiViewport() || forceGeometryShader);
943 	}
944 
945 	// Returns true if we should use the static and dynamic values exchanged.
946 	// This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon8f7ea4da0111::TestConfig947 	bool isReversed () const
948 	{
949 		return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
950 				sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
951 	}
952 
953 	// Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon8f7ea4da0111::TestConfig954 	void swapValues ()
955 	{
956 		vertexGenerator.swapValues();
957 		cullModeConfig.swapValues();
958 		frontFaceConfig.swapValues();
959 		topologyConfig.swapValues();
960 		viewportConfig.swapValues();
961 		scissorConfig.swapValues();
962 		strideConfig.swapValues();
963 		depthTestEnableConfig.swapValues();
964 		depthWriteEnableConfig.swapValues();
965 		depthCompareOpConfig.swapValues();
966 		depthBoundsTestEnableConfig.swapValues();
967 		stencilTestEnableConfig.swapValues();
968 		stencilOpConfig.swapValues();
969 		depthBiasEnableConfig.swapValues();
970 		rastDiscardEnableConfig.swapValues();
971 		primRestartEnableConfig.swapValues();
972 		logicOpConfig.swapValues();
973 		patchControlPointsConfig.swapValues();
974 		depthBiasConfig.swapValues();
975 
976 		m_swappedValues = !m_swappedValues;
977 	}
978 
979 	// Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon8f7ea4da0111::TestConfig980 	deUint32 numIterations () const
981 	{
982 		deUint32 iterations = 0u;
983 
984 		switch (sequenceOrdering)
985 		{
986 		case SequenceOrdering::TWO_DRAWS_DYNAMIC:
987 		case SequenceOrdering::TWO_DRAWS_STATIC:
988 			iterations = 2u;
989 			break;
990 		default:
991 			iterations = 1u;
992 			break;
993 		}
994 
995 		return iterations;
996 	}
997 
998 	// Returns true if we're testing the logic op.
testLogicOpvkt::pipeline::__anon8f7ea4da0111::TestConfig999 	bool testLogicOp () const
1000 	{
1001 		return static_cast<bool>(logicOpConfig.dynamicValue);
1002 	}
1003 
1004 	// Returns true if we're testing the patch control points.
testPatchControlPointsvkt::pipeline::__anon8f7ea4da0111::TestConfig1005 	bool testPatchControlPoints () const
1006 	{
1007 		return static_cast<bool>(patchControlPointsConfig.dynamicValue);
1008 	}
1009 
1010 	// Returns true if the topology class is patches for tessellation.
patchesTopologyvkt::pipeline::__anon8f7ea4da0111::TestConfig1011 	bool patchesTopology () const
1012 	{
1013 		return (getTopologyClass(topologyConfig.staticValue) == TopologyClass::PATCH);
1014 	}
1015 
1016 	// Returns true if the test needs tessellation shaders.
needsTessellationvkt::pipeline::__anon8f7ea4da0111::TestConfig1017 	bool needsTessellation () const
1018 	{
1019 		return (testPatchControlPoints() || patchesTopology());
1020 	}
1021 
1022 	// Returns true if the test needs an index buffer.
needsIndexBuffervkt::pipeline::__anon8f7ea4da0111::TestConfig1023 	bool needsIndexBuffer () const
1024 	{
1025 		return static_cast<bool>(primRestartEnableConfig.dynamicValue);
1026 	}
1027 
1028 	// Returns true if the test needs the depth bias clamp feature.
needsDepthBiasClampFeaturevkt::pipeline::__anon8f7ea4da0111::TestConfig1029 	bool needsDepthBiasClampFeature () const
1030 	{
1031 		return (getActiveDepthBiasParams().clamp != 0.0f);
1032 	}
1033 
1034 	// Returns the appropriate color image format for the test.
colorFormatvkt::pipeline::__anon8f7ea4da0111::TestConfig1035 	vk::VkFormat colorFormat () const
1036 	{
1037 		// Pick int color format when testing logic op.
1038 		return (testLogicOp() ? kIntColorFormat : kUnormColorFormat);
1039 	}
1040 
1041 	// Returns the list of dynamic states affected by this config.
getDynamicStatesvkt::pipeline::__anon8f7ea4da0111::TestConfig1042 	std::vector<vk::VkDynamicState> getDynamicStates () const
1043 	{
1044 		std::vector<vk::VkDynamicState> dynamicStates;
1045 
1046 		if (depthBiasConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS);
1047 		if (cullModeConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
1048 		if (frontFaceConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
1049 		if (topologyConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
1050 		if (viewportConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
1051 		if (scissorConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
1052 		if (strideConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
1053 		if (depthTestEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
1054 		if (depthWriteEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
1055 		if (depthCompareOpConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
1056 		if (depthBoundsTestEnableConfig.dynamicValue)	dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
1057 		if (stencilTestEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
1058 		if (stencilOpConfig.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
1059 		if (vertexGenerator.dynamicValue)				dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
1060 		if (patchControlPointsConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
1061 		if (rastDiscardEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
1062 		if (depthBiasEnableConfig.dynamicValue)			dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
1063 		if (logicOpConfig.dynamicValue)					dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
1064 		if (primRestartEnableConfig.dynamicValue)		dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
1065 
1066 		return dynamicStates;
1067 	}
1068 
1069 	// Returns the list of extensions needed by this config.
getRequiredExtensionsvkt::pipeline::__anon8f7ea4da0111::TestConfig1070 	std::vector<std::string> getRequiredExtensions () const
1071 	{
1072 		std::vector<std::string> extensions;
1073 
1074 		if (cullModeConfig.dynamicValue
1075 		    || frontFaceConfig.dynamicValue
1076 		    || topologyConfig.dynamicValue
1077 		    || viewportConfig.dynamicValue
1078 		    || scissorConfig.dynamicValue
1079 		    || strideConfig.dynamicValue
1080 		    || depthTestEnableConfig.dynamicValue
1081 		    || depthWriteEnableConfig.dynamicValue
1082 		    || depthCompareOpConfig.dynamicValue
1083 		    || depthBoundsTestEnableConfig.dynamicValue
1084 		    || stencilTestEnableConfig.dynamicValue
1085 		    || stencilOpConfig.dynamicValue)
1086 		{
1087 			extensions.push_back("VK_EXT_extended_dynamic_state");
1088 		}
1089 
1090 		if (vertexGenerator.dynamicValue)
1091 		{
1092 			extensions.push_back("VK_EXT_vertex_input_dynamic_state");
1093 		}
1094 
1095 		if (patchControlPointsConfig.dynamicValue
1096 		    || rastDiscardEnableConfig.dynamicValue
1097 		    || depthBiasEnableConfig.dynamicValue
1098 		    || logicOpConfig.dynamicValue
1099 		    || primRestartEnableConfig.dynamicValue)
1100 		{
1101 			extensions.push_back("VK_EXT_extended_dynamic_state2");
1102 		}
1103 
1104 		return extensions;
1105 	}
1106 
1107 private:
1108 	// Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
1109 	// has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
1110 	// expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
1111 	// pipeline with wrong values and a static one with good values.
1112 	//
1113 	// Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
1114 	// 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
1115 	// given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
1116 	bool m_swappedValues;
1117 };
1118 
1119 struct PushConstants
1120 {
1121 	tcu::Vec4	triangleColor;
1122 	float		meshDepth;
1123 	deInt32		viewPortIndex;
1124 	float		scaleX;
1125 	float		scaleY;
1126 	float		offsetX;
1127 	float		offsetY;
1128 	float		stripScale;
1129 };
1130 
copy(vk::VkStencilOpState & dst,const StencilOpParams & src)1131 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
1132 {
1133 	dst.failOp		= src.failOp;
1134 	dst.passOp		= src.passOp;
1135 	dst.depthFailOp	= src.depthFailOp;
1136 	dst.compareOp	= src.compareOp;
1137 }
1138 
1139 class ExtendedDynamicStateTest : public vkt::TestCase
1140 {
1141 public:
1142 							ExtendedDynamicStateTest		(tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ExtendedDynamicStateTest(void)1143 	virtual					~ExtendedDynamicStateTest		(void) {}
1144 
1145 	virtual void			checkSupport					(Context& context) const;
1146 	virtual void			initPrograms					(vk::SourceCollections& programCollection) const;
1147 	virtual TestInstance*	createInstance					(Context& context) const;
1148 
1149 private:
1150 	TestConfig				m_testConfig;
1151 };
1152 
1153 class ExtendedDynamicStateInstance : public vkt::TestInstance
1154 {
1155 public:
1156 								ExtendedDynamicStateInstance	(Context& context, const TestConfig& testConfig);
~ExtendedDynamicStateInstance(void)1157 	virtual						~ExtendedDynamicStateInstance	(void) {}
1158 
1159 	virtual tcu::TestStatus		iterate							(void);
1160 
1161 private:
1162 	TestConfig					m_testConfig;
1163 };
1164 
ExtendedDynamicStateTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)1165 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
1166 	: vkt::TestCase	(testCtx, name, description)
1167 	, m_testConfig	(testConfig)
1168 {
1169 	const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
1170 	DE_UNREF(staticTopologyClass); // For release builds.
1171 
1172 	// Matching topology classes.
1173 	DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
1174 			  staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
1175 
1176 	// Supported topology classes for these tests.
1177 	DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE
1178 		|| staticTopologyClass == TopologyClass::PATCH);
1179 
1180 	// Make sure these are consistent.
1181 	DE_ASSERT(!(m_testConfig.testPatchControlPoints() && !m_testConfig.patchesTopology()));
1182 	DE_ASSERT(!(m_testConfig.patchesTopology() && m_testConfig.getActivePatchControlPoints() <= 1u));
1183 }
1184 
checkSupport(Context & context) const1185 void ExtendedDynamicStateTest::checkSupport (Context& context) const
1186 {
1187 	const auto&	vki				= context.getInstanceInterface();
1188 	const auto	physicalDevice	= context.getPhysicalDevice();
1189 
1190 	// Check extension support.
1191 	const auto requiredExtensions = m_testConfig.getRequiredExtensions();
1192 	for (const auto& extension : requiredExtensions)
1193 		context.requireDeviceFunctionality(extension);
1194 
1195 	// Needed for extended state included as part of VK_EXT_extended_dynamic_state2.
1196 	if (de::contains(begin(requiredExtensions), end(requiredExtensions), "VK_EXT_extended_dynamic_state2"))
1197 	{
1198 		const auto& eds2Features = context.getExtendedDynamicState2FeaturesEXT();
1199 
1200 		if (m_testConfig.testLogicOp() && !eds2Features.extendedDynamicState2LogicOp)
1201 			TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing LogicOp dynamically is not supported");
1202 
1203 		if (m_testConfig.testPatchControlPoints() && !eds2Features.extendedDynamicState2PatchControlPoints)
1204 			TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing patch control points dynamically is not supported");
1205 	}
1206 
1207 	// Check the number of viewports needed and the corresponding limits.
1208 	const auto&	viewportConfig	= m_testConfig.viewportConfig;
1209 	auto		numViewports	= viewportConfig.staticValue.size();
1210 
1211 	if (viewportConfig.dynamicValue)
1212 		numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
1213 
1214 	if (numViewports > 1)
1215 	{
1216 		const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
1217 		if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
1218 			TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
1219 	}
1220 
1221 	const auto&	dbTestEnable	= m_testConfig.depthBoundsTestEnableConfig;
1222 	const bool	useDepthBounds	= (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
1223 
1224 	if (useDepthBounds || m_testConfig.needsGeometryShader() || m_testConfig.needsTessellation() || m_testConfig.needsDepthBiasClampFeature())
1225 	{
1226 		const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
1227 
1228 		// Check depth bounds test support.
1229 		if (useDepthBounds && !features.depthBounds)
1230 			TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
1231 
1232 		// Check geometry shader support.
1233 		if (m_testConfig.needsGeometryShader() && !features.geometryShader)
1234 			TCU_THROW(NotSupportedError, "Geometry shader not supported");
1235 
1236 		// Check tessellation support
1237 		if (m_testConfig.needsTessellation() && !features.tessellationShader)
1238 			TCU_THROW(NotSupportedError, "Tessellation feature not supported");
1239 
1240 		// Check depth bias clamp feature.
1241 		if (m_testConfig.needsDepthBiasClampFeature() && !features.depthBiasClamp)
1242 			TCU_THROW(NotSupportedError, "Depth bias clamp not supported");
1243 	}
1244 
1245 	// Check color image format support (depth/stencil will be chosen at runtime).
1246 	const vk::VkFormatFeatureFlags	kColorFeatures	= (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1247 
1248 	// Pick int color format for logic op
1249 	vk::VkFormat					colorFormat		= m_testConfig.colorFormat();
1250 	const auto						colorProperties	= vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, colorFormat);
1251 
1252 	if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
1253 		TCU_THROW(NotSupportedError, "Required color image features not supported");
1254 }
1255 
initPrograms(vk::SourceCollections & programCollection) const1256 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
1257 {
1258 	std::ostringstream pushSource;
1259 	std::ostringstream vertSourceTemplateStream;
1260 	std::ostringstream fragSource;
1261 	std::ostringstream geomSource;
1262 	std::ostringstream tescSource;
1263 	std::ostringstream teseSource;
1264 
1265 	pushSource
1266 		<< "layout(push_constant, std430) uniform PushConstantsBlock {\n"
1267 		<< "    vec4  triangleColor;\n"
1268 		<< "    float depthValue;\n"
1269 		<< "    int   viewPortIndex;\n"
1270 		<< "    float scaleX;\n"
1271 		<< "    float scaleY;\n"
1272 		<< "    float offsetX;\n"
1273 		<< "    float offsetY;\n"
1274 		<< "    float stripScale;\n"
1275 		<< "} pushConstants;\n"
1276 		;
1277 	const auto pushConstants = pushSource.str();
1278 
1279 	// The actual generator, attributes and calculations.
1280 	const auto			activeGen	= m_testConfig.getActiveVertexGenerator();
1281 	const auto			attribDecls	= activeGen->getAttributeDeclarations();
1282 	const auto			coordCalcs	= activeGen->getVertexCoordCalc();
1283 
1284 	// The static generator, attributes and calculations, for the static pipeline, if needed.
1285 	const auto			inactiveGen		= m_testConfig.getInactiveVertexGenerator();
1286 	const auto			staticAttribDec	= inactiveGen->getAttributeDeclarations();
1287 	const auto			staticCoordCalc	= inactiveGen->getVertexCoordCalc();
1288 
1289 	std::ostringstream	activeAttribs;
1290 	std::ostringstream	activeCalcs;
1291 	std::ostringstream	inactiveAttribs;
1292 	std::ostringstream	inactiveCalcs;
1293 
1294 	for (const auto& decl : attribDecls)
1295 		activeAttribs << decl << "\n";
1296 
1297 	for (const auto& statement : coordCalcs)
1298 		activeCalcs << "    " << statement << "\n";
1299 
1300 	for (const auto& decl : staticAttribDec)
1301 		inactiveAttribs << decl << "\n";
1302 
1303 	for (const auto& statement : staticCoordCalc)
1304 		inactiveCalcs << "    " << statement << "\n";
1305 
1306 	vertSourceTemplateStream
1307 		<< "#version 450\n"
1308 		<< pushConstants
1309 		<< "${ATTRIBUTES}"
1310 		<< "out gl_PerVertex\n"
1311 		<< "{\n"
1312 		<< "    vec4 gl_Position;\n"
1313 		<< "};\n"
1314 		<< "void main() {\n"
1315 		<< "${CALCULATIONS}"
1316 		<< "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
1317 		<< "    vec2 stripOffset;\n"
1318 		<< "    switch (gl_VertexIndex) {\n"
1319 		<< "    case 0: stripOffset = vec2(0.0, 0.0); break;\n"
1320 		<< "    case 1: stripOffset = vec2(0.0, 1.0); break;\n"
1321 		<< "    case 2: stripOffset = vec2(1.0, 0.0); break;\n"
1322 		<< "    case 3: stripOffset = vec2(1.0, 1.0); break;\n"
1323 		<< "    case 4: stripOffset = vec2(2.0, 0.0); break;\n"
1324 		<< "    case 5: stripOffset = vec2(2.0, 1.0); break;\n"
1325 		<< "    default: stripOffset = vec2(-1000.0); break;\n"
1326 		<< "    }\n"
1327 		<< "    gl_Position.xy += pushConstants.stripScale * stripOffset;\n"
1328 		<< "}\n"
1329 		;
1330 
1331 	tcu::StringTemplate vertSourceTemplate (vertSourceTemplateStream.str());
1332 
1333 	std::map<std::string, std::string> activeMap;
1334 	std::map<std::string, std::string> inactiveMap;
1335 
1336 	activeMap["ATTRIBUTES"]		= activeAttribs.str();
1337 	activeMap["CALCULATIONS"]	= activeCalcs.str();
1338 
1339 	inactiveMap["ATTRIBUTES"]	= inactiveAttribs.str();
1340 	inactiveMap["CALCULATIONS"]	= inactiveCalcs.str();
1341 
1342 	const auto activeVertSource		= vertSourceTemplate.specialize(activeMap);
1343 	const auto inactiveVertSource	= vertSourceTemplate.specialize(inactiveMap);
1344 
1345 	const auto colorFormat	= m_testConfig.colorFormat();
1346 	const auto vecType		= (vk::isUnormFormat(colorFormat) ? "vec4" : "uvec4");
1347 
1348 	fragSource
1349 		<< "#version 450\n"
1350 		<< pushConstants
1351 		<< "layout(location=0) out " << vecType << " color;\n"
1352 		<< "void main() {\n"
1353 		<< "    color = " << vecType << "(pushConstants.triangleColor);\n"
1354 		<< "}\n"
1355 		;
1356 
1357 	if (m_testConfig.needsGeometryShader())
1358 	{
1359 		const auto			topologyClass	= getTopologyClass(m_testConfig.topologyConfig.staticValue);
1360 		const std::string	inputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
1361 		const deUint32		vertexCount		= ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
1362 		const std::string	outputPrimitive	= ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
1363 
1364 		geomSource
1365 			<< "#version 450\n"
1366 			<< "layout (" << inputPrimitive << ") in;\n"
1367 			<< "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
1368 			<< (m_testConfig.isMultiViewport() ? pushConstants : "")
1369 			<< "in gl_PerVertex\n"
1370 			<< "{\n"
1371 			<< "    vec4 gl_Position;\n"
1372 			<< "} gl_in[" << vertexCount << "];\n"
1373 			<< "out gl_PerVertex\n"
1374 			<< "{\n"
1375 			<< "    vec4 gl_Position;\n"
1376 			<< "};\n"
1377 			<< "void main() {\n"
1378 			<< (m_testConfig.isMultiViewport() ? "    gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "")
1379 			;
1380 
1381 		for (deUint32 i = 0; i < vertexCount; ++i)
1382 		{
1383 			geomSource
1384 				<< "    gl_Position = gl_in[" << i << "].gl_Position;\n"
1385 				<< "    EmitVertex();\n"
1386 				;
1387 		}
1388 
1389 		geomSource
1390 			<< "}\n"
1391 			;
1392 	}
1393 
1394 	if (m_testConfig.needsTessellation())
1395 	{
1396 		tescSource
1397 			<< "#version 450\n"
1398 			<< "#extension GL_EXT_tessellation_shader : require\n"
1399 			<< "layout(vertices=3) out;\n"
1400 			<< "in gl_PerVertex\n"
1401 			<< "{\n"
1402 			<< "    vec4 gl_Position;\n"
1403 			<< "} gl_in[gl_MaxPatchVertices];\n"
1404 			<< "out gl_PerVertex\n"
1405 			<< "{\n"
1406 			<< "  vec4 gl_Position;\n"
1407 			<< "} gl_out[];\n"
1408 			<< "void main() {\n"
1409 			<< "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1410 			<< "  gl_TessLevelOuter[0] = 3.0;\n"
1411 			<< "  gl_TessLevelOuter[1] = 3.0;\n"
1412 			<< "  gl_TessLevelOuter[2] = 3.0;\n"
1413 			<< "  gl_TessLevelInner[0] = 3.0;\n"
1414 			<< "}\n"
1415 			;
1416 		teseSource
1417 			<< "#version 450\n"
1418 			<< "#extension GL_EXT_tessellation_shader : require\n"
1419 			<< "layout(triangles) in;\n"
1420 			<< "in gl_PerVertex\n"
1421 			<< "{\n"
1422 			<< "  vec4 gl_Position;\n"
1423 			<< "} gl_in[gl_MaxPatchVertices];\n"
1424 			<< "out gl_PerVertex\n"
1425 			<< "{\n"
1426 			<< "  vec4 gl_Position;\n"
1427 			<< "};\n"
1428 			<< "void main() {\n"
1429 			<< "  gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
1430 			<< "                 gl_in[1].gl_Position * gl_TessCoord.y + \n"
1431 			<< "                 gl_in[2].gl_Position * gl_TessCoord.z);\n"
1432 			<< "}\n";
1433 	}
1434 
1435 	// In reversed test configurations, the pipeline with dynamic state needs to have the inactive shader.
1436 	const auto kReversed = m_testConfig.isReversed();
1437 	programCollection.glslSources.add("dynamicVert") << glu::VertexSource(kReversed ? inactiveVertSource : activeVertSource);
1438 	programCollection.glslSources.add("staticVert") << glu::VertexSource(kReversed ? activeVertSource : inactiveVertSource);
1439 
1440 	programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
1441 	if (m_testConfig.needsGeometryShader())
1442 		programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
1443 	if (m_testConfig.needsTessellation())
1444 	{
1445 		programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
1446 		programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
1447 	}
1448 }
1449 
createInstance(Context & context) const1450 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
1451 {
1452 	return new ExtendedDynamicStateInstance(context, m_testConfig);
1453 }
1454 
ExtendedDynamicStateInstance(Context & context,const TestConfig & testConfig)1455 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
1456 	: vkt::TestInstance	(context)
1457 	, m_testConfig		(testConfig)
1458 {
1459 }
1460 
1461 struct VertexBufferInfo
1462 {
VertexBufferInfovkt::pipeline::__anon8f7ea4da0111::VertexBufferInfo1463 	VertexBufferInfo ()
1464 		: buffer	()
1465 		, offset	(0ull)
1466 		, dataSize	(0ull)
1467 	{}
1468 
VertexBufferInfovkt::pipeline::__anon8f7ea4da0111::VertexBufferInfo1469 	VertexBufferInfo (VertexBufferInfo&& other)
1470 		: buffer	(other.buffer.release())
1471 		, offset	(other.offset)
1472 		, dataSize	(other.dataSize)
1473 	{}
1474 
1475 	de::MovePtr<vk::BufferWithMemory>	buffer;
1476 	vk::VkDeviceSize					offset;
1477 	vk::VkDeviceSize					dataSize;
1478 };
1479 
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)1480 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
1481 {
1482 	log << tcu::TestLog::ImageSet(setName, setDesc)
1483 		<< tcu::TestLog::Image(setName + "Result", "Result image", result)
1484 		<< tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
1485 		<< tcu::TestLog::EndImageSet;
1486 }
1487 
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)1488 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
1489 {
1490 	auto&	alloc	= buffer.getAllocation();
1491 	auto	dst		= reinterpret_cast<char*>(alloc.getHostPtr());
1492 
1493 	deMemcpy(dst + offset, src, size);
1494 	vk::flushAlloc(vkd, device, alloc);
1495 }
1496 
1497 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)1498 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
1499 {
1500 	if (testConfig.cullModeConfig.dynamicValue)
1501 		vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
1502 
1503 	if (testConfig.frontFaceConfig.dynamicValue)
1504 		vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
1505 
1506 	if (testConfig.topologyConfig.dynamicValue)
1507 		vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
1508 
1509 	if (testConfig.viewportConfig.dynamicValue)
1510 	{
1511 		const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
1512 		vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
1513 	}
1514 
1515 	if (testConfig.scissorConfig.dynamicValue)
1516 	{
1517 		const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
1518 		vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
1519 	}
1520 
1521 	if (testConfig.depthTestEnableConfig.dynamicValue)
1522 		vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
1523 
1524 	if (testConfig.depthWriteEnableConfig.dynamicValue)
1525 		vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
1526 
1527 	if (testConfig.depthCompareOpConfig.dynamicValue)
1528 		vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
1529 
1530 	if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
1531 		vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
1532 
1533 	if (testConfig.stencilTestEnableConfig.dynamicValue)
1534 		vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
1535 
1536 	if (testConfig.depthBiasEnableConfig.dynamicValue)
1537 		vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
1538 
1539 	if (testConfig.depthBiasConfig.dynamicValue)
1540 	{
1541 		const auto& bias = testConfig.depthBiasConfig.dynamicValue.get();
1542 		vkd.cmdSetDepthBias(cmdBuffer, bias.constantFactor, bias.clamp, 0.0f);
1543 	}
1544 
1545 	if (testConfig.rastDiscardEnableConfig.dynamicValue)
1546 		vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
1547 
1548 	if (testConfig.primRestartEnableConfig.dynamicValue)
1549 		vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
1550 
1551 	if (testConfig.logicOpConfig.dynamicValue)
1552 		vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
1553 
1554 	if (testConfig.patchControlPointsConfig.dynamicValue)
1555 		vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
1556 
1557 	if (testConfig.stencilOpConfig.dynamicValue)
1558 	{
1559 		for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
1560 			vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
1561 	}
1562 
1563 	if (testConfig.vertexGenerator.dynamicValue)
1564 	{
1565 		const auto generator	= testConfig.vertexGenerator.dynamicValue.get();
1566 		const auto bindings		= generator->getBindingDescriptions2(testConfig.strideConfig.staticValue);
1567 		const auto attributes	= generator->getAttributeDescriptions2();
1568 
1569 		vkd.cmdSetVertexInputEXT(cmdBuffer,
1570 			static_cast<deUint32>(bindings.size()), de::dataOrNull(bindings),
1571 			static_cast<deUint32>(attributes.size()), de::dataOrNull(attributes));
1572 	}
1573 }
1574 
1575 // Bind the appropriate vertex buffers using dynamic strides if the test configuration needs a dynamic stride.
1576 // 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)1577 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)
1578 {
1579 	if (!testConfig.strideConfig.dynamicValue)
1580 		return false;
1581 
1582 	const auto& viewportVec = testConfig.getActiveViewportVec();
1583 	DE_UNREF(viewportVec); // For release builds.
1584 
1585 	// When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
1586 	// orderings if we have several viewports or meshes.
1587 	DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
1588 				|| testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
1589 				|| testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1590 
1591 	// Split buffers, offsets, sizes and strides into their own vectors for the call.
1592 	std::vector<vk::VkBuffer>		buffers;
1593 	std::vector<vk::VkDeviceSize>	offsets;
1594 	std::vector<vk::VkDeviceSize>	sizes;
1595 	const auto						strides = testConfig.strideConfig.dynamicValue.get();
1596 
1597 	const auto& chosenBuffers = (testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers);
1598 
1599 	buffers.reserve	(chosenBuffers.size());
1600 	offsets.reserve	(chosenBuffers.size());
1601 	sizes.reserve	(chosenBuffers.size());
1602 	DE_ASSERT(chosenBuffers.size() == strides.size());
1603 
1604 	for (const auto& vertBuffer : chosenBuffers)
1605 	{
1606 		buffers.push_back	(vertBuffer.buffer->get());
1607 		offsets.push_back	(vertBuffer.offset);
1608 		sizes.push_back		(vertBuffer.dataSize);
1609 	}
1610 
1611 	vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, static_cast<deUint32>(chosenBuffers.size()), buffers.data(), offsets.data(), sizes.data(), strides.data());
1612 
1613 	return true;
1614 }
1615 
1616 // 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)1617 void bindVertexBuffers (const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, const std::vector<VertexBufferInfo>& vertexBuffers)
1618 {
1619 	std::vector<vk::VkBuffer>		buffers;
1620 	std::vector<vk::VkDeviceSize>	offsets;
1621 
1622 	buffers.reserve	(vertexBuffers.size());
1623 	offsets.reserve	(vertexBuffers.size());
1624 
1625 	for (const auto& vertBuffer : vertexBuffers)
1626 	{
1627 		buffers.push_back	(vertBuffer.buffer->get());
1628 		offsets.push_back	(vertBuffer.offset);
1629 	}
1630 
1631 	vkd.cmdBindVertexBuffers(cmdBuffer, 0u, static_cast<deUint32>(vertexBuffers.size()), buffers.data(), offsets.data());
1632 }
1633 
1634 
1635 // 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)1636 void prepareVertexBuffers (	std::vector<VertexBufferInfo>&	buffers,
1637 							const vk::DeviceInterface&		vkd,
1638 							vk::VkDevice					device,
1639 							vk::Allocator&					allocator,
1640 							const VertexGenerator*			generator,
1641 							const std::vector<tcu::Vec2>&	vertices,
1642 							deUint32						dataOffset,
1643 							deUint32						trailingSize)
1644 {
1645 	const deUint32	paddingBytes	= 0xDEADBEEFu;
1646 	const auto		vertexData		= generator->createVertexData(vertices, dataOffset, trailingSize, &paddingBytes, sizeof(paddingBytes));
1647 
1648 	for (const auto& bufferBytes : vertexData)
1649 	{
1650 		const auto bufferSize	= static_cast<vk::VkDeviceSize>(de::dataSize(bufferBytes));
1651 		const auto extraSize	= static_cast<vk::VkDeviceSize>(dataOffset + trailingSize);
1652 		DE_ASSERT(bufferSize > extraSize);
1653 		const auto dataSize		= bufferSize - extraSize;
1654 
1655 		// Create a full-size buffer but remember the data size and offset for it.
1656 		const auto createInfo = vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1657 
1658 		VertexBufferInfo bufferInfo;
1659 		bufferInfo.buffer	= de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vkd, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
1660 		bufferInfo.offset	= static_cast<vk::VkDeviceSize>(dataOffset);
1661 		bufferInfo.dataSize	= dataSize;
1662 		buffers.emplace_back(std::move(bufferInfo));
1663 
1664 		// Copy the whole contents to the full buffer.
1665 		copyAndFlush(vkd, device, *buffers.back().buffer, 0, bufferBytes.data(), de::dataSize(bufferBytes));
1666 	}
1667 }
1668 
iterate(void)1669 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
1670 {
1671 	using ImageWithMemoryVec	= std::vector<std::unique_ptr<vk::ImageWithMemory>>;
1672 	using ImageViewVec			= std::vector<vk::Move<vk::VkImageView>>;
1673 	using FramebufferVec		= std::vector<vk::Move<vk::VkFramebuffer>>;
1674 
1675 	const auto&	vki					= m_context.getInstanceInterface();
1676 	const auto&	vkd					= m_context.getDeviceInterface();
1677 	const auto	physicalDevice		= m_context.getPhysicalDevice();
1678 	const auto	device				= m_context.getDevice();
1679 	auto&		allocator			= m_context.getDefaultAllocator();
1680 	const auto	queue				= m_context.getUniversalQueue();
1681 	const auto	queueIndex			= m_context.getUniversalQueueFamilyIndex();
1682 	auto&		log					= m_context.getTestContext().getLog();
1683 
1684 	const auto	kReversed			= m_testConfig.isReversed();
1685 	const auto	kNumIterations		= m_testConfig.numIterations();
1686 	const auto	kSequenceOrdering	= m_testConfig.sequenceOrdering;
1687 
1688 	const auto						kFramebufferExtent	= vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
1689 	const vk::VkImageUsageFlags		kColorUsage			= (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1690 	const vk::VkImageUsageFlags		kDSUsage			= (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1691 	const vk::VkFormatFeatureFlags	kDSFeatures			= (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1692 	const auto						colorFormat			= m_testConfig.colorFormat();
1693 
1694 	// Choose depth/stencil format.
1695 	const DepthStencilFormat* dsFormatInfo = nullptr;
1696 
1697 	for (const auto& kDepthStencilFormat : kDepthStencilFormats)
1698 	{
1699 		const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormat.imageFormat);
1700 		if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
1701 		{
1702 			dsFormatInfo = &kDepthStencilFormat;
1703 			break;
1704 		}
1705 	}
1706 
1707 	// Note: Not Supported insted of Fail because the transfer feature is not mandatory.
1708 	if (!dsFormatInfo)
1709 		TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
1710 	log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
1711 
1712 	// Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
1713 	// where we will bind the static pipeline last before drawing.
1714 	if (kReversed)
1715 		m_testConfig.swapValues();
1716 
1717 	// Create color and depth/stencil images.
1718 	ImageWithMemoryVec colorImages;
1719 	ImageWithMemoryVec dsImages;
1720 
1721 	const vk::VkImageCreateInfo colorImageInfo =
1722 	{
1723 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
1724 		nullptr,									//	const void*				pNext;
1725 		0u,											//	VkImageCreateFlags		flags;
1726 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
1727 		colorFormat,								//	VkFormat				format;
1728 		kFramebufferExtent,							//	VkExtent3D				extent;
1729 		1u,											//	deUint32				mipLevels;
1730 		1u,											//	deUint32				arrayLayers;
1731 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
1732 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
1733 		kColorUsage,								//	VkImageUsageFlags		usage;
1734 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
1735 		1u,											//	deUint32				queueFamilyIndexCount;
1736 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
1737 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
1738 	};
1739 	for (deUint32 i = 0u; i < kNumIterations; ++i)
1740 		colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
1741 
1742 	const vk::VkImageCreateInfo dsImageInfo =
1743 	{
1744 		vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,	//	VkStructureType			sType;
1745 		nullptr,									//	const void*				pNext;
1746 		0u,											//	VkImageCreateFlags		flags;
1747 		vk::VK_IMAGE_TYPE_2D,						//	VkImageType				imageType;
1748 		dsFormatInfo->imageFormat,					//	VkFormat				format;
1749 		kFramebufferExtent,							//	VkExtent3D				extent;
1750 		1u,											//	deUint32				mipLevels;
1751 		1u,											//	deUint32				arrayLayers;
1752 		vk::VK_SAMPLE_COUNT_1_BIT,					//	VkSampleCountFlagBits	samples;
1753 		vk::VK_IMAGE_TILING_OPTIMAL,				//	VkImageTiling			tiling;
1754 		kDSUsage,									//	VkImageUsageFlags		usage;
1755 		vk::VK_SHARING_MODE_EXCLUSIVE,				//	VkSharingMode			sharingMode;
1756 		1u,											//	deUint32				queueFamilyIndexCount;
1757 		&queueIndex,								//	const deUint32*			pQueueFamilyIndices;
1758 		vk::VK_IMAGE_LAYOUT_UNDEFINED,				//	VkImageLayout			initialLayout;
1759 	};
1760 	for (deUint32 i = 0u; i < kNumIterations; ++i)
1761 		dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
1762 
1763 	const auto colorSubresourceRange	= vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1764 	const auto dsSubresourceRange		= vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
1765 
1766 	ImageViewVec colorImageViews;
1767 	ImageViewVec dsImageViews;
1768 
1769 	for (const auto& img : colorImages)
1770 		colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
1771 
1772 	for (const auto& img : dsImages)
1773 		dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
1774 
1775 	// Vertex buffer.
1776 	const auto			topologyClass	= getTopologyClass(m_testConfig.topologyConfig.staticValue);
1777 	std::vector<tcu::Vec2>		vertices;
1778 	std::vector<deUint32>		indices{ 0, 1, 2, 3, 0xFFFFFFFF, 2, 3, 4, 5 };
1779 
1780 	if (topologyClass == TopologyClass::TRIANGLE)
1781 	{
1782 		// Full-screen triangle strip with 6 vertices.
1783 		//
1784 		// 0        2        4
1785 		//  +-------+-------+
1786 		//  |      XX      X|
1787 		//  |     X X     X |
1788 		//  |    X  X    X  |
1789 		//  |   X   X   X   |
1790 		//  |  X    X  X    |
1791 		//  | X     X X     |
1792 		//  |X      XX      |
1793 		//  +-------+-------+
1794 		// 1        3       5
1795 		vertices.reserve(6u);
1796 		vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
1797 		vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
1798 		vertices.push_back(tcu::Vec2( 0.0f, -1.0f));
1799 		vertices.push_back(tcu::Vec2( 0.0f,  1.0f));
1800 		vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1801 		vertices.push_back(tcu::Vec2( 1.0f,  1.0f));
1802 	}
1803 	else if (topologyClass == TopologyClass::PATCH)
1804 	{
1805 		DE_ASSERT(m_testConfig.getActivePatchControlPoints() > 1u);
1806 
1807 		// 2 triangles making a quad
1808 		vertices.reserve(6u);
1809 		vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
1810 		vertices.push_back(tcu::Vec2( 1.0f,  1.0f));
1811 		vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1812 		vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1813 		vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
1814 		vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
1815 	}
1816 	else // TopologyClass::LINE
1817 	{
1818 		// 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.
1819 		vertices.reserve(kFramebufferHeight * 4u);
1820 		const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
1821 		for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
1822 		{
1823 			// Offset of 0.5 pixels + one line per row from -1 to 1.
1824 			const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
1825 			vertices.push_back(tcu::Vec2(-1.0f, yCoord));
1826 			vertices.push_back(tcu::Vec2(-0.5f, yCoord));
1827 			vertices.push_back(tcu::Vec2( 0.5f, yCoord));
1828 			vertices.push_back(tcu::Vec2( 1.0f, yCoord));
1829 		}
1830 	}
1831 
1832 	if (m_testConfig.singleVertex)
1833 		vertices.resize(1);
1834 
1835 	// Reversed vertices order in triangle strip (1, 0, 3, 2, 5, 4)
1836 	std::vector<tcu::Vec2> rvertices;
1837 	if (topologyClass == TopologyClass::TRIANGLE)
1838 	{
1839 		DE_ASSERT(!vertices.empty());
1840 		if (m_testConfig.singleVertex)
1841 			rvertices.push_back(vertices[0]);
1842 		else
1843 		{
1844 			rvertices.reserve(6u);
1845 			rvertices.push_back(vertices[1]);
1846 			rvertices.push_back(vertices[0]);
1847 			rvertices.push_back(vertices[3]);
1848 			rvertices.push_back(vertices[2]);
1849 			rvertices.push_back(vertices[5]);
1850 			rvertices.push_back(vertices[4]);
1851 		}
1852 	}
1853 
1854 	if (topologyClass != TopologyClass::TRIANGLE)
1855 	{
1856 		for (const auto& mesh : m_testConfig.meshParams)
1857 		{
1858 			DE_UNREF(mesh); // For release builds.
1859 			DE_ASSERT(!mesh.reversed);
1860 		}
1861 	}
1862 
1863 	// Buffers with vertex data for the different bindings.
1864 	std::vector<VertexBufferInfo> vertBuffers;
1865 	std::vector<VertexBufferInfo> rvertBuffers;
1866 
1867 	{
1868 		const auto dataOffset	= static_cast<deUint32>(m_testConfig.vertexDataOffset);
1869 		const auto trailingSize	= static_cast<deUint32>(m_testConfig.vertexDataExtraBytes);
1870 		const auto generator	= m_testConfig.getActiveVertexGenerator();
1871 		prepareVertexBuffers(vertBuffers, vkd, device, allocator, generator, vertices, dataOffset, trailingSize);
1872 		if (topologyClass == TopologyClass::TRIANGLE)
1873 			prepareVertexBuffers(rvertBuffers, vkd, device, allocator, generator, rvertices, dataOffset, trailingSize);
1874 	}
1875 
1876 	// Index buffer.
1877 	const auto indexDataSize			= static_cast<vk::VkDeviceSize>(de::dataSize(indices));
1878 	const auto indexBufferInfo			= vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1879 	vk::BufferWithMemory indexBuffer	(vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible);
1880 	copyAndFlush(vkd, device, indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
1881 
1882 	// Descriptor set layout.
1883 	vk::DescriptorSetLayoutBuilder layoutBuilder;
1884 	const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1885 
1886 	// Pipeline layout.
1887 	vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1888 	if (m_testConfig.isMultiViewport())
1889 		pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1890 
1891 	const vk::VkPushConstantRange pushConstantRange =
1892 	{
1893 		pushConstantStageFlags,							//	VkShaderStageFlags	stageFlags;
1894 		0u,												//	deUint32			offset;
1895 		static_cast<deUint32>(sizeof(PushConstants)),	//	deUint32			size;
1896 	};
1897 
1898 	const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1899 	{
1900 		vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,	//	VkStructureType					sType;
1901 		nullptr,											//	const void*						pNext;
1902 		0u,													//	VkPipelineLayoutCreateFlags		flags;
1903 		1u,													//	deUint32						setLayoutCount;
1904 		&descriptorSetLayout.get(),							//	const VkDescriptorSetLayout*	pSetLayouts;
1905 		1u,													//	deUint32						pushConstantRangeCount;
1906 		&pushConstantRange,									//	const VkPushConstantRange*		pPushConstantRanges;
1907 	};
1908 	const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
1909 
1910 	// Render pass with single subpass.
1911 	const vk::VkAttachmentReference colorAttachmentReference =
1912 	{
1913 		0u,												//	deUint32		attachment;
1914 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1915 	};
1916 
1917 	const vk::VkAttachmentReference dsAttachmentReference =
1918 	{
1919 		1u,														//	deUint32		attachment;
1920 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout	layout;
1921 	};
1922 
1923 	const vk::VkSubpassDescription subpassDescription =
1924 	{
1925 		0u,										//	VkSubpassDescriptionFlags		flags;
1926 		vk::VK_PIPELINE_BIND_POINT_GRAPHICS,	//	VkPipelineBindPoint				pipelineBindPoint;
1927 		0u,										//	deUint32						inputAttachmentCount;
1928 		nullptr,								//	const VkAttachmentReference*	pInputAttachments;
1929 		1u,										//	deUint32						colorAttachmentCount;
1930 		&colorAttachmentReference,				//	const VkAttachmentReference*	pColorAttachments;
1931 		nullptr,								//	const VkAttachmentReference*	pResolveAttachments;
1932 		&dsAttachmentReference,					//	const VkAttachmentReference*	pDepthStencilAttachment;
1933 		0u,										//	deUint32						preserveAttachmentCount;
1934 		nullptr,								//	const deUint32*					pPreserveAttachments;
1935 	};
1936 
1937 	std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
1938 
1939 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
1940 	{
1941 		0u,												//	VkAttachmentDescriptionFlags	flags;
1942 		colorFormat,									//	VkFormat						format;
1943 		vk::VK_SAMPLE_COUNT_1_BIT,						//	VkSampleCountFlagBits			samples;
1944 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,				//	VkAttachmentLoadOp				loadOp;
1945 		vk::VK_ATTACHMENT_STORE_OP_STORE,				//	VkAttachmentStoreOp				storeOp;
1946 		vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,			//	VkAttachmentLoadOp				stencilLoadOp;
1947 		vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,			//	VkAttachmentStoreOp				stencilStoreOp;
1948 		vk::VK_IMAGE_LAYOUT_UNDEFINED,					//	VkImageLayout					initialLayout;
1949 		vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1950 	});
1951 
1952 	attachmentDescriptions.push_back(vk::VkAttachmentDescription
1953 	{
1954 		0u,														//	VkAttachmentDescriptionFlags	flags;
1955 		dsFormatInfo->imageFormat,								//	VkFormat						format;
1956 		vk::VK_SAMPLE_COUNT_1_BIT,								//	VkSampleCountFlagBits			samples;
1957 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				loadOp;
1958 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				storeOp;
1959 		vk::VK_ATTACHMENT_LOAD_OP_CLEAR,						//	VkAttachmentLoadOp				stencilLoadOp;
1960 		vk::VK_ATTACHMENT_STORE_OP_STORE,						//	VkAttachmentStoreOp				stencilStoreOp;
1961 		vk::VK_IMAGE_LAYOUT_UNDEFINED,							//	VkImageLayout					initialLayout;
1962 		vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,	//	VkImageLayout					finalLayout;
1963 	});
1964 
1965 	const vk::VkRenderPassCreateInfo renderPassCreateInfo =
1966 	{
1967 		vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,			//	VkStructureType					sType;
1968 		nullptr,												//	const void*						pNext;
1969 		0u,														//	VkRenderPassCreateFlags			flags;
1970 		static_cast<deUint32>(attachmentDescriptions.size()),	//	deUint32						attachmentCount;
1971 		attachmentDescriptions.data(),							//	const VkAttachmentDescription*	pAttachments;
1972 		1u,														//	deUint32						subpassCount;
1973 		&subpassDescription,									//	const VkSubpassDescription*		pSubpasses;
1974 		0u,														//	deUint32						dependencyCount;
1975 		nullptr,												//	const VkSubpassDependency*		pDependencies;
1976 	};
1977 	const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
1978 
1979 	// Framebuffers.
1980 	FramebufferVec framebuffers;
1981 
1982 	DE_ASSERT(colorImageViews.size() == dsImageViews.size());
1983 	for (size_t imgIdx = 0; imgIdx < colorImageViews.size(); ++imgIdx)
1984 	{
1985 		std::vector<vk::VkImageView> attachments;
1986 		attachments.push_back(colorImageViews[imgIdx].get());
1987 		attachments.push_back(dsImageViews[imgIdx].get());
1988 
1989 		const vk::VkFramebufferCreateInfo framebufferCreateInfo =
1990 		{
1991 			vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,	//	VkStructureType				sType;
1992 			nullptr,										//	const void*					pNext;
1993 			0u,												//	VkFramebufferCreateFlags	flags;
1994 			renderPass.get(),								//	VkRenderPass				renderPass;
1995 			static_cast<deUint32>(attachments.size()),		//	deUint32					attachmentCount;
1996 			attachments.data(),								//	const VkImageView*			pAttachments;
1997 			kFramebufferWidth,								//	deUint32					width;
1998 			kFramebufferHeight,								//	deUint32					height;
1999 			1u,												//	deUint32					layers;
2000 		};
2001 
2002 		framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
2003 	}
2004 
2005 	// Shader modules.
2006 	const auto						dynamicVertModule	= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("dynamicVert"), 0u);
2007 	const auto						staticVertModule	= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("staticVert"), 0u);
2008 	const auto						fragModule			= vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
2009 	vk::Move<vk::VkShaderModule>	geomModule;
2010 	vk::Move<vk::VkShaderModule>	tescModule;
2011 	vk::Move<vk::VkShaderModule>	teseModule;
2012 
2013 	if (m_testConfig.needsGeometryShader())
2014 		geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
2015 
2016 	if (m_testConfig.needsTessellation())
2017 	{
2018 		tescModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
2019 		teseModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
2020 	}
2021 
2022 	// Shader stages.
2023 	std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
2024 	std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStaticStages;
2025 
2026 	vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
2027 	{
2028 		vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,	//	VkStructureType						sType;
2029 		nullptr,													//	const void*							pNext;
2030 		0u,															//	VkPipelineShaderStageCreateFlags	flags;
2031 		vk::VK_SHADER_STAGE_FRAGMENT_BIT,							//	VkShaderStageFlagBits				stage;
2032 		fragModule.get(),											//	VkShaderModule						module;
2033 		"main",														//	const char*							pName;
2034 		nullptr,													//	const VkSpecializationInfo*			pSpecializationInfo;
2035 	};
2036 
2037 	shaderStages.push_back(shaderStageCreateInfo);
2038 
2039 	if (m_testConfig.needsGeometryShader())
2040 	{
2041 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
2042 		shaderStageCreateInfo.module = geomModule.get();
2043 		shaderStages.push_back(shaderStageCreateInfo);
2044 	}
2045 
2046 	if (m_testConfig.needsTessellation())
2047 	{
2048 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2049 		shaderStageCreateInfo.module = tescModule.get();
2050 		shaderStages.push_back(shaderStageCreateInfo);
2051 
2052 		shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2053 		shaderStageCreateInfo.module = teseModule.get();
2054 		shaderStages.push_back(shaderStageCreateInfo);
2055 	}
2056 
2057 	// Both vectors are the same up to here. Then, they differ in the vertex stage.
2058 	shaderStaticStages = shaderStages;
2059 	shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_VERTEX_BIT;
2060 
2061 	shaderStageCreateInfo.module = dynamicVertModule.get();
2062 	shaderStages.push_back(shaderStageCreateInfo);
2063 
2064 	shaderStageCreateInfo.module = staticVertModule.get();
2065 	shaderStaticStages.push_back(shaderStageCreateInfo);
2066 
2067 	// Input state.
2068 	const auto vertexBindings	= m_testConfig.vertexGenerator.staticValue->getBindingDescriptions(m_testConfig.strideConfig.staticValue);
2069 	const auto vertexAttributes	= m_testConfig.vertexGenerator.staticValue->getAttributeDescriptions();
2070 
2071 	const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
2072 	{
2073 		vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,	//	VkStructureType								sType;
2074 		nullptr,														//	const void*									pNext;
2075 		0u,																//	VkPipelineVertexInputStateCreateFlags		flags;
2076 		static_cast<deUint32>(vertexBindings.size()),					//	deUint32									vertexBindingDescriptionCount;
2077 		vertexBindings.data(),											//	const VkVertexInputBindingDescription*		pVertexBindingDescriptions;
2078 		static_cast<deUint32>(vertexAttributes.size()),					//	deUint32									vertexAttributeDescriptionCount;
2079 		vertexAttributes.data(),										//	const VkVertexInputAttributeDescription*	pVertexAttributeDescriptions;
2080 	};
2081 
2082 	// Input assembly.
2083 	const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
2084 	{
2085 		vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,	//	VkStructureType							sType;
2086 		nullptr,															//	const void*								pNext;
2087 		0u,																	//	VkPipelineInputAssemblyStateCreateFlags	flags;
2088 		m_testConfig.topologyConfig.staticValue,							//	VkPrimitiveTopology						topology;
2089 		makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue),		//	VkBool32								primitiveRestartEnable;
2090 	};
2091 
2092 	// Viewport state.
2093 	if (m_testConfig.viewportConfig.dynamicValue)
2094 		DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
2095 	else
2096 		DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
2097 
2098 	if (m_testConfig.scissorConfig.dynamicValue)
2099 		DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
2100 	else
2101 		DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
2102 
2103 	// The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
2104 	const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
2105 
2106 	// For the static pipeline.
2107 	const vk::VkPipelineViewportStateCreateInfo staticViewportStateCreateInfo =
2108 	{
2109 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,					//	VkStructureType						sType;
2110 		nullptr,																	//	const void*							pNext;
2111 		0u,																			//	VkPipelineViewportStateCreateFlags	flags;
2112 		minStaticCount,																//	deUint32							viewportCount;
2113 		m_testConfig.viewportConfig.staticValue.data(),								//	const VkViewport*					pViewports;
2114 		minStaticCount,																//	deUint32							scissorCount;
2115 		m_testConfig.scissorConfig.staticValue.data(),								//	const VkRect2D*						pScissors;
2116 	};
2117 
2118 	// For the dynamic pipeline.
2119 	const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
2120 		? m_testConfig.viewportConfig.dynamicValue.get().size()
2121 		: m_testConfig.viewportConfig.staticValue.size());
2122 
2123 	const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
2124 		? m_testConfig.scissorConfig.dynamicValue.get().size()
2125 		: m_testConfig.scissorConfig.staticValue.size());
2126 
2127 	const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
2128 
2129 	// The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
2130 	const vk::VkPipelineViewportStateCreateInfo dynamicViewportStateCreateInfo =
2131 	{
2132 		vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,					//	VkStructureType						sType;
2133 		nullptr,																	//	const void*							pNext;
2134 		0u,																			//	VkPipelineViewportStateCreateFlags	flags;
2135 		(m_testConfig.viewportConfig.dynamicValue ? 0u : minDynamicCount),			//	deUint32							viewportCount;
2136 		m_testConfig.viewportConfig.staticValue.data(),								//	const VkViewport*					pViewports;
2137 		(m_testConfig.scissorConfig.dynamicValue ? 0u : minDynamicCount),			//	deUint32							scissorCount;
2138 		m_testConfig.scissorConfig.staticValue.data(),								//	const VkRect2D*						pScissors;
2139 	};
2140 
2141 	// Rasterization state.
2142 	vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
2143 	{
2144 		vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,	//	VkStructureType							sType;
2145 		nullptr,														//	const void*								pNext;
2146 		0u,																//	VkPipelineRasterizationStateCreateFlags	flags;
2147 		VK_FALSE,														//	VkBool32								depthClampEnable;
2148 		makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue),	//	VkBool32								rasterizerDiscardEnable;
2149 		vk::VK_POLYGON_MODE_FILL,										//	VkPolygonMode							polygonMode;
2150 		m_testConfig.cullModeConfig.staticValue,						//	VkCullModeFlags							cullMode;
2151 		m_testConfig.frontFaceConfig.staticValue,						//	VkFrontFace								frontFace;
2152 		makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue),	//	VkBool32								depthBiasEnable;
2153 		m_testConfig.depthBiasConfig.staticValue.constantFactor,		//	float									depthBiasConstantFactor;
2154 		m_testConfig.depthBiasConfig.staticValue.clamp,					//	float									depthBiasClamp;
2155 		0.0f,															//	float									depthBiasSlopeFactor;
2156 		1.0f,															//	float									lineWidth;
2157 	};
2158 
2159 	// Multisample state.
2160 	const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
2161 	{
2162 		vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,	//	VkStructureType							sType;
2163 		nullptr,														//	const void*								pNext;
2164 		0u,																//	VkPipelineMultisampleStateCreateFlags	flags;
2165 		vk::VK_SAMPLE_COUNT_1_BIT,										//	VkSampleCountFlagBits					rasterizationSamples;
2166 		VK_FALSE,														//	VkBool32								sampleShadingEnable;
2167 		0.0f,															//	float									minSampleShading;
2168 		nullptr,														//	const VkSampleMask*						pSampleMask;
2169 		VK_FALSE,														//	VkBool32								alphaToCoverageEnable;
2170 		VK_FALSE,														//	VkBool32								alphaToOneEnable;
2171 	};
2172 
2173 	// Depth/stencil state.
2174 	vk::VkStencilOpState	staticFrontStencil;
2175 	vk::VkStencilOpState	staticBackStencil;
2176 	bool					staticFrontStencilSet	= false;
2177 	bool					staticBackStencilSet	= false;
2178 
2179 	// Common setup for the front and back operations.
2180 	staticFrontStencil.compareMask	= 0xFFu;
2181 	staticFrontStencil.writeMask	= 0xFFu;
2182 	staticFrontStencil.reference	= m_testConfig.referenceStencil;
2183 	staticBackStencil				= staticFrontStencil;
2184 
2185 	for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
2186 	{
2187 		if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
2188 		{
2189 			copy(staticFrontStencil, op);
2190 			staticFrontStencilSet = true;
2191 		}
2192 		if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
2193 		{
2194 			copy(staticBackStencil, op);
2195 			staticBackStencilSet = true;
2196 		}
2197 	}
2198 
2199 	// Default values for the static part.
2200 	if (!staticFrontStencilSet)
2201 		copy(staticFrontStencil, kDefaultStencilOpParams);
2202 	if (!staticBackStencilSet)
2203 		copy(staticBackStencil, kDefaultStencilOpParams);
2204 
2205 	const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
2206 	{
2207 		vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,		//	VkStructureType							sType;
2208 		nullptr,															//	const void*								pNext;
2209 		0u,																	//	VkPipelineDepthStencilStateCreateFlags	flags;
2210 		makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),		//	VkBool32								depthTestEnable;
2211 		makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),		//	VkBool32								depthWriteEnable;
2212 		m_testConfig.depthCompareOpConfig.staticValue,						//	VkCompareOp								depthCompareOp;
2213 		makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue),	//	VkBool32								depthBoundsTestEnable;
2214 		makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),		//	VkBool32								stencilTestEnable;
2215 		staticFrontStencil,													//	VkStencilOpState						front;
2216 		staticBackStencil,													//	VkStencilOpState						back;
2217 		m_testConfig.minDepthBounds,										//	float									minDepthBounds;
2218 		m_testConfig.maxDepthBounds,										//	float									maxDepthBounds;
2219 	};
2220 
2221 	// Dynamic state. Here we will set all states which have a dynamic value.
2222 	const auto dynamicStates = m_testConfig.getDynamicStates();
2223 
2224 	const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
2225 	{
2226 		vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,	//	VkStructureType						sType;
2227 		nullptr,													//	const void*							pNext;
2228 		0u,															//	VkPipelineDynamicStateCreateFlags	flags;
2229 		static_cast<deUint32>(dynamicStates.size()),				//	deUint32							dynamicStateCount;
2230 		de::dataOrNull(dynamicStates),								//	const VkDynamicState*				pDynamicStates;
2231 	};
2232 
2233 	const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
2234 	{
2235 		VK_FALSE,						// VkBool32                 blendEnable
2236 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            srcColorBlendFactor
2237 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            dstColorBlendFactor
2238 		vk::VK_BLEND_OP_ADD,			// VkBlendOp                colorBlendOp
2239 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            srcAlphaBlendFactor
2240 		vk::VK_BLEND_FACTOR_ZERO,		// VkBlendFactor            dstAlphaBlendFactor
2241 		vk::VK_BLEND_OP_ADD,			// VkBlendOp                alphaBlendOp
2242 		vk::VK_COLOR_COMPONENT_R_BIT	// VkColorComponentFlags    colorWriteMask
2243 		| vk::VK_COLOR_COMPONENT_G_BIT
2244 		| vk::VK_COLOR_COMPONENT_B_BIT
2245 		| vk::VK_COLOR_COMPONENT_A_BIT
2246 	};
2247 
2248 	const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
2249 	{
2250 		vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,	// VkStructureType                               sType
2251 		nullptr,														// const void*                                   pNext
2252 		0u,																// VkPipelineColorBlendStateCreateFlags          flags
2253 		makeVkBool32(m_testConfig.testLogicOp()),						// VkBool32                                      logicOpEnable
2254 		m_testConfig.logicOpConfig.staticValue,							// VkLogicOp                                     logicOp
2255 		1u,																// deUint32                                      attachmentCount
2256 		&colorBlendAttachmentState,										// const VkPipelineColorBlendAttachmentState*    pAttachments
2257 		{ 0.0f, 0.0f, 0.0f, 0.0f }										// float                                         blendConstants[4]
2258 	};
2259 
2260 	const vk::VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo =
2261 	{
2262 		vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,	// VkStructureType                               sType
2263 		nullptr,														// const void*                                   pNext
2264 		0u,																// VkPipelineTessellationStateCreateFlags        flags
2265 		m_testConfig.patchControlPointsConfig.staticValue,				// uint32_t										 patchControlPoints
2266 	};
2267 
2268 	const auto pTessellationState = (m_testConfig.needsTessellation() ? &pipelineTessellationStateCreateInfo : nullptr);
2269 
2270 	const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
2271 	{
2272 		vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,	//	VkStructureType									sType;
2273 		nullptr,												//	const void*										pNext;
2274 		0u,														//	VkPipelineCreateFlags							flags;
2275 		static_cast<deUint32>(shaderStages.size()),				//	deUint32										stageCount;
2276 		shaderStages.data(),									//	const VkPipelineShaderStageCreateInfo*			pStages;
2277 		&vertexInputStateCreateInfo,							//	const VkPipelineVertexInputStateCreateInfo*		pVertexInputState;
2278 		&inputAssemblyStateCreateInfo,							//	const VkPipelineInputAssemblyStateCreateInfo*	pInputAssemblyState;
2279 		pTessellationState,										//	const VkPipelineTessellationStateCreateInfo*		pTessellationState;
2280 		nullptr,												//	const VkPipelineViewportStateCreateInfo *	pViewportState;
2281 		&rasterizationStateCreateInfo,							//	const VkPipelineRasterizationStateCreateInfo*	pRasterizationState;
2282 		&multisampleStateCreateInfo,							//	const VkPipelineMultisampleStateCreateInfo*		pMultisampleState;
2283 		&depthStencilStateCreateInfo,							//	const VkPipelineDepthStencilStateCreateInfo*	pDepthStencilState;
2284 		&colorBlendStateCreateInfo,								//	const VkPipelineColorBlendStateCreateInfo*		pColorBlendState;
2285 		nullptr,												//	const VkPipelineDynamicStateCreateInfo*			pDynamicState;
2286 		pipelineLayout.get(),									//	VkPipelineLayout								layout;
2287 		renderPass.get(),										//	VkRenderPass									renderPass;
2288 		0u,														//	deUint32										subpass;
2289 		DE_NULL,												//	VkPipeline										basePipelineHandle;
2290 		0,														//	deInt32											basePipelineIndex;
2291 	};
2292 
2293 	vk::Move<vk::VkPipeline>	staticPipeline;
2294 	const bool					bindStaticFirst		= (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES	||
2295 													   kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES	||
2296 													   kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
2297 	const bool					useStaticPipeline	= (bindStaticFirst || kReversed);
2298 
2299 	// Create static pipeline when needed.
2300 	if (useStaticPipeline)
2301 	{
2302 		auto staticPipelineCreateInfo			= graphicsPipelineCreateInfoTemplate;
2303 		staticPipelineCreateInfo.pViewportState	= &staticViewportStateCreateInfo;
2304 		staticPipelineCreateInfo.pStages		= shaderStaticStages.data();
2305 		staticPipeline							= vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
2306 	}
2307 
2308 	// Create dynamic pipeline.
2309 	vk::Move<vk::VkPipeline> graphicsPipeline;
2310 	{
2311 		auto dynamicPipelineCreateInfo				= graphicsPipelineCreateInfoTemplate;
2312 		dynamicPipelineCreateInfo.pDynamicState		= &dynamicStateCreateInfo;
2313 		dynamicPipelineCreateInfo.pViewportState	= &dynamicViewportStateCreateInfo;
2314 		graphicsPipeline							= vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
2315 	}
2316 
2317 	// Command buffer.
2318 	const auto cmdPool		= vk::makeCommandPool(vkd, device, queueIndex);
2319 	const auto cmdBufferPtr	= vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2320 	const auto cmdBuffer	= cmdBufferPtr.get();
2321 
2322 	// Clear values, clear to green for dynamic logicOp
2323 	std::vector<vk::VkClearValue> clearValues;
2324 	clearValues.push_back(m_testConfig.clearColorValue);
2325 	clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
2326 
2327 	// Record command buffer.
2328 	vk::beginCommandBuffer(vkd, cmdBuffer);
2329 
2330 	for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
2331 	{
2332 		// Track in-advance vertex buffer binding.
2333 		bool boundInAdvance = false;
2334 
2335 		// Maybe set extended dynamic state here.
2336 		if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
2337 		{
2338 			setDynamicStates(m_testConfig, vkd, cmdBuffer);
2339 			boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2340 		}
2341 
2342 		// Begin render pass.
2343 		vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
2344 
2345 			// Bind a static pipeline first if needed.
2346 			if (bindStaticFirst && iteration == 0u)
2347 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2348 
2349 			// Maybe set extended dynamic state here.
2350 			if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
2351 			{
2352 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
2353 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2354 			}
2355 
2356 			// Bind dynamic pipeline.
2357 			if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
2358 				 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
2359 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2360 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2361 			{
2362 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
2363 			}
2364 
2365 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2366 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2367 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2368 			{
2369 				setDynamicStates(m_testConfig, vkd, cmdBuffer);
2370 				boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2371 			}
2372 
2373 			// Bind a static pipeline last if needed.
2374 			if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2375 				(kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
2376 			{
2377 				vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2378 			}
2379 
2380 			const auto& viewportVec = m_testConfig.getActiveViewportVec();
2381 			for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
2382 			{
2383 				for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
2384 				{
2385 					// Push constants.
2386 					PushConstants pushConstants =
2387 					{
2388 						m_testConfig.meshParams[meshIdx].color,			//	tcu::Vec4	triangleColor;
2389 						m_testConfig.meshParams[meshIdx].depth,			//	float		meshDepth;
2390 						static_cast<deInt32>(viewportIdx),				//	deInt32		viewPortIndex;
2391 						m_testConfig.meshParams[meshIdx].scaleX,		//	float		scaleX;
2392 						m_testConfig.meshParams[meshIdx].scaleY,		//	float		scaleY;
2393 						m_testConfig.meshParams[meshIdx].offsetX,		//	float		offsetX;
2394 						m_testConfig.meshParams[meshIdx].offsetY,		//	float		offsetY;
2395 						m_testConfig.meshParams[meshIdx].stripScale,	//	float		stripScale;
2396 					};
2397 					vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
2398 
2399 					// Track vertex bounding state for this mesh.
2400 					bool boundBeforeDraw = false;
2401 
2402 					// Maybe set extended dynamic state here.
2403 					if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
2404 					{
2405 						setDynamicStates(m_testConfig, vkd, cmdBuffer);
2406 						boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffers, rvertBuffers);
2407 					}
2408 
2409 					// Bind vertex buffer with static stride if needed and draw.
2410 					if (!(boundInAdvance || boundBeforeDraw))
2411 					{
2412 						bindVertexBuffers(vkd, cmdBuffer, (m_testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers));
2413 						if (m_testConfig.needsIndexBuffer())
2414 						{
2415 							vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0, vk::VK_INDEX_TYPE_UINT32);
2416 						}
2417 					}
2418 
2419 					// Draw mesh.
2420 					if (m_testConfig.needsIndexBuffer())
2421 					{
2422 						deUint32 numIndices = static_cast<deUint32>(indices.size());
2423 						// For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
2424 						// So, draw without using the invalid (0xFFFFFFFF) index, the second draw with primitive restart enabled will replace the results
2425 						// using all indices.
2426 						if (iteration == 0u &&
2427 							(m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
2428 							m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
2429 							numIndices = 3u;
2430 						vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
2431 					}
2432 					else
2433 					{
2434 						deUint32 vertex_count = static_cast<deUint32>(vertices.size());
2435 						if (m_testConfig.singleVertex)
2436 							vertex_count = m_testConfig.singleVertexDrawCount;
2437 						vkd.cmdDraw(cmdBuffer, vertex_count, 1u, 0u, 0u);
2438 					}
2439 				}
2440 			}
2441 
2442 		vk::endRenderPass(vkd, cmdBuffer);
2443 	}
2444 
2445 	vk::endCommandBuffer(vkd, cmdBuffer);
2446 
2447 	// Submit commands.
2448 	vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2449 
2450 	// Read result image aspects from the last used framebuffer.
2451 	const tcu::UVec2	renderSize		(kFramebufferWidth, kFramebufferHeight);
2452 	const auto			colorBuffer		= readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImages.back()->get(), colorFormat, renderSize);
2453 	const auto			depthBuffer		= readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
2454 	const auto			stencilBuffer	= readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
2455 	const auto			colorAccess		= colorBuffer->getAccess();
2456 	const auto			depthAccess		= depthBuffer->getAccess();
2457 	const auto			stencilAccess	= stencilBuffer->getAccess();
2458 
2459 	const int kWidth	= static_cast<int>(kFramebufferWidth);
2460 	const int kHeight	= static_cast<int>(kFramebufferHeight);
2461 
2462 	// Generate reference color buffer.
2463 	const auto				tcuColorFormat			= vk::mapVkFormat(colorFormat);
2464 	tcu::TextureLevel		referenceColorLevel		(tcuColorFormat, kWidth, kHeight);
2465 	tcu::PixelBufferAccess	referenceColorAccess	= referenceColorLevel.getAccess();
2466 	m_testConfig.referenceColor(referenceColorAccess);
2467 
2468 	const tcu::TextureFormat	errorFormat			(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
2469 	tcu::TextureLevel			colorError			(errorFormat, kWidth, kHeight);
2470 	tcu::TextureLevel			depthError			(errorFormat, kWidth, kHeight);
2471 	tcu::TextureLevel			stencilError		(errorFormat, kWidth, kHeight);
2472 	const auto					colorErrorAccess	= colorError.getAccess();
2473 	const auto					depthErrorAccess	= depthError.getAccess();
2474 	const auto					stencilErrorAccess	= stencilError.getAccess();
2475 	const tcu::Vec4				kGood				(0.0f, 1.0f, 0.0f, 1.0f);
2476 	const tcu::Vec4				kBad				(1.0f, 0.0f, 0.0f, 1.0f);
2477 
2478 	// Check expected values.
2479 	const auto	minDepth		= m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
2480 	const auto	maxDepth		= m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
2481 	bool		colorMatch		= true;
2482 	bool		depthMatch		= true;
2483 	bool		stencilMatch	= true;
2484 	bool		match;
2485 
2486 	for (int y = 0; y < kHeight; ++y)
2487 	for (int x = 0; x < kWidth; ++x)
2488 	{
2489 		if (vk::isUnormFormat(colorFormat))
2490 		{
2491 			auto colorPixel		= colorAccess.getPixel(x, y);
2492 			auto expectedPixel	= referenceColorAccess.getPixel(x, y);
2493 			match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kUnormColorThreshold));
2494 		}
2495 		else
2496 		{
2497 			DE_ASSERT(vk::isUintFormat(colorFormat));
2498 			auto colorPixel		= colorAccess.getPixelUint(x, y);
2499 			auto expectedPixel	= referenceColorAccess.getPixelUint(x, y);
2500 			match = (colorPixel == expectedPixel);
2501 		}
2502 
2503 		colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
2504 		if (!match)
2505 			colorMatch = false;
2506 
2507 		const auto depthPixel = depthAccess.getPixDepth(x, y);
2508 		match = de::inRange(depthPixel, minDepth, maxDepth);
2509 		depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
2510 		if (!match)
2511 			depthMatch = false;
2512 
2513 		const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
2514 		match = (stencilPixel == m_testConfig.expectedStencil);
2515 		stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
2516 		if (!match)
2517 			stencilMatch = false;
2518 	}
2519 
2520 	if (!(colorMatch && depthMatch && stencilMatch))
2521 	{
2522 		if (!colorMatch)
2523 			logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
2524 
2525 		if (!depthMatch)
2526 			logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
2527 
2528 		if (!stencilMatch)
2529 			logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
2530 
2531 		return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
2532 	}
2533 
2534 	return tcu::TestStatus::pass("Pass");
2535 }
2536 
stencilPasses(vk::VkCompareOp op,deUint8 storedValue,deUint8 referenceValue)2537 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
2538 {
2539 	switch (op)
2540 	{
2541 	case vk::VK_COMPARE_OP_NEVER:				return false;
2542 	case vk::VK_COMPARE_OP_LESS:				return (referenceValue <	storedValue);
2543 	case vk::VK_COMPARE_OP_EQUAL:				return (referenceValue ==	storedValue);
2544 	case vk::VK_COMPARE_OP_LESS_OR_EQUAL:		return (referenceValue <=	storedValue);
2545 	case vk::VK_COMPARE_OP_GREATER:				return (referenceValue >	storedValue);
2546 	case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:	return (referenceValue >=	storedValue);
2547 	case vk::VK_COMPARE_OP_ALWAYS:				return true;
2548 	default: DE_ASSERT(false); return false;
2549 	}
2550 
2551 	return false;	// Unreachable.
2552 }
2553 
stencilResult(vk::VkStencilOp op,deUint8 storedValue,deUint8 referenceValue,deUint8 min,deUint8 max)2554 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
2555 {
2556 	deUint8 result = storedValue;
2557 
2558 	switch (op)
2559 	{
2560 	case vk::VK_STENCIL_OP_KEEP:					break;
2561 	case vk::VK_STENCIL_OP_ZERO:					result = 0; break;
2562 	case vk::VK_STENCIL_OP_REPLACE:					result = referenceValue; break;
2563 	case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:		result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
2564 	case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:		result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
2565 	case vk::VK_STENCIL_OP_INVERT:					result = static_cast<deUint8>(~result); break;
2566 	case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:		result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
2567 	case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:		result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
2568 	default: DE_ASSERT(false); break;
2569 	}
2570 
2571 	return result;
2572 }
2573 
2574 } // anonymous namespace
2575 
createExtendedDynamicStateTests(tcu::TestContext & testCtx)2576 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
2577 {
2578 	de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
2579 
2580 	// Auxiliar constants.
2581 	const deUint32	kHalfWidthU	= kFramebufferWidth/2u;
2582 	const deInt32	kHalfWidthI	= static_cast<deInt32>(kHalfWidthU);
2583 	const float		kHalfWidthF	= static_cast<float>(kHalfWidthU);
2584 	const float		kHeightF	= static_cast<float>(kFramebufferHeight);
2585 
2586 	static const struct
2587 	{
2588 		SequenceOrdering	ordering;
2589 		std::string			name;
2590 		std::string			desc;
2591 	} kOrderingCases[] =
2592 	{
2593 		{ SequenceOrdering::CMD_BUFFER_START,	"cmd_buffer_start",		"Dynamic state set after command buffer start"																								},
2594 		{ SequenceOrdering::BEFORE_DRAW,		"before_draw",			"Dynamic state set just before drawing"																										},
2595 		{ 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"						},
2596 		{ SequenceOrdering::AFTER_PIPELINES,	"after_pipelines",		"Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"									},
2597 		{ 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"	},
2598 		{ SequenceOrdering::TWO_DRAWS_DYNAMIC,	"two_draws_dynamic",	"Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again"											},
2599 		{ SequenceOrdering::TWO_DRAWS_STATIC,	"two_draws_static",		"Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again"											},
2600 	};
2601 
2602 	for (const auto& kOrderingCase : kOrderingCases)
2603 	{
2604 		const auto& kOrdering		= kOrderingCase.ordering;
2605 
2606 		de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
2607 
2608 		// Cull modes.
2609 		{
2610 			TestConfig config(kOrdering);
2611 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_BIT;
2612 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
2613 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
2614 		}
2615 		{
2616 			TestConfig config(kOrdering);
2617 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_FRONT_AND_BACK;
2618 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
2619 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
2620 		}
2621 		{
2622 			TestConfig config(kOrdering);
2623 			// Make triangles look back.
2624 			config.meshParams[0].reversed		= true;
2625 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2626 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
2627 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
2628 		}
2629 		{
2630 			TestConfig config(kOrdering);
2631 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_NONE;
2632 			config.cullModeConfig.dynamicValue	= tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
2633 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2634 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
2635 		}
2636 
2637 		// Front face.
2638 		{
2639 			TestConfig config(kOrdering);
2640 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2641 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
2642 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2643 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
2644 		}
2645 		{
2646 			TestConfig config(kOrdering);
2647 			// Pass triangles in clockwise order.
2648 			config.meshParams[0].reversed		= true;
2649 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2650 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2651 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2652 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
2653 		}
2654 		{
2655 			TestConfig config(kOrdering);
2656 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2657 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2658 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2659 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2660 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
2661 		}
2662 		{
2663 			TestConfig config(kOrdering);
2664 			// Pass triangles in clockwise order.
2665 			config.meshParams[0].reversed		= true;
2666 			config.cullModeConfig.staticValue	= vk::VK_CULL_MODE_BACK_BIT;
2667 			config.frontFaceConfig.staticValue	= vk::VK_FRONT_FACE_CLOCKWISE;
2668 			config.frontFaceConfig.dynamicValue	= tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2669 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2670 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
2671 		}
2672 
2673 		// Rasterizer discard
2674 		{
2675 			TestConfig config(kOrdering);
2676 			config.rastDiscardEnableConfig.staticValue = false;
2677 			config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
2678 			config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2679 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
2680 		}
2681 		{
2682 			TestConfig config(kOrdering);
2683 			config.rastDiscardEnableConfig.staticValue = true;
2684 			config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
2685 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
2686 		}
2687 
2688 		// Logic op
2689 		{
2690 			TestConfig config(kOrdering);
2691 			config.logicOpConfig.staticValue = vk::VK_LOGIC_OP_CLEAR;
2692 			config.logicOpConfig.dynamicValue = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
2693 			// Clear to green, paint in blue, expect cyan due to logic op.
2694 			config.meshParams[0].color = kLogicOpTriangleColor;
2695 			config.clearColorValue = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
2696 			config.referenceColor = SingleColorGenerator(kLogicOpFinalColor);
2697 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
2698 		}
2699 
2700 		// Dynamically enable primitive restart
2701 		{
2702 			TestConfig config(kOrdering);
2703 			config.primRestartEnableConfig.staticValue = false;
2704 			config.primRestartEnableConfig.dynamicValue = tcu::just(true);
2705 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "prim_restart_enable", "Dynamically enable primitiveRestart", config));
2706 		}
2707 
2708 		// Dynamically change the number of primitive control points
2709 		{
2710 			TestConfig config(kOrdering);
2711 			config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
2712 			config.patchControlPointsConfig.staticValue = 1;
2713 			config.patchControlPointsConfig.dynamicValue = 3;
2714 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points", "Dynamically change patch control points", config));
2715 		}
2716 
2717 		// Dynamic topology.
2718 		{
2719 			TestConfig baseConfig(kOrdering);
2720 
2721 			for (int i = 0; i < 2; ++i)
2722 			{
2723 				const bool forceGeometryShader = (i > 0);
2724 
2725 				static const struct
2726 				{
2727 					vk::VkPrimitiveTopology staticVal;
2728 					vk::VkPrimitiveTopology dynamicVal;
2729 				} kTopologyCases[] =
2730 				{
2731 					{ vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,	vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP	},
2732 					{ vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,		vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP		},
2733 					{ vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,		vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST		},
2734 				};
2735 
2736 				for (const auto& kTopologyCase : kTopologyCases)
2737 				{
2738 					TestConfig config(baseConfig);
2739 					config.forceGeometryShader					= forceGeometryShader;
2740 					config.topologyConfig.staticValue			= kTopologyCase.staticVal;
2741 					config.topologyConfig.dynamicValue			= tcu::just<vk::VkPrimitiveTopology>(kTopologyCase.dynamicVal);
2742 					config.patchControlPointsConfig.staticValue	= (config.needsTessellation() ? 3u : 1u);
2743 
2744 					const std::string	className	= topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
2745 					const std::string	name		= "topology_" + className + (forceGeometryShader ? "_geom" : "");
2746 					const std::string	desc		= "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "");
2747 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
2748 				}
2749 			}
2750 		}
2751 
2752 		// Viewport.
2753 		{
2754 			TestConfig config(kOrdering);
2755 			// 2 scissors, bad static single viewport.
2756 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2757 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2758 			config.viewportConfig.dynamicValue	= ViewportVec{
2759 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2760 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2761 			};
2762 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
2763 		}
2764 		{
2765 			TestConfig config(kOrdering);
2766 			// Bad static reduced viewport.
2767 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2768 			config.viewportConfig.staticValue	= ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
2769 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
2770 		}
2771 		{
2772 			TestConfig config(kOrdering);
2773 			// 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
2774 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2775 			config.viewportConfig.staticValue	= ViewportVec{
2776 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
2777 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
2778 			};
2779 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2780 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
2781 		}
2782 		{
2783 			TestConfig config(kOrdering);
2784 			// 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
2785 			config.scissorConfig.staticValue	= ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2786 			config.viewportConfig.staticValue	= ViewportVec{
2787 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),		// Left.
2788 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),	// Right.
2789 			};
2790 			config.viewportConfig.dynamicValue	= ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2791 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2792 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
2793 		}
2794 
2795 		// Scissor.
2796 		{
2797 			TestConfig config(kOrdering);
2798 			// 2 viewports, bad static single scissor.
2799 			config.viewportConfig.staticValue	= ViewportVec{
2800 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2801 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2802 			};
2803 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2804 			config.scissorConfig.dynamicValue	= ScissorVec{
2805 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2806 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2807 			};
2808 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
2809 		}
2810 		{
2811 			TestConfig config(kOrdering);
2812 			// 1 viewport, bad static single scissor.
2813 			config.scissorConfig.staticValue	= ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2814 			config.scissorConfig.dynamicValue	= ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
2815 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
2816 		}
2817 		{
2818 			TestConfig config(kOrdering);
2819 			// 2 viewports, 2 reversed scissors that need fixing.
2820 			config.viewportConfig.staticValue	= ViewportVec{
2821 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2822 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2823 			};
2824 			config.scissorConfig.staticValue	= ScissorVec{
2825 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2826 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2827 			};
2828 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2829 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
2830 		}
2831 		{
2832 			TestConfig config(kOrdering);
2833 			// 2 viewports, 2 scissors switched to prevent drawing.
2834 			config.viewportConfig.staticValue	= ViewportVec{
2835 				vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2836 				vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2837 			};
2838 			config.scissorConfig.staticValue	= ScissorVec{
2839 				vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2840 				vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2841 			};
2842 			config.scissorConfig.dynamicValue	= ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2843 			config.referenceColor				= SingleColorGenerator(kDefaultClearColor);
2844 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
2845 		}
2846 
2847 		// Stride.
2848 		{
2849 			struct
2850 			{
2851 				const VertexGenerator*	factory;
2852 				const std::string		prefix;
2853 			} strideCases[] =
2854 			{
2855 				{ getVertexWithPaddingGenerator(),			"stride"		},
2856 				{ getVertexWithExtraAttributesGenerator(),	"large_stride"	},
2857 			};
2858 
2859 			for (const auto& strideCase : strideCases)
2860 			{
2861 				const auto	factory			= strideCase.factory;
2862 				const auto&	prefix			= strideCase.prefix;
2863 				const auto	vertexStrides	= factory->getVertexDataStrides();
2864 				StrideVec	halfStrides;
2865 
2866 				halfStrides.reserve(vertexStrides.size());
2867 				for (const auto& stride : vertexStrides)
2868 					halfStrides.push_back(stride / 2u);
2869 
2870 				if (factory == getVertexWithExtraAttributesGenerator() && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
2871 				{
2872 					// This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
2873 					// stride being less than the extent of the binding for the second attribute.
2874 					continue;
2875 				}
2876 
2877 				{
2878 					TestConfig config(kOrdering, factory);
2879 					config.strideConfig.staticValue		= halfStrides;
2880 					config.strideConfig.dynamicValue	= vertexStrides;
2881 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix, "Dynamically set stride", config));
2882 				}
2883 				{
2884 					TestConfig config(kOrdering, factory);
2885 					config.strideConfig.staticValue		= halfStrides;
2886 					config.strideConfig.dynamicValue	= vertexStrides;
2887 					config.vertexDataOffset				= vertexStrides[0];
2888 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset", "Dynamically set stride using a nonzero vertex data offset", config));
2889 				}
2890 				{
2891 					TestConfig config(kOrdering, factory);
2892 					config.strideConfig.staticValue		= halfStrides;
2893 					config.strideConfig.dynamicValue	= vertexStrides;
2894 					config.vertexDataOffset				= vertexStrides[0];
2895 					config.vertexDataExtraBytes			= config.vertexDataOffset;
2896 
2897 					// 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.
2898 					config.referenceColor				= HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2899 					config.meshParams[0].scaleY			= 0.5f;
2900 					config.meshParams[0].offsetY		= -0.5f;
2901 
2902 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding", "Dynamically set stride using a nonzero vertex data offset and extra bytes", config));
2903 				}
2904 			}
2905 
2906 			// Dynamic stride of 0
2907 			{
2908 				TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator());
2909 				config.strideConfig.staticValue		= config.getActiveVertexGenerator()->getVertexDataStrides();
2910 				config.strideConfig.dynamicValue	= { 0 };
2911 				config.vertexDataOffset				= 4;
2912 				config.singleVertex					= true;
2913 				config.singleVertexDrawCount		= 6;
2914 
2915 				// Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
2916 				// offscreen vertex and draw something in the bottom half.
2917 				config.referenceColor			= HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2918 				config.meshParams[0].scaleY		= 0.5f;
2919 				config.meshParams[0].offsetY	= -0.5f;
2920 
2921 				// Use strip scale to synthesize a strip from a vertex attribute which remains constant over the draw call.
2922 				config.meshParams[0].stripScale = 1.0f;
2923 
2924 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "zero_stride_with_offset", "Dynamically set zero stride using a nonzero vertex data offset", config));
2925 			}
2926 		}
2927 
2928 		// Depth test enable.
2929 		{
2930 			TestConfig config(kOrdering);
2931 			config.depthTestEnableConfig.staticValue	= false;
2932 			config.depthTestEnableConfig.dynamicValue	= tcu::just(true);
2933 			// By default, the depth test never passes when enabled.
2934 			config.referenceColor						= SingleColorGenerator(kDefaultClearColor);
2935 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
2936 		}
2937 		{
2938 			TestConfig config(kOrdering);
2939 			config.depthTestEnableConfig.staticValue	= true;
2940 			config.depthTestEnableConfig.dynamicValue	= tcu::just(false);
2941 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
2942 		}
2943 
2944 		// Depth write enable.
2945 		{
2946 			TestConfig config(kOrdering);
2947 
2948 			// Enable depth test and set values so it passes.
2949 			config.depthTestEnableConfig.staticValue	= true;
2950 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
2951 			config.clearDepthValue						= 0.5f;
2952 			config.meshParams[0].depth					= 0.25f;
2953 
2954 			// Enable writes and expect the mesh value.
2955 			config.depthWriteEnableConfig.staticValue	= false;
2956 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(true);
2957 			config.expectedDepth						= 0.25f;
2958 
2959 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
2960 		}
2961 		{
2962 			TestConfig config(kOrdering);
2963 
2964 			// Enable depth test and set values so it passes.
2965 			config.depthTestEnableConfig.staticValue	= true;
2966 			config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
2967 			config.clearDepthValue						= 0.5f;
2968 			config.meshParams[0].depth					= 0.25f;
2969 
2970 			// But disable writing dynamically and expect the clear value.
2971 			config.depthWriteEnableConfig.staticValue	= true;
2972 			config.depthWriteEnableConfig.dynamicValue	= tcu::just(false);
2973 			config.expectedDepth						= 0.5f;
2974 
2975 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
2976 		}
2977 
2978 		// Depth bias enable with static or dynamic depth bias parameters.
2979 		{
2980 			const DepthBiasParams kAlternativeDepthBiasParams = { 2e7f, 0.25f };
2981 
2982 			for (int dynamicBiasIter = 0; dynamicBiasIter < 2; ++dynamicBiasIter)
2983 			{
2984 				const bool useDynamicBias = (dynamicBiasIter > 0);
2985 
2986 				{
2987 					TestConfig config(kOrdering);
2988 
2989 					// Enable depth test and write 1.0f
2990 					config.depthTestEnableConfig.staticValue = true;
2991 					config.depthWriteEnableConfig.staticValue = true;
2992 					config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2993 					// Clear depth buffer to 0.25f
2994 					config.clearDepthValue = 0.25f;
2995 					// Write depth to 0.5f
2996 					config.meshParams[0].depth = 0.5f;
2997 
2998 					// Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
2999 					if (useDynamicBias)
3000 					{
3001 						config.depthBiasConfig.staticValue	= kNoDepthBiasParams;
3002 						config.depthBiasConfig.dynamicValue	= kAlternativeDepthBiasParams;
3003 					}
3004 					else
3005 					{
3006 						config.depthBiasConfig.staticValue	= kAlternativeDepthBiasParams;
3007 					}
3008 
3009 					config.depthBiasEnableConfig.staticValue = false;
3010 					config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
3011 					config.expectedDepth = 0.75f;
3012 
3013 					std::string caseName = "depth_bias_enable";
3014 					std::string caseDesc = "Dynamically enable the depth bias";
3015 
3016 					if (useDynamicBias)
3017 					{
3018 						caseName += "_dynamic_bias_params";
3019 						caseDesc += " and set the bias params dynamically";
3020 					}
3021 
3022 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3023 				}
3024 				{
3025 					TestConfig config(kOrdering);
3026 
3027 					// Enable depth test and write 1.0f
3028 					config.depthTestEnableConfig.staticValue = true;
3029 					config.depthWriteEnableConfig.staticValue = true;
3030 					config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
3031 					// Clear depth buffer to 0.25f
3032 					config.clearDepthValue = 0.25f;
3033 					// Write depth to 0.5f
3034 					config.meshParams[0].depth = 0.5f;
3035 
3036 					// Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
3037 					if (useDynamicBias)
3038 					{
3039 						config.depthBiasConfig.staticValue	= kNoDepthBiasParams;
3040 						config.depthBiasConfig.dynamicValue	= kAlternativeDepthBiasParams;
3041 					}
3042 					else
3043 					{
3044 						config.depthBiasConfig.staticValue	= kAlternativeDepthBiasParams;
3045 					}
3046 
3047 					config.depthBiasEnableConfig.staticValue = true;
3048 					config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
3049 					config.expectedDepth = 0.5f;
3050 
3051 					std::string caseName = "depth_bias_disable";
3052 					std::string caseDesc = "Dynamically disable the depth bias";
3053 
3054 					if (useDynamicBias)
3055 					{
3056 						caseName += "_dynamic_bias_params";
3057 						caseDesc += " and set the bias params dynamically";
3058 					}
3059 
3060 					orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3061 				}
3062 			}
3063 		}
3064 
3065 		// Depth compare op.
3066 		{
3067 			TestConfig baseConfig(kOrdering);
3068 			const tcu::Vec4 kAlternativeColor				(0.0f, 0.0f, 0.5f, 1.0f);
3069 			baseConfig.depthTestEnableConfig.staticValue	= true;
3070 			baseConfig.depthWriteEnableConfig.staticValue	= true;
3071 			baseConfig.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_NEVER;
3072 			baseConfig.clearDepthValue						= 0.5f;
3073 
3074 			{
3075 				TestConfig config = baseConfig;
3076 				config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_ALWAYS;
3077 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NEVER;
3078 				config.meshParams[0].depth					= 0.25f;
3079 				config.expectedDepth						= 0.5f;
3080 				config.referenceColor						= SingleColorGenerator(kDefaultClearColor);
3081 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
3082 			}
3083 			{
3084 				TestConfig config = baseConfig;
3085 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS;
3086 				config.meshParams[0].depth					= 0.25f;
3087 				config.expectedDepth						= 0.25f;
3088 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
3089 			}
3090 			{
3091 				TestConfig config = baseConfig;
3092 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER;
3093 				config.meshParams[0].depth					= 0.75f;
3094 				config.expectedDepth						= 0.75f;
3095 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
3096 			}
3097 			{
3098 				TestConfig config = baseConfig;
3099 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_EQUAL;
3100 				config.meshParams[0].depth					= 0.5f;
3101 				config.meshParams[0].color					= kAlternativeColor;
3102 				// Draw another mesh in front to verify it does not pass the equality test.
3103 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
3104 				config.expectedDepth						= 0.5f;
3105 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
3106 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
3107 			}
3108 			{
3109 				TestConfig config = baseConfig;
3110 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3111 				config.meshParams[0].depth					= 0.25f;
3112 				config.expectedDepth						= 0.25f;
3113 				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));
3114 			}
3115 			{
3116 				TestConfig config = baseConfig;
3117 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3118 				config.meshParams[0].depth					= 0.5f;
3119 				config.expectedDepth						= 0.5f;
3120 				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));
3121 			}
3122 			{
3123 				TestConfig config = baseConfig;
3124 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3125 				config.meshParams[0].depth					= 0.25f;
3126 				// Draw another mesh with the same depth in front of it.
3127 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
3128 				config.expectedDepth						= 0.25f;
3129 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
3130 				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));
3131 			}
3132 			{
3133 				TestConfig config = baseConfig;
3134 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3135 				config.meshParams[0].depth					= 0.75f;
3136 				config.expectedDepth						= 0.75f;
3137 				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));
3138 			}
3139 			{
3140 				TestConfig config = baseConfig;
3141 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3142 				config.meshParams[0].depth					= 0.5f;
3143 				config.expectedDepth						= 0.5f;
3144 				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));
3145 			}
3146 			{
3147 				TestConfig config = baseConfig;
3148 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3149 				config.meshParams[0].depth					= 0.75f;
3150 				// Draw another mesh with the same depth in front of it.
3151 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
3152 				config.expectedDepth						= 0.75f;
3153 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
3154 				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));
3155 			}
3156 			{
3157 				TestConfig config = baseConfig;
3158 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_NOT_EQUAL;
3159 
3160 				// Draw first mesh in front.
3161 				config.meshParams[0].depth					= 0.25f;
3162 				// Draw another mesh in the back, this should pass too.
3163 				config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
3164 				// Finally a new mesh with the same depth. This should not pass.
3165 				config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
3166 
3167 				config.referenceColor						= SingleColorGenerator(kAlternativeColor);
3168 				config.expectedDepth						= 0.5f;
3169 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
3170 			}
3171 			{
3172 				TestConfig config = baseConfig;
3173 				config.depthCompareOpConfig.dynamicValue	= vk::VK_COMPARE_OP_ALWAYS;
3174 
3175 				config.meshParams[0].depth					= 0.5f;
3176 				config.expectedDepth						= 0.5f;
3177 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
3178 
3179 				config.meshParams[0].depth					= 0.25f;
3180 				config.expectedDepth						= 0.25f;
3181 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
3182 
3183 				config.meshParams[0].depth					= 0.75f;
3184 				config.expectedDepth						= 0.75f;
3185 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
3186 			}
3187 		}
3188 
3189 		// Depth bounds test.
3190 		{
3191 			TestConfig baseConfig(kOrdering);
3192 			baseConfig.minDepthBounds							= 0.25f;
3193 			baseConfig.maxDepthBounds							= 0.75f;
3194 			baseConfig.meshParams[0].depth						= 0.0f;
3195 
3196 			{
3197 				TestConfig config = baseConfig;
3198 				config.depthBoundsTestEnableConfig.staticValue	= false;
3199 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(true);
3200 				config.referenceColor							= SingleColorGenerator(kDefaultClearColor);
3201 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
3202 			}
3203 			{
3204 				TestConfig config = baseConfig;
3205 				config.depthBoundsTestEnableConfig.staticValue	= true;
3206 				config.depthBoundsTestEnableConfig.dynamicValue	= tcu::just(false);
3207 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
3208 			}
3209 		}
3210 
3211 		// Stencil test enable.
3212 		{
3213 			TestConfig config(kOrdering);
3214 			config.stencilTestEnableConfig.staticValue				= false;
3215 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(true);
3216 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
3217 			config.referenceColor									= SingleColorGenerator(kDefaultClearColor);
3218 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
3219 		}
3220 		{
3221 			TestConfig config(kOrdering);
3222 			config.stencilTestEnableConfig.staticValue				= true;
3223 			config.stencilTestEnableConfig.dynamicValue				= tcu::just(false);
3224 			config.stencilOpConfig.staticValue.front().compareOp	= vk::VK_COMPARE_OP_NEVER;
3225 			orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
3226 		}
3227 
3228 		// Stencil operation. Many combinations are possible.
3229 		{
3230 			static const struct
3231 			{
3232 				vk::VkStencilFaceFlags	face;
3233 				std::string				name;
3234 			} kFaces[] =
3235 			{
3236 				{ vk::VK_STENCIL_FACE_FRONT_BIT,			"face_front"		},
3237 				{ vk::VK_STENCIL_FACE_BACK_BIT,				"face_back"			},
3238 				{ vk::VK_STENCIL_FRONT_AND_BACK,			"face_both_single"	},
3239 				{ vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM,	"face_both_dual"	},	// MAX_ENUM is a placeholder.
3240 			};
3241 
3242 			static const struct
3243 			{
3244 				vk::VkCompareOp		compareOp;
3245 				std::string			name;
3246 			} kCompare[] =
3247 			{
3248 				{ vk::VK_COMPARE_OP_NEVER,				"xf"		},
3249 				{ vk::VK_COMPARE_OP_LESS,				"lt"		},
3250 				{ vk::VK_COMPARE_OP_EQUAL,				"eq"		},
3251 				{ vk::VK_COMPARE_OP_LESS_OR_EQUAL,		"le"		},
3252 				{ vk::VK_COMPARE_OP_GREATER,			"gt"		},
3253 				{ vk::VK_COMPARE_OP_GREATER_OR_EQUAL,	"ge"		},
3254 				{ vk::VK_COMPARE_OP_ALWAYS,				"xt"		},
3255 			};
3256 
3257 			using u8vec = std::vector<deUint8>;
3258 
3259 			static const auto kMinVal	= std::numeric_limits<deUint8>::min();
3260 			static const auto kMaxVal	= std::numeric_limits<deUint8>::max();
3261 			static const auto kMidVal	= static_cast<deUint8>(kMaxVal * 2u / 5u);
3262 			static const auto kMinValI	= static_cast<int>(kMinVal);
3263 			static const auto kMaxValI	= static_cast<int>(kMaxVal);
3264 
3265 			static const struct
3266 			{
3267 				vk::VkStencilOp		stencilOp;
3268 				std::string			name;
3269 				u8vec				clearValues;	// One test per clear value interesting for this operation.
3270 				vk::VkStencilOp		incompatibleOp;	// Alternative operation giving incompatible results for the given values.
3271 			} kStencilOps[] =
3272 			{
3273 				{ vk::VK_STENCIL_OP_KEEP,					"keep",			u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
3274 				{ vk::VK_STENCIL_OP_ZERO,					"zero",			u8vec{kMidVal},					vk::VK_STENCIL_OP_KEEP					},
3275 				{ vk::VK_STENCIL_OP_REPLACE,				"replace",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
3276 				{ vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP,	"inc_clamp",	u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_ZERO					},
3277 				{ vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP,	"dec_clamp",	u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP	},
3278 				{ vk::VK_STENCIL_OP_INVERT,					"invert",		u8vec{kMidVal},					vk::VK_STENCIL_OP_ZERO					},
3279 				{ vk::VK_STENCIL_OP_INCREMENT_AND_WRAP,		"inc_wrap",		u8vec{kMaxVal - 1, kMaxVal},	vk::VK_STENCIL_OP_KEEP					},
3280 				{ vk::VK_STENCIL_OP_DECREMENT_AND_WRAP,		"dec_wrap",		u8vec{kMinVal + 1, kMinVal},	vk::VK_STENCIL_OP_KEEP					},
3281 			};
3282 
3283 			for (const auto& face : kFaces)
3284 			for (const auto& compare : kCompare)
3285 			for (const auto& op : kStencilOps)
3286 			{
3287 				// Try clearing the stencil value with different values.
3288 				for (const auto clearVal : op.clearValues)
3289 				{
3290 					// Use interesting values as the reference stencil value.
3291 					for (int delta = -1; delta <= 1; ++delta)
3292 					{
3293 						const int refVal = clearVal + delta;
3294 						if (refVal < kMinValI || refVal > kMaxValI)
3295 							continue;
3296 
3297 						const auto refValU8		= static_cast<deUint8>(refVal);
3298 						const auto refValU32	= static_cast<deUint32>(refVal);
3299 
3300 						// Calculate outcome of the stencil test itself.
3301 						const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
3302 
3303 						// If the test passes, use an additional variant for the depthFail operation.
3304 						const int subCases = (wouldPass ? 2 : 1);
3305 
3306 						for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
3307 						{
3308 							const bool depthFail	= (subCaseIdx > 0);				// depthFail would be the second variant.
3309 							const bool globalPass	= (wouldPass && !depthFail);	// Global result of the stencil+depth test.
3310 
3311 							// Start tuning test parameters.
3312 							TestConfig config(kOrdering);
3313 
3314 							// No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
3315 							if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
3316 							{
3317 								// Default parameters are OK.
3318 							}
3319 							else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
3320 							{
3321 								// Reverse the mesh so it applies the back operation.
3322 								config.meshParams[0].reversed = true;
3323 							}
3324 							else	// Front and back.
3325 							{
3326 								// Draw both a front and a back-facing mesh so both are applied.
3327 								// The first mesh will be drawn in the top half and the second mesh in the bottom half.
3328 
3329 								// Make the second mesh a reversed copy of the first mesh.
3330 								config.meshParams.push_back(config.meshParams.front());
3331 								config.meshParams.back().reversed = true;
3332 
3333 								// Apply scale and offset to the top mesh.
3334 								config.meshParams.front().scaleY = 0.5f;
3335 								config.meshParams.front().offsetY = -0.5f;
3336 
3337 								// Apply scale and offset to the bottom mesh.
3338 								config.meshParams.back().scaleY = 0.5f;
3339 								config.meshParams.back().offsetY = 0.5f;
3340 							}
3341 
3342 							// Enable the stencil test.
3343 							config.stencilTestEnableConfig.staticValue = true;
3344 
3345 							// Set dynamic configuration.
3346 							StencilOpParams dynamicStencilConfig;
3347 							dynamicStencilConfig.faceMask		= face.face;
3348 							dynamicStencilConfig.compareOp		= compare.compareOp;
3349 							dynamicStencilConfig.failOp			= vk::VK_STENCIL_OP_MAX_ENUM;
3350 							dynamicStencilConfig.passOp			= vk::VK_STENCIL_OP_MAX_ENUM;
3351 							dynamicStencilConfig.depthFailOp	= vk::VK_STENCIL_OP_MAX_ENUM;
3352 
3353 							// Set operations so only the appropriate operation for this case gives the right result.
3354 							vk::VkStencilOp* activeOp		= nullptr;
3355 							vk::VkStencilOp* inactiveOps[2]	= { nullptr, nullptr };
3356 							if (wouldPass)
3357 							{
3358 								if (depthFail)
3359 								{
3360 									activeOp		= &dynamicStencilConfig.depthFailOp;
3361 									inactiveOps[0]	= &dynamicStencilConfig.passOp;
3362 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
3363 								}
3364 								else
3365 								{
3366 									activeOp		= &dynamicStencilConfig.passOp;
3367 									inactiveOps[0]	= &dynamicStencilConfig.depthFailOp;
3368 									inactiveOps[1]	= &dynamicStencilConfig.failOp;
3369 								}
3370 							}
3371 							else
3372 							{
3373 								activeOp		= &dynamicStencilConfig.failOp;
3374 								inactiveOps[0]	= &dynamicStencilConfig.passOp;
3375 								inactiveOps[1]	= &dynamicStencilConfig.depthFailOp;
3376 							}
3377 
3378 							*activeOp = op.stencilOp;
3379 							*inactiveOps[0] = op.incompatibleOp;
3380 							*inactiveOps[1] = op.incompatibleOp;
3381 
3382 							// Make sure all ops have been configured properly.
3383 							DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
3384 							DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
3385 							DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
3386 
3387 							// Set an incompatible static operation too.
3388 							auto& staticStencilConfig		= config.stencilOpConfig.staticValue.front();
3389 							staticStencilConfig.faceMask	= face.face;
3390 							staticStencilConfig.compareOp	= (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
3391 							staticStencilConfig.passOp		= op.incompatibleOp;
3392 							staticStencilConfig.failOp		= op.incompatibleOp;
3393 							staticStencilConfig.depthFailOp	= op.incompatibleOp;
3394 
3395 							// Set dynamic configuration.
3396 							StencilOpVec stencilOps;
3397 							stencilOps.push_back(dynamicStencilConfig);
3398 
3399 							if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
3400 							{
3401 								// This is the dual case. We will set the front and back face values with two separate calls.
3402 								stencilOps.push_back(stencilOps.front());
3403 								stencilOps.front().faceMask		= vk::VK_STENCIL_FACE_FRONT_BIT;
3404 								stencilOps.back().faceMask		= vk::VK_STENCIL_FACE_BACK_BIT;
3405 								staticStencilConfig.faceMask	= vk::VK_STENCIL_FACE_FRONT_AND_BACK;
3406 							}
3407 
3408 							config.stencilOpConfig.dynamicValue	= tcu::just(stencilOps);
3409 							config.clearStencilValue			= clearVal;
3410 							config.referenceStencil				= refValU32;
3411 
3412 							if (depthFail)
3413 							{
3414 								// Enable depth test and make it fail.
3415 								config.depthTestEnableConfig.staticValue	= true;
3416 								config.clearDepthValue						= 0.5f;
3417 								config.depthCompareOpConfig.staticValue		= vk::VK_COMPARE_OP_LESS;
3418 
3419 								for (auto& meshPar : config.meshParams)
3420 									meshPar.depth = 0.75f;
3421 							}
3422 
3423 							// Set expected outcome.
3424 							config.referenceColor	= SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor);
3425 							config.expectedDepth	= config.clearDepthValue; // No depth writing by default.
3426 							config.expectedStencil	= stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
3427 
3428 							const std::string testName = std::string("stencil_state")
3429 								+ "_" + face.name
3430 								+ "_" + compare.name
3431 								+ "_" + op.name
3432 								+ "_clear_" + de::toString(static_cast<int>(clearVal))
3433 								+ "_ref_" + de::toString(refVal)
3434 								+ "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
3435 
3436 							orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
3437 						}
3438 					}
3439 				}
3440 			}
3441 		}
3442 
3443 		// Vertex input.
3444 		{
3445 			// TWO_DRAWS_STATIC would be invalid because it violates VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the
3446 			// dynamic stride being less than the extent of the binding for the second attribute.
3447 			if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
3448 			{
3449 				const auto	staticGen	= getVertexWithPaddingGenerator();
3450 				const auto	dynamicGen	= getVertexWithExtraAttributesGenerator();
3451 				const auto	goodStrides	= dynamicGen->getVertexDataStrides();
3452 				StrideVec	badStrides;
3453 
3454 				badStrides.reserve(goodStrides.size());
3455 				for (const auto& stride : goodStrides)
3456 					badStrides.push_back(stride / 2u);
3457 
3458 				TestConfig config(kOrdering, staticGen, dynamicGen);
3459 				config.strideConfig.staticValue			= badStrides;
3460 				config.strideConfig.dynamicValue		= goodStrides;
3461 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input", "Dynamically set vertex input", config));
3462 			}
3463 
3464 			{
3465 				// Variant without mixing in the stride config.
3466 				TestConfig config(kOrdering, getVertexWithPaddingGenerator(), getVertexWithExtraAttributesGenerator());
3467 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_no_dyn_stride", "Dynamically set vertex input without using dynamic strides", config));
3468 			}
3469 
3470 			{
3471 				// Variant using multiple bindings.
3472 				TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator(), getVertexWithMultipleBindingsGenerator());
3473 				orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_multiple_bindings", "Dynamically set vertex input with multiple bindings", config));
3474 			}
3475 		}
3476 
3477 		extendedDynamicStateGroup->addChild(orderingGroup.release());
3478 	}
3479 
3480 	return extendedDynamicStateGroup.release();
3481 }
3482 
3483 } // pipeline
3484 } // vkt
3485