Merge pull request #276 from Ella-0/master
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / pipeline / vktPipelineExtendedDynamicStateTests.cpp
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
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.
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
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.
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>
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         {
200                 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:
210         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
217         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
224         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.
232         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.
240         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.
248         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
255         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
260         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         {
272                 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:
285         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
293         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
301         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
309         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
317         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
324         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
331         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
336         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
359                 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
371                 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
383                 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
394                 Zeros (const tcu::Vec2&)
395                         : zeros (0.0f, 0.0f)
396                 {}
397         };
398
399 public:
400         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
412         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
423         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
436         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
449         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
465         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
481         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
496         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.
551         StaticAndDynamicPair (const T& value)
552                 : staticValue   (value)
553                 , dynamicValue  (tcu::nothing<T>())
554         {
555         }
556
557         // Helper constructor to set both.
558         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.
565         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           fanScale;
614
615         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                           fanScale_       = 0.0f)
623                 : color         (color_)
624                 , depth         (depth_)
625                 , reversed      (reversed_)
626                 , scaleX        (scaleX_)
627                 , scaleY        (scaleY_)
628                 , offsetX       (offsetX_)
629                 , offsetY       (offsetY_)
630                 , fanScale      (fanScale_)
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:
651         SingleColorGenerator (const tcu::Vec4& color)
652                 : m_colorFloat  (color)
653                 , m_colorUint   (0u)
654                 , isUint                (false)
655         {}
656
657         SingleColorGenerator (const tcu::UVec4& color)
658                 : m_colorFloat  (0.0f)
659                 , m_colorUint   (color)
660                 , isUint                (true)
661         {}
662
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:
688         HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
689                 : m_top(top), m_bottom(bottom)
690         {}
691
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
711 const VertexGenerator* getVertexWithPaddingGenerator ()
712 {
713         static const VertexWithPadding vertexWithPadding;
714         return &vertexWithPadding;
715 }
716
717 const VertexGenerator* getVertexWithExtraAttributesGenerator ()
718 {
719         static const VertexWithExtraAttributes vertexWithExtraAttributes;
720         return &vertexWithExtraAttributes;
721 }
722
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.
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.
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
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
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.
859         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 fan with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
880                 , topologyConfig                                (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
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.
902         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.
908         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.
914         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.
920         deUint32 getActivePatchControlPoints () const
921         {
922                 return ((patchControlPointsConfig.dynamicValue && !m_swappedValues) ? patchControlPointsConfig.dynamicValue.get() : patchControlPointsConfig.staticValue);
923         }
924
925         // Get the active depth bias parameters.
926         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.
932         bool isMultiViewport () const
933         {
934                 return (getActiveViewportVec().size() > 1);
935         }
936
937         // Returns true if the case needs a geometry shader.
938         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.
947         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.
954         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.
980         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.
999         bool testLogicOp () const
1000         {
1001                 return static_cast<bool>(logicOpConfig.dynamicValue);
1002         }
1003
1004         // Returns true if we're testing the patch control points.
1005         bool testPatchControlPoints () const
1006         {
1007                 return static_cast<bool>(patchControlPointsConfig.dynamicValue);
1008         }
1009
1010         // Returns true if the topology class is patches for tessellation.
1011         bool patchesTopology () const
1012         {
1013                 return (getTopologyClass(topologyConfig.staticValue) == TopologyClass::PATCH);
1014         }
1015
1016         // Returns true if the test needs tessellation shaders.
1017         bool needsTessellation () const
1018         {
1019                 return (testPatchControlPoints() || patchesTopology());
1020         }
1021
1022         // Returns true if the test needs an index buffer.
1023         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.
1029         bool needsDepthBiasClampFeature () const
1030         {
1031                 return (getActiveDepthBiasParams().clamp != 0.0f);
1032         }
1033
1034         // Returns the appropriate color image format for the test.
1035         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.
1042         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.
1070         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           fanScale;
1129 };
1130
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);
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);
1157         virtual                                         ~ExtendedDynamicStateInstance   (void) {}
1158
1159         virtual tcu::TestStatus         iterate                                                 (void);
1160
1161 private:
1162         TestConfig                                      m_testConfig;
1163 };
1164
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
1185 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
1256 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 fanScale;\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 fanOffset;\n"
1318                 << "    switch (gl_VertexIndex) {\n"
1319                 << "    case 0: fanOffset = vec2(0.0, 0.0); break;\n"
1320                 << "    case 1: fanOffset = vec2(1.0, 0.0); break;\n"
1321                 << "    case 2: fanOffset = vec2(1.0, -1.0); break;\n"
1322                 << "    case 3: fanOffset = vec2(0.0, -1.0); break;\n"
1323                 << "    case 4: fanOffset = vec2(-1.0, -1.0); break;\n"
1324                 << "    case 5: fanOffset = vec2(-1.0, 0.0); break;\n"
1325                 << "    default: fanOffset = vec2(-1000.0); break;\n"
1326                 << "    }\n"
1327                 << "    gl_Position.xy += pushConstants.fanScale * fanOffset;\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
1436
1437         programCollection.glslSources.add("vert") << glu::VertexSource(activeVertSource);
1438         programCollection.glslSources.add("vert2") << glu::VertexSource(inactiveVertSource);
1439         programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
1440         if (m_testConfig.needsGeometryShader())
1441                 programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
1442         if (m_testConfig.needsTessellation())
1443         {
1444                 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
1445                 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
1446         }
1447 }
1448
1449 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
1450 {
1451         return new ExtendedDynamicStateInstance(context, m_testConfig);
1452 }
1453
1454 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
1455         : vkt::TestInstance     (context)
1456         , m_testConfig          (testConfig)
1457 {
1458 }
1459
1460 struct VertexBufferInfo
1461 {
1462         VertexBufferInfo ()
1463                 : buffer        ()
1464                 , offset        (0ull)
1465                 , dataSize      (0ull)
1466         {}
1467
1468         VertexBufferInfo (VertexBufferInfo&& other)
1469                 : buffer        (other.buffer.release())
1470                 , offset        (other.offset)
1471                 , dataSize      (other.dataSize)
1472         {}
1473
1474         de::MovePtr<vk::BufferWithMemory>       buffer;
1475         vk::VkDeviceSize                                        offset;
1476         vk::VkDeviceSize                                        dataSize;
1477 };
1478
1479 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
1480 {
1481         log << tcu::TestLog::ImageSet(setName, setDesc)
1482                 << tcu::TestLog::Image(setName + "Result", "Result image", result)
1483                 << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
1484                 << tcu::TestLog::EndImageSet;
1485 }
1486
1487 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
1488 {
1489         auto&   alloc   = buffer.getAllocation();
1490         auto    dst             = reinterpret_cast<char*>(alloc.getHostPtr());
1491
1492         deMemcpy(dst + offset, src, size);
1493         vk::flushAlloc(vkd, device, alloc);
1494 }
1495
1496 // Sets values for dynamic states if needed according to the test configuration.
1497 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
1498 {
1499         if (testConfig.cullModeConfig.dynamicValue)
1500                 vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
1501
1502         if (testConfig.frontFaceConfig.dynamicValue)
1503                 vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
1504
1505         if (testConfig.topologyConfig.dynamicValue)
1506                 vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
1507
1508         if (testConfig.viewportConfig.dynamicValue)
1509         {
1510                 const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
1511                 vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
1512         }
1513
1514         if (testConfig.scissorConfig.dynamicValue)
1515         {
1516                 const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
1517                 vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
1518         }
1519
1520         if (testConfig.depthTestEnableConfig.dynamicValue)
1521                 vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
1522
1523         if (testConfig.depthWriteEnableConfig.dynamicValue)
1524                 vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
1525
1526         if (testConfig.depthCompareOpConfig.dynamicValue)
1527                 vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
1528
1529         if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
1530                 vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
1531
1532         if (testConfig.stencilTestEnableConfig.dynamicValue)
1533                 vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
1534
1535         if (testConfig.depthBiasEnableConfig.dynamicValue)
1536                 vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
1537
1538         if (testConfig.depthBiasConfig.dynamicValue)
1539         {
1540                 const auto& bias = testConfig.depthBiasConfig.dynamicValue.get();
1541                 vkd.cmdSetDepthBias(cmdBuffer, bias.constantFactor, bias.clamp, 0.0f);
1542         }
1543
1544         if (testConfig.rastDiscardEnableConfig.dynamicValue)
1545                 vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
1546
1547         if (testConfig.primRestartEnableConfig.dynamicValue)
1548                 vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
1549
1550         if (testConfig.logicOpConfig.dynamicValue)
1551                 vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
1552
1553         if (testConfig.patchControlPointsConfig.dynamicValue)
1554                 vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
1555
1556         if (testConfig.stencilOpConfig.dynamicValue)
1557         {
1558                 for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
1559                         vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
1560         }
1561
1562         if (testConfig.vertexGenerator.dynamicValue)
1563         {
1564                 const auto generator    = testConfig.vertexGenerator.dynamicValue.get();
1565                 const auto bindings             = generator->getBindingDescriptions2(testConfig.strideConfig.staticValue);
1566                 const auto attributes   = generator->getAttributeDescriptions2();
1567
1568                 vkd.cmdSetVertexInputEXT(cmdBuffer,
1569                         static_cast<deUint32>(bindings.size()), de::dataOrNull(bindings),
1570                         static_cast<deUint32>(attributes.size()), de::dataOrNull(attributes));
1571         }
1572 }
1573
1574 // Bind the appropriate vertex buffers using dynamic strides if the test configuration needs a dynamic stride.
1575 // Return true if the vertex buffer was bound.
1576 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)
1577 {
1578         if (!testConfig.strideConfig.dynamicValue)
1579                 return false;
1580
1581         const auto& viewportVec = testConfig.getActiveViewportVec();
1582         DE_UNREF(viewportVec); // For release builds.
1583
1584         // When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
1585         // orderings if we have several viewports or meshes.
1586         DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
1587                                 || testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
1588                                 || testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1589
1590         // Split buffers, offsets, sizes and strides into their own vectors for the call.
1591         std::vector<vk::VkBuffer>               buffers;
1592         std::vector<vk::VkDeviceSize>   offsets;
1593         std::vector<vk::VkDeviceSize>   sizes;
1594         const auto                                              strides = testConfig.strideConfig.dynamicValue.get();
1595
1596         const auto& chosenBuffers = (testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers);
1597
1598         buffers.reserve (chosenBuffers.size());
1599         offsets.reserve (chosenBuffers.size());
1600         sizes.reserve   (chosenBuffers.size());
1601         DE_ASSERT(chosenBuffers.size() == strides.size());
1602
1603         for (const auto& vertBuffer : chosenBuffers)
1604         {
1605                 buffers.push_back       (vertBuffer.buffer->get());
1606                 offsets.push_back       (vertBuffer.offset);
1607                 sizes.push_back         (vertBuffer.dataSize);
1608         }
1609
1610         vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, static_cast<deUint32>(chosenBuffers.size()), buffers.data(), offsets.data(), sizes.data(), strides.data());
1611
1612         return true;
1613 }
1614
1615 // Bind the given vertex buffers with the non-dynamic call. Similar to maybeBindVertexBufferDynStride but simpler.
1616 void bindVertexBuffers (const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, const std::vector<VertexBufferInfo>& vertexBuffers)
1617 {
1618         std::vector<vk::VkBuffer>               buffers;
1619         std::vector<vk::VkDeviceSize>   offsets;
1620
1621         buffers.reserve (vertexBuffers.size());
1622         offsets.reserve (vertexBuffers.size());
1623
1624         for (const auto& vertBuffer : vertexBuffers)
1625         {
1626                 buffers.push_back       (vertBuffer.buffer->get());
1627                 offsets.push_back       (vertBuffer.offset);
1628         }
1629
1630         vkd.cmdBindVertexBuffers(cmdBuffer, 0u, static_cast<deUint32>(vertexBuffers.size()), buffers.data(), offsets.data());
1631 }
1632
1633
1634 // Create a vector of VertexBufferInfo elements using the given vertex generator and set of vertices.
1635 void prepareVertexBuffers (     std::vector<VertexBufferInfo>&  buffers,
1636                                                         const vk::DeviceInterface&              vkd,
1637                                                         vk::VkDevice                                    device,
1638                                                         vk::Allocator&                                  allocator,
1639                                                         const VertexGenerator*                  generator,
1640                                                         const std::vector<tcu::Vec2>&   vertices,
1641                                                         deUint32                                                dataOffset,
1642                                                         deUint32                                                trailingSize)
1643 {
1644         const deUint32  paddingBytes    = 0xDEADBEEFu;
1645         const auto              vertexData              = generator->createVertexData(vertices, dataOffset, trailingSize, &paddingBytes, sizeof(paddingBytes));
1646
1647         for (const auto& bufferBytes : vertexData)
1648         {
1649                 const auto bufferSize   = static_cast<vk::VkDeviceSize>(de::dataSize(bufferBytes));
1650                 const auto extraSize    = static_cast<vk::VkDeviceSize>(dataOffset + trailingSize);
1651                 DE_ASSERT(bufferSize > extraSize);
1652                 const auto dataSize             = bufferSize - extraSize;
1653
1654                 // Create a full-size buffer but remember the data size and offset for it.
1655                 const auto createInfo = vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1656
1657                 VertexBufferInfo bufferInfo;
1658                 bufferInfo.buffer       = de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vkd, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
1659                 bufferInfo.offset       = static_cast<vk::VkDeviceSize>(dataOffset);
1660                 bufferInfo.dataSize     = dataSize;
1661                 buffers.emplace_back(std::move(bufferInfo));
1662
1663                 // Copy the whole contents to the full buffer.
1664                 copyAndFlush(vkd, device, *buffers.back().buffer, 0, bufferBytes.data(), de::dataSize(bufferBytes));
1665         }
1666 }
1667
1668 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
1669 {
1670         using ImageWithMemoryVec        = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
1671         using ImageViewVec                      = std::vector<vk::Move<vk::VkImageView>>;
1672         using FramebufferVec            = std::vector<vk::Move<vk::VkFramebuffer>>;
1673
1674         const auto&     vki                                     = m_context.getInstanceInterface();
1675         const auto&     vkd                                     = m_context.getDeviceInterface();
1676         const auto      physicalDevice          = m_context.getPhysicalDevice();
1677         const auto      device                          = m_context.getDevice();
1678         auto&           allocator                       = m_context.getDefaultAllocator();
1679         const auto      queue                           = m_context.getUniversalQueue();
1680         const auto      queueIndex                      = m_context.getUniversalQueueFamilyIndex();
1681         auto&           log                                     = m_context.getTestContext().getLog();
1682
1683         const auto      kReversed                       = m_testConfig.isReversed();
1684         const auto      kNumIterations          = m_testConfig.numIterations();
1685         const auto      kSequenceOrdering       = m_testConfig.sequenceOrdering;
1686
1687         const auto                                              kFramebufferExtent      = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
1688         const vk::VkImageUsageFlags             kColorUsage                     = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1689         const vk::VkImageUsageFlags             kDSUsage                        = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1690         const vk::VkFormatFeatureFlags  kDSFeatures                     = (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1691         const auto                                              colorFormat                     = m_testConfig.colorFormat();
1692
1693         // Choose depth/stencil format.
1694         const DepthStencilFormat* dsFormatInfo = nullptr;
1695
1696         for (const auto& kDepthStencilFormat : kDepthStencilFormats)
1697         {
1698                 const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormat.imageFormat);
1699                 if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
1700                 {
1701                         dsFormatInfo = &kDepthStencilFormat;
1702                         break;
1703                 }
1704         }
1705
1706         // Note: Not Supported insted of Fail because the transfer feature is not mandatory.
1707         if (!dsFormatInfo)
1708                 TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
1709         log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
1710
1711         // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
1712         // where we will bind the static pipeline last before drawing.
1713         if (kReversed)
1714                 m_testConfig.swapValues();
1715
1716         // Create color and depth/stencil images.
1717         ImageWithMemoryVec colorImages;
1718         ImageWithMemoryVec dsImages;
1719
1720         const vk::VkImageCreateInfo colorImageInfo =
1721         {
1722                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,        //      VkStructureType                 sType;
1723                 nullptr,                                                                        //      const void*                             pNext;
1724                 0u,                                                                                     //      VkImageCreateFlags              flags;
1725                 vk::VK_IMAGE_TYPE_2D,                                           //      VkImageType                             imageType;
1726                 colorFormat,                                                            //      VkFormat                                format;
1727                 kFramebufferExtent,                                                     //      VkExtent3D                              extent;
1728                 1u,                                                                                     //      deUint32                                mipLevels;
1729                 1u,                                                                                     //      deUint32                                arrayLayers;
1730                 vk::VK_SAMPLE_COUNT_1_BIT,                                      //      VkSampleCountFlagBits   samples;
1731                 vk::VK_IMAGE_TILING_OPTIMAL,                            //      VkImageTiling                   tiling;
1732                 kColorUsage,                                                            //      VkImageUsageFlags               usage;
1733                 vk::VK_SHARING_MODE_EXCLUSIVE,                          //      VkSharingMode                   sharingMode;
1734                 1u,                                                                                     //      deUint32                                queueFamilyIndexCount;
1735                 &queueIndex,                                                            //      const deUint32*                 pQueueFamilyIndices;
1736                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                          //      VkImageLayout                   initialLayout;
1737         };
1738         for (deUint32 i = 0u; i < kNumIterations; ++i)
1739                 colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
1740
1741         const vk::VkImageCreateInfo dsImageInfo =
1742         {
1743                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,        //      VkStructureType                 sType;
1744                 nullptr,                                                                        //      const void*                             pNext;
1745                 0u,                                                                                     //      VkImageCreateFlags              flags;
1746                 vk::VK_IMAGE_TYPE_2D,                                           //      VkImageType                             imageType;
1747                 dsFormatInfo->imageFormat,                                      //      VkFormat                                format;
1748                 kFramebufferExtent,                                                     //      VkExtent3D                              extent;
1749                 1u,                                                                                     //      deUint32                                mipLevels;
1750                 1u,                                                                                     //      deUint32                                arrayLayers;
1751                 vk::VK_SAMPLE_COUNT_1_BIT,                                      //      VkSampleCountFlagBits   samples;
1752                 vk::VK_IMAGE_TILING_OPTIMAL,                            //      VkImageTiling                   tiling;
1753                 kDSUsage,                                                                       //      VkImageUsageFlags               usage;
1754                 vk::VK_SHARING_MODE_EXCLUSIVE,                          //      VkSharingMode                   sharingMode;
1755                 1u,                                                                                     //      deUint32                                queueFamilyIndexCount;
1756                 &queueIndex,                                                            //      const deUint32*                 pQueueFamilyIndices;
1757                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                          //      VkImageLayout                   initialLayout;
1758         };
1759         for (deUint32 i = 0u; i < kNumIterations; ++i)
1760                 dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
1761
1762         const auto colorSubresourceRange        = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1763         const auto dsSubresourceRange           = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
1764
1765         ImageViewVec colorImageViews;
1766         ImageViewVec dsImageViews;
1767
1768         for (const auto& img : colorImages)
1769                 colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
1770
1771         for (const auto& img : dsImages)
1772                 dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
1773
1774         // Vertex buffer.
1775         const auto                                                                      topologyClass   = getTopologyClass(m_testConfig.topologyConfig.staticValue);
1776         const std::vector<deUint32>                                     indices                 { 0, 1, 2, 3, 0xFFFFFFFF, 4, 5, 0, 3 };
1777         std::vector<tcu::Vec2>                                          vertices;
1778
1779         if (topologyClass == TopologyClass::TRIANGLE)
1780         {
1781                 // Full-screen triangle fan with 6 vertices.
1782                 //
1783                 // 4        3        2
1784                 //  +-------+-------+
1785                 //  |X      X      X|
1786                 //  | X     X     X |
1787                 //  |  X    X    X  |
1788                 //  |   X   X   X   |
1789                 //  |    X  X  X    |
1790                 //  |     X X X     |
1791                 //  |      XXX      |
1792                 //  +-------+-------+
1793                 // 5        0        1
1794                 vertices.reserve(6u);
1795                 vertices.push_back(tcu::Vec2( 0.0f,  1.0f));
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(-1.0f, -1.0f));
1800                 vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
1801         }
1802         else if (topologyClass == TopologyClass::PATCH)
1803         {
1804                 DE_ASSERT(m_testConfig.getActivePatchControlPoints() > 1u);
1805
1806                 // 2 triangles making a quad
1807                 vertices.reserve(6u);
1808                 vertices.push_back(tcu::Vec2(-1.0f,  1.0f));
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         }
1815         else // TopologyClass::LINE
1816         {
1817                 // 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.
1818                 vertices.reserve(kFramebufferHeight * 4u);
1819                 const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
1820                 for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
1821                 {
1822                         // Offset of 0.5 pixels + one line per row from -1 to 1.
1823                         const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
1824                         vertices.push_back(tcu::Vec2(-1.0f, yCoord));
1825                         vertices.push_back(tcu::Vec2(-0.5f, yCoord));
1826                         vertices.push_back(tcu::Vec2( 0.5f, yCoord));
1827                         vertices.push_back(tcu::Vec2( 1.0f, yCoord));
1828                 }
1829         }
1830
1831         if (m_testConfig.singleVertex)
1832                 vertices.resize(1);
1833
1834         // Reversed vertices, except for the first one (0, 5, 4, 3, 2, 1): clockwise mesh for triangles. Not to be used with lines.
1835         std::vector<tcu::Vec2> rvertices;
1836         if (topologyClass == TopologyClass::TRIANGLE)
1837         {
1838                 DE_ASSERT(!vertices.empty());
1839                 rvertices.reserve(vertices.size());
1840                 rvertices.push_back(vertices[0]);
1841                 std::copy_n(vertices.rbegin(), vertices.size() - 1u, std::back_inserter(rvertices));
1842         }
1843
1844         if (topologyClass != TopologyClass::TRIANGLE)
1845         {
1846                 for (const auto& mesh : m_testConfig.meshParams)
1847                 {
1848                         DE_UNREF(mesh); // For release builds.
1849                         DE_ASSERT(!mesh.reversed);
1850                 }
1851         }
1852
1853         // Buffers with vertex data for the different bindings.
1854         std::vector<VertexBufferInfo> vertBuffers;
1855         std::vector<VertexBufferInfo> rvertBuffers;
1856
1857         {
1858                 const auto dataOffset   = static_cast<deUint32>(m_testConfig.vertexDataOffset);
1859                 const auto trailingSize = static_cast<deUint32>(m_testConfig.vertexDataExtraBytes);
1860                 const auto generator    = m_testConfig.getActiveVertexGenerator();
1861                 prepareVertexBuffers(vertBuffers, vkd, device, allocator, generator, vertices, dataOffset, trailingSize);
1862                 if (topologyClass == TopologyClass::TRIANGLE)
1863                         prepareVertexBuffers(rvertBuffers, vkd, device, allocator, generator, rvertices, dataOffset, trailingSize);
1864         }
1865
1866         // Index buffer.
1867         const auto indexDataSize                        = static_cast<vk::VkDeviceSize>(de::dataSize(indices));
1868         const auto indexBufferInfo                      = vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1869         vk::BufferWithMemory indexBuffer        (vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible);
1870         copyAndFlush(vkd, device, indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
1871
1872         // Descriptor set layout.
1873         vk::DescriptorSetLayoutBuilder layoutBuilder;
1874         const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1875
1876         // Pipeline layout.
1877         vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1878         if (m_testConfig.isMultiViewport())
1879                 pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1880
1881         const vk::VkPushConstantRange pushConstantRange =
1882         {
1883                 pushConstantStageFlags,                                                 //      VkShaderStageFlags      stageFlags;
1884                 0u,                                                                                             //      deUint32                        offset;
1885                 static_cast<deUint32>(sizeof(PushConstants)),   //      deUint32                        size;
1886         };
1887
1888         const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1889         {
1890                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,      //      VkStructureType                                 sType;
1891                 nullptr,                                                                                        //      const void*                                             pNext;
1892                 0u,                                                                                                     //      VkPipelineLayoutCreateFlags             flags;
1893                 1u,                                                                                                     //      deUint32                                                setLayoutCount;
1894                 &descriptorSetLayout.get(),                                                     //      const VkDescriptorSetLayout*    pSetLayouts;
1895                 1u,                                                                                                     //      deUint32                                                pushConstantRangeCount;
1896                 &pushConstantRange,                                                                     //      const VkPushConstantRange*              pPushConstantRanges;
1897         };
1898         const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
1899
1900         // Render pass with single subpass.
1901         const vk::VkAttachmentReference colorAttachmentReference =
1902         {
1903                 0u,                                                                                             //      deUint32                attachment;
1904                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   //      VkImageLayout   layout;
1905         };
1906
1907         const vk::VkAttachmentReference dsAttachmentReference =
1908         {
1909                 1u,                                                                                                             //      deUint32                attachment;
1910                 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,   //      VkImageLayout   layout;
1911         };
1912
1913         const vk::VkSubpassDescription subpassDescription =
1914         {
1915                 0u,                                                                             //      VkSubpassDescriptionFlags               flags;
1916                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,    //      VkPipelineBindPoint                             pipelineBindPoint;
1917                 0u,                                                                             //      deUint32                                                inputAttachmentCount;
1918                 nullptr,                                                                //      const VkAttachmentReference*    pInputAttachments;
1919                 1u,                                                                             //      deUint32                                                colorAttachmentCount;
1920                 &colorAttachmentReference,                              //      const VkAttachmentReference*    pColorAttachments;
1921                 nullptr,                                                                //      const VkAttachmentReference*    pResolveAttachments;
1922                 &dsAttachmentReference,                                 //      const VkAttachmentReference*    pDepthStencilAttachment;
1923                 0u,                                                                             //      deUint32                                                preserveAttachmentCount;
1924                 nullptr,                                                                //      const deUint32*                                 pPreserveAttachments;
1925         };
1926
1927         std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
1928
1929         attachmentDescriptions.push_back(vk::VkAttachmentDescription
1930         {
1931                 0u,                                                                                             //      VkAttachmentDescriptionFlags    flags;
1932                 colorFormat,                                                                    //      VkFormat                                                format;
1933                 vk::VK_SAMPLE_COUNT_1_BIT,                                              //      VkSampleCountFlagBits                   samples;
1934                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                //      VkAttachmentLoadOp                              loadOp;
1935                 vk::VK_ATTACHMENT_STORE_OP_STORE,                               //      VkAttachmentStoreOp                             storeOp;
1936                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,                    //      VkAttachmentLoadOp                              stencilLoadOp;
1937                 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                   //      VkAttachmentStoreOp                             stencilStoreOp;
1938                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                                  //      VkImageLayout                                   initialLayout;
1939                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   //      VkImageLayout                                   finalLayout;
1940         });
1941
1942         attachmentDescriptions.push_back(vk::VkAttachmentDescription
1943         {
1944                 0u,                                                                                                             //      VkAttachmentDescriptionFlags    flags;
1945                 dsFormatInfo->imageFormat,                                                              //      VkFormat                                                format;
1946                 vk::VK_SAMPLE_COUNT_1_BIT,                                                              //      VkSampleCountFlagBits                   samples;
1947                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                //      VkAttachmentLoadOp                              loadOp;
1948                 vk::VK_ATTACHMENT_STORE_OP_STORE,                                               //      VkAttachmentStoreOp                             storeOp;
1949                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                //      VkAttachmentLoadOp                              stencilLoadOp;
1950                 vk::VK_ATTACHMENT_STORE_OP_STORE,                                               //      VkAttachmentStoreOp                             stencilStoreOp;
1951                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                                                  //      VkImageLayout                                   initialLayout;
1952                 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,   //      VkImageLayout                                   finalLayout;
1953         });
1954
1955         const vk::VkRenderPassCreateInfo renderPassCreateInfo =
1956         {
1957                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                  //      VkStructureType                                 sType;
1958                 nullptr,                                                                                                //      const void*                                             pNext;
1959                 0u,                                                                                                             //      VkRenderPassCreateFlags                 flags;
1960                 static_cast<deUint32>(attachmentDescriptions.size()),   //      deUint32                                                attachmentCount;
1961                 attachmentDescriptions.data(),                                                  //      const VkAttachmentDescription*  pAttachments;
1962                 1u,                                                                                                             //      deUint32                                                subpassCount;
1963                 &subpassDescription,                                                                    //      const VkSubpassDescription*             pSubpasses;
1964                 0u,                                                                                                             //      deUint32                                                dependencyCount;
1965                 nullptr,                                                                                                //      const VkSubpassDependency*              pDependencies;
1966         };
1967         const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
1968
1969         // Framebuffers.
1970         FramebufferVec framebuffers;
1971
1972         DE_ASSERT(colorImageViews.size() == dsImageViews.size());
1973         for (size_t imgIdx = 0; imgIdx < colorImageViews.size(); ++imgIdx)
1974         {
1975                 std::vector<vk::VkImageView> attachments;
1976                 attachments.push_back(colorImageViews[imgIdx].get());
1977                 attachments.push_back(dsImageViews[imgIdx].get());
1978
1979                 const vk::VkFramebufferCreateInfo framebufferCreateInfo =
1980                 {
1981                         vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,  //      VkStructureType                         sType;
1982                         nullptr,                                                                                //      const void*                                     pNext;
1983                         0u,                                                                                             //      VkFramebufferCreateFlags        flags;
1984                         renderPass.get(),                                                               //      VkRenderPass                            renderPass;
1985                         static_cast<deUint32>(attachments.size()),              //      deUint32                                        attachmentCount;
1986                         attachments.data(),                                                             //      const VkImageView*                      pAttachments;
1987                         kFramebufferWidth,                                                              //      deUint32                                        width;
1988                         kFramebufferHeight,                                                             //      deUint32                                        height;
1989                         1u,                                                                                             //      deUint32                                        layers;
1990                 };
1991
1992                 framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
1993         }
1994
1995         // Shader modules.
1996         const auto                                              vertModule      = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
1997         const auto                                              vertModule2     = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert2"), 0u);
1998         const auto                                              fragModule      = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
1999         vk::Move<vk::VkShaderModule>    geomModule;
2000         vk::Move<vk::VkShaderModule>    tescModule;
2001         vk::Move<vk::VkShaderModule>    teseModule;
2002
2003         if (m_testConfig.needsGeometryShader())
2004                 geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
2005
2006         if (m_testConfig.needsTessellation())
2007         {
2008                 tescModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
2009                 teseModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
2010         }
2011
2012         // Shader stages.
2013         std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
2014         std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStaticStages;
2015
2016         vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
2017         {
2018                 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,        //      VkStructureType                                         sType;
2019                 nullptr,                                                                                                        //      const void*                                                     pNext;
2020                 0u,                                                                                                                     //      VkPipelineShaderStageCreateFlags        flags;
2021                 vk::VK_SHADER_STAGE_FRAGMENT_BIT,                                                       //      VkShaderStageFlagBits                           stage;
2022                 fragModule.get(),                                                                                       //      VkShaderModule                                          module;
2023                 "main",                                                                                                         //      const char*                                                     pName;
2024                 nullptr,                                                                                                        //      const VkSpecializationInfo*                     pSpecializationInfo;
2025         };
2026
2027         shaderStages.push_back(shaderStageCreateInfo);
2028
2029         if (m_testConfig.needsGeometryShader())
2030         {
2031                 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
2032                 shaderStageCreateInfo.module = geomModule.get();
2033                 shaderStages.push_back(shaderStageCreateInfo);
2034         }
2035
2036         if (m_testConfig.needsTessellation())
2037         {
2038                 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2039                 shaderStageCreateInfo.module = tescModule.get();
2040                 shaderStages.push_back(shaderStageCreateInfo);
2041
2042                 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2043                 shaderStageCreateInfo.module = teseModule.get();
2044                 shaderStages.push_back(shaderStageCreateInfo);
2045         }
2046
2047         // Both vectors are the same up to here. Then, they differ in the vertex stage.
2048         shaderStaticStages = shaderStages;
2049         shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_VERTEX_BIT;
2050
2051         shaderStageCreateInfo.module = vertModule.get();
2052         shaderStages.push_back(shaderStageCreateInfo);
2053
2054         shaderStageCreateInfo.module = vertModule2.get();
2055         shaderStaticStages.push_back(shaderStageCreateInfo);
2056
2057         // Input state.
2058         const auto vertexBindings       = m_testConfig.vertexGenerator.staticValue->getBindingDescriptions(m_testConfig.strideConfig.staticValue);
2059         const auto vertexAttributes     = m_testConfig.vertexGenerator.staticValue->getAttributeDescriptions();
2060
2061         const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
2062         {
2063                 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,  //      VkStructureType                                                         sType;
2064                 nullptr,                                                                                                                //      const void*                                                                     pNext;
2065                 0u,                                                                                                                             //      VkPipelineVertexInputStateCreateFlags           flags;
2066                 static_cast<deUint32>(vertexBindings.size()),                                   //      deUint32                                                                        vertexBindingDescriptionCount;
2067                 vertexBindings.data(),                                                                                  //      const VkVertexInputBindingDescription*          pVertexBindingDescriptions;
2068                 static_cast<deUint32>(vertexAttributes.size()),                                 //      deUint32                                                                        vertexAttributeDescriptionCount;
2069                 vertexAttributes.data(),                                                                                //      const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions;
2070         };
2071
2072         // Input assembly.
2073         const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
2074         {
2075                 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,        //      VkStructureType                                                 sType;
2076                 nullptr,                                                                                                                        //      const void*                                                             pNext;
2077                 0u,                                                                                                                                     //      VkPipelineInputAssemblyStateCreateFlags flags;
2078                 m_testConfig.topologyConfig.staticValue,                                                        //      VkPrimitiveTopology                                             topology;
2079                 makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue),         //      VkBool32                                                                primitiveRestartEnable;
2080         };
2081
2082         // Viewport state.
2083         if (m_testConfig.viewportConfig.dynamicValue)
2084                 DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
2085         else
2086                 DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
2087
2088         if (m_testConfig.scissorConfig.dynamicValue)
2089                 DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
2090         else
2091                 DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
2092
2093         // The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
2094         const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
2095
2096         // For the static pipeline.
2097         const vk::VkPipelineViewportStateCreateInfo staticViewportStateCreateInfo =
2098         {
2099                 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                                      //      VkStructureType                                         sType;
2100                 nullptr,                                                                                                                                        //      const void*                                                     pNext;
2101                 0u,                                                                                                                                                     //      VkPipelineViewportStateCreateFlags      flags;
2102                 minStaticCount,                                                                                                                         //      deUint32                                                        viewportCount;
2103                 m_testConfig.viewportConfig.staticValue.data(),                                                         //      const VkViewport*                                       pViewports;
2104                 minStaticCount,                                                                                                                         //      deUint32                                                        scissorCount;
2105                 m_testConfig.scissorConfig.staticValue.data(),                                                          //      const VkRect2D*                                         pScissors;
2106         };
2107
2108         // For the dynamic pipeline.
2109         const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
2110                 ? m_testConfig.viewportConfig.dynamicValue.get().size()
2111                 : m_testConfig.viewportConfig.staticValue.size());
2112
2113         const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
2114                 ? m_testConfig.scissorConfig.dynamicValue.get().size()
2115                 : m_testConfig.scissorConfig.staticValue.size());
2116
2117         const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
2118
2119         // The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
2120         const vk::VkPipelineViewportStateCreateInfo dynamicViewportStateCreateInfo =
2121         {
2122                 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                                      //      VkStructureType                                         sType;
2123                 nullptr,                                                                                                                                        //      const void*                                                     pNext;
2124                 0u,                                                                                                                                                     //      VkPipelineViewportStateCreateFlags      flags;
2125                 (m_testConfig.viewportConfig.dynamicValue ? 0u : minDynamicCount),                      //      deUint32                                                        viewportCount;
2126                 m_testConfig.viewportConfig.staticValue.data(),                                                         //      const VkViewport*                                       pViewports;
2127                 (m_testConfig.scissorConfig.dynamicValue ? 0u : minDynamicCount),                       //      deUint32                                                        scissorCount;
2128                 m_testConfig.scissorConfig.staticValue.data(),                                                          //      const VkRect2D*                                         pScissors;
2129         };
2130
2131         // Rasterization state.
2132         vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
2133         {
2134                 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //      VkStructureType                                                 sType;
2135                 nullptr,                                                                                                                //      const void*                                                             pNext;
2136                 0u,                                                                                                                             //      VkPipelineRasterizationStateCreateFlags flags;
2137                 VK_FALSE,                                                                                                               //      VkBool32                                                                depthClampEnable;
2138                 makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue), //      VkBool32                                                                rasterizerDiscardEnable;
2139                 vk::VK_POLYGON_MODE_FILL,                                                                               //      VkPolygonMode                                                   polygonMode;
2140                 m_testConfig.cullModeConfig.staticValue,                                                //      VkCullModeFlags                                                 cullMode;
2141                 m_testConfig.frontFaceConfig.staticValue,                                               //      VkFrontFace                                                             frontFace;
2142                 makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue),   //      VkBool32                                                                depthBiasEnable;
2143                 m_testConfig.depthBiasConfig.staticValue.constantFactor,                //      float                                                                   depthBiasConstantFactor;
2144                 m_testConfig.depthBiasConfig.staticValue.clamp,                                 //      float                                                                   depthBiasClamp;
2145                 0.0f,                                                                                                                   //      float                                                                   depthBiasSlopeFactor;
2146                 1.0f,                                                                                                                   //      float                                                                   lineWidth;
2147         };
2148
2149         // Multisample state.
2150         const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
2151         {
2152                 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,   //      VkStructureType                                                 sType;
2153                 nullptr,                                                                                                                //      const void*                                                             pNext;
2154                 0u,                                                                                                                             //      VkPipelineMultisampleStateCreateFlags   flags;
2155                 vk::VK_SAMPLE_COUNT_1_BIT,                                                                              //      VkSampleCountFlagBits                                   rasterizationSamples;
2156                 VK_FALSE,                                                                                                               //      VkBool32                                                                sampleShadingEnable;
2157                 0.0f,                                                                                                                   //      float                                                                   minSampleShading;
2158                 nullptr,                                                                                                                //      const VkSampleMask*                                             pSampleMask;
2159                 VK_FALSE,                                                                                                               //      VkBool32                                                                alphaToCoverageEnable;
2160                 VK_FALSE,                                                                                                               //      VkBool32                                                                alphaToOneEnable;
2161         };
2162
2163         // Depth/stencil state.
2164         vk::VkStencilOpState    staticFrontStencil;
2165         vk::VkStencilOpState    staticBackStencil;
2166         bool                                    staticFrontStencilSet   = false;
2167         bool                                    staticBackStencilSet    = false;
2168
2169         // Common setup for the front and back operations.
2170         staticFrontStencil.compareMask  = 0xFFu;
2171         staticFrontStencil.writeMask    = 0xFFu;
2172         staticFrontStencil.reference    = m_testConfig.referenceStencil;
2173         staticBackStencil                               = staticFrontStencil;
2174
2175         for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
2176         {
2177                 if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
2178                 {
2179                         copy(staticFrontStencil, op);
2180                         staticFrontStencilSet = true;
2181                 }
2182                 if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
2183                 {
2184                         copy(staticBackStencil, op);
2185                         staticBackStencilSet = true;
2186                 }
2187         }
2188
2189         // Default values for the static part.
2190         if (!staticFrontStencilSet)
2191                 copy(staticFrontStencil, kDefaultStencilOpParams);
2192         if (!staticBackStencilSet)
2193                 copy(staticBackStencil, kDefaultStencilOpParams);
2194
2195         const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
2196         {
2197                 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,         //      VkStructureType                                                 sType;
2198                 nullptr,                                                                                                                        //      const void*                                                             pNext;
2199                 0u,                                                                                                                                     //      VkPipelineDepthStencilStateCreateFlags  flags;
2200                 makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),           //      VkBool32                                                                depthTestEnable;
2201                 makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),          //      VkBool32                                                                depthWriteEnable;
2202                 m_testConfig.depthCompareOpConfig.staticValue,                                          //      VkCompareOp                                                             depthCompareOp;
2203                 makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue),     //      VkBool32                                                                depthBoundsTestEnable;
2204                 makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),         //      VkBool32                                                                stencilTestEnable;
2205                 staticFrontStencil,                                                                                                     //      VkStencilOpState                                                front;
2206                 staticBackStencil,                                                                                                      //      VkStencilOpState                                                back;
2207                 m_testConfig.minDepthBounds,                                                                            //      float                                                                   minDepthBounds;
2208                 m_testConfig.maxDepthBounds,                                                                            //      float                                                                   maxDepthBounds;
2209         };
2210
2211         // Dynamic state. Here we will set all states which have a dynamic value.
2212         const auto dynamicStates = m_testConfig.getDynamicStates();
2213
2214         const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
2215         {
2216                 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,       //      VkStructureType                                         sType;
2217                 nullptr,                                                                                                        //      const void*                                                     pNext;
2218                 0u,                                                                                                                     //      VkPipelineDynamicStateCreateFlags       flags;
2219                 static_cast<deUint32>(dynamicStates.size()),                            //      deUint32                                                        dynamicStateCount;
2220                 de::dataOrNull(dynamicStates),                                                          //      const VkDynamicState*                           pDynamicStates;
2221         };
2222
2223         const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
2224         {
2225                 VK_FALSE,                                               // VkBool32                 blendEnable
2226                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcColorBlendFactor
2227                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstColorBlendFactor
2228                 vk::VK_BLEND_OP_ADD,                    // VkBlendOp                colorBlendOp
2229                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcAlphaBlendFactor
2230                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstAlphaBlendFactor
2231                 vk::VK_BLEND_OP_ADD,                    // VkBlendOp                alphaBlendOp
2232                 vk::VK_COLOR_COMPONENT_R_BIT    // VkColorComponentFlags    colorWriteMask
2233                 | vk::VK_COLOR_COMPONENT_G_BIT
2234                 | vk::VK_COLOR_COMPONENT_B_BIT
2235                 | vk::VK_COLOR_COMPONENT_A_BIT
2236         };
2237
2238         const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
2239         {
2240                 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,   // VkStructureType                               sType
2241                 nullptr,                                                                                                                // const void*                                   pNext
2242                 0u,                                                                                                                             // VkPipelineColorBlendStateCreateFlags          flags
2243                 makeVkBool32(m_testConfig.testLogicOp()),                                               // VkBool32                                      logicOpEnable
2244                 m_testConfig.logicOpConfig.staticValue,                                                 // VkLogicOp                                     logicOp
2245                 1u,                                                                                                                             // deUint32                                      attachmentCount
2246                 &colorBlendAttachmentState,                                                                             // const VkPipelineColorBlendAttachmentState*    pAttachments
2247                 { 0.0f, 0.0f, 0.0f, 0.0f }                                                                              // float                                         blendConstants[4]
2248         };
2249
2250         const vk::VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo =
2251         {
2252                 vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,  // VkStructureType                               sType
2253                 nullptr,                                                                                                                // const void*                                   pNext
2254                 0u,                                                                                                                             // VkPipelineTessellationStateCreateFlags        flags
2255                 m_testConfig.patchControlPointsConfig.staticValue,                              // uint32_t                                                                              patchControlPoints
2256         };
2257
2258         const auto pTessellationState = (m_testConfig.needsTessellation() ? &pipelineTessellationStateCreateInfo : nullptr);
2259
2260         const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
2261         {
2262                 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,    //      VkStructureType                                                                 sType;
2263                 nullptr,                                                                                                //      const void*                                                                             pNext;
2264                 0u,                                                                                                             //      VkPipelineCreateFlags                                                   flags;
2265                 static_cast<deUint32>(shaderStages.size()),                             //      deUint32                                                                                stageCount;
2266                 shaderStages.data(),                                                                    //      const VkPipelineShaderStageCreateInfo*                  pStages;
2267                 &vertexInputStateCreateInfo,                                                    //      const VkPipelineVertexInputStateCreateInfo*             pVertexInputState;
2268                 &inputAssemblyStateCreateInfo,                                                  //      const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState;
2269                 pTessellationState,                                                                             //      const VkPipelineTessellationStateCreateInfo*            pTessellationState;
2270                 nullptr,                                                                                                //      const VkPipelineViewportStateCreateInfo *       pViewportState;
2271                 &rasterizationStateCreateInfo,                                                  //      const VkPipelineRasterizationStateCreateInfo*   pRasterizationState;
2272                 &multisampleStateCreateInfo,                                                    //      const VkPipelineMultisampleStateCreateInfo*             pMultisampleState;
2273                 &depthStencilStateCreateInfo,                                                   //      const VkPipelineDepthStencilStateCreateInfo*    pDepthStencilState;
2274                 &colorBlendStateCreateInfo,                                                             //      const VkPipelineColorBlendStateCreateInfo*              pColorBlendState;
2275                 nullptr,                                                                                                //      const VkPipelineDynamicStateCreateInfo*                 pDynamicState;
2276                 pipelineLayout.get(),                                                                   //      VkPipelineLayout                                                                layout;
2277                 renderPass.get(),                                                                               //      VkRenderPass                                                                    renderPass;
2278                 0u,                                                                                                             //      deUint32                                                                                subpass;
2279                 DE_NULL,                                                                                                //      VkPipeline                                                                              basePipelineHandle;
2280                 0,                                                                                                              //      deInt32                                                                                 basePipelineIndex;
2281         };
2282
2283         vk::Move<vk::VkPipeline>        staticPipeline;
2284         const bool                                      bindStaticFirst         = (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES     ||
2285                                                                                                            kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES       ||
2286                                                                                                            kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
2287         const bool                                      useStaticPipeline       = (bindStaticFirst || kReversed);
2288
2289         // Create static pipeline when needed.
2290         if (useStaticPipeline)
2291         {
2292                 auto staticPipelineCreateInfo                   = graphicsPipelineCreateInfoTemplate;
2293                 staticPipelineCreateInfo.pViewportState = &staticViewportStateCreateInfo;
2294                 staticPipelineCreateInfo.pStages                = shaderStaticStages.data();
2295                 staticPipeline                                                  = vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
2296         }
2297
2298         // Create dynamic pipeline.
2299         vk::Move<vk::VkPipeline> graphicsPipeline;
2300         {
2301                 auto dynamicPipelineCreateInfo                          = graphicsPipelineCreateInfoTemplate;
2302                 dynamicPipelineCreateInfo.pDynamicState         = &dynamicStateCreateInfo;
2303                 dynamicPipelineCreateInfo.pViewportState        = &dynamicViewportStateCreateInfo;
2304                 graphicsPipeline                                                        = vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
2305         }
2306
2307         // Command buffer.
2308         const auto cmdPool              = vk::makeCommandPool(vkd, device, queueIndex);
2309         const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2310         const auto cmdBuffer    = cmdBufferPtr.get();
2311
2312         // Clear values, clear to green for dynamic logicOp
2313         std::vector<vk::VkClearValue> clearValues;
2314         clearValues.push_back(m_testConfig.clearColorValue);
2315         clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
2316
2317         // Record command buffer.
2318         vk::beginCommandBuffer(vkd, cmdBuffer);
2319
2320         for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
2321         {
2322                 // Track in-advance vertex buffer binding.
2323                 bool boundInAdvance = false;
2324
2325                 // Maybe set extended dynamic state here.
2326                 if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
2327                 {
2328                         setDynamicStates(m_testConfig, vkd, cmdBuffer);
2329                         boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2330                 }
2331
2332                 // Begin render pass.
2333                 vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
2334
2335                         // Bind a static pipeline first if needed.
2336                         if (bindStaticFirst && iteration == 0u)
2337                                 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2338
2339                         // Maybe set extended dynamic state here.
2340                         if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
2341                         {
2342                                 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2343                                 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2344                         }
2345
2346                         // Bind dynamic pipeline.
2347                         if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
2348                                  kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
2349                                 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2350                                 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2351                         {
2352                                 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
2353                         }
2354
2355                         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2356                                 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2357                                 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2358                         {
2359                                 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2360                                 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2361                         }
2362
2363                         // Bind a static pipeline last if needed.
2364                         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2365                                 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
2366                         {
2367                                 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2368                         }
2369
2370                         const auto& viewportVec = m_testConfig.getActiveViewportVec();
2371                         for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
2372                         {
2373                                 for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
2374                                 {
2375                                         // Push constants.
2376                                         PushConstants pushConstants =
2377                                         {
2378                                                 m_testConfig.meshParams[meshIdx].color,         //      tcu::Vec4       triangleColor;
2379                                                 m_testConfig.meshParams[meshIdx].depth,         //      float           meshDepth;
2380                                                 static_cast<deInt32>(viewportIdx),                      //      deInt32         viewPortIndex;
2381                                                 m_testConfig.meshParams[meshIdx].scaleX,        //      float           scaleX;
2382                                                 m_testConfig.meshParams[meshIdx].scaleY,        //      float           scaleY;
2383                                                 m_testConfig.meshParams[meshIdx].offsetX,       //      float           offsetX;
2384                                                 m_testConfig.meshParams[meshIdx].offsetY,       //      float           offsetY;
2385                                                 m_testConfig.meshParams[meshIdx].fanScale,      //      float           fanScale;
2386                                         };
2387                                         vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
2388
2389                                         // Track vertex bounding state for this mesh.
2390                                         bool boundBeforeDraw = false;
2391
2392                                         // Maybe set extended dynamic state here.
2393                                         if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
2394                                         {
2395                                                 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2396                                                 boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffers, rvertBuffers);
2397                                         }
2398
2399                                         // Bind vertex buffer with static stride if needed and draw.
2400                                         if (!(boundInAdvance || boundBeforeDraw))
2401                                         {
2402                                                 bindVertexBuffers(vkd, cmdBuffer, (m_testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers));
2403                                                 if (m_testConfig.needsIndexBuffer())
2404                                                 {
2405                                                         vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0, vk::VK_INDEX_TYPE_UINT32);
2406                                                 }
2407                                         }
2408
2409                                         // Draw mesh.
2410                                         if (m_testConfig.needsIndexBuffer())
2411                                         {
2412                                                 deUint32 numIndices = static_cast<deUint32>(indices.size());
2413                                                 // For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
2414                                                 // So, draw without using the invalid (0xFFFFFFFF) index, the second draw with primitive restart enabled will replace the results
2415                                                 // using all indices.
2416                                                 if (iteration == 0u &&
2417                                                         (m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
2418                                                         m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
2419                                                         numIndices = 3u;
2420                                                 vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
2421                                         }
2422                                         else
2423                                         {
2424                                                 deUint32 vertex_count = static_cast<deUint32>(vertices.size());
2425                                                 if (m_testConfig.singleVertex)
2426                                                         vertex_count = m_testConfig.singleVertexDrawCount;
2427                                                 vkd.cmdDraw(cmdBuffer, vertex_count, 1u, 0u, 0u);
2428                                         }
2429                                 }
2430                         }
2431
2432                 vk::endRenderPass(vkd, cmdBuffer);
2433         }
2434
2435         vk::endCommandBuffer(vkd, cmdBuffer);
2436
2437         // Submit commands.
2438         vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2439
2440         // Read result image aspects from the last used framebuffer.
2441         const tcu::UVec2        renderSize              (kFramebufferWidth, kFramebufferHeight);
2442         const auto                      colorBuffer             = readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImages.back()->get(), colorFormat, renderSize);
2443         const auto                      depthBuffer             = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
2444         const auto                      stencilBuffer   = readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
2445         const auto                      colorAccess             = colorBuffer->getAccess();
2446         const auto                      depthAccess             = depthBuffer->getAccess();
2447         const auto                      stencilAccess   = stencilBuffer->getAccess();
2448
2449         const int kWidth        = static_cast<int>(kFramebufferWidth);
2450         const int kHeight       = static_cast<int>(kFramebufferHeight);
2451
2452         // Generate reference color buffer.
2453         const auto                              tcuColorFormat                  = vk::mapVkFormat(colorFormat);
2454         tcu::TextureLevel               referenceColorLevel             (tcuColorFormat, kWidth, kHeight);
2455         tcu::PixelBufferAccess  referenceColorAccess    = referenceColorLevel.getAccess();
2456         m_testConfig.referenceColor(referenceColorAccess);
2457
2458         const tcu::TextureFormat        errorFormat                     (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
2459         tcu::TextureLevel                       colorError                      (errorFormat, kWidth, kHeight);
2460         tcu::TextureLevel                       depthError                      (errorFormat, kWidth, kHeight);
2461         tcu::TextureLevel                       stencilError            (errorFormat, kWidth, kHeight);
2462         const auto                                      colorErrorAccess        = colorError.getAccess();
2463         const auto                                      depthErrorAccess        = depthError.getAccess();
2464         const auto                                      stencilErrorAccess      = stencilError.getAccess();
2465         const tcu::Vec4                         kGood                           (0.0f, 1.0f, 0.0f, 1.0f);
2466         const tcu::Vec4                         kBad                            (1.0f, 0.0f, 0.0f, 1.0f);
2467
2468         // Check expected values.
2469         const auto      minDepth                = m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
2470         const auto      maxDepth                = m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
2471         bool            colorMatch              = true;
2472         bool            depthMatch              = true;
2473         bool            stencilMatch    = true;
2474         bool            match;
2475
2476         for (int y = 0; y < kHeight; ++y)
2477         for (int x = 0; x < kWidth; ++x)
2478         {
2479                 if (vk::isUnormFormat(colorFormat))
2480                 {
2481                         auto colorPixel         = colorAccess.getPixel(x, y);
2482                         auto expectedPixel      = referenceColorAccess.getPixel(x, y);
2483                         match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kUnormColorThreshold));
2484                 }
2485                 else
2486                 {
2487                         DE_ASSERT(vk::isUintFormat(colorFormat));
2488                         auto colorPixel         = colorAccess.getPixelUint(x, y);
2489                         auto expectedPixel      = referenceColorAccess.getPixelUint(x, y);
2490                         match = (colorPixel == expectedPixel);
2491                 }
2492
2493                 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
2494                 if (!match)
2495                         colorMatch = false;
2496
2497                 const auto depthPixel = depthAccess.getPixDepth(x, y);
2498                 match = de::inRange(depthPixel, minDepth, maxDepth);
2499                 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
2500                 if (!match)
2501                         depthMatch = false;
2502
2503                 const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
2504                 match = (stencilPixel == m_testConfig.expectedStencil);
2505                 stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
2506                 if (!match)
2507                         stencilMatch = false;
2508         }
2509
2510         if (!(colorMatch && depthMatch && stencilMatch))
2511         {
2512                 if (!colorMatch)
2513                         logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
2514
2515                 if (!depthMatch)
2516                         logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
2517
2518                 if (!stencilMatch)
2519                         logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
2520
2521                 return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
2522         }
2523
2524         return tcu::TestStatus::pass("Pass");
2525 }
2526
2527 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
2528 {
2529         switch (op)
2530         {
2531         case vk::VK_COMPARE_OP_NEVER:                           return false;
2532         case vk::VK_COMPARE_OP_LESS:                            return (referenceValue <        storedValue);
2533         case vk::VK_COMPARE_OP_EQUAL:                           return (referenceValue ==       storedValue);
2534         case vk::VK_COMPARE_OP_LESS_OR_EQUAL:           return (referenceValue <=       storedValue);
2535         case vk::VK_COMPARE_OP_GREATER:                         return (referenceValue >        storedValue);
2536         case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:        return (referenceValue >=       storedValue);
2537         case vk::VK_COMPARE_OP_ALWAYS:                          return true;
2538         default: DE_ASSERT(false); return false;
2539         }
2540
2541         return false;   // Unreachable.
2542 }
2543
2544 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
2545 {
2546         deUint8 result = storedValue;
2547
2548         switch (op)
2549         {
2550         case vk::VK_STENCIL_OP_KEEP:                                    break;
2551         case vk::VK_STENCIL_OP_ZERO:                                    result = 0; break;
2552         case vk::VK_STENCIL_OP_REPLACE:                                 result = referenceValue; break;
2553         case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:             result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
2554         case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:             result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
2555         case vk::VK_STENCIL_OP_INVERT:                                  result = static_cast<deUint8>(~result); break;
2556         case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:              result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
2557         case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:              result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
2558         default: DE_ASSERT(false); break;
2559         }
2560
2561         return result;
2562 }
2563
2564 } // anonymous namespace
2565
2566 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
2567 {
2568         de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
2569
2570         // Auxiliar constants.
2571         const deUint32  kHalfWidthU     = kFramebufferWidth/2u;
2572         const deInt32   kHalfWidthI     = static_cast<deInt32>(kHalfWidthU);
2573         const float             kHalfWidthF     = static_cast<float>(kHalfWidthU);
2574         const float             kHeightF        = static_cast<float>(kFramebufferHeight);
2575
2576         static const struct
2577         {
2578                 SequenceOrdering        ordering;
2579                 std::string                     name;
2580                 std::string                     desc;
2581         } kOrderingCases[] =
2582         {
2583                 { SequenceOrdering::CMD_BUFFER_START,   "cmd_buffer_start",             "Dynamic state set after command buffer start"                                                                                                                                                                                          },
2584                 { SequenceOrdering::BEFORE_DRAW,                "before_draw",                  "Dynamic state set just before drawing"                                                                                                                                                                                                         },
2585                 { 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"                                           },
2586                 { SequenceOrdering::AFTER_PIPELINES,    "after_pipelines",              "Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"                                                                      },
2587                 { 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"      },
2588                 { SequenceOrdering::TWO_DRAWS_DYNAMIC,  "two_draws_dynamic",    "Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again"                                                                                     },
2589                 { SequenceOrdering::TWO_DRAWS_STATIC,   "two_draws_static",             "Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again"                                                                                     },
2590         };
2591
2592         for (const auto& kOrderingCase : kOrderingCases)
2593         {
2594                 const auto& kOrdering           = kOrderingCase.ordering;
2595
2596                 de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
2597
2598                 // Cull modes.
2599                 {
2600                         TestConfig config(kOrdering);
2601                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_FRONT_BIT;
2602                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
2603                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
2604                 }
2605                 {
2606                         TestConfig config(kOrdering);
2607                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_FRONT_AND_BACK;
2608                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
2609                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
2610                 }
2611                 {
2612                         TestConfig config(kOrdering);
2613                         // Make triangles look back.
2614                         config.meshParams[0].reversed           = true;
2615                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
2616                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
2617                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
2618                 }
2619                 {
2620                         TestConfig config(kOrdering);
2621                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_NONE;
2622                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
2623                         config.referenceColor                           = SingleColorGenerator(kDefaultClearColor);
2624                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
2625                 }
2626
2627                 // Front face.
2628                 {
2629                         TestConfig config(kOrdering);
2630                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
2631                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_CLOCKWISE;
2632                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2633                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
2634                 }
2635                 {
2636                         TestConfig config(kOrdering);
2637                         // Pass triangles in clockwise order.
2638                         config.meshParams[0].reversed           = true;
2639                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
2640                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2641                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2642                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
2643                 }
2644                 {
2645                         TestConfig config(kOrdering);
2646                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
2647                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2648                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2649                         config.referenceColor                           = SingleColorGenerator(kDefaultClearColor);
2650                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
2651                 }
2652                 {
2653                         TestConfig config(kOrdering);
2654                         // Pass triangles in clockwise order.
2655                         config.meshParams[0].reversed           = true;
2656                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
2657                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_CLOCKWISE;
2658                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2659                         config.referenceColor                           = SingleColorGenerator(kDefaultClearColor);
2660                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
2661                 }
2662
2663                 // Rasterizer discard
2664                 {
2665                         TestConfig config(kOrdering);
2666                         config.rastDiscardEnableConfig.staticValue = false;
2667                         config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
2668                         config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2669                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
2670                 }
2671                 {
2672                         TestConfig config(kOrdering);
2673                         config.rastDiscardEnableConfig.staticValue = true;
2674                         config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
2675                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
2676                 }
2677
2678                 // Logic op
2679                 {
2680                         TestConfig config(kOrdering);
2681                         config.logicOpConfig.staticValue = vk::VK_LOGIC_OP_CLEAR;
2682                         config.logicOpConfig.dynamicValue = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
2683                         // Clear to green, paint in blue, expect cyan due to logic op.
2684                         config.meshParams[0].color = kLogicOpTriangleColor;
2685                         config.clearColorValue = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
2686                         config.referenceColor = SingleColorGenerator(kLogicOpFinalColor);
2687                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
2688                 }
2689
2690                 // Dynamically enable primitive restart
2691                 {
2692                         TestConfig config(kOrdering);
2693                         config.primRestartEnableConfig.staticValue = false;
2694                         config.primRestartEnableConfig.dynamicValue = tcu::just(true);
2695                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "prim_restart_enable", "Dynamically enable primitiveRestart", config));
2696                 }
2697
2698                 // Dynamically change the number of primitive control points
2699                 {
2700                         TestConfig config(kOrdering);
2701                         config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
2702                         config.patchControlPointsConfig.staticValue = 1;
2703                         config.patchControlPointsConfig.dynamicValue = 3;
2704                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points", "Dynamically change patch control points", config));
2705                 }
2706
2707                 // Dynamic topology.
2708                 {
2709                         TestConfig baseConfig(kOrdering);
2710
2711                         for (int i = 0; i < 2; ++i)
2712                         {
2713                                 const bool forceGeometryShader = (i > 0);
2714
2715                                 static const struct
2716                                 {
2717                                         vk::VkPrimitiveTopology staticVal;
2718                                         vk::VkPrimitiveTopology dynamicVal;
2719                                 } kTopologyCases[] =
2720                                 {
2721                                         { vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,      vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN  },
2722                                         { vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,          vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP    },
2723                                         { vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,         vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST    },
2724                                 };
2725
2726                                 for (const auto& kTopologyCase : kTopologyCases)
2727                                 {
2728                                         TestConfig config(baseConfig);
2729                                         config.forceGeometryShader                                      = forceGeometryShader;
2730                                         config.topologyConfig.staticValue                       = kTopologyCase.staticVal;
2731                                         config.topologyConfig.dynamicValue                      = tcu::just<vk::VkPrimitiveTopology>(kTopologyCase.dynamicVal);
2732                                         config.patchControlPointsConfig.staticValue     = (config.needsTessellation() ? 3u : 1u);
2733
2734                                         const std::string       className       = topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
2735                                         const std::string       name            = "topology_" + className + (forceGeometryShader ? "_geom" : "");
2736                                         const std::string       desc            = "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "");
2737                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
2738                                 }
2739                         }
2740                 }
2741
2742                 // Viewport.
2743                 {
2744                         TestConfig config(kOrdering);
2745                         // 2 scissors, bad static single viewport.
2746                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2747                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2748                         config.viewportConfig.dynamicValue      = ViewportVec{
2749                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2750                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2751                         };
2752                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
2753                 }
2754                 {
2755                         TestConfig config(kOrdering);
2756                         // Bad static reduced viewport.
2757                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2758                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
2759                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
2760                 }
2761                 {
2762                         TestConfig config(kOrdering);
2763                         // 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
2764                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2765                         config.viewportConfig.staticValue       = ViewportVec{
2766                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2767                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),                // Left.
2768                         };
2769                         config.viewportConfig.dynamicValue      = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2770                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
2771                 }
2772                 {
2773                         TestConfig config(kOrdering);
2774                         // 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
2775                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2776                         config.viewportConfig.staticValue       = ViewportVec{
2777                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),                // Left.
2778                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2779                         };
2780                         config.viewportConfig.dynamicValue      = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2781                         config.referenceColor                           = SingleColorGenerator(kDefaultClearColor);
2782                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
2783                 }
2784
2785                 // Scissor.
2786                 {
2787                         TestConfig config(kOrdering);
2788                         // 2 viewports, bad static single scissor.
2789                         config.viewportConfig.staticValue       = ViewportVec{
2790                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2791                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2792                         };
2793                         config.scissorConfig.staticValue        = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2794                         config.scissorConfig.dynamicValue       = ScissorVec{
2795                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2796                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2797                         };
2798                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
2799                 }
2800                 {
2801                         TestConfig config(kOrdering);
2802                         // 1 viewport, bad static single scissor.
2803                         config.scissorConfig.staticValue        = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2804                         config.scissorConfig.dynamicValue       = ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
2805                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
2806                 }
2807                 {
2808                         TestConfig config(kOrdering);
2809                         // 2 viewports, 2 reversed scissors that need fixing.
2810                         config.viewportConfig.staticValue       = ViewportVec{
2811                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2812                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2813                         };
2814                         config.scissorConfig.staticValue        = ScissorVec{
2815                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2816                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2817                         };
2818                         config.scissorConfig.dynamicValue       = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2819                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
2820                 }
2821                 {
2822                         TestConfig config(kOrdering);
2823                         // 2 viewports, 2 scissors switched to prevent drawing.
2824                         config.viewportConfig.staticValue       = ViewportVec{
2825                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2826                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2827                         };
2828                         config.scissorConfig.staticValue        = ScissorVec{
2829                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2830                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2831                         };
2832                         config.scissorConfig.dynamicValue       = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2833                         config.referenceColor                           = SingleColorGenerator(kDefaultClearColor);
2834                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
2835                 }
2836
2837                 // Stride.
2838                 {
2839                         struct
2840                         {
2841                                 const VertexGenerator*  factory;
2842                                 const std::string               prefix;
2843                         } strideCases[] =
2844                         {
2845                                 { getVertexWithPaddingGenerator(),                      "stride"                },
2846                                 { getVertexWithExtraAttributesGenerator(),      "large_stride"  },
2847                         };
2848
2849                         for (const auto& strideCase : strideCases)
2850                         {
2851                                 const auto      factory                 = strideCase.factory;
2852                                 const auto&     prefix                  = strideCase.prefix;
2853                                 const auto      vertexStrides   = factory->getVertexDataStrides();
2854                                 StrideVec       halfStrides;
2855
2856                                 halfStrides.reserve(vertexStrides.size());
2857                                 for (const auto& stride : vertexStrides)
2858                                         halfStrides.push_back(stride / 2u);
2859
2860                                 if (factory == getVertexWithExtraAttributesGenerator() && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
2861                                 {
2862                                         // This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
2863                                         // stride being less than the extent of the binding for the second attribute.
2864                                         continue;
2865                                 }
2866
2867                                 {
2868                                         TestConfig config(kOrdering, factory);
2869                                         config.strideConfig.staticValue         = halfStrides;
2870                                         config.strideConfig.dynamicValue        = vertexStrides;
2871                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix, "Dynamically set stride", config));
2872                                 }
2873                                 {
2874                                         TestConfig config(kOrdering, factory);
2875                                         config.strideConfig.staticValue         = halfStrides;
2876                                         config.strideConfig.dynamicValue        = vertexStrides;
2877                                         config.vertexDataOffset                         = vertexStrides[0];
2878                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset", "Dynamically set stride using a nonzero vertex data offset", config));
2879                                 }
2880                                 {
2881                                         TestConfig config(kOrdering, factory);
2882                                         config.strideConfig.staticValue         = halfStrides;
2883                                         config.strideConfig.dynamicValue        = vertexStrides;
2884                                         config.vertexDataOffset                         = vertexStrides[0];
2885                                         config.vertexDataExtraBytes                     = config.vertexDataOffset;
2886
2887                                         // 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.
2888                                         config.referenceColor                           = HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2889                                         config.meshParams[0].scaleY                     = 0.5f;
2890                                         config.meshParams[0].offsetY            = -0.5f;
2891
2892                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding", "Dynamically set stride using a nonzero vertex data offset and extra bytes", config));
2893                                 }
2894                         }
2895
2896                         // Dynamic stride of 0
2897                         {
2898                                 TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator());
2899                                 config.strideConfig.staticValue         = config.getActiveVertexGenerator()->getVertexDataStrides();
2900                                 config.strideConfig.dynamicValue        = { 0 };
2901                                 config.vertexDataOffset                         = 4;
2902                                 config.singleVertex                 = true;
2903                                 config.singleVertexDrawCount        = 6;
2904
2905                                 // Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
2906                                 // offscreen vertex and draw something in the bottom half.
2907                                 config.referenceColor                   = HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2908                                 config.meshParams[0].scaleY             = 0.5f;
2909                                 config.meshParams[0].offsetY    = -0.5f;
2910
2911                                 // Use fan scale to synthesize a fan from a vertex attribute which remains constant over the draw call.
2912                                 config.meshParams[0].fanScale = 1.0f;
2913
2914                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "zero_stride_with_offset", "Dynamically set zero stride using a nonzero vertex data offset", config));
2915                         }
2916                 }
2917
2918                 // Depth test enable.
2919                 {
2920                         TestConfig config(kOrdering);
2921                         config.depthTestEnableConfig.staticValue        = false;
2922                         config.depthTestEnableConfig.dynamicValue       = tcu::just(true);
2923                         // By default, the depth test never passes when enabled.
2924                         config.referenceColor                                           = SingleColorGenerator(kDefaultClearColor);
2925                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
2926                 }
2927                 {
2928                         TestConfig config(kOrdering);
2929                         config.depthTestEnableConfig.staticValue        = true;
2930                         config.depthTestEnableConfig.dynamicValue       = tcu::just(false);
2931                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
2932                 }
2933
2934                 // Depth write enable.
2935                 {
2936                         TestConfig config(kOrdering);
2937
2938                         // Enable depth test and set values so it passes.
2939                         config.depthTestEnableConfig.staticValue        = true;
2940                         config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
2941                         config.clearDepthValue                                          = 0.5f;
2942                         config.meshParams[0].depth                                      = 0.25f;
2943
2944                         // Enable writes and expect the mesh value.
2945                         config.depthWriteEnableConfig.staticValue       = false;
2946                         config.depthWriteEnableConfig.dynamicValue      = tcu::just(true);
2947                         config.expectedDepth                                            = 0.25f;
2948
2949                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
2950                 }
2951                 {
2952                         TestConfig config(kOrdering);
2953
2954                         // Enable depth test and set values so it passes.
2955                         config.depthTestEnableConfig.staticValue        = true;
2956                         config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
2957                         config.clearDepthValue                                          = 0.5f;
2958                         config.meshParams[0].depth                                      = 0.25f;
2959
2960                         // But disable writing dynamically and expect the clear value.
2961                         config.depthWriteEnableConfig.staticValue       = true;
2962                         config.depthWriteEnableConfig.dynamicValue      = tcu::just(false);
2963                         config.expectedDepth                                            = 0.5f;
2964
2965                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
2966                 }
2967
2968                 // Depth bias enable with static or dynamic depth bias parameters.
2969                 {
2970                         const DepthBiasParams kAlternativeDepthBiasParams = { 2e7f, 0.25f };
2971
2972                         for (int dynamicBiasIter = 0; dynamicBiasIter < 2; ++dynamicBiasIter)
2973                         {
2974                                 const bool useDynamicBias = (dynamicBiasIter > 0);
2975
2976                                 {
2977                                         TestConfig config(kOrdering);
2978
2979                                         // Enable depth test and write 1.0f
2980                                         config.depthTestEnableConfig.staticValue = true;
2981                                         config.depthWriteEnableConfig.staticValue = true;
2982                                         config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2983                                         // Clear depth buffer to 0.25f
2984                                         config.clearDepthValue = 0.25f;
2985                                         // Write depth to 0.5f
2986                                         config.meshParams[0].depth = 0.5f;
2987
2988                                         // Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
2989                                         if (useDynamicBias)
2990                                         {
2991                                                 config.depthBiasConfig.staticValue      = kNoDepthBiasParams;
2992                                                 config.depthBiasConfig.dynamicValue     = kAlternativeDepthBiasParams;
2993                                         }
2994                                         else
2995                                         {
2996                                                 config.depthBiasConfig.staticValue      = kAlternativeDepthBiasParams;
2997                                         }
2998
2999                                         config.depthBiasEnableConfig.staticValue = false;
3000                                         config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
3001                                         config.expectedDepth = 0.75f;
3002
3003                                         std::string caseName = "depth_bias_enable";
3004                                         std::string caseDesc = "Dynamically enable the depth bias";
3005
3006                                         if (useDynamicBias)
3007                                         {
3008                                                 caseName += "_dynamic_bias_params";
3009                                                 caseDesc += " and set the bias params dynamically";
3010                                         }
3011
3012                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3013                                 }
3014                                 {
3015                                         TestConfig config(kOrdering);
3016
3017                                         // Enable depth test and write 1.0f
3018                                         config.depthTestEnableConfig.staticValue = true;
3019                                         config.depthWriteEnableConfig.staticValue = true;
3020                                         config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
3021                                         // Clear depth buffer to 0.25f
3022                                         config.clearDepthValue = 0.25f;
3023                                         // Write depth to 0.5f
3024                                         config.meshParams[0].depth = 0.5f;
3025
3026                                         // Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
3027                                         if (useDynamicBias)
3028                                         {
3029                                                 config.depthBiasConfig.staticValue      = kNoDepthBiasParams;
3030                                                 config.depthBiasConfig.dynamicValue     = kAlternativeDepthBiasParams;
3031                                         }
3032                                         else
3033                                         {
3034                                                 config.depthBiasConfig.staticValue      = kAlternativeDepthBiasParams;
3035                                         }
3036
3037                                         config.depthBiasEnableConfig.staticValue = true;
3038                                         config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
3039                                         config.expectedDepth = 0.5f;
3040
3041                                         std::string caseName = "depth_bias_disable";
3042                                         std::string caseDesc = "Dynamically disable the depth bias";
3043
3044                                         if (useDynamicBias)
3045                                         {
3046                                                 caseName += "_dynamic_bias_params";
3047                                                 caseDesc += " and set the bias params dynamically";
3048                                         }
3049
3050                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3051                                 }
3052                         }
3053                 }
3054
3055                 // Depth compare op.
3056                 {
3057                         TestConfig baseConfig(kOrdering);
3058                         const tcu::Vec4 kAlternativeColor                               (0.0f, 0.0f, 0.5f, 1.0f);
3059                         baseConfig.depthTestEnableConfig.staticValue    = true;
3060                         baseConfig.depthWriteEnableConfig.staticValue   = true;
3061                         baseConfig.depthCompareOpConfig.staticValue             = vk::VK_COMPARE_OP_NEVER;
3062                         baseConfig.clearDepthValue                                              = 0.5f;
3063
3064                         {
3065                                 TestConfig config = baseConfig;
3066                                 config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_ALWAYS;
3067                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_NEVER;
3068                                 config.meshParams[0].depth                                      = 0.25f;
3069                                 config.expectedDepth                                            = 0.5f;
3070                                 config.referenceColor                                           = SingleColorGenerator(kDefaultClearColor);
3071                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
3072                         }
3073                         {
3074                                 TestConfig config = baseConfig;
3075                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS;
3076                                 config.meshParams[0].depth                                      = 0.25f;
3077                                 config.expectedDepth                                            = 0.25f;
3078                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
3079                         }
3080                         {
3081                                 TestConfig config = baseConfig;
3082                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER;
3083                                 config.meshParams[0].depth                                      = 0.75f;
3084                                 config.expectedDepth                                            = 0.75f;
3085                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
3086                         }
3087                         {
3088                                 TestConfig config = baseConfig;
3089                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_EQUAL;
3090                                 config.meshParams[0].depth                                      = 0.5f;
3091                                 config.meshParams[0].color                                      = kAlternativeColor;
3092                                 // Draw another mesh in front to verify it does not pass the equality test.
3093                                 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
3094                                 config.expectedDepth                                            = 0.5f;
3095                                 config.referenceColor                                           = SingleColorGenerator(kAlternativeColor);
3096                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
3097                         }
3098                         {
3099                                 TestConfig config = baseConfig;
3100                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3101                                 config.meshParams[0].depth                                      = 0.25f;
3102                                 config.expectedDepth                                            = 0.25f;
3103                                 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));
3104                         }
3105                         {
3106                                 TestConfig config = baseConfig;
3107                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3108                                 config.meshParams[0].depth                                      = 0.5f;
3109                                 config.expectedDepth                                            = 0.5f;
3110                                 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));
3111                         }
3112                         {
3113                                 TestConfig config = baseConfig;
3114                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3115                                 config.meshParams[0].depth                                      = 0.25f;
3116                                 // Draw another mesh with the same depth in front of it.
3117                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
3118                                 config.expectedDepth                                            = 0.25f;
3119                                 config.referenceColor                                           = SingleColorGenerator(kAlternativeColor);
3120                                 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));
3121                         }
3122                         {
3123                                 TestConfig config = baseConfig;
3124                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3125                                 config.meshParams[0].depth                                      = 0.75f;
3126                                 config.expectedDepth                                            = 0.75f;
3127                                 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));
3128                         }
3129                         {
3130                                 TestConfig config = baseConfig;
3131                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3132                                 config.meshParams[0].depth                                      = 0.5f;
3133                                 config.expectedDepth                                            = 0.5f;
3134                                 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));
3135                         }
3136                         {
3137                                 TestConfig config = baseConfig;
3138                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3139                                 config.meshParams[0].depth                                      = 0.75f;
3140                                 // Draw another mesh with the same depth in front of it.
3141                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
3142                                 config.expectedDepth                                            = 0.75f;
3143                                 config.referenceColor                                           = SingleColorGenerator(kAlternativeColor);
3144                                 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));
3145                         }
3146                         {
3147                                 TestConfig config = baseConfig;
3148                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_NOT_EQUAL;
3149
3150                                 // Draw first mesh in front.
3151                                 config.meshParams[0].depth                                      = 0.25f;
3152                                 // Draw another mesh in the back, this should pass too.
3153                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
3154                                 // Finally a new mesh with the same depth. This should not pass.
3155                                 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
3156
3157                                 config.referenceColor                                           = SingleColorGenerator(kAlternativeColor);
3158                                 config.expectedDepth                                            = 0.5f;
3159                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
3160                         }
3161                         {
3162                                 TestConfig config = baseConfig;
3163                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_ALWAYS;
3164
3165                                 config.meshParams[0].depth                                      = 0.5f;
3166                                 config.expectedDepth                                            = 0.5f;
3167                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
3168
3169                                 config.meshParams[0].depth                                      = 0.25f;
3170                                 config.expectedDepth                                            = 0.25f;
3171                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
3172
3173                                 config.meshParams[0].depth                                      = 0.75f;
3174                                 config.expectedDepth                                            = 0.75f;
3175                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
3176                         }
3177                 }
3178
3179                 // Depth bounds test.
3180                 {
3181                         TestConfig baseConfig(kOrdering);
3182                         baseConfig.minDepthBounds                                                       = 0.25f;
3183                         baseConfig.maxDepthBounds                                                       = 0.75f;
3184                         baseConfig.meshParams[0].depth                                          = 0.0f;
3185
3186                         {
3187                                 TestConfig config = baseConfig;
3188                                 config.depthBoundsTestEnableConfig.staticValue  = false;
3189                                 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(true);
3190                                 config.referenceColor                                                   = SingleColorGenerator(kDefaultClearColor);
3191                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
3192                         }
3193                         {
3194                                 TestConfig config = baseConfig;
3195                                 config.depthBoundsTestEnableConfig.staticValue  = true;
3196                                 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(false);
3197                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
3198                         }
3199                 }
3200
3201                 // Stencil test enable.
3202                 {
3203                         TestConfig config(kOrdering);
3204                         config.stencilTestEnableConfig.staticValue                              = false;
3205                         config.stencilTestEnableConfig.dynamicValue                             = tcu::just(true);
3206                         config.stencilOpConfig.staticValue.front().compareOp    = vk::VK_COMPARE_OP_NEVER;
3207                         config.referenceColor                                                                   = SingleColorGenerator(kDefaultClearColor);
3208                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
3209                 }
3210                 {
3211                         TestConfig config(kOrdering);
3212                         config.stencilTestEnableConfig.staticValue                              = true;
3213                         config.stencilTestEnableConfig.dynamicValue                             = tcu::just(false);
3214                         config.stencilOpConfig.staticValue.front().compareOp    = vk::VK_COMPARE_OP_NEVER;
3215                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
3216                 }
3217
3218                 // Stencil operation. Many combinations are possible.
3219                 {
3220                         static const struct
3221                         {
3222                                 vk::VkStencilFaceFlags  face;
3223                                 std::string                             name;
3224                         } kFaces[] =
3225                         {
3226                                 { vk::VK_STENCIL_FACE_FRONT_BIT,                        "face_front"            },
3227                                 { vk::VK_STENCIL_FACE_BACK_BIT,                         "face_back"                     },
3228                                 { vk::VK_STENCIL_FRONT_AND_BACK,                        "face_both_single"      },
3229                                 { vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM,       "face_both_dual"        },      // MAX_ENUM is a placeholder.
3230                         };
3231
3232                         static const struct
3233                         {
3234                                 vk::VkCompareOp         compareOp;
3235                                 std::string                     name;
3236                         } kCompare[] =
3237                         {
3238                                 { vk::VK_COMPARE_OP_NEVER,                              "xf"            },
3239                                 { vk::VK_COMPARE_OP_LESS,                               "lt"            },
3240                                 { vk::VK_COMPARE_OP_EQUAL,                              "eq"            },
3241                                 { vk::VK_COMPARE_OP_LESS_OR_EQUAL,              "le"            },
3242                                 { vk::VK_COMPARE_OP_GREATER,                    "gt"            },
3243                                 { vk::VK_COMPARE_OP_GREATER_OR_EQUAL,   "ge"            },
3244                                 { vk::VK_COMPARE_OP_ALWAYS,                             "xt"            },
3245                         };
3246
3247                         using u8vec = std::vector<deUint8>;
3248
3249                         static const auto kMinVal       = std::numeric_limits<deUint8>::min();
3250                         static const auto kMaxVal       = std::numeric_limits<deUint8>::max();
3251                         static const auto kMidVal       = static_cast<deUint8>(kMaxVal * 2u / 5u);
3252                         static const auto kMinValI      = static_cast<int>(kMinVal);
3253                         static const auto kMaxValI      = static_cast<int>(kMaxVal);
3254
3255                         static const struct
3256                         {
3257                                 vk::VkStencilOp         stencilOp;
3258                                 std::string                     name;
3259                                 u8vec                           clearValues;    // One test per clear value interesting for this operation.
3260                                 vk::VkStencilOp         incompatibleOp; // Alternative operation giving incompatible results for the given values.
3261                         } kStencilOps[] =
3262                         {
3263                                 { vk::VK_STENCIL_OP_KEEP,                                       "keep",                 u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
3264                                 { vk::VK_STENCIL_OP_ZERO,                                       "zero",                 u8vec{kMidVal},                                 vk::VK_STENCIL_OP_KEEP                                  },
3265                                 { vk::VK_STENCIL_OP_REPLACE,                            "replace",              u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
3266                                 { vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP,        "inc_clamp",    u8vec{kMaxVal - 1, kMaxVal},    vk::VK_STENCIL_OP_ZERO                                  },
3267                                 { vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP,        "dec_clamp",    u8vec{kMinVal + 1, kMinVal},    vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP   },
3268                                 { vk::VK_STENCIL_OP_INVERT,                                     "invert",               u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
3269                                 { vk::VK_STENCIL_OP_INCREMENT_AND_WRAP,         "inc_wrap",             u8vec{kMaxVal - 1, kMaxVal},    vk::VK_STENCIL_OP_KEEP                                  },
3270                                 { vk::VK_STENCIL_OP_DECREMENT_AND_WRAP,         "dec_wrap",             u8vec{kMinVal + 1, kMinVal},    vk::VK_STENCIL_OP_KEEP                                  },
3271                         };
3272
3273                         for (const auto& face : kFaces)
3274                         for (const auto& compare : kCompare)
3275                         for (const auto& op : kStencilOps)
3276                         {
3277                                 // Try clearing the stencil value with different values.
3278                                 for (const auto clearVal : op.clearValues)
3279                                 {
3280                                         // Use interesting values as the reference stencil value.
3281                                         for (int delta = -1; delta <= 1; ++delta)
3282                                         {
3283                                                 const int refVal = clearVal + delta;
3284                                                 if (refVal < kMinValI || refVal > kMaxValI)
3285                                                         continue;
3286
3287                                                 const auto refValU8             = static_cast<deUint8>(refVal);
3288                                                 const auto refValU32    = static_cast<deUint32>(refVal);
3289
3290                                                 // Calculate outcome of the stencil test itself.
3291                                                 const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
3292
3293                                                 // If the test passes, use an additional variant for the depthFail operation.
3294                                                 const int subCases = (wouldPass ? 2 : 1);
3295
3296                                                 for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
3297                                                 {
3298                                                         const bool depthFail    = (subCaseIdx > 0);                             // depthFail would be the second variant.
3299                                                         const bool globalPass   = (wouldPass && !depthFail);    // Global result of the stencil+depth test.
3300
3301                                                         // Start tuning test parameters.
3302                                                         TestConfig config(kOrdering);
3303
3304                                                         // No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
3305                                                         if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
3306                                                         {
3307                                                                 // Default parameters are OK.
3308                                                         }
3309                                                         else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
3310                                                         {
3311                                                                 // Reverse the mesh so it applies the back operation.
3312                                                                 config.meshParams[0].reversed = true;
3313                                                         }
3314                                                         else    // Front and back.
3315                                                         {
3316                                                                 // Draw both a front and a back-facing mesh so both are applied.
3317                                                                 // The first mesh will be drawn in the top half and the second mesh in the bottom half.
3318
3319                                                                 // Make the second mesh a reversed copy of the first mesh.
3320                                                                 config.meshParams.push_back(config.meshParams.front());
3321                                                                 config.meshParams.back().reversed = true;
3322
3323                                                                 // Apply scale and offset to the top mesh.
3324                                                                 config.meshParams.front().scaleY = 0.5f;
3325                                                                 config.meshParams.front().offsetY = -0.5f;
3326
3327                                                                 // Apply scale and offset to the bottom mesh.
3328                                                                 config.meshParams.back().scaleY = 0.5f;
3329                                                                 config.meshParams.back().offsetY = 0.5f;
3330                                                         }
3331
3332                                                         // Enable the stencil test.
3333                                                         config.stencilTestEnableConfig.staticValue = true;
3334
3335                                                         // Set dynamic configuration.
3336                                                         StencilOpParams dynamicStencilConfig;
3337                                                         dynamicStencilConfig.faceMask           = face.face;
3338                                                         dynamicStencilConfig.compareOp          = compare.compareOp;
3339                                                         dynamicStencilConfig.failOp                     = vk::VK_STENCIL_OP_MAX_ENUM;
3340                                                         dynamicStencilConfig.passOp                     = vk::VK_STENCIL_OP_MAX_ENUM;
3341                                                         dynamicStencilConfig.depthFailOp        = vk::VK_STENCIL_OP_MAX_ENUM;
3342
3343                                                         // Set operations so only the appropriate operation for this case gives the right result.
3344                                                         vk::VkStencilOp* activeOp               = nullptr;
3345                                                         vk::VkStencilOp* inactiveOps[2] = { nullptr, nullptr };
3346                                                         if (wouldPass)
3347                                                         {
3348                                                                 if (depthFail)
3349                                                                 {
3350                                                                         activeOp                = &dynamicStencilConfig.depthFailOp;
3351                                                                         inactiveOps[0]  = &dynamicStencilConfig.passOp;
3352                                                                         inactiveOps[1]  = &dynamicStencilConfig.failOp;
3353                                                                 }
3354                                                                 else
3355                                                                 {
3356                                                                         activeOp                = &dynamicStencilConfig.passOp;
3357                                                                         inactiveOps[0]  = &dynamicStencilConfig.depthFailOp;
3358                                                                         inactiveOps[1]  = &dynamicStencilConfig.failOp;
3359                                                                 }
3360                                                         }
3361                                                         else
3362                                                         {
3363                                                                 activeOp                = &dynamicStencilConfig.failOp;
3364                                                                 inactiveOps[0]  = &dynamicStencilConfig.passOp;
3365                                                                 inactiveOps[1]  = &dynamicStencilConfig.depthFailOp;
3366                                                         }
3367
3368                                                         *activeOp = op.stencilOp;
3369                                                         *inactiveOps[0] = op.incompatibleOp;
3370                                                         *inactiveOps[1] = op.incompatibleOp;
3371
3372                                                         // Make sure all ops have been configured properly.
3373                                                         DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
3374                                                         DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
3375                                                         DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
3376
3377                                                         // Set an incompatible static operation too.
3378                                                         auto& staticStencilConfig               = config.stencilOpConfig.staticValue.front();
3379                                                         staticStencilConfig.faceMask    = face.face;
3380                                                         staticStencilConfig.compareOp   = (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
3381                                                         staticStencilConfig.passOp              = op.incompatibleOp;
3382                                                         staticStencilConfig.failOp              = op.incompatibleOp;
3383                                                         staticStencilConfig.depthFailOp = op.incompatibleOp;
3384
3385                                                         // Set dynamic configuration.
3386                                                         StencilOpVec stencilOps;
3387                                                         stencilOps.push_back(dynamicStencilConfig);
3388
3389                                                         if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
3390                                                         {
3391                                                                 // This is the dual case. We will set the front and back face values with two separate calls.
3392                                                                 stencilOps.push_back(stencilOps.front());
3393                                                                 stencilOps.front().faceMask             = vk::VK_STENCIL_FACE_FRONT_BIT;
3394                                                                 stencilOps.back().faceMask              = vk::VK_STENCIL_FACE_BACK_BIT;
3395                                                                 staticStencilConfig.faceMask    = vk::VK_STENCIL_FACE_FRONT_AND_BACK;
3396                                                         }
3397
3398                                                         config.stencilOpConfig.dynamicValue     = tcu::just(stencilOps);
3399                                                         config.clearStencilValue                        = clearVal;
3400                                                         config.referenceStencil                         = refValU32;
3401
3402                                                         if (depthFail)
3403                                                         {
3404                                                                 // Enable depth test and make it fail.
3405                                                                 config.depthTestEnableConfig.staticValue        = true;
3406                                                                 config.clearDepthValue                                          = 0.5f;
3407                                                                 config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
3408
3409                                                                 for (auto& meshPar : config.meshParams)
3410                                                                         meshPar.depth = 0.75f;
3411                                                         }
3412
3413                                                         // Set expected outcome.
3414                                                         config.referenceColor   = SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor);
3415                                                         config.expectedDepth    = config.clearDepthValue; // No depth writing by default.
3416                                                         config.expectedStencil  = stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
3417
3418                                                         const std::string testName = std::string("stencil_state")
3419                                                                 + "_" + face.name
3420                                                                 + "_" + compare.name
3421                                                                 + "_" + op.name
3422                                                                 + "_clear_" + de::toString(static_cast<int>(clearVal))
3423                                                                 + "_ref_" + de::toString(refVal)
3424                                                                 + "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
3425
3426                                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
3427                                                 }
3428                                         }
3429                                 }
3430                         }
3431                 }
3432
3433                 // Vertex input.
3434                 {
3435                         // TWO_DRAWS_STATIC would be invalid because it violates VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the
3436                         // dynamic stride being less than the extent of the binding for the second attribute.
3437                         if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
3438                         {
3439                                 const auto      staticGen       = getVertexWithPaddingGenerator();
3440                                 const auto      dynamicGen      = getVertexWithExtraAttributesGenerator();
3441                                 const auto      goodStrides     = dynamicGen->getVertexDataStrides();
3442                                 StrideVec       badStrides;
3443
3444                                 badStrides.reserve(goodStrides.size());
3445                                 for (const auto& stride : goodStrides)
3446                                         badStrides.push_back(stride / 2u);
3447
3448                                 TestConfig config(kOrdering, staticGen, dynamicGen);
3449                                 config.strideConfig.staticValue                 = badStrides;
3450                                 config.strideConfig.dynamicValue                = goodStrides;
3451                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input", "Dynamically set vertex input", config));
3452                         }
3453
3454                         {
3455                                 // Variant without mixing in the stride config.
3456                                 TestConfig config(kOrdering, getVertexWithPaddingGenerator(), getVertexWithExtraAttributesGenerator());
3457                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_no_dyn_stride", "Dynamically set vertex input without using dynamic strides", config));
3458                         }
3459
3460                         {
3461                                 // Variant using multiple bindings.
3462                                 TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator(), getVertexWithMultipleBindingsGenerator());
3463                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_multiple_bindings", "Dynamically set vertex input with multiple bindings", config));
3464                         }
3465                 }
3466
3467                 extendedDynamicStateGroup->addChild(orderingGroup.release());
3468         }
3469
3470         return extendedDynamicStateGroup.release();
3471 }
3472
3473 } // pipeline
3474 } // vkt