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