1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2020 The Khronos Group Inc.
6  * Copyright (c) 2020 Valve Corporation.
7  * Copyright (c) 2023 LunarG, Inc.
8  * Copyright (c) 2023 Nintendo
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  *//*
23  * \file
24  * \brief Extended dynamic state tests
25 *//*--------------------------------------------------------------------*/
26 
27 #include "vktPipelineExtendedDynamicStateTests.hpp"
28 #include "vktPipelineExtendedDynamicStateMiscTests.hpp"
29 #include "vktPipelineImageUtil.hpp"
30 #include "vktTestCase.hpp"
31 #include "vktCustomInstancesDevices.hpp"
32 
33 #include "vkDefs.hpp"
34 #include "vkTypeUtil.hpp"
35 #include "vkQueryUtil.hpp"
36 #include "vkObjUtil.hpp"
37 #include "vkBufferWithMemory.hpp"
38 #include "vkImageWithMemory.hpp"
39 #include "vkBuilderUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "vkImageUtil.hpp"
42 #include "vkBarrierUtil.hpp"
43 
44 #include "tcuVector.hpp"
45 #include "tcuMaybe.hpp"
46 #include "tcuTestLog.hpp"
47 #include "tcuVectorUtil.hpp"
48 #include "tcuStringTemplate.hpp"
49 #include "tcuTextureUtil.hpp"
50 #include "tcuCommandLine.hpp"
51 
52 #include "deUniquePtr.hpp"
53 #include "deStringUtil.hpp"
54 
55 #include <vector>
56 #include <sstream>
57 #include <algorithm>
58 #include <utility>
59 #include <iterator>
60 #include <string>
61 #include <limits>
62 #include <memory>
63 #include <functional>
64 #include <cstddef>
65 #include <set>
66 #include <array>
67 #include <map>
68 
69 namespace vkt
70 {
71 namespace pipeline
72 {
73 
74 namespace
75 {
76 
makeVkBool32(bool value)77 inline vk::VkBool32 makeVkBool32(bool value)
78 {
79     return (value ? VK_TRUE : VK_FALSE);
80 }
81 
82 #ifndef CTS_USES_VULKANSC
makeProvokingVertexMode(bool lastVertex)83 vk::VkProvokingVertexModeEXT makeProvokingVertexMode(bool lastVertex)
84 {
85     return (lastVertex ? vk::VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT : vk::VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT);
86 }
87 #endif // CTS_USES_VULKANSC
88 
89 // Framebuffer size.
90 constexpr uint32_t kFramebufferWidth  = 64u;
91 constexpr uint32_t kFramebufferHeight = 64u;
92 const auto kFramebufferExtent         = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
93 
94 // Image formats.
95 constexpr vk::VkFormat kUnormColorFormat  = vk::VK_FORMAT_R8G8B8A8_UNORM;
96 constexpr vk::VkFormat kIntColorFormat    = vk::VK_FORMAT_R8G8B8A8_UINT;
97 constexpr vk::VkFormat kIntRedColorFormat = vk::VK_FORMAT_R32_UINT;
98 const tcu::Vec4 kUnormColorThreshold(0.005f); // 1/255 < 0.005 < 2/255.
99 
100 // This sample count must be supported for all formats supporting VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT.
101 // See 44.1.1. Supported Sample Counts.
102 const auto kMultiSampleCount  = vk::VK_SAMPLE_COUNT_4_BIT;
103 const auto kSingleSampleCount = vk::VK_SAMPLE_COUNT_1_BIT;
104 
105 // Image usage flags.
106 const vk::VkImageUsageFlags kColorUsage =
107     (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
108 const vk::VkImageUsageFlags kDSUsage =
109     (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
110 
111 // Color components.
112 const auto CR = vk::VK_COLOR_COMPONENT_R_BIT;
113 const auto CG = vk::VK_COLOR_COMPONENT_G_BIT;
114 const auto CB = vk::VK_COLOR_COMPONENT_B_BIT;
115 const auto CA = vk::VK_COLOR_COMPONENT_A_BIT;
116 
componentCodes(vk::VkColorComponentFlags components)117 std::string componentCodes(vk::VkColorComponentFlags components)
118 {
119     std::string name;
120 
121     if ((components & CR) != 0u)
122         name += "r";
123     if ((components & CG) != 0u)
124         name += "g";
125     if ((components & CB) != 0u)
126         name += "b";
127     if ((components & CA) != 0u)
128         name += "a";
129 
130     if (name.empty())
131         name = "0";
132     return name;
133 }
134 
135 // Chooses clear or geometry color depending on the selected components.
filterColor(const tcu::Vec4 & clearColor,const tcu::Vec4 & color,vk::VkColorComponentFlags components)136 tcu::Vec4 filterColor(const tcu::Vec4 &clearColor, const tcu::Vec4 &color, vk::VkColorComponentFlags components)
137 {
138     const tcu::Vec4 finalColor(
139         (((components & CR) != 0u) ? color[0] : clearColor[0]), (((components & CG) != 0u) ? color[1] : clearColor[1]),
140         (((components & CB) != 0u) ? color[2] : clearColor[2]), (((components & CA) != 0u) ? color[3] : clearColor[3]));
141     return finalColor;
142 }
143 
144 struct DepthStencilFormat
145 {
146     vk::VkFormat imageFormat;
147     float depthThreshold;
148 };
149 
150 const DepthStencilFormat kDepthStencilFormats[] = {
151     {vk::VK_FORMAT_D32_SFLOAT_S8_UINT, 0.0f},
152     {vk::VK_FORMAT_D24_UNORM_S8_UINT, 1.0e-07f}, // 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
153 };
154 
155 using StrideVec = std::vector<vk::VkDeviceSize>;
156 
157 enum class TopologyClass
158 {
159     POINT,
160     LINE,
161     TRIANGLE,
162     PATCH,
163     INVALID,
164 };
165 
topologyClassName(TopologyClass tclass)166 std::string topologyClassName(TopologyClass tclass)
167 {
168     switch (tclass)
169     {
170     case TopologyClass::POINT:
171         return "point";
172     case TopologyClass::LINE:
173         return "line";
174     case TopologyClass::TRIANGLE:
175         return "triangle";
176     case TopologyClass::PATCH:
177         return "patch";
178     default:
179         break;
180     }
181 
182     DE_ASSERT(false);
183     return "";
184 }
185 
186 // We will use several data types in vertex bindings. Each type will need to define a few things.
187 class VertexGenerator
188 {
189 public:
~VertexGenerator()190     virtual ~VertexGenerator()
191     {
192     }
193 
194     // Some generators may need specific features.
checkSupport(Context &) const195     virtual void checkSupport(Context &) const
196     {
197     }
198 
199     // For GLSL.
200 
201     // Vertex input/output attribute declarations in GLSL form. One sentence per element.
202     virtual std::vector<std::string> getAttributeDeclarations() const = 0;
203 
204     // Get statements to calculate a vec2 called "vertexCoords" using the vertex input attributes.
205     virtual std::vector<std::string> getVertexCoordCalc() const = 0;
206 
207     // Get vertex binding declarations as part of descriptor sets, used for mesh shading.
208     virtual std::vector<std::string> getDescriptorDeclarations() const = 0;
209 
210     // Get statements to calculate a vec2 called "vertexCoords" using descriptor members.
211     virtual std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const = 0;
212 
213     // Get fragment input attribute declarations in GLSL form. One sentence per element.
getFragInputAttributes() const214     virtual std::vector<std::string> getFragInputAttributes() const
215     {
216         return std::vector<std::string>();
217     }
218 
219     // Get fragment output post-calculations, maybe altering the "color" output variable.
getFragOutputCalc() const220     virtual std::vector<std::string> getFragOutputCalc() const
221     {
222         return std::vector<std::string>();
223     }
224 
225     // GLSL extensions if needed.
getGLSLExtensions() const226     virtual std::vector<std::string> getGLSLExtensions() const
227     {
228         return std::vector<std::string>();
229     }
230 
231     // For the pipeline.
232 
233     // Vertex attributes for VkPipelineVertexInputStateCreateInfo.
234     virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const = 0;
235 
236     // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
237     virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const = 0;
238 
239     // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
240     virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const = 0;
241 
242     // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
243     virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
244         const StrideVec &strides) const = 0;
245 
246     // Create buffer data given an array of coordinates and an initial padding.
247     virtual std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
248                                                                vk::VkDeviceSize dataOffset,
249                                                                vk::VkDeviceSize trailingPadding,
250                                                                const void *paddingPattern,
251                                                                size_t patternSize) const = 0;
252 
253     // Stride of vertex data in each binding.
254     virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const = 0;
255 };
256 
257 // Auxiliar function to create these structs more easily.
makeVertexInputAttributeDescription2EXT(uint32_t location,uint32_t binding,vk::VkFormat format,uint32_t offset)258 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT(uint32_t location, uint32_t binding,
259                                                                                   vk::VkFormat format, uint32_t offset)
260 {
261     vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
262     desc.location                                  = location;
263     desc.binding                                   = binding;
264     desc.format                                    = format;
265     desc.offset                                    = offset;
266     return desc;
267 }
268 
makeVertexInputBindingDescription2EXT(uint32_t binding,uint32_t stride,vk::VkVertexInputRate inputRate)269 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT(uint32_t binding, uint32_t stride,
270                                                                               vk::VkVertexInputRate inputRate)
271 {
272     vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
273     desc.binding                                 = binding;
274     desc.stride                                  = stride;
275     desc.inputRate                               = inputRate;
276     desc.divisor                                 = 1u;
277     return desc;
278 }
279 
280 // Fill a section of the given buffer (from offset to offset+count) with repeating copies of the given data.
fillWithPattern(void * ptr_,size_t offset,size_t count,const void * src,size_t srcSize)281 void fillWithPattern(void *ptr_, size_t offset, size_t count, const void *src, size_t srcSize)
282 {
283     auto ptr       = reinterpret_cast<char *>(ptr_);
284     size_t done    = 0u;
285     size_t pending = count;
286 
287     while (pending > 0u)
288     {
289         const size_t stepSize = de::min(srcSize, pending);
290         deMemcpy(ptr + offset + done, src, stepSize);
291         done += stepSize;
292         pending -= stepSize;
293     }
294 }
295 
296 // Create a single binding vertex data vector given a type T for vertex data.
297 template <class T>
createSingleBindingVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize)298 std::vector<uint8_t> createSingleBindingVertexData(const std::vector<tcu::Vec2> &coords, vk::VkDeviceSize dataOffset,
299                                                    vk::VkDeviceSize trailingPadding, const void *paddingPattern,
300                                                    size_t patternSize)
301 {
302     DE_ASSERT(!coords.empty());
303 
304     const auto dataOffsetSz      = static_cast<size_t>(dataOffset);
305     const auto trailingPaddingSz = static_cast<size_t>(trailingPadding);
306 
307     std::vector<uint8_t> buffer;
308     buffer.resize(dataOffsetSz + coords.size() * sizeof(T) + trailingPaddingSz);
309 
310     fillWithPattern(buffer.data(), 0u, dataOffsetSz, paddingPattern, patternSize);
311 
312     auto pos = dataOffsetSz;
313     for (const auto &coord : coords)
314     {
315         new (&buffer[pos]) T(coord);
316         pos += sizeof(T);
317     }
318 
319     fillWithPattern(buffer.data(), pos, trailingPaddingSz, paddingPattern, patternSize);
320 
321     return buffer;
322 }
323 
324 // Vertices in buffers will have 2 components and a padding to properly test the stride.
325 // This is the vertex type that will be used normally.
326 class VertexWithPadding : public VertexGenerator
327 {
328 protected:
329     struct VertexData
330     {
VertexDatavkt::pipeline::__anon3cc04b6f0111::VertexWithPadding::VertexData331         VertexData(const tcu::Vec2 &coords_) : coords(coords_), padding(0.0f, 0.0f)
332         {
333         }
334 
335         tcu::Vec2 coords;
336         tcu::Vec2 padding;
337     };
338 
339 public:
getAttributeDeclarations() const340     std::vector<std::string> getAttributeDeclarations() const override
341     {
342         std::vector<std::string> declarations;
343         declarations.push_back("layout(location=0) in vec2 position;");
344         return declarations;
345     }
346 
getVertexCoordCalc() const347     std::vector<std::string> getVertexCoordCalc() const override
348     {
349         std::vector<std::string> statements;
350         statements.push_back("vec2 vertexCoords = position;");
351         return statements;
352     }
353 
getDescriptorDeclarations() const354     std::vector<std::string> getDescriptorDeclarations() const override
355     {
356         std::vector<std::string> declarations;
357         declarations.reserve(7u);
358         declarations.push_back("struct VertexData {");
359         declarations.push_back("    vec2 position;");
360         declarations.push_back("    vec2 padding;");
361         declarations.push_back("};");
362         declarations.push_back("layout(set=0, binding=0, std430) readonly buffer S0B0Block {");
363         declarations.push_back("    VertexData data[];");
364         declarations.push_back("} s0b0buffer;");
365         return declarations;
366     }
367 
getDescriptorCoordCalc(TopologyClass topology) const368     std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const override
369     {
370         std::vector<std::string> statements;
371 
372         if (topology == TopologyClass::TRIANGLE)
373         {
374             statements.reserve(4u);
375             statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
376             statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
377             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
378             statements.push_back("vec2 vertexCoords = s0b0buffer.data[invIndex].position;");
379         }
380         else if (topology == TopologyClass::LINE)
381         {
382             statements.reserve(9u);
383             statements.push_back("const uint linesPerRow = 3u;");
384             statements.push_back("const uint verticesPerRow = 4u;");
385             statements.push_back("uint lineIndex = uint(gl_WorkGroupID.x);");
386             statements.push_back("uint rowIndex = lineIndex / linesPerRow;");
387             statements.push_back("uint lineInRow = lineIndex % linesPerRow;");
388             statements.push_back("uint firstVertex = rowIndex * verticesPerRow + lineInRow;");
389             statements.push_back("uint indices[2] = uint[](firstVertex, firstVertex + 1u);");
390             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
391             statements.push_back("vec2 vertexCoords = s0b0buffer.data[invIndex].position;");
392         }
393         else
394             DE_ASSERT(false);
395 
396         return statements;
397     }
398 
getAttributeDescriptions() const399     std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
400     {
401         std::vector<vk::VkVertexInputAttributeDescription> descriptions;
402         descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
403         return descriptions;
404     }
405 
406     // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
getAttributeDescriptions2() const407     std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
408     {
409         std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
410         descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
411         return descriptions;
412     }
413 
414     // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
getBindingDescriptions(const StrideVec & strides) const415     std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const override
416     {
417         std::vector<vk::VkVertexInputBindingDescription> descriptions;
418         descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(strides.at(0)),
419                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
420         return descriptions;
421     }
422 
423     // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
getBindingDescriptions2(const StrideVec & strides) const424     std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
425         const StrideVec &strides) const override
426     {
427         std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
428         descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<uint32_t>(strides.at(0)),
429                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
430         return descriptions;
431     }
432 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const433     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
434                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
435                                                        const void *paddingPattern, size_t patternSize) const override
436     {
437         return std::vector<std::vector<uint8_t>>(
438             1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern,
439                                                           patternSize));
440     }
441 
getVertexDataStrides() const442     std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
443     {
444         return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
445     }
446 };
447 
448 // Vertices in buffers will have 2 components and a padding. Same as VertexWithPadding but using 16-bit floats.
449 class VertexWithPadding16 : public VertexGenerator
450 {
451 protected:
452     struct VertexData
453     {
VertexDatavkt::pipeline::__anon3cc04b6f0111::VertexWithPadding16::VertexData454         VertexData(const tcu::Vec2 &coords_)
455             : coords(tcu::Float16(coords_.x()), tcu::Float16(coords_.y()))
456             , padding(tcu::Float16(0.0f), tcu::Float16(0.0f))
457         {
458         }
459 
460         tcu::F16Vec2 coords;
461         tcu::F16Vec2 padding;
462     };
463 
464 public:
checkSupport(Context & context) const465     void checkSupport(Context &context) const override
466     {
467         // We need shaderFloat16 and storageInputOutput16.
468         const auto &sf16i8Features = context.getShaderFloat16Int8Features();
469         if (!sf16i8Features.shaderFloat16)
470             TCU_THROW(NotSupportedError, "shaderFloat16 not supported");
471 
472         const auto &storage16Features = context.get16BitStorageFeatures();
473         if (!storage16Features.storageInputOutput16)
474             TCU_THROW(NotSupportedError, "storageInputOutput16 not supported");
475     }
476 
getGLSLExtensions() const477     std::vector<std::string> getGLSLExtensions() const override
478     {
479         std::vector<std::string> extensions;
480         extensions.push_back("#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require");
481         return extensions;
482     }
483 
getAttributeDeclarations() const484     std::vector<std::string> getAttributeDeclarations() const override
485     {
486         std::vector<std::string> declarations;
487         declarations.push_back("layout(location=0) in f16vec2 position;");
488         return declarations;
489     }
490 
getVertexCoordCalc() const491     std::vector<std::string> getVertexCoordCalc() const override
492     {
493         std::vector<std::string> statements;
494         statements.push_back("f16vec2 vertexCoords = position;");
495         return statements;
496     }
497 
getDescriptorDeclarations() const498     std::vector<std::string> getDescriptorDeclarations() const override
499     {
500         std::vector<std::string> declarations;
501         declarations.reserve(7u);
502         declarations.push_back("struct VertexData {");
503         declarations.push_back("    f16vec2 position;");
504         declarations.push_back("    f16vec2 padding;");
505         declarations.push_back("};");
506         declarations.push_back("layout(set=0, binding=0, std430) readonly buffer S0B0Block {");
507         declarations.push_back("    VertexData data[];");
508         declarations.push_back("} s0b0buffer;");
509         return declarations;
510     }
511 
getDescriptorCoordCalc(TopologyClass topology) const512     std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const override
513     {
514         std::vector<std::string> statements;
515 
516         if (topology == TopologyClass::TRIANGLE)
517         {
518             statements.reserve(4u);
519             statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
520             statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
521             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
522             statements.push_back("f16vec2 vertexCoords = s0b0buffer.data[invIndex].position;");
523         }
524         else if (topology == TopologyClass::LINE)
525         {
526             statements.reserve(9u);
527             statements.push_back("const uint linesPerRow = 3u;");
528             statements.push_back("const uint verticesPerRow = 4u;");
529             statements.push_back("uint lineIndex = uint(gl_WorkGroupID.x);");
530             statements.push_back("uint rowIndex = lineIndex / linesPerRow;");
531             statements.push_back("uint lineInRow = lineIndex % linesPerRow;");
532             statements.push_back("uint firstVertex = rowIndex * verticesPerRow + lineInRow;");
533             statements.push_back("uint indices[2] = uint[](firstVertex, firstVertex + 1u);");
534             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
535             statements.push_back("f16vec2 vertexCoords = s0b0buffer.data[invIndex].position;");
536         }
537         else
538             DE_ASSERT(false);
539 
540         return statements;
541     }
542 
getAttributeDescriptions() const543     std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
544     {
545         std::vector<vk::VkVertexInputAttributeDescription> descriptions;
546         descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R16G16_SFLOAT, 0u));
547         return descriptions;
548     }
549 
550     // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
getAttributeDescriptions2() const551     std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
552     {
553         std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
554         descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R16G16_SFLOAT, 0u));
555         return descriptions;
556     }
557 
558     // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
getBindingDescriptions(const StrideVec & strides) const559     std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const override
560     {
561         std::vector<vk::VkVertexInputBindingDescription> descriptions;
562         descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(strides.at(0)),
563                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
564         return descriptions;
565     }
566 
567     // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
getBindingDescriptions2(const StrideVec & strides) const568     std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
569         const StrideVec &strides) const override
570     {
571         std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
572         descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<uint32_t>(strides.at(0)),
573                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
574         return descriptions;
575     }
576 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const577     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
578                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
579                                                        const void *paddingPattern, size_t patternSize) const override
580     {
581         return std::vector<std::vector<uint8_t>>(
582             1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern,
583                                                           patternSize));
584     }
585 
getVertexDataStrides() const586     std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
587     {
588         return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
589     }
590 };
591 
592 // Two buffers (bindings): one with vertex data, stored contiguously without paddings, and one with instance data. Instance data
593 // will not be stored contiguously: the stride will be twice that of the data size, and the padding space filled with "garbage".
594 // Real instance data will contain a scale and an offset similar to the ones from push constants, and will be used to properly scale
595 // and offset meshes to make them cover the top and bottom halves of the framebuffer.
596 class VertexWithInstanceData : public VertexGenerator
597 {
598 protected:
599     struct InstanceData
600     {
InstanceDatavkt::pipeline::__anon3cc04b6f0111::VertexWithInstanceData::InstanceData601         InstanceData(const tcu::Vec2 &scaleAndOffsetY_)
602             : scaleAndOffsetY(scaleAndOffsetY_)
603             , garbage(0.0f /* bad scale */, 777.0f /* bad offset */)
604         {
605         }
606 
607         tcu::Vec2 scaleAndOffsetY;
608         tcu::Vec2 garbage;
609     };
610 
611 public:
getAttributeDeclarations() const612     std::vector<std::string> getAttributeDeclarations() const override
613     {
614         std::vector<std::string> declarations;
615         declarations.push_back("layout(location=0) in vec2 position;");
616         declarations.push_back("layout(location=1) in vec2 scaleAndOffsetY;");
617         return declarations;
618     }
619 
getVertexCoordCalc() const620     std::vector<std::string> getVertexCoordCalc() const override
621     {
622         std::vector<std::string> statements;
623         statements.push_back(
624             "vec2 vertexCoords = vec2(position.x, position.y * scaleAndOffsetY.x + scaleAndOffsetY.y);");
625         return statements;
626     }
627 
getDescriptorDeclarations() const628     std::vector<std::string> getDescriptorDeclarations() const override
629     {
630         DE_ASSERT(false); // This vertex generator should not be used with mesh shaders.
631         return std::vector<std::string>();
632     }
633 
getDescriptorCoordCalc(TopologyClass) const634     std::vector<std::string> getDescriptorCoordCalc(TopologyClass) const override
635     {
636         DE_ASSERT(false); // This vertex generator should not be used with mesh shaders.
637         return std::vector<std::string>();
638     }
639 
getAttributeDescriptions() const640     std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
641     {
642         std::vector<vk::VkVertexInputAttributeDescription> descriptions;
643         descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
644         descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
645         return descriptions;
646     }
647 
648     // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
getAttributeDescriptions2() const649     std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
650     {
651         std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
652         descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
653         descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
654         return descriptions;
655     }
656 
657     // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
getBindingDescriptions(const StrideVec & strides) const658     std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const override
659     {
660         std::vector<vk::VkVertexInputBindingDescription> descriptions;
661         descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(strides.at(0)),
662                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
663         descriptions.push_back(vk::makeVertexInputBindingDescription(1u, static_cast<uint32_t>(strides.at(1)),
664                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
665         return descriptions;
666     }
667 
668     // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
getBindingDescriptions2(const StrideVec & strides) const669     std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
670         const StrideVec &strides) const override
671     {
672         std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
673         descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<uint32_t>(strides.at(0)),
674                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
675         descriptions.push_back(makeVertexInputBindingDescription2EXT(1u, static_cast<uint32_t>(strides.at(1)),
676                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
677         return descriptions;
678     }
679 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const680     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
681                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
682                                                        const void *paddingPattern, size_t patternSize) const override
683     {
684         // Instance data for 2 instances. Scale and offset like we do with push constants.
685         const std::vector<tcu::Vec2> instanceIds{
686             tcu::Vec2(0.5f, -0.5f),
687             tcu::Vec2(0.5f, 0.5f),
688         };
689 
690         std::vector<std::vector<uint8_t>> buffers;
691         buffers.reserve(2u);
692         buffers.push_back(
693             createSingleBindingVertexData<tcu::Vec2>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
694         buffers.push_back(createSingleBindingVertexData<InstanceData>(instanceIds, dataOffset, trailingPadding,
695                                                                       paddingPattern, patternSize));
696 
697         return buffers;
698     }
699 
getVertexDataStrides() const700     std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
701     {
702         std::vector<vk::VkDeviceSize> strides;
703         strides.reserve(2u);
704         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(tcu::Vec2)));
705         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(InstanceData)));
706         return strides;
707     }
708 };
709 
710 // Vertex generator used when testing provoking vertices. It has an extra flat vertex output that's also a frag input. Note this
711 // generator only works with 3 vertices.
712 class ProvokingVertexWithPadding : public VertexWithPadding
713 {
714 protected:
715     bool m_lastVertex;
716 
717 public:
ProvokingVertexWithPadding(bool lastVertex)718     ProvokingVertexWithPadding(bool lastVertex) : m_lastVertex(lastVertex)
719     {
720     }
721 
getAttributeDeclarations() const722     std::vector<std::string> getAttributeDeclarations() const override
723     {
724         auto declarations = VertexWithPadding::getAttributeDeclarations();
725         declarations.push_back("layout(location=0) flat out uint colorMultiplier;");
726         return declarations;
727     }
728 
getDescriptorDeclarations() const729     std::vector<std::string> getDescriptorDeclarations() const override
730     {
731         auto declarations = VertexWithPadding::getDescriptorDeclarations();
732         declarations.push_back("layout(location=0) flat out uint colorMultiplier[];");
733         return declarations;
734     }
735 
getVertexCoordCalc() const736     std::vector<std::string> getVertexCoordCalc() const override
737     {
738         auto statements = VertexWithPadding::getVertexCoordCalc();
739         statements.push_back("const bool provokingLast = " + std::string(m_lastVertex ? "true" : "false") + ";");
740         statements.push_back("colorMultiplier = (((!provokingLast && gl_VertexIndex == 0) || (provokingLast && "
741                              "gl_VertexIndex == 2)) ? 1 : 0);");
742         return statements;
743     }
744 
getDescriptorCoordCalc(TopologyClass topology) const745     std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const override
746     {
747         auto statements = VertexWithPadding::getDescriptorCoordCalc(topology);
748         statements.push_back("const bool provokingLast = " + std::string(m_lastVertex ? "true" : "false") + ";");
749         statements.push_back(
750             "colorMultiplier[gl_LocalInvocationIndex] = (((!provokingLast && gl_LocalInvocationIndex == 0) || "
751             "(provokingLast && gl_LocalInvocationIndex == gl_WorkGroupSize.x - 1u)) ? 1 : 0);");
752         return statements;
753     }
754 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const755     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
756                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
757                                                        const void *paddingPattern, size_t patternSize) const override
758     {
759         static constexpr uint32_t kExpectecdCoordCount = 3u;
760         DE_UNREF(kExpectecdCoordCount); // For release builds.
761         DE_ASSERT(coords.size() == kExpectecdCoordCount);
762         return VertexWithPadding::createVertexData(coords, dataOffset, trailingPadding, paddingPattern, patternSize);
763     }
764 
getFragInputAttributes() const765     std::vector<std::string> getFragInputAttributes() const override
766     {
767         std::vector<std::string> declarations;
768         declarations.push_back("layout(location=0) flat in uint colorMultiplier;");
769         return declarations;
770     }
771 
getFragOutputCalc() const772     std::vector<std::string> getFragOutputCalc() const override
773     {
774         std::vector<std::string> statements;
775         statements.push_back("color = color * float(colorMultiplier);");
776         return statements;
777     }
778 };
779 
780 // Vertices with coordinates, padding and an extra constant field.
781 class VertexWithExtraAttributes : public VertexGenerator
782 {
783 protected:
784     struct VertexData
785     {
VertexDatavkt::pipeline::__anon3cc04b6f0111::VertexWithExtraAttributes::VertexData786         VertexData(const tcu::Vec2 &coords_) : coords(coords_), ones(1.0f, 1.0f)
787         {
788             deMemset(padding, 0, sizeof(padding));
789         }
790 
791         tcu::Vec2 coords;
792         tcu::Vec2 padding[10];
793         tcu::Vec2 ones;
794     };
795 
796 public:
getAttributeDeclarations() const797     std::vector<std::string> getAttributeDeclarations() const override
798     {
799         std::vector<std::string> declarations;
800         declarations.reserve(2u);
801         declarations.push_back("layout(location=0) in vec2 position;");
802         declarations.push_back("layout(location=1) in vec2 ones;");
803         return declarations;
804     }
805 
getVertexCoordCalc() const806     std::vector<std::string> getVertexCoordCalc() const override
807     {
808         std::vector<std::string> statements;
809         statements.reserve(2u);
810         statements.push_back("vec2 vertexCoords = position;");
811         statements.push_back("vertexCoords = vertexCoords * ones;");
812         return statements;
813     }
814 
getDescriptorDeclarations() const815     std::vector<std::string> getDescriptorDeclarations() const override
816     {
817         std::vector<std::string> declarations;
818         declarations.reserve(8u);
819         declarations.push_back("struct VertexData {");
820         declarations.push_back("    vec2 coords;");
821         declarations.push_back("    vec2 padding[10];");
822         declarations.push_back("    vec2 ones;");
823         declarations.push_back("};");
824         declarations.push_back("layout(set=0, binding=0, std430) readonly buffer S0B0Block {");
825         declarations.push_back("    VertexData data[];");
826         declarations.push_back("} s0b0buffer;");
827         return declarations;
828     }
829 
getDescriptorCoordCalc(TopologyClass topology) const830     std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const override
831     {
832         std::vector<std::string> statements;
833 
834         if (topology == TopologyClass::TRIANGLE)
835         {
836             statements.reserve(6u);
837             statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
838             statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
839             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
840             statements.push_back("vec2 auxPos = s0b0buffer.data[invIndex].coords;");
841             statements.push_back("vec2 auxOnes = s0b0buffer.data[invIndex].ones;");
842             statements.push_back("vec2 vertexCoords = auxPos * auxOnes;");
843         }
844         else if (topology == TopologyClass::LINE)
845         {
846             statements.reserve(11u);
847             statements.push_back("const uint linesPerRow = 3u;");
848             statements.push_back("const uint verticesPerRow = 4u;");
849             statements.push_back("uint lineIndex = uint(gl_WorkGroupID.x);");
850             statements.push_back("uint rowIndex = lineIndex / linesPerRow;");
851             statements.push_back("uint lineInRow = lineIndex % linesPerRow;");
852             statements.push_back("uint firstVertex = rowIndex * verticesPerRow + lineInRow;");
853             statements.push_back("uint indices[2] = uint[](firstVertex, firstVertex + 1u);");
854             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
855             statements.push_back("vec2 auxPos = s0b0buffer.data[invIndex].coords;");
856             statements.push_back("vec2 auxOnes = s0b0buffer.data[invIndex].ones;");
857             statements.push_back("vec2 vertexCoords = auxPos * auxOnes;");
858         }
859         else
860             DE_ASSERT(false);
861 
862         return statements;
863     }
864 
getAttributeDescriptions() const865     std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
866     {
867         std::vector<vk::VkVertexInputAttributeDescription> descriptions;
868         descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
869         descriptions.push_back(vk::makeVertexInputAttributeDescription(
870             1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexData, ones))));
871         return descriptions;
872     }
873 
getAttributeDescriptions2() const874     std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
875     {
876         std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
877         descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
878         descriptions.push_back(makeVertexInputAttributeDescription2EXT(
879             1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(VertexData, ones))));
880         return descriptions;
881     }
882 
getBindingDescriptions(const StrideVec & strides) const883     std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const override
884     {
885         std::vector<vk::VkVertexInputBindingDescription> descriptions;
886         descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(strides.at(0)),
887                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
888         return descriptions;
889     }
890 
getBindingDescriptions2(const StrideVec & strides) const891     std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
892         const StrideVec &strides) const override
893     {
894         std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
895         descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<uint32_t>(strides.at(0)),
896                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
897         return descriptions;
898     }
899 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const900     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
901                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
902                                                        const void *paddingPattern, size_t patternSize) const override
903     {
904         return std::vector<std::vector<uint8_t>>(
905             1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern,
906                                                           patternSize));
907     }
908 
getVertexDataStrides() const909     std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
910     {
911         return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
912     }
913 };
914 
915 // Vertices using multiple bindings and constant fields.
916 // Binding 0: no data actually used.
917 // Binding 1: contains location 0, array of PaddingOnes.
918 // Binding 2: no data actually used.
919 // Binding 3: contains location 1, array of CoordsData.
920 // Binding 4: no data actually used.
921 // Binding 5: contains location 2, array of OneZeroPadding.
922 // See getAttributeDeclarations().
923 class MultipleBindingsVertex : public VertexGenerator
924 {
925 protected:
926     struct CoordsData
927     {
928         tcu::Vec2 padding0;
929         tcu::Vec2 coords;
930         tcu::Vec2 padding1;
931 
CoordsDatavkt::pipeline::__anon3cc04b6f0111::MultipleBindingsVertex::CoordsData932         CoordsData(const tcu::Vec2 &coords_) : padding0(0.0f, 3.0f), coords(coords_), padding1(3.0f, 0.0f)
933         {
934         }
935     };
936 
937     struct PaddingOnes
938     {
939         tcu::Vec2 padding[4];
940         tcu::Vec2 ones;
941 
PaddingOnesvkt::pipeline::__anon3cc04b6f0111::MultipleBindingsVertex::PaddingOnes942         PaddingOnes(const tcu::Vec2 &) : ones(1.0f, 1.0f)
943         {
944             deMemset(&padding, 0, sizeof(padding));
945         }
946     };
947 
948     struct OneZeroPadding
949     {
950         tcu::Vec4 oneZero;
951         tcu::Vec2 padding[3];
952 
OneZeroPaddingvkt::pipeline::__anon3cc04b6f0111::MultipleBindingsVertex::OneZeroPadding953         OneZeroPadding(const tcu::Vec2 &) : oneZero(1.0f, 1.0f, 0.0f, 0.0f)
954         {
955             deMemset(&padding, 0, sizeof(padding));
956         }
957     };
958 
959     struct Zeros
960     {
961         tcu::Vec2 zeros;
962 
Zerosvkt::pipeline::__anon3cc04b6f0111::MultipleBindingsVertex::Zeros963         Zeros(const tcu::Vec2 &) : zeros(0.0f, 0.0f)
964         {
965         }
966     };
967 
968 public:
getAttributeDeclarations() const969     std::vector<std::string> getAttributeDeclarations() const override
970     {
971         std::vector<std::string> declarations;
972         declarations.reserve(3u);
973 
974         declarations.push_back("layout(location=0) in vec2 ones;");
975         declarations.push_back("layout(location=1) in vec2 position;");
976         declarations.push_back("layout(location=2) in vec4 oneZero;");
977 
978         return declarations;
979     }
980 
getVertexCoordCalc() const981     std::vector<std::string> getVertexCoordCalc() const override
982     {
983         std::vector<std::string> statements;
984         statements.reserve(2u);
985 
986         statements.push_back("vec2 vertexCoords = position;");
987         statements.push_back("vertexCoords = ((vertexCoords * ones) + oneZero.zw) * oneZero.xy;");
988 
989         return statements;
990     }
991 
getDescriptorDeclarations() const992     std::vector<std::string> getDescriptorDeclarations() const override
993     {
994         std::vector<std::string> declarations;
995         declarations.reserve(23u);
996 
997         declarations.push_back("struct PaddingOnes {");
998         declarations.push_back("    vec2 padding[4];");
999         declarations.push_back("    vec2 ones;");
1000         declarations.push_back("};");
1001         declarations.push_back("struct CoordsData {");
1002         declarations.push_back("    vec2 padding0;");
1003         declarations.push_back("    vec2 coords;");
1004         declarations.push_back("    vec2 padding1;");
1005         declarations.push_back("};");
1006         declarations.push_back("struct OneZeroPadding {");
1007         declarations.push_back("    vec2 ones;"); // Note: we split the vec4 into two vec2s to match CPU-side alignment.
1008         declarations.push_back("    vec2 zeros;");
1009         declarations.push_back("    vec2 padding[3];");
1010         declarations.push_back("};");
1011         declarations.push_back("layout(set=0, binding=1, std430) readonly buffer S0B1Block {");
1012         declarations.push_back("    PaddingOnes data[];");
1013         declarations.push_back("} s0b1buffer;");
1014         declarations.push_back("layout(set=0, binding=3, std430) readonly buffer S0B3Block {");
1015         declarations.push_back("    CoordsData data[];");
1016         declarations.push_back("} s0b3buffer;");
1017         declarations.push_back("layout(set=0, binding=4, std430) readonly buffer S0B5Block {");
1018         declarations.push_back("    OneZeroPadding data[];");
1019         declarations.push_back("} s0b5buffer;");
1020 
1021         return declarations;
1022     }
1023 
getDescriptorCoordCalc(TopologyClass topology) const1024     std::vector<std::string> getDescriptorCoordCalc(TopologyClass topology) const override
1025     {
1026         std::vector<std::string> statements;
1027 
1028         if (topology == TopologyClass::TRIANGLE)
1029         {
1030             statements.reserve(8u);
1031             statements.push_back("uint prim = uint(gl_WorkGroupID.x);");
1032             statements.push_back("uint indices[3] = uint[](prim, (prim + (1 + prim % 2)), (prim + (2 - prim % 2)));");
1033             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
1034             statements.push_back("vec2 auxOnes1 = s0b1buffer.data[invIndex].ones;");
1035             statements.push_back("vec2 auxCoords = s0b3buffer.data[invIndex].coords;");
1036             statements.push_back("vec2 auxOnes5 = s0b5buffer.data[invIndex].ones;");
1037             statements.push_back("vec2 auxZeros = s0b5buffer.data[invIndex].zeros;");
1038             statements.push_back("vec2 vertexCoords = ((auxCoords * auxOnes1) + auxZeros) * auxOnes5;");
1039         }
1040         else if (topology == TopologyClass::LINE)
1041         {
1042             statements.reserve(13u);
1043             statements.push_back("const uint linesPerRow = 3u;");
1044             statements.push_back("const uint verticesPerRow = 4u;");
1045             statements.push_back("uint lineIndex = uint(gl_WorkGroupID.x);");
1046             statements.push_back("uint rowIndex = lineIndex / linesPerRow;");
1047             statements.push_back("uint lineInRow = lineIndex % linesPerRow;");
1048             statements.push_back("uint firstVertex = rowIndex * verticesPerRow + lineInRow;");
1049             statements.push_back("uint indices[2] = uint[](firstVertex, firstVertex + 1u);");
1050             statements.push_back("uint invIndex = indices[gl_LocalInvocationIndex];");
1051             statements.push_back("vec2 auxOnes1 = s0b1buffer.data[invIndex].ones;");
1052             statements.push_back("vec2 auxCoords = s0b3buffer.data[invIndex].coords;");
1053             statements.push_back("vec2 auxOnes5 = s0b5buffer.data[invIndex].ones;");
1054             statements.push_back("vec2 auxZeros = s0b5buffer.data[invIndex].zeros;");
1055             statements.push_back("vec2 vertexCoords = ((auxCoords * auxOnes1) + auxZeros) * auxOnes5;");
1056         }
1057         else
1058             DE_ASSERT(false);
1059 
1060         return statements;
1061     }
1062 
getAttributeDescriptions() const1063     std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
1064     {
1065         // We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
1066         std::vector<vk::VkVertexInputAttributeDescription> descriptions;
1067         descriptions.reserve(3u);
1068 
1069         descriptions.push_back(vk::makeVertexInputAttributeDescription(
1070             1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(CoordsData, coords))));
1071         descriptions.push_back(vk::makeVertexInputAttributeDescription(
1072             2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(offsetof(OneZeroPadding, oneZero))));
1073         descriptions.push_back(vk::makeVertexInputAttributeDescription(
1074             0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(PaddingOnes, ones))));
1075 
1076         return descriptions;
1077     }
1078 
getAttributeDescriptions2() const1079     std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
1080     {
1081         // We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
1082         std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
1083         descriptions.reserve(3u);
1084 
1085         descriptions.push_back(makeVertexInputAttributeDescription2EXT(
1086             2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(offsetof(OneZeroPadding, oneZero))));
1087         descriptions.push_back(makeVertexInputAttributeDescription2EXT(
1088             1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(CoordsData, coords))));
1089         descriptions.push_back(makeVertexInputAttributeDescription2EXT(
1090             0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(PaddingOnes, ones))));
1091 
1092         return descriptions;
1093     }
1094 
getBindingDescriptions(const StrideVec & strides) const1095     std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec &strides) const override
1096     {
1097         // Provide descriptions out of order to make it more interesting.
1098         std::vector<vk::VkVertexInputBindingDescription> descriptions;
1099         descriptions.reserve(6u);
1100 
1101         descriptions.push_back(vk::makeVertexInputBindingDescription(2u, static_cast<uint32_t>(strides.at(2)),
1102                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1103         descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<uint32_t>(strides.at(0)),
1104                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1105         descriptions.push_back(vk::makeVertexInputBindingDescription(1u, static_cast<uint32_t>(strides.at(1)),
1106                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1107         descriptions.push_back(vk::makeVertexInputBindingDescription(4u, static_cast<uint32_t>(strides.at(4)),
1108                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1109         descriptions.push_back(vk::makeVertexInputBindingDescription(3u, static_cast<uint32_t>(strides.at(3)),
1110                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1111         descriptions.push_back(vk::makeVertexInputBindingDescription(5u, static_cast<uint32_t>(strides.at(5)),
1112                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1113 
1114         return descriptions;
1115     }
1116 
getBindingDescriptions2(const StrideVec & strides) const1117     std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(
1118         const StrideVec &strides) const override
1119     {
1120         // Provide descriptions out of order to make it more interesting.
1121         std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
1122         descriptions.reserve(6u);
1123 
1124         descriptions.push_back(makeVertexInputBindingDescription2EXT(2u, static_cast<uint32_t>(strides.at(2)),
1125                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1126         descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<uint32_t>(strides.at(0)),
1127                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1128         descriptions.push_back(makeVertexInputBindingDescription2EXT(1u, static_cast<uint32_t>(strides.at(1)),
1129                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1130         descriptions.push_back(makeVertexInputBindingDescription2EXT(5u, static_cast<uint32_t>(strides.at(5)),
1131                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1132         descriptions.push_back(makeVertexInputBindingDescription2EXT(4u, static_cast<uint32_t>(strides.at(4)),
1133                                                                      vk::VK_VERTEX_INPUT_RATE_INSTANCE));
1134         descriptions.push_back(makeVertexInputBindingDescription2EXT(3u, static_cast<uint32_t>(strides.at(3)),
1135                                                                      vk::VK_VERTEX_INPUT_RATE_VERTEX));
1136 
1137         return descriptions;
1138     }
1139 
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const1140     std::vector<std::vector<uint8_t>> createVertexData(const std::vector<tcu::Vec2> &coords,
1141                                                        vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding,
1142                                                        const void *paddingPattern, size_t patternSize) const override
1143     {
1144         std::vector<std::vector<uint8_t>> result;
1145         result.reserve(6u);
1146 
1147         result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern,
1148                                                               patternSize)); // Not actually used.
1149         result.push_back(
1150             createSingleBindingVertexData<PaddingOnes>(coords, dataOffset, trailingPadding, paddingPattern,
1151                                                        patternSize)); // Binding 1 contains location=0 as PaddingOnes.
1152         result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern,
1153                                                               patternSize)); // Not actually used.
1154         result.push_back(
1155             createSingleBindingVertexData<CoordsData>(coords, dataOffset, trailingPadding, paddingPattern,
1156                                                       patternSize)); // Binding 3 contains location=1 as CoordsData.
1157         result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern,
1158                                                               patternSize)); // Not actually used.
1159         result.push_back(createSingleBindingVertexData<OneZeroPadding>(
1160             coords, dataOffset, trailingPadding, paddingPattern,
1161             patternSize)); // Binding 5 contains location=2 as OneZeroPadding.
1162 
1163         return result;
1164     }
1165 
getVertexDataStrides() const1166     std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
1167     {
1168         std::vector<vk::VkDeviceSize> strides;
1169         strides.reserve(6u);
1170 
1171         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
1172         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(PaddingOnes)));
1173         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
1174         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(CoordsData)));
1175         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
1176         strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(OneZeroPadding)));
1177 
1178         return strides;
1179     }
1180 };
1181 
1182 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
1183 struct StencilOpParams
1184 {
1185     vk::VkStencilFaceFlags faceMask;
1186     vk::VkStencilOp failOp;
1187     vk::VkStencilOp passOp;
1188     vk::VkStencilOp depthFailOp;
1189     vk::VkCompareOp compareOp;
1190 };
1191 
1192 const StencilOpParams kDefaultStencilOpParams = {vk::VK_STENCIL_FACE_FRONT_AND_BACK, vk::VK_STENCIL_OP_KEEP,
1193                                                  vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP,
1194                                                  vk::VK_COMPARE_OP_ALWAYS};
1195 
1196 struct DepthBiasParams
1197 {
1198     float constantFactor;
1199     float clamp;
1200 };
1201 
isAdvancedBlendOp(const vk::VkBlendOp blendOp)1202 bool isAdvancedBlendOp(const vk::VkBlendOp blendOp)
1203 {
1204     bool advanced = false;
1205 
1206     switch (blendOp)
1207     {
1208     case vk::VK_BLEND_OP_ZERO_EXT:
1209     case vk::VK_BLEND_OP_SRC_EXT:
1210     case vk::VK_BLEND_OP_DST_EXT:
1211     case vk::VK_BLEND_OP_SRC_OVER_EXT:
1212     case vk::VK_BLEND_OP_DST_OVER_EXT:
1213     case vk::VK_BLEND_OP_SRC_IN_EXT:
1214     case vk::VK_BLEND_OP_DST_IN_EXT:
1215     case vk::VK_BLEND_OP_SRC_OUT_EXT:
1216     case vk::VK_BLEND_OP_DST_OUT_EXT:
1217     case vk::VK_BLEND_OP_SRC_ATOP_EXT:
1218     case vk::VK_BLEND_OP_DST_ATOP_EXT:
1219     case vk::VK_BLEND_OP_XOR_EXT:
1220     case vk::VK_BLEND_OP_MULTIPLY_EXT:
1221     case vk::VK_BLEND_OP_SCREEN_EXT:
1222     case vk::VK_BLEND_OP_OVERLAY_EXT:
1223     case vk::VK_BLEND_OP_DARKEN_EXT:
1224     case vk::VK_BLEND_OP_LIGHTEN_EXT:
1225     case vk::VK_BLEND_OP_COLORDODGE_EXT:
1226     case vk::VK_BLEND_OP_COLORBURN_EXT:
1227     case vk::VK_BLEND_OP_HARDLIGHT_EXT:
1228     case vk::VK_BLEND_OP_SOFTLIGHT_EXT:
1229     case vk::VK_BLEND_OP_DIFFERENCE_EXT:
1230     case vk::VK_BLEND_OP_EXCLUSION_EXT:
1231     case vk::VK_BLEND_OP_INVERT_EXT:
1232     case vk::VK_BLEND_OP_INVERT_RGB_EXT:
1233     case vk::VK_BLEND_OP_LINEARDODGE_EXT:
1234     case vk::VK_BLEND_OP_LINEARBURN_EXT:
1235     case vk::VK_BLEND_OP_VIVIDLIGHT_EXT:
1236     case vk::VK_BLEND_OP_LINEARLIGHT_EXT:
1237     case vk::VK_BLEND_OP_PINLIGHT_EXT:
1238     case vk::VK_BLEND_OP_HARDMIX_EXT:
1239     case vk::VK_BLEND_OP_HSL_HUE_EXT:
1240     case vk::VK_BLEND_OP_HSL_SATURATION_EXT:
1241     case vk::VK_BLEND_OP_HSL_COLOR_EXT:
1242     case vk::VK_BLEND_OP_HSL_LUMINOSITY_EXT:
1243     case vk::VK_BLEND_OP_PLUS_EXT:
1244     case vk::VK_BLEND_OP_PLUS_CLAMPED_EXT:
1245     case vk::VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT:
1246     case vk::VK_BLEND_OP_PLUS_DARKER_EXT:
1247     case vk::VK_BLEND_OP_MINUS_EXT:
1248     case vk::VK_BLEND_OP_MINUS_CLAMPED_EXT:
1249     case vk::VK_BLEND_OP_CONTRAST_EXT:
1250     case vk::VK_BLEND_OP_INVERT_OVG_EXT:
1251     case vk::VK_BLEND_OP_RED_EXT:
1252     case vk::VK_BLEND_OP_GREEN_EXT:
1253     case vk::VK_BLEND_OP_BLUE_EXT:
1254         advanced = true;
1255         break;
1256     default:
1257         advanced = false;
1258         break;
1259     }
1260 
1261     return advanced;
1262 }
1263 
1264 struct ColorBlendEq
1265 {
1266     vk::VkBlendFactor srcColorBlendFactor;
1267     vk::VkBlendFactor dstColorBlendFactor;
1268     vk::VkBlendOp colorBlendOp;
1269     vk::VkBlendFactor srcAlphaBlendFactor;
1270     vk::VkBlendFactor dstAlphaBlendFactor;
1271     vk::VkBlendOp alphaBlendOp;
1272 
ColorBlendEqvkt::pipeline::__anon3cc04b6f0111::ColorBlendEq1273     ColorBlendEq()
1274         : srcColorBlendFactor(vk::VK_BLEND_FACTOR_ZERO)
1275         , dstColorBlendFactor(vk::VK_BLEND_FACTOR_ZERO)
1276         , colorBlendOp(vk::VK_BLEND_OP_ADD)
1277         , srcAlphaBlendFactor(vk::VK_BLEND_FACTOR_ZERO)
1278         , dstAlphaBlendFactor(vk::VK_BLEND_FACTOR_ZERO)
1279         , alphaBlendOp(vk::VK_BLEND_OP_ADD)
1280     {
1281     }
1282 
ColorBlendEqvkt::pipeline::__anon3cc04b6f0111::ColorBlendEq1283     ColorBlendEq(vk::VkBlendFactor srcColorBlendFactor_, vk::VkBlendFactor dstColorBlendFactor_,
1284                  vk::VkBlendOp colorBlendOp_, vk::VkBlendFactor srcAlphaBlendFactor_,
1285                  vk::VkBlendFactor dstAlphaBlendFactor_, vk::VkBlendOp alphaBlendOp_)
1286         : srcColorBlendFactor(srcColorBlendFactor_)
1287         , dstColorBlendFactor(dstColorBlendFactor_)
1288         , colorBlendOp(colorBlendOp_)
1289         , srcAlphaBlendFactor(srcAlphaBlendFactor_)
1290         , dstAlphaBlendFactor(dstAlphaBlendFactor_)
1291         , alphaBlendOp(alphaBlendOp_)
1292     {
1293         if (isAdvancedBlendOp(colorBlendOp))
1294             DE_ASSERT(colorBlendOp == alphaBlendOp);
1295     }
1296 
isAdvancedvkt::pipeline::__anon3cc04b6f0111::ColorBlendEq1297     bool isAdvanced() const
1298     {
1299         return isAdvancedBlendOp(colorBlendOp);
1300     }
1301 };
1302 
1303 const DepthBiasParams kNoDepthBiasParams = {0.0f, 0.0f};
1304 
1305 struct LineStippleParams
1306 {
1307     uint32_t factor;
1308     uint16_t pattern;
1309 };
1310 
1311 enum class LineRasterizationMode
1312 {
1313     NONE = 0,
1314     RECTANGULAR,
1315     BRESENHAM,
1316     SMOOTH,
1317 };
1318 
1319 using ViewportVec       = std::vector<vk::VkViewport>;
1320 using ScissorVec        = std::vector<vk::VkRect2D>;
1321 using StencilOpVec      = std::vector<StencilOpParams>;
1322 using SampleMaskVec     = std::vector<vk::VkSampleMask>;
1323 using OptRastStream     = tcu::Maybe<uint32_t>;
1324 using OptBoolean        = tcu::Maybe<bool>;
1325 using OptStippleParams  = tcu::Maybe<LineStippleParams>;
1326 using OptLineRasterMode = tcu::Maybe<LineRasterizationMode>;
1327 using OptSampleCount    = tcu::Maybe<vk::VkSampleCountFlagBits>;
1328 using CovModTableVec    = std::vector<float>;
1329 using BlendConstArray   = std::array<float, 4>;
1330 using DepthBoundsParams = std::pair<float, float>;
1331 #ifndef CTS_USES_VULKANSC
1332 using ViewportSwzVec   = std::vector<vk::VkViewportSwizzleNV>;
1333 using OptDepthBiasRepr = tcu::Maybe<vk::VkDepthBiasRepresentationInfoEXT>;
1334 #endif // CTS_USES_VULKANSC
1335 
1336 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
1337 template <typename T>
1338 struct StaticAndDynamicPair
1339 {
1340     T staticValue;
1341     tcu::Maybe<T> dynamicValue;
1342 
1343     // Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon3cc04b6f0111::StaticAndDynamicPair1344     StaticAndDynamicPair(const T &value) : staticValue(value), dynamicValue(tcu::Nothing)
1345     {
1346     }
1347 
1348     // Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon3cc04b6f0111::StaticAndDynamicPair1349     StaticAndDynamicPair(const T &sVal, const T &dVal) : staticValue(sVal), dynamicValue(tcu::just<T>(dVal))
1350     {
1351     }
1352 
1353     // If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon3cc04b6f0111::StaticAndDynamicPair1354     void swapValues(void)
1355     {
1356         if (!dynamicValue)
1357             return;
1358         std::swap(staticValue, dynamicValue.get());
1359     }
1360 };
1361 
1362 // For anything boolean, see below.
1363 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
1364 
1365 // Configuration for every aspect of the extended dynamic state.
1366 using CullModeConfig               = StaticAndDynamicPair<vk::VkCullModeFlags>;
1367 using FrontFaceConfig              = StaticAndDynamicPair<vk::VkFrontFace>;
1368 using TopologyConfig               = StaticAndDynamicPair<vk::VkPrimitiveTopology>;
1369 using ViewportConfig               = StaticAndDynamicPair<ViewportVec>; // At least one element.
1370 using ScissorConfig                = StaticAndDynamicPair<ScissorVec>;  // At least one element.
1371 using StrideConfig                 = StaticAndDynamicPair<StrideVec>;   // At least one element.
1372 using DepthTestEnableConfig        = BooleanFlagConfig;
1373 using DepthWriteEnableConfig       = BooleanFlagConfig;
1374 using DepthCompareOpConfig         = StaticAndDynamicPair<vk::VkCompareOp>;
1375 using DepthBoundsTestEnableConfig  = BooleanFlagConfig;
1376 using DepthBoundsConfig            = StaticAndDynamicPair<DepthBoundsParams>;
1377 using StencilTestEnableConfig      = BooleanFlagConfig;
1378 using StencilOpConfig              = StaticAndDynamicPair<StencilOpVec>; // At least one element.
1379 using VertexGeneratorConfig        = StaticAndDynamicPair<const VertexGenerator *>;
1380 using DepthBiasEnableConfig        = BooleanFlagConfig;
1381 using RastDiscardEnableConfig      = BooleanFlagConfig;
1382 using PrimRestartEnableConfig      = BooleanFlagConfig;
1383 using LogicOpConfig                = StaticAndDynamicPair<vk::VkLogicOp>;
1384 using PatchControlPointsConfig     = StaticAndDynamicPair<uint8_t>;
1385 using DepthBiasConfig              = StaticAndDynamicPair<DepthBiasParams>;
1386 using TessDomainOriginConfig       = StaticAndDynamicPair<vk::VkTessellationDomainOrigin>;
1387 using DepthClampEnableConfig       = BooleanFlagConfig;
1388 using PolygonModeConfig            = StaticAndDynamicPair<vk::VkPolygonMode>;
1389 using SampleMaskConfig             = StaticAndDynamicPair<SampleMaskVec>;
1390 using AlphaToCoverageConfig        = BooleanFlagConfig;
1391 using AlphaToOneConfig             = BooleanFlagConfig;
1392 using ColorWriteEnableConfig       = BooleanFlagConfig;
1393 using ColorWriteMaskConfig         = StaticAndDynamicPair<vk::VkColorComponentFlags>;
1394 using RasterizationStreamConfig    = StaticAndDynamicPair<OptRastStream>;
1395 using LogicOpEnableConfig          = BooleanFlagConfig;
1396 using ColorBlendEnableConfig       = BooleanFlagConfig;
1397 using ColorBlendEquationConfig     = StaticAndDynamicPair<ColorBlendEq>;
1398 using BlendConstantsConfig         = StaticAndDynamicPair<BlendConstArray>;
1399 using ProvokingVertexConfig        = StaticAndDynamicPair<OptBoolean>; // First vertex boolean flag.
1400 using NegativeOneToOneConfig       = StaticAndDynamicPair<OptBoolean>;
1401 using DepthClipEnableConfig        = StaticAndDynamicPair<OptBoolean>;
1402 using LineStippleEnableConfig      = BooleanFlagConfig;
1403 using LineStippleParamsConfig      = StaticAndDynamicPair<OptStippleParams>;
1404 using SampleLocationsEnableConfig  = BooleanFlagConfig;
1405 using ConservativeRasterModeConfig = StaticAndDynamicPair<vk::VkConservativeRasterizationModeEXT>;
1406 using ExtraPrimitiveOverEstConfig =
1407     StaticAndDynamicPair<float>; // Negative numbers will mean we're not interested in setting it.
1408 using LineRasterModeConfig          = StaticAndDynamicPair<OptLineRasterMode>;
1409 using CoverageToColorEnableConfig   = BooleanFlagConfig;
1410 using CoverageToColorLocationConfig = StaticAndDynamicPair<uint32_t>;
1411 using RasterizationSamplesConfig    = StaticAndDynamicPair<vk::VkSampleCountFlagBits>;
1412 using LineWidthConfig               = StaticAndDynamicPair<float>;
1413 #ifndef CTS_USES_VULKANSC
1414 using CoverageModulationModeConfig = StaticAndDynamicPair<vk::VkCoverageModulationModeNV>;
1415 using CoverageModTableEnableConfig = BooleanFlagConfig;
1416 using CoverageModTableConfig       = StaticAndDynamicPair<CovModTableVec>;
1417 using CoverageReductionModeConfig  = StaticAndDynamicPair<vk::VkCoverageReductionModeNV>;
1418 using ViewportSwizzleConfig        = StaticAndDynamicPair<ViewportSwzVec>;
1419 using ShadingRateImageEnableConfig = BooleanFlagConfig;
1420 using ViewportWScalingEnableConfig = BooleanFlagConfig;
1421 using ReprFragTestEnableConfig     = BooleanFlagConfig;
1422 #endif // CTS_USES_VULKANSC
1423 
1424 const tcu::Vec4 kDefaultTriangleColor(0.0f, 0.0f, 1.0f, 1.0f);  // Opaque blue.
1425 const tcu::Vec4 kDefaultClearColor(0.0f, 0.0f, 0.0f, 1.0f);     // Opaque black.
1426 const tcu::Vec4 kTransparentColor(0.0f, 0.0f, 1.0f, 0.0f);      // Transparent version of kDefaultTriangleColor.
1427 const tcu::Vec4 kTransparentClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Transparent version of kDefaultClearColor.
1428 const tcu::Vec4 kOpaqueWhite(1.0f, 1.0f, 1.0f, 1.0f);           // Opaque white, all components active.
1429 
1430 const tcu::UVec4 kLogicOpTriangleColor(0u, 0u, 255u, 255u); // Opaque blue.
1431 const tcu::UVec4 kGreenClearColor(0u, 255u, 0u, 255u);      // Opaque green, UINT.
1432 const tcu::UVec4 kLogicOpFinalColor(0u, 255u, 255u, 255u);  // Opaque cyan, UINT.
1433 
1434 // Same as kLogicOpTriangleColor. Note: tcu::Vec4 and will be cast to the appropriate type in the shader.
1435 const tcu::Vec4 kLogicOpTriangleColorFl(static_cast<float>(kLogicOpTriangleColor.x()),
1436                                         static_cast<float>(kLogicOpTriangleColor.y()),
1437                                         static_cast<float>(kLogicOpTriangleColor.w()),
1438                                         static_cast<float>(kLogicOpTriangleColor.z()));
1439 
1440 struct MeshParams
1441 {
1442     tcu::Vec4 color;
1443     float depth;
1444     bool reversed;
1445     float scaleX;
1446     float scaleY;
1447     float offsetX;
1448     float offsetY;
1449     float stripScale;
1450 
MeshParamsvkt::pipeline::__anon3cc04b6f0111::MeshParams1451     MeshParams(const tcu::Vec4 &color_ = kDefaultTriangleColor, float depth_ = 0.0f, bool reversed_ = false,
1452                float scaleX_ = 1.0f, float scaleY_ = 1.0f, float offsetX_ = 0.0f, float offsetY_ = 0.0f,
1453                float stripScale_ = 0.0f)
1454         : color(color_)
1455         , depth(depth_)
1456         , reversed(reversed_)
1457         , scaleX(scaleX_)
1458         , scaleY(scaleY_)
1459         , offsetX(offsetX_)
1460         , offsetY(offsetY_)
1461         , stripScale(stripScale_)
1462     {
1463     }
1464 };
1465 
1466 enum class SequenceOrdering
1467 {
1468     CMD_BUFFER_START = 0, // Set state at the start of the command buffer.
1469     BEFORE_DRAW      = 1, // After binding dynamic pipeline and just before drawing.
1470     BETWEEN_PIPELINES =
1471         2, // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
1472     AFTER_PIPELINES    = 3, // After a static state pipeline and a second dynamic state pipeline have been bound.
1473     BEFORE_GOOD_STATIC = 4, // Before a static state pipeline with the correct values has been bound.
1474     TWO_DRAWS_DYNAMIC =
1475         5, // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
1476     TWO_DRAWS_STATIC =
1477         6, // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
1478 };
1479 
1480 // This is used when generating some test cases.
1481 enum class ColorBlendSubCase
1482 {
1483     EQ_ONLY    = 0, // Only the equation is dynamic.
1484     ALL_CB     = 1, // All color blending states are dynamic.
1485     ALL_BUT_LO = 2, // All color blending states are dynamic, except for the ones related to logic op.
1486 };
1487 
1488 class ReferenceColorGenerator
1489 {
1490 public:
1491     typedef std::unique_ptr<ReferenceColorGenerator> P;
~ReferenceColorGenerator()1492     virtual ~ReferenceColorGenerator()
1493     {
1494     }
1495 
1496     virtual void operator()(tcu::PixelBufferAccess &) const = 0;
1497     virtual P clone() const                                 = 0;
1498 };
1499 
1500 using ColorVerificator = std::function<bool(const tcu::ConstPixelBufferAccess & /*result*/,
1501                                             const tcu::ConstPixelBufferAccess & /*reference*/,
1502                                             const tcu::PixelBufferAccess & /*errorMask*/)>;
1503 
1504 // Most tests expect a single output color in the whole image.
1505 class SingleColorGenerator : public ReferenceColorGenerator
1506 {
1507 public:
SingleColorGenerator(const tcu::Vec4 & color)1508     SingleColorGenerator(const tcu::Vec4 &color) : m_colorFloat(color), m_colorUint(0u), isUint(false)
1509     {
1510     }
1511 
SingleColorGenerator(const tcu::UVec4 & color)1512     SingleColorGenerator(const tcu::UVec4 &color) : m_colorFloat(0.0f), m_colorUint(color), isUint(true)
1513     {
1514     }
1515 
operator ()(tcu::PixelBufferAccess & access) const1516     void operator()(tcu::PixelBufferAccess &access) const override
1517     {
1518         const auto kWidth  = access.getWidth();
1519         const auto kHeight = access.getHeight();
1520 
1521         for (int y = 0; y < kHeight; ++y)
1522             for (int x = 0; x < kWidth; ++x)
1523             {
1524                 if (isUint)
1525                     access.setPixel(m_colorUint, x, y);
1526                 else
1527                     access.setPixel(m_colorFloat, x, y);
1528             }
1529     }
1530 
clone() const1531     P clone() const override
1532     {
1533         return P(new SingleColorGenerator(*this));
1534     }
1535 
1536 private:
1537     const tcu::Vec4 m_colorFloat;
1538     const tcu::UVec4 m_colorUint;
1539     const bool isUint;
1540 };
1541 
1542 // Some tests expect the upper half and the lower half having different color values.
1543 class HorizontalSplitGenerator : public ReferenceColorGenerator
1544 {
1545 public:
HorizontalSplitGenerator(const tcu::Vec4 & top,const tcu::Vec4 & bottom)1546     HorizontalSplitGenerator(const tcu::Vec4 &top, const tcu::Vec4 &bottom) : m_top(top), m_bottom(bottom)
1547     {
1548     }
1549 
operator ()(tcu::PixelBufferAccess & access) const1550     void operator()(tcu::PixelBufferAccess &access) const override
1551     {
1552         const auto kWidth      = access.getWidth();
1553         const auto kHeight     = access.getHeight();
1554         const auto kHalfHeight = kHeight / 2;
1555 
1556         for (int y = 0; y < kHeight; ++y)
1557             for (int x = 0; x < kWidth; ++x)
1558             {
1559                 const auto &color = (y < kHalfHeight ? m_top : m_bottom);
1560                 access.setPixel(color, x, y);
1561             }
1562     }
1563 
clone() const1564     P clone() const override
1565     {
1566         return P(new HorizontalSplitGenerator(*this));
1567     }
1568 
1569 private:
1570     const tcu::Vec4 m_top;
1571     const tcu::Vec4 m_bottom;
1572 };
1573 
1574 // Primitive restart tests expect the last line to have some missing pixels.
1575 class LastSegmentMissingGenerator : public ReferenceColorGenerator
1576 {
1577 public:
LastSegmentMissingGenerator(const tcu::Vec4 & geomColor,const tcu::Vec4 & clearColor)1578     LastSegmentMissingGenerator(const tcu::Vec4 &geomColor, const tcu::Vec4 &clearColor)
1579         : m_geomColor(geomColor)
1580         , m_clearColor(clearColor)
1581     {
1582     }
1583 
operator ()(tcu::PixelBufferAccess & access) const1584     void operator()(tcu::PixelBufferAccess &access) const override
1585     {
1586         constexpr auto kWidth            = static_cast<int>(kFramebufferWidth);
1587         constexpr auto kHeight           = static_cast<int>(kFramebufferHeight);
1588         constexpr auto kLastSegmentStart = static_cast<int>(kWidth * 0.75f);
1589 
1590         for (int y = 0; y < kHeight; ++y)
1591             for (int x = 0; x < kWidth; ++x)
1592             {
1593                 // The last segment of the last line has the background color.
1594                 const auto &color = ((y == kHeight - 1 && x >= kLastSegmentStart) ? m_clearColor : m_geomColor);
1595                 access.setPixel(color, x, y);
1596             }
1597     }
1598 
clone() const1599     P clone() const override
1600     {
1601         return P(new LastSegmentMissingGenerator(*this));
1602     }
1603 
1604 private:
1605     const tcu::Vec4 m_geomColor;
1606     const tcu::Vec4 m_clearColor;
1607 };
1608 
1609 // Some tests (like stippled line tests) expect vertical stripes of a given width.
1610 class VerticalStripesGenerator : public ReferenceColorGenerator
1611 {
1612 public:
VerticalStripesGenerator(const tcu::Vec4 & left,const tcu::Vec4 & right,uint32_t width)1613     VerticalStripesGenerator(const tcu::Vec4 &left, const tcu::Vec4 &right, uint32_t width)
1614         : m_left(left)
1615         , m_right(right)
1616         , m_width(width)
1617     {
1618         DE_ASSERT(width > 0 && width <= static_cast<uint32_t>(std::numeric_limits<int>::max()));
1619     }
1620 
operator ()(tcu::PixelBufferAccess & access) const1621     void operator()(tcu::PixelBufferAccess &access) const override
1622     {
1623         constexpr auto kWidth  = static_cast<int>(kFramebufferWidth);
1624         constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
1625 
1626         for (int y = 0; y < kHeight; ++y)
1627             for (int x = 0; x < kWidth; ++x)
1628             {
1629                 const int stripeIdx = x / static_cast<int>(m_width);
1630                 const auto &color   = ((stripeIdx % 2 == 0) ? m_left : m_right);
1631                 access.setPixel(color, x, y);
1632             }
1633     }
1634 
clone() const1635     P clone() const override
1636     {
1637         return P(new VerticalStripesGenerator(*this));
1638     }
1639 
1640 private:
1641     const tcu::Vec4 m_left;
1642     const tcu::Vec4 m_right;
1643     const uint32_t m_width;
1644 };
1645 
1646 // Some tests may expect a center strip in the framebuffer having a different color.
1647 class CenterStripGenerator : public ReferenceColorGenerator
1648 {
1649 public:
CenterStripGenerator(const tcu::Vec4 & sides,const tcu::Vec4 & center)1650     CenterStripGenerator(const tcu::Vec4 &sides, const tcu::Vec4 &center) : m_sides(sides), m_center(center)
1651     {
1652     }
1653 
operator ()(tcu::PixelBufferAccess & access) const1654     void operator()(tcu::PixelBufferAccess &access) const override
1655     {
1656         constexpr auto kWidth  = static_cast<int>(kFramebufferWidth);
1657         constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
1658 
1659         for (int y = 0; y < kHeight; ++y)
1660             for (int x = 0; x < kWidth; ++x)
1661             {
1662                 const auto &color = ((x >= kWidth / 4 && x < (kWidth * 3) / 4) ? m_center : m_sides);
1663                 access.setPixel(color, x, y);
1664             }
1665     }
1666 
clone() const1667     P clone() const override
1668     {
1669         return P(new CenterStripGenerator(*this));
1670     }
1671 
1672 private:
1673     const tcu::Vec4 m_sides;
1674     const tcu::Vec4 m_center;
1675 };
1676 
1677 // Tests using an off-center triangle may want this generator: fill the image with a solid color but leave the top and left edges in
1678 // a different color.
1679 class TopLeftBorderGenerator : public ReferenceColorGenerator
1680 {
1681 public:
TopLeftBorderGenerator(const tcu::Vec4 & mainColor,const tcu::Vec4 & borderLeft,const tcu::Vec4 & corner,const tcu::Vec4 & borderTop)1682     TopLeftBorderGenerator(const tcu::Vec4 &mainColor, const tcu::Vec4 &borderLeft, const tcu::Vec4 &corner,
1683                            const tcu::Vec4 &borderTop)
1684         : m_mainColor(mainColor)
1685         , m_borderLeft(borderLeft)
1686         , m_corner(corner)
1687         , m_borderTop(borderTop)
1688     {
1689     }
1690 
operator ()(tcu::PixelBufferAccess & access) const1691     void operator()(tcu::PixelBufferAccess &access) const override
1692     {
1693         const auto kWidth  = access.getWidth();
1694         const auto kHeight = access.getHeight();
1695 
1696         for (int y = 0; y < kHeight; ++y)
1697             for (int x = 0; x < kWidth; ++x)
1698             {
1699                 tcu::Vec4 color;
1700 
1701                 if (x == 0)
1702                 {
1703                     if (y == 0)
1704                         color = m_corner;
1705                     else
1706                         color = m_borderLeft;
1707                 }
1708                 else if (y == 0)
1709                     color = m_borderTop;
1710                 else
1711                     color = m_mainColor;
1712 
1713                 access.setPixel(color, x, y);
1714             }
1715     }
1716 
clone() const1717     P clone() const override
1718     {
1719         return P(new TopLeftBorderGenerator(*this));
1720     }
1721 
1722 private:
1723     const tcu::Vec4 m_mainColor;
1724     const tcu::Vec4 m_borderLeft;
1725     const tcu::Vec4 m_corner;
1726     const tcu::Vec4 m_borderTop;
1727 };
1728 
removeAlpha(const tcu::Vec4 & color)1729 tcu::Vec3 removeAlpha(const tcu::Vec4 &color)
1730 {
1731     const tcu::Vec3 rgb(color.x(), color.y(), color.z());
1732     return rgb;
1733 }
1734 
1735 // Verifies the top left pixel matches exactly.
verifyTopLeftCorner(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask,bool partialAlpha)1736 bool verifyTopLeftCorner(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1737                          const tcu::PixelBufferAccess &errorMask, bool partialAlpha)
1738 {
1739     // Check corner.
1740     const auto resultColor    = result.getPixel(0, 0);
1741     const auto referenceColor = reference.getPixel(0, 0);
1742 
1743     const auto resultColorRGB    = removeAlpha(resultColor);
1744     const auto referenceColorRGB = removeAlpha(referenceColor);
1745 
1746     const auto red   = tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f);
1747     const auto green = tcu::Vec4(0.0f, 1.0f, 0.0f, 1.0f);
1748     const auto black = tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f);
1749     const bool alphaMatch =
1750         (partialAlpha ? (resultColor.w() > 0.0f && resultColor.w() < 1.0f) : (resultColor.w() == referenceColor.w()));
1751     const bool match = ((resultColorRGB == referenceColorRGB) && alphaMatch);
1752 
1753     tcu::clear(errorMask, black);
1754     errorMask.setPixel((match ? green : red), 0, 0);
1755 
1756     return match;
1757 }
1758 
verifyTopLeftCornerExactly(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask)1759 bool verifyTopLeftCornerExactly(const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &reference,
1760                                 const tcu::PixelBufferAccess &errorMask)
1761 {
1762     return verifyTopLeftCorner(result, reference, errorMask, false /*partialAlpha*/);
1763 }
1764 
verifyTopLeftCornerWithPartialAlpha(const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & reference,const tcu::PixelBufferAccess & errorMask)1765 bool verifyTopLeftCornerWithPartialAlpha(const tcu::ConstPixelBufferAccess &result,
1766                                          const tcu::ConstPixelBufferAccess &reference,
1767                                          const tcu::PixelBufferAccess &errorMask)
1768 {
1769     return verifyTopLeftCorner(result, reference, errorMask, true /*partialAlpha*/);
1770 }
1771 
getVertexWithPaddingGenerator()1772 const VertexGenerator *getVertexWithPaddingGenerator()
1773 {
1774     static VertexWithPadding vertexWithPadding;
1775     return &vertexWithPadding;
1776 }
1777 
getVertexWithPadding16Generator()1778 const VertexGenerator *getVertexWithPadding16Generator()
1779 {
1780     static VertexWithPadding16 vertexWithPadding16;
1781     return &vertexWithPadding16;
1782 }
1783 
getVertexWithExtraAttributesGenerator()1784 const VertexGenerator *getVertexWithExtraAttributesGenerator()
1785 {
1786     static VertexWithExtraAttributes vertexWithExtraAttributes;
1787     return &vertexWithExtraAttributes;
1788 }
1789 
getVertexWithMultipleBindingsGenerator()1790 const VertexGenerator *getVertexWithMultipleBindingsGenerator()
1791 {
1792     static MultipleBindingsVertex multipleBindingsVertex;
1793     return &multipleBindingsVertex;
1794 }
1795 
getProvokingVertexWithPaddingGenerator(bool lastVertex)1796 const VertexGenerator *getProvokingVertexWithPaddingGenerator(bool lastVertex)
1797 {
1798     if (lastVertex)
1799     {
1800         static ProvokingVertexWithPadding provokingVertexGeneratorLastVtx(true);
1801         return &provokingVertexGeneratorLastVtx;
1802     }
1803     static ProvokingVertexWithPadding provokingVertexGeneratorFirstVtx(false);
1804     return &provokingVertexGeneratorFirstVtx;
1805 }
1806 
getVertexWithInstanceDataGenerator()1807 const VertexGenerator *getVertexWithInstanceDataGenerator()
1808 {
1809     static VertexWithInstanceData vertexWithInstanceData;
1810     return &vertexWithInstanceData;
1811 }
1812 
1813 // Create VertexGeneratorConfig varying constructor depending on having none, only the static or both.
makeVertexGeneratorConfig(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)1814 VertexGeneratorConfig makeVertexGeneratorConfig(const VertexGenerator *staticGen, const VertexGenerator *dynamicGen)
1815 {
1816     DE_ASSERT(!(dynamicGen && !staticGen));
1817     if (dynamicGen)
1818         return VertexGeneratorConfig(staticGen, dynamicGen);
1819     if (staticGen)
1820         return VertexGeneratorConfig(staticGen);
1821     return VertexGeneratorConfig(getVertexWithPaddingGenerator()); // Only static part with a default option.
1822 }
1823 
1824 // Similar to makeVertexGeneratorConfig, choosing the final value.
chooseVertexGenerator(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)1825 const VertexGenerator *chooseVertexGenerator(const VertexGenerator *staticGen, const VertexGenerator *dynamicGen)
1826 {
1827     DE_ASSERT(!(dynamicGen && !staticGen));
1828     if (dynamicGen)
1829         return dynamicGen;
1830     if (staticGen)
1831         return staticGen;
1832     return getVertexWithPaddingGenerator();
1833 }
1834 
1835 #ifndef CTS_USES_VULKANSC
1836 // Is a particular dynamic state incompatible with mesh shading pipelines?
isMeshShadingPipelineIncompatible(vk::VkDynamicState state)1837 bool isMeshShadingPipelineIncompatible(vk::VkDynamicState state)
1838 {
1839     switch (state)
1840     {
1841     case vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT:
1842     case vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT:
1843     case vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT:
1844     case vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT:
1845     case vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT:
1846         return true;
1847     default:
1848         return false;
1849     }
1850 
1851     // Unreachable.
1852     DE_ASSERT(false);
1853     return false;
1854 }
1855 
1856 // Is a particular dynamic state compatible with mesh shading pipelines?
isMeshShadingPipelineCompatible(vk::VkDynamicState state)1857 bool isMeshShadingPipelineCompatible(vk::VkDynamicState state)
1858 {
1859     return !isMeshShadingPipelineIncompatible(state);
1860 }
1861 #endif // CTS_USES_VULKANSC
1862 
getTopologyClass(vk::VkPrimitiveTopology topology)1863 TopologyClass getTopologyClass(vk::VkPrimitiveTopology topology)
1864 {
1865     switch (topology)
1866     {
1867     case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
1868         return TopologyClass::POINT;
1869     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
1870     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
1871     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
1872     case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
1873         return TopologyClass::LINE;
1874     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
1875     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
1876     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
1877     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
1878     case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
1879         return TopologyClass::TRIANGLE;
1880     case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
1881         return TopologyClass::PATCH;
1882     default:
1883         break;
1884     }
1885 
1886     DE_ASSERT(false);
1887     return TopologyClass::INVALID;
1888 }
1889 
selectLineRasterizationMode(const vk::VkPhysicalDeviceLineRasterizationFeaturesEXT & lineRasterFeatures,bool stippleRequired,const tcu::Maybe<LineRasterizationMode> & pref)1890 LineRasterizationMode selectLineRasterizationMode(
1891     const vk::VkPhysicalDeviceLineRasterizationFeaturesEXT &lineRasterFeatures, bool stippleRequired,
1892     const tcu::Maybe<LineRasterizationMode> &pref)
1893 {
1894     LineRasterizationMode selectedMode = LineRasterizationMode::NONE;
1895     const bool hasPref                 = static_cast<bool>(pref);
1896 
1897     if ((!hasPref || pref.get() == LineRasterizationMode::RECTANGULAR) && lineRasterFeatures.rectangularLines &&
1898         (!stippleRequired || lineRasterFeatures.stippledRectangularLines))
1899         selectedMode = LineRasterizationMode::RECTANGULAR;
1900     else if ((!hasPref || pref.get() == LineRasterizationMode::BRESENHAM) && lineRasterFeatures.bresenhamLines &&
1901              (!stippleRequired || lineRasterFeatures.stippledBresenhamLines))
1902         selectedMode = LineRasterizationMode::BRESENHAM;
1903     else if ((!hasPref || pref.get() == LineRasterizationMode::SMOOTH) && lineRasterFeatures.smoothLines &&
1904              (!stippleRequired || lineRasterFeatures.stippledSmoothLines))
1905         selectedMode = LineRasterizationMode::SMOOTH;
1906 
1907     return selectedMode;
1908 }
1909 
makeLineRasterizationMode(LineRasterizationMode mode)1910 vk::VkLineRasterizationModeEXT makeLineRasterizationMode(LineRasterizationMode mode)
1911 {
1912     vk::VkLineRasterizationModeEXT modeEXT = vk::VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT;
1913 
1914     switch (mode)
1915     {
1916     case LineRasterizationMode::RECTANGULAR:
1917         modeEXT = vk::VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
1918         break;
1919     case LineRasterizationMode::BRESENHAM:
1920         modeEXT = vk::VK_LINE_RASTERIZATION_MODE_BRESENHAM_EXT;
1921         break;
1922     case LineRasterizationMode::SMOOTH:
1923         modeEXT = vk::VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
1924         break;
1925     default:
1926         DE_ASSERT(false);
1927         break;
1928     }
1929 
1930     return modeEXT;
1931 }
1932 
1933 struct TestConfig
1934 {
1935     // Should we use pipeline_library to construct pipeline.
1936     vk::PipelineConstructionType pipelineConstructionType;
1937 
1938     // Main sequence ordering.
1939     SequenceOrdering sequenceOrdering;
1940 
1941     // Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
1942     std::vector<MeshParams> meshParams; // Mesh parameters for each full-screen layer of geometry.
1943     uint32_t referenceStencil;          // Reference stencil value.
1944 
1945     // Clearing parameters for the framebuffer.
1946     vk::VkClearValue clearColorValue;
1947     float clearDepthValue;
1948     uint32_t clearStencilValue;
1949 
1950     // Expected output in the attachments.
1951     ReferenceColorGenerator::P referenceColor;
1952     float expectedDepth;
1953     uint32_t expectedStencil;
1954 
1955     // Optional verification routine.
1956     tcu::Maybe<ColorVerificator> colorVerificator;
1957 
1958     // Force inclusion of passthrough geometry shader or not.
1959     bool forceGeometryShader;
1960 
1961     // Use mesh shaders instead of classic pipelines.
1962     bool useMeshShaders;
1963 
1964     // Bind an unused mesh shading pipeline before binding the dynamic pipeline.
1965     // This will only be used in the CMD_BUFFER_START sequence ordering, to minimize the number of cases.
1966     bool bindUnusedMeshShadingPipeline;
1967 
1968     // Force single vertex in the VBO.
1969     bool singleVertex;
1970     uint32_t singleVertexDrawCount;
1971 
1972     // Force using an oversized triangle as the mesh.
1973     bool oversizedTriangle;
1974 
1975     // Force using a single triangle with a small offset as the mesh.
1976     bool offCenterTriangle;
1977     tcu::Vec2 offCenterProportion; // Relative to pixel size.
1978 
1979     // Force using a single oblique line: this helps test line rasterization mode.
1980     bool obliqueLine;
1981 
1982     // Offset and extra room after the vertex buffer data.
1983     vk::VkDeviceSize vertexDataOffset;
1984     vk::VkDeviceSize vertexDataExtraBytes;
1985 
1986     // Bind and draw with a pipeline that uses dynamic patch control points but doesn't actually use a tessellation
1987     // shader, before using the real pipelines being tested.
1988     bool useExtraDynPCPPipeline;
1989     // Bind and draw with a pipeline that uses same dynamic states, before using the real pipelines being tested.
1990     bool useExtraDynPipeline;
1991 
1992     // Optional, to be used specifically for color attachments when testing coverage modulation and reduction.
1993     bool coverageModulation;
1994     bool coverageReduction;
1995     OptSampleCount colorSampleCount;
1996 
1997     // Rasterization stream, if needed, used in the geometry shader.
1998     OptRastStream shaderRasterizationStream;
1999 
2000     // Sample locations, which may be used if testing sample locations.
2001     tcu::Vec2 sampleLocations;
2002 
2003     // Optional maximum value for primitiveOverestimationSize so the test works properly.
2004     tcu::Maybe<float> maxPrimitiveOverestimationSize;
2005 
2006     // Number of color attachments in the subpass. Note the fragment shader will only write to the last one.
2007     uint32_t colorAttachmentCount;
2008 
2009     // Instance count.
2010     uint32_t instanceCount;
2011 
2012     // Use viewport swizzle or not.
2013     bool viewportSwizzle;
2014 
2015     // Use shading rate image configuration or not.
2016     bool shadingRateImage;
2017 
2018     // Use viewport W scaling or not.
2019     bool viewportWScaling;
2020 
2021     // Use representative fragment test or not.
2022     bool representativeFragmentTest;
2023 
2024     // Insert extra indices for restarting lines.
2025     bool extraLineRestarts;
2026 
2027     // Consider both the basic and advanced color blend states dynamic if any of them is dynamic.
2028     bool colorBlendBoth;
2029 
2030     // Use color write enable state.
2031     bool useColorWriteEnable;
2032 
2033     // Force UNORM color format.
2034     bool forceUnormColorFormat;
2035 
2036     // Used in some tests to verify color blend pAttachments can be null if all its state is dynamic.
2037     bool nullStaticColorBlendAttPtr;
2038 
2039     // Verify color blend attachment count can be 0 if all its state is dynamic.
2040     bool colorBlendAttCnt0;
2041 
2042     // Disable advanced blending coherent operations or not.
2043     bool disableAdvBlendingCoherentOps;
2044 
2045     // Use dual source blending.
2046     bool dualSrcBlend;
2047 
2048     // Use null pointers when possible for static state.
2049     bool favorStaticNullPointers;
2050 
2051     // Force using atomic counters in the frag shader to count frag shader invocations.
2052     bool forceAtomicCounters;
2053 
2054     // When setting the sample mask dynamically, we can use an alternative sample count specified here.
2055     OptSampleCount dynamicSampleMaskCount;
2056 
2057 #ifndef CTS_USES_VULKANSC
2058     // This structure is optional and can be included statically in the rasterization info or dynamically in vkCmdSetDepthBias2.
2059     OptDepthBiasRepr depthBiasReprInfo;
2060 #endif // CTS_USES_VULKANSC
2061 
2062     tcu::TextureChannelClass neededDepthChannelClass;
2063     float extraDepthThreshold;
2064 
2065     // Static values for sampleShadingEnable and minSampleShading.
2066     bool sampleShadingEnable;
2067     float minSampleShading;
2068 
2069     // Force alpha to one feature disabled.
2070     bool disableAlphaToOneFeature;
2071 
2072     // Static and dynamic pipeline configuration.
2073     VertexGeneratorConfig vertexGenerator;
2074     CullModeConfig cullModeConfig;
2075     FrontFaceConfig frontFaceConfig;
2076     TopologyConfig topologyConfig;
2077     ViewportConfig viewportConfig;
2078     ScissorConfig scissorConfig;
2079     StrideConfig strideConfig;
2080     DepthTestEnableConfig depthTestEnableConfig;
2081     DepthWriteEnableConfig depthWriteEnableConfig;
2082     DepthCompareOpConfig depthCompareOpConfig;
2083     DepthBoundsTestEnableConfig depthBoundsTestEnableConfig;
2084     DepthBoundsConfig depthBoundsConfig;
2085     StencilTestEnableConfig stencilTestEnableConfig;
2086     StencilOpConfig stencilOpConfig;
2087     DepthBiasEnableConfig depthBiasEnableConfig;
2088     RastDiscardEnableConfig rastDiscardEnableConfig;
2089     PrimRestartEnableConfig primRestartEnableConfig;
2090     LogicOpConfig logicOpConfig;
2091     PatchControlPointsConfig patchControlPointsConfig;
2092     DepthBiasConfig depthBiasConfig;
2093     TessDomainOriginConfig tessDomainOriginConfig;
2094     DepthClampEnableConfig depthClampEnableConfig;
2095     PolygonModeConfig polygonModeConfig;
2096     SampleMaskConfig sampleMaskConfig;
2097     AlphaToCoverageConfig alphaToCoverageConfig;
2098     AlphaToOneConfig alphaToOneConfig;
2099     ColorWriteEnableConfig colorWriteEnableConfig;
2100     ColorWriteMaskConfig colorWriteMaskConfig;
2101     RasterizationStreamConfig rasterizationStreamConfig;
2102     LogicOpEnableConfig logicOpEnableConfig;
2103     ColorBlendEnableConfig colorBlendEnableConfig;
2104     ColorBlendEquationConfig colorBlendEquationConfig;
2105     BlendConstantsConfig blendConstantsConfig;
2106     ProvokingVertexConfig provokingVertexConfig;
2107     NegativeOneToOneConfig negativeOneToOneConfig;
2108     DepthClipEnableConfig depthClipEnableConfig;
2109     LineStippleEnableConfig lineStippleEnableConfig;
2110     LineStippleParamsConfig lineStippleParamsConfig;
2111     SampleLocationsEnableConfig sampleLocationsEnableConfig;
2112     ConservativeRasterModeConfig conservativeRasterModeConfig;
2113     ExtraPrimitiveOverEstConfig extraPrimitiveOverEstConfig;
2114     LineRasterModeConfig lineRasterModeConfig;
2115     CoverageToColorEnableConfig coverageToColorEnableConfig;
2116     CoverageToColorLocationConfig coverageToColorLocationConfig;
2117     RasterizationSamplesConfig rasterizationSamplesConfig;
2118     LineWidthConfig lineWidthConfig;
2119 #ifndef CTS_USES_VULKANSC
2120     CoverageModulationModeConfig coverageModulationModeConfig;
2121     CoverageModTableEnableConfig coverageModTableEnableConfig;
2122     CoverageModTableConfig coverageModTableConfig;
2123     CoverageReductionModeConfig coverageReductionModeConfig;
2124     ViewportSwizzleConfig viewportSwizzleConfig;
2125     ShadingRateImageEnableConfig shadingRateImageEnableConfig;
2126     ViewportWScalingEnableConfig viewportWScalingEnableConfig;
2127     ReprFragTestEnableConfig reprFragTestEnableConfig;
2128 #endif // CTS_USES_VULKANSC
2129 
2130     // Sane defaults.
TestConfigvkt::pipeline::__anon3cc04b6f0111::TestConfig2131     TestConfig(vk::PipelineConstructionType pipelineType, SequenceOrdering ordering, bool useMeshShaders_,
2132                const VertexGenerator *staticVertexGenerator  = nullptr,
2133                const VertexGenerator *dynamicVertexGenerator = nullptr)
2134         : pipelineConstructionType(pipelineType)
2135         , sequenceOrdering(ordering)
2136         , meshParams(1u, MeshParams())
2137         , referenceStencil(0u)
2138         , clearColorValue(vk::makeClearValueColor(kDefaultClearColor))
2139         , clearDepthValue(1.0f)
2140         , clearStencilValue(0u)
2141         , referenceColor(new SingleColorGenerator(kDefaultTriangleColor))
2142         , expectedDepth(1.0f)
2143         , expectedStencil(0u)
2144         , colorVerificator(tcu::Nothing)
2145         , forceGeometryShader(false)
2146         , useMeshShaders(useMeshShaders_)
2147         , bindUnusedMeshShadingPipeline(false)
2148         , singleVertex(false)
2149         , singleVertexDrawCount(0)
2150         , oversizedTriangle(false)
2151         , offCenterTriangle(false)
2152         , offCenterProportion(0.0f, 0.0f)
2153         , obliqueLine(false)
2154         , vertexDataOffset(0ull)
2155         , vertexDataExtraBytes(0ull)
2156         , useExtraDynPCPPipeline(false)
2157         , useExtraDynPipeline(false)
2158         , coverageModulation(false)
2159         , coverageReduction(false)
2160         , colorSampleCount(tcu::Nothing)
2161         , shaderRasterizationStream(tcu::Nothing)
2162         , sampleLocations(0.5f, 0.5f)
2163         , colorAttachmentCount(1u)
2164         , instanceCount(1u)
2165         , viewportSwizzle(false)
2166         , shadingRateImage(false)
2167         , viewportWScaling(false)
2168         , representativeFragmentTest(false)
2169         , extraLineRestarts(false)
2170         , colorBlendBoth(false)
2171         , useColorWriteEnable(false)
2172         , forceUnormColorFormat(false)
2173         , nullStaticColorBlendAttPtr(false)
2174         , colorBlendAttCnt0(false)
2175         , disableAdvBlendingCoherentOps(false)
2176         , dualSrcBlend(false)
2177         , favorStaticNullPointers(false)
2178         , forceAtomicCounters(false)
2179         , dynamicSampleMaskCount(tcu::Nothing)
2180 #ifndef CTS_USES_VULKANSC
2181         , depthBiasReprInfo(tcu::Nothing)
2182 #endif // CTS_USES_VULKANSC
2183         , neededDepthChannelClass(tcu::TEXTURECHANNELCLASS_LAST)
2184         , extraDepthThreshold(0.0f)
2185         , sampleShadingEnable(false)
2186         , minSampleShading(0.0f)
2187         , disableAlphaToOneFeature(false)
2188         , vertexGenerator(makeVertexGeneratorConfig(staticVertexGenerator, dynamicVertexGenerator))
2189         , cullModeConfig(static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
2190         , frontFaceConfig(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
2191         // By default we will use a triangle strip with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
2192         , topologyConfig(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
2193         , viewportConfig(ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
2194         , scissorConfig(ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
2195         // By default, the vertex stride is the size of a vertex according to the chosen vertex type.
2196         , strideConfig(chooseVertexGenerator(staticVertexGenerator, dynamicVertexGenerator)->getVertexDataStrides())
2197         , depthTestEnableConfig(false)
2198         , depthWriteEnableConfig(false)
2199         , depthCompareOpConfig(vk::VK_COMPARE_OP_NEVER)
2200         , depthBoundsTestEnableConfig(false)
2201         , depthBoundsConfig(std::make_pair(0.0f, 1.0f))
2202         , stencilTestEnableConfig(false)
2203         , stencilOpConfig(StencilOpVec(1u, kDefaultStencilOpParams))
2204         , depthBiasEnableConfig(false)
2205         , rastDiscardEnableConfig(false)
2206         , primRestartEnableConfig(false)
2207         , logicOpConfig(vk::VK_LOGIC_OP_CLEAR)
2208         , patchControlPointsConfig(1u)
2209         , depthBiasConfig(kNoDepthBiasParams)
2210         , tessDomainOriginConfig(vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
2211         , depthClampEnableConfig(false)
2212         , polygonModeConfig(vk::VK_POLYGON_MODE_FILL)
2213         , sampleMaskConfig(SampleMaskVec())
2214         , alphaToCoverageConfig(false)
2215         , alphaToOneConfig(false)
2216         , colorWriteEnableConfig(true)
2217         , colorWriteMaskConfig(CR | CG | CB | CA)
2218         , rasterizationStreamConfig(tcu::Nothing)
2219         , logicOpEnableConfig(false)
2220         , colorBlendEnableConfig(false)
2221         , colorBlendEquationConfig(ColorBlendEq())
2222         , blendConstantsConfig(BlendConstArray{0.0f, 0.0f, 0.0f, 0.0f})
2223         , provokingVertexConfig(tcu::Nothing)
2224         , negativeOneToOneConfig(tcu::Nothing)
2225         , depthClipEnableConfig(tcu::Nothing)
2226         , lineStippleEnableConfig(false)
2227         , lineStippleParamsConfig(tcu::Nothing)
2228         , sampleLocationsEnableConfig(false)
2229         , conservativeRasterModeConfig(vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT)
2230         , extraPrimitiveOverEstConfig(-1.0f)
2231         , lineRasterModeConfig(tcu::Nothing)
2232         , coverageToColorEnableConfig(false)
2233         , coverageToColorLocationConfig(0u)
2234         , rasterizationSamplesConfig(kSingleSampleCount)
2235         , lineWidthConfig(1.0f)
2236 #ifndef CTS_USES_VULKANSC
2237         , coverageModulationModeConfig(vk::VK_COVERAGE_MODULATION_MODE_NONE_NV)
2238         , coverageModTableEnableConfig(false)
2239         , coverageModTableConfig(CovModTableVec())
2240         , coverageReductionModeConfig(vk::VK_COVERAGE_REDUCTION_MODE_MERGE_NV)
2241         , viewportSwizzleConfig(ViewportSwzVec())
2242         , shadingRateImageEnableConfig(false)
2243         , viewportWScalingEnableConfig(false)
2244         , reprFragTestEnableConfig(false)
2245 #endif // CTS_USES_VULKANSC
2246         , m_swappedValues(false)
2247     {
2248     }
2249 
TestConfigvkt::pipeline::__anon3cc04b6f0111::TestConfig2250     TestConfig(const TestConfig &other)
2251         : pipelineConstructionType(other.pipelineConstructionType)
2252         , sequenceOrdering(other.sequenceOrdering)
2253         , meshParams(other.meshParams)
2254         , referenceStencil(other.referenceStencil)
2255         , clearColorValue(other.clearColorValue)
2256         , clearDepthValue(other.clearDepthValue)
2257         , clearStencilValue(other.clearStencilValue)
2258         , referenceColor(other.referenceColor->clone())
2259         , expectedDepth(other.expectedDepth)
2260         , expectedStencil(other.expectedStencil)
2261         , colorVerificator(other.colorVerificator)
2262         , forceGeometryShader(other.forceGeometryShader)
2263         , useMeshShaders(other.useMeshShaders)
2264         , bindUnusedMeshShadingPipeline(other.bindUnusedMeshShadingPipeline)
2265         , singleVertex(other.singleVertex)
2266         , singleVertexDrawCount(other.singleVertexDrawCount)
2267         , oversizedTriangle(other.oversizedTriangle)
2268         , offCenterTriangle(other.offCenterTriangle)
2269         , offCenterProportion(other.offCenterProportion)
2270         , obliqueLine(other.obliqueLine)
2271         , vertexDataOffset(other.vertexDataOffset)
2272         , vertexDataExtraBytes(other.vertexDataExtraBytes)
2273         , useExtraDynPCPPipeline(other.useExtraDynPCPPipeline)
2274         , useExtraDynPipeline(other.useExtraDynPipeline)
2275         , coverageModulation(other.coverageModulation)
2276         , coverageReduction(other.coverageReduction)
2277         , colorSampleCount(other.colorSampleCount)
2278         , shaderRasterizationStream(other.shaderRasterizationStream)
2279         , sampleLocations(other.sampleLocations)
2280         , colorAttachmentCount(other.colorAttachmentCount)
2281         , instanceCount(other.instanceCount)
2282         , viewportSwizzle(other.viewportSwizzle)
2283         , shadingRateImage(other.shadingRateImage)
2284         , viewportWScaling(other.viewportWScaling)
2285         , representativeFragmentTest(other.representativeFragmentTest)
2286         , extraLineRestarts(other.extraLineRestarts)
2287         , colorBlendBoth(other.colorBlendBoth)
2288         , useColorWriteEnable(other.useColorWriteEnable)
2289         , forceUnormColorFormat(other.forceUnormColorFormat)
2290         , nullStaticColorBlendAttPtr(other.nullStaticColorBlendAttPtr)
2291         , colorBlendAttCnt0(other.colorBlendAttCnt0)
2292         , disableAdvBlendingCoherentOps(other.disableAdvBlendingCoherentOps)
2293         , dualSrcBlend(other.dualSrcBlend)
2294         , favorStaticNullPointers(other.favorStaticNullPointers)
2295         , forceAtomicCounters(other.forceAtomicCounters)
2296         , dynamicSampleMaskCount(other.dynamicSampleMaskCount)
2297 #ifndef CTS_USES_VULKANSC
2298         , depthBiasReprInfo(other.depthBiasReprInfo)
2299 #endif // CTS_USES_VULKANSC
2300         , neededDepthChannelClass(other.neededDepthChannelClass)
2301         , extraDepthThreshold(other.extraDepthThreshold)
2302         , sampleShadingEnable(other.sampleShadingEnable)
2303         , minSampleShading(other.minSampleShading)
2304         , disableAlphaToOneFeature(other.disableAlphaToOneFeature)
2305         , vertexGenerator(other.vertexGenerator)
2306         , cullModeConfig(other.cullModeConfig)
2307         , frontFaceConfig(other.frontFaceConfig)
2308         , topologyConfig(other.topologyConfig)
2309         , viewportConfig(other.viewportConfig)
2310         , scissorConfig(other.scissorConfig)
2311         , strideConfig(other.strideConfig)
2312         , depthTestEnableConfig(other.depthTestEnableConfig)
2313         , depthWriteEnableConfig(other.depthWriteEnableConfig)
2314         , depthCompareOpConfig(other.depthCompareOpConfig)
2315         , depthBoundsTestEnableConfig(other.depthBoundsTestEnableConfig)
2316         , depthBoundsConfig(other.depthBoundsConfig)
2317         , stencilTestEnableConfig(other.stencilTestEnableConfig)
2318         , stencilOpConfig(other.stencilOpConfig)
2319         , depthBiasEnableConfig(other.depthBiasEnableConfig)
2320         , rastDiscardEnableConfig(other.rastDiscardEnableConfig)
2321         , primRestartEnableConfig(other.primRestartEnableConfig)
2322         , logicOpConfig(other.logicOpConfig)
2323         , patchControlPointsConfig(other.patchControlPointsConfig)
2324         , depthBiasConfig(other.depthBiasConfig)
2325         , tessDomainOriginConfig(other.tessDomainOriginConfig)
2326         , depthClampEnableConfig(other.depthClampEnableConfig)
2327         , polygonModeConfig(other.polygonModeConfig)
2328         , sampleMaskConfig(other.sampleMaskConfig)
2329         , alphaToCoverageConfig(other.alphaToCoverageConfig)
2330         , alphaToOneConfig(other.alphaToOneConfig)
2331         , colorWriteEnableConfig(other.colorWriteEnableConfig)
2332         , colorWriteMaskConfig(other.colorWriteMaskConfig)
2333         , rasterizationStreamConfig(other.rasterizationStreamConfig)
2334         , logicOpEnableConfig(other.logicOpEnableConfig)
2335         , colorBlendEnableConfig(other.colorBlendEnableConfig)
2336         , colorBlendEquationConfig(other.colorBlendEquationConfig)
2337         , blendConstantsConfig(other.blendConstantsConfig)
2338         , provokingVertexConfig(other.provokingVertexConfig)
2339         , negativeOneToOneConfig(other.negativeOneToOneConfig)
2340         , depthClipEnableConfig(other.depthClipEnableConfig)
2341         , lineStippleEnableConfig(other.lineStippleEnableConfig)
2342         , lineStippleParamsConfig(other.lineStippleParamsConfig)
2343         , sampleLocationsEnableConfig(other.sampleLocationsEnableConfig)
2344         , conservativeRasterModeConfig(other.conservativeRasterModeConfig)
2345         , extraPrimitiveOverEstConfig(other.extraPrimitiveOverEstConfig)
2346         , lineRasterModeConfig(other.lineRasterModeConfig)
2347         , coverageToColorEnableConfig(other.coverageToColorEnableConfig)
2348         , coverageToColorLocationConfig(other.coverageToColorLocationConfig)
2349         , rasterizationSamplesConfig(other.rasterizationSamplesConfig)
2350         , lineWidthConfig(other.lineWidthConfig)
2351 #ifndef CTS_USES_VULKANSC
2352         , coverageModulationModeConfig(other.coverageModulationModeConfig)
2353         , coverageModTableEnableConfig(other.coverageModTableEnableConfig)
2354         , coverageModTableConfig(other.coverageModTableConfig)
2355         , coverageReductionModeConfig(other.coverageReductionModeConfig)
2356         , viewportSwizzleConfig(other.viewportSwizzleConfig)
2357         , shadingRateImageEnableConfig(other.shadingRateImageEnableConfig)
2358         , viewportWScalingEnableConfig(other.viewportWScalingEnableConfig)
2359         , reprFragTestEnableConfig(other.reprFragTestEnableConfig)
2360 #endif // CTS_USES_VULKANSC
2361         , m_swappedValues(other.m_swappedValues)
2362     {
2363     }
2364 
2365     // Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anon3cc04b6f0111::TestConfig2366     const ViewportVec &getActiveViewportVec() const
2367     {
2368         return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() :
2369                                                                     viewportConfig.staticValue);
2370     }
2371 
2372     // Gets the proper vertex generator according to the test config.
getActiveVertexGeneratorvkt::pipeline::__anon3cc04b6f0111::TestConfig2373     const VertexGenerator *getActiveVertexGenerator() const
2374     {
2375         return ((vertexGenerator.dynamicValue && !m_swappedValues) ? vertexGenerator.dynamicValue.get() :
2376                                                                      vertexGenerator.staticValue);
2377     }
2378 
2379     // Gets the inactive vertex generator according to the test config. If there's only one, return that.
getInactiveVertexGeneratorvkt::pipeline::__anon3cc04b6f0111::TestConfig2380     const VertexGenerator *getInactiveVertexGenerator() const
2381     {
2382         return ((vertexGenerator.dynamicValue && m_swappedValues) ? vertexGenerator.dynamicValue.get() :
2383                                                                     vertexGenerator.staticValue);
2384     }
2385 
2386     // Get the active number of patch control points according to the test config.
getActivePatchControlPointsvkt::pipeline::__anon3cc04b6f0111::TestConfig2387     uint32_t getActivePatchControlPoints() const
2388     {
2389         return ((patchControlPointsConfig.dynamicValue && !m_swappedValues) ?
2390                     patchControlPointsConfig.dynamicValue.get() :
2391                     patchControlPointsConfig.staticValue);
2392     }
2393 
2394     // Get the active depth bias parameters.
getActiveDepthBiasParamsvkt::pipeline::__anon3cc04b6f0111::TestConfig2395     DepthBiasParams getActiveDepthBiasParams() const
2396     {
2397         return ((depthBiasConfig.dynamicValue && !m_swappedValues) ? depthBiasConfig.dynamicValue.get() :
2398                                                                      depthBiasConfig.staticValue);
2399     }
2400 
getActiveTessellationDomainOriginvkt::pipeline::__anon3cc04b6f0111::TestConfig2401     vk::VkTessellationDomainOrigin getActiveTessellationDomainOrigin() const
2402     {
2403         return ((tessDomainOriginConfig.dynamicValue && !m_swappedValues) ? tessDomainOriginConfig.dynamicValue.get() :
2404                                                                             tessDomainOriginConfig.staticValue);
2405     }
2406 
getActivePolygonModevkt::pipeline::__anon3cc04b6f0111::TestConfig2407     vk::VkPolygonMode getActivePolygonMode() const
2408     {
2409         return ((polygonModeConfig.dynamicValue && !m_swappedValues) ? polygonModeConfig.dynamicValue.get() :
2410                                                                        polygonModeConfig.staticValue);
2411     }
2412 
getActiveSampleCountvkt::pipeline::__anon3cc04b6f0111::TestConfig2413     vk::VkSampleCountFlagBits getActiveSampleCount() const
2414     {
2415         return ((rasterizationSamplesConfig.dynamicValue && !m_swappedValues) ?
2416                     rasterizationSamplesConfig.dynamicValue.get() :
2417                     rasterizationSamplesConfig.staticValue);
2418     }
2419 
getActiveAlphaToOnevkt::pipeline::__anon3cc04b6f0111::TestConfig2420     bool getActiveAlphaToOne() const
2421     {
2422         return ((alphaToOneConfig.dynamicValue && !m_swappedValues) ? alphaToOneConfig.dynamicValue.get() :
2423                                                                       alphaToOneConfig.staticValue);
2424     }
2425 
rasterizationStreamStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2426     bool rasterizationStreamStruct() const
2427     {
2428         return (static_cast<bool>(rasterizationStreamConfig.staticValue) ||
2429                 (static_cast<bool>(rasterizationStreamConfig.dynamicValue) &&
2430                  static_cast<bool>(rasterizationStreamConfig.dynamicValue.get())));
2431     }
2432 
provokingVertexStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2433     bool provokingVertexStruct() const
2434     {
2435         return (static_cast<bool>(provokingVertexConfig.staticValue) ||
2436                 (static_cast<bool>(provokingVertexConfig.dynamicValue) &&
2437                  static_cast<bool>(provokingVertexConfig.dynamicValue.get())));
2438     }
2439 
negativeOneToOneStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2440     bool negativeOneToOneStruct() const
2441     {
2442         return (static_cast<bool>(negativeOneToOneConfig.staticValue) ||
2443                 (static_cast<bool>(negativeOneToOneConfig.dynamicValue) &&
2444                  static_cast<bool>(negativeOneToOneConfig.dynamicValue.get())));
2445     }
2446 
depthClipEnableStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2447     bool depthClipEnableStruct() const
2448     {
2449         return (static_cast<bool>(depthClipEnableConfig.staticValue) ||
2450                 (static_cast<bool>(depthClipEnableConfig.dynamicValue) &&
2451                  static_cast<bool>(depthClipEnableConfig.dynamicValue.get())));
2452     }
2453 
hasStaticLineStippleParamsvkt::pipeline::__anon3cc04b6f0111::TestConfig2454     bool hasStaticLineStippleParams() const
2455     {
2456         return (static_cast<bool>(lineStippleParamsConfig.staticValue));
2457     }
2458 
hasStaticLineRasterModevkt::pipeline::__anon3cc04b6f0111::TestConfig2459     bool hasStaticLineRasterMode() const
2460     {
2461         return (static_cast<bool>(lineRasterModeConfig.staticValue));
2462     }
2463 
hasLineStippleParamsvkt::pipeline::__anon3cc04b6f0111::TestConfig2464     bool hasLineStippleParams() const
2465     {
2466         return (hasStaticLineStippleParams() || (static_cast<bool>(lineStippleParamsConfig.dynamicValue) &&
2467                                                  static_cast<bool>(lineStippleParamsConfig.dynamicValue.get())));
2468     }
2469 
hasLineRasterModevkt::pipeline::__anon3cc04b6f0111::TestConfig2470     bool hasLineRasterMode() const
2471     {
2472         return (hasStaticLineRasterMode() || (static_cast<bool>(lineRasterModeConfig.dynamicValue) &&
2473                                               static_cast<bool>(lineRasterModeConfig.dynamicValue.get())));
2474     }
2475 
lineStippleSupportRequiredvkt::pipeline::__anon3cc04b6f0111::TestConfig2476     bool lineStippleSupportRequired() const
2477     {
2478         return (lineStippleEnableConfig.staticValue || (static_cast<bool>(lineStippleEnableConfig.dynamicValue) &&
2479                                                         lineStippleEnableConfig.dynamicValue.get()));
2480     }
2481 
lineRasterStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2482     bool lineRasterStruct() const
2483     {
2484         return (static_cast<bool>(lineStippleEnableConfig.dynamicValue) || lineStippleEnableConfig.staticValue ||
2485                 hasStaticLineStippleParams() || hasStaticLineRasterMode());
2486     }
2487 
lineRasterizationExtvkt::pipeline::__anon3cc04b6f0111::TestConfig2488     bool lineRasterizationExt() const
2489     {
2490         return (lineRasterStruct() || hasLineStippleParams() || hasLineRasterMode());
2491     }
2492 
sampleLocationsStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2493     bool sampleLocationsStruct() const
2494     {
2495         return (static_cast<bool>(sampleLocationsEnableConfig.dynamicValue) || sampleLocationsEnableConfig.staticValue);
2496     }
2497 
coverageToColorStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2498     bool coverageToColorStruct() const
2499     {
2500         return (static_cast<bool>(coverageToColorEnableConfig.dynamicValue) || coverageToColorEnableConfig.staticValue);
2501     }
2502 
conservativeRasterStructvkt::pipeline::__anon3cc04b6f0111::TestConfig2503     bool conservativeRasterStruct() const
2504     {
2505         return (static_cast<bool>(conservativeRasterModeConfig.dynamicValue) ||
2506                 conservativeRasterModeConfig.staticValue != vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT ||
2507                 static_cast<bool>(extraPrimitiveOverEstConfig.dynamicValue) ||
2508                 extraPrimitiveOverEstConfig.staticValue >= 0.0f);
2509     }
2510 
getActiveConservativeRasterModevkt::pipeline::__anon3cc04b6f0111::TestConfig2511     vk::VkConservativeRasterizationModeEXT getActiveConservativeRasterMode() const
2512     {
2513         return ((static_cast<bool>(conservativeRasterModeConfig.dynamicValue) && !m_swappedValues) ?
2514                     conservativeRasterModeConfig.dynamicValue.get() :
2515                     conservativeRasterModeConfig.staticValue);
2516     }
2517 
getActiveExtraPrimitiveOverEstSizevkt::pipeline::__anon3cc04b6f0111::TestConfig2518     float getActiveExtraPrimitiveOverEstSize() const
2519     {
2520         return ((static_cast<bool>(extraPrimitiveOverEstConfig.dynamicValue) && !m_swappedValues) ?
2521                     extraPrimitiveOverEstConfig.dynamicValue.get() :
2522                     extraPrimitiveOverEstConfig.staticValue);
2523     }
2524 
getActiveNegativeOneToOneValuevkt::pipeline::__anon3cc04b6f0111::TestConfig2525     bool getActiveNegativeOneToOneValue() const
2526     {
2527         const bool staticValue =
2528             (static_cast<bool>(negativeOneToOneConfig.staticValue) ? negativeOneToOneConfig.staticValue.get() : false);
2529         const bool hasDynamicValue = (static_cast<bool>(negativeOneToOneConfig.dynamicValue) &&
2530                                       static_cast<bool>(negativeOneToOneConfig.dynamicValue.get()));
2531         const tcu::Maybe<bool> dynamicValue =
2532             (hasDynamicValue ? tcu::just(negativeOneToOneConfig.dynamicValue->get()) : tcu::nothing<bool>());
2533 
2534         return ((hasDynamicValue && !m_swappedValues) ? dynamicValue.get() : staticValue);
2535     }
2536 
getActiveDepthClipEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2537     bool getActiveDepthClipEnable() const
2538     {
2539         const bool staticValue =
2540             (static_cast<bool>(depthClipEnableConfig.staticValue) ? depthClipEnableConfig.staticValue.get() : true);
2541         const bool hasDynamicValue = (static_cast<bool>(depthClipEnableConfig.dynamicValue) &&
2542                                       static_cast<bool>(depthClipEnableConfig.dynamicValue.get()));
2543         const tcu::Maybe<bool> dynamicValue =
2544             (hasDynamicValue ? tcu::just(depthClipEnableConfig.dynamicValue->get()) : tcu::nothing<bool>());
2545 
2546         return ((hasDynamicValue && !m_swappedValues) ? dynamicValue.get() : staticValue);
2547     }
2548 
getActiveLineWidthvkt::pipeline::__anon3cc04b6f0111::TestConfig2549     float getActiveLineWidth() const
2550     {
2551         return ((static_cast<bool>(lineWidthConfig.dynamicValue) && !m_swappedValues) ?
2552                     lineWidthConfig.dynamicValue.get() :
2553                     lineWidthConfig.staticValue);
2554     }
2555 
2556     // Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anon3cc04b6f0111::TestConfig2557     bool isMultiViewport() const
2558     {
2559         return (getActiveViewportVec().size() > 1);
2560     }
2561 
2562     // Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anon3cc04b6f0111::TestConfig2563     bool needsGeometryShader() const
2564     {
2565         // Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
2566         // commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
2567         return ((isMultiViewport() && (!useMeshShaders)) || forceGeometryShader ||
2568                 static_cast<bool>(shaderRasterizationStream));
2569     }
2570 
2571     // Returns true if we should use the static and dynamic values exchanged.
2572     // This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon3cc04b6f0111::TestConfig2573     bool isReversed() const
2574     {
2575         return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2576                 sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
2577     }
2578 
2579     // Returns true if the ordering needs to bind a static pipeline first.
bindStaticFirstvkt::pipeline::__anon3cc04b6f0111::TestConfig2580     bool bindStaticFirst() const
2581     {
2582         return (sequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
2583                 sequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
2584                 sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
2585     }
2586 
2587     // Returns true if the test uses a static pipeline.
useStaticPipelinevkt::pipeline::__anon3cc04b6f0111::TestConfig2588     bool useStaticPipeline() const
2589     {
2590         return (bindStaticFirst() || isReversed());
2591     }
2592 
2593     // Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon3cc04b6f0111::TestConfig2594     void swapValues()
2595     {
2596         vertexGenerator.swapValues();
2597         cullModeConfig.swapValues();
2598         frontFaceConfig.swapValues();
2599         topologyConfig.swapValues();
2600         viewportConfig.swapValues();
2601         scissorConfig.swapValues();
2602         strideConfig.swapValues();
2603         depthTestEnableConfig.swapValues();
2604         depthWriteEnableConfig.swapValues();
2605         depthCompareOpConfig.swapValues();
2606         depthBoundsTestEnableConfig.swapValues();
2607         depthBoundsConfig.swapValues();
2608         stencilTestEnableConfig.swapValues();
2609         stencilOpConfig.swapValues();
2610         depthBiasEnableConfig.swapValues();
2611         rastDiscardEnableConfig.swapValues();
2612         primRestartEnableConfig.swapValues();
2613         logicOpConfig.swapValues();
2614         patchControlPointsConfig.swapValues();
2615         depthBiasConfig.swapValues();
2616         tessDomainOriginConfig.swapValues();
2617         depthClampEnableConfig.swapValues();
2618         polygonModeConfig.swapValues();
2619         sampleMaskConfig.swapValues();
2620         alphaToCoverageConfig.swapValues();
2621         alphaToOneConfig.swapValues();
2622         colorWriteEnableConfig.swapValues();
2623         colorWriteMaskConfig.swapValues();
2624         rasterizationStreamConfig.swapValues();
2625         logicOpEnableConfig.swapValues();
2626         colorBlendEnableConfig.swapValues();
2627         colorBlendEquationConfig.swapValues();
2628         blendConstantsConfig.swapValues();
2629         provokingVertexConfig.swapValues();
2630         negativeOneToOneConfig.swapValues();
2631         depthClipEnableConfig.swapValues();
2632         lineStippleEnableConfig.swapValues();
2633         lineStippleParamsConfig.swapValues();
2634         sampleLocationsEnableConfig.swapValues();
2635         conservativeRasterModeConfig.swapValues();
2636         extraPrimitiveOverEstConfig.swapValues();
2637         lineRasterModeConfig.swapValues();
2638         coverageToColorEnableConfig.swapValues();
2639         coverageToColorLocationConfig.swapValues();
2640         rasterizationSamplesConfig.swapValues();
2641         lineWidthConfig.swapValues();
2642 #ifndef CTS_USES_VULKANSC
2643         coverageModulationModeConfig.swapValues();
2644         coverageModTableEnableConfig.swapValues();
2645         coverageModTableConfig.swapValues();
2646         coverageReductionModeConfig.swapValues();
2647         viewportSwizzleConfig.swapValues();
2648         shadingRateImageEnableConfig.swapValues();
2649         viewportWScalingEnableConfig.swapValues();
2650         reprFragTestEnableConfig.swapValues();
2651 #endif // CTS_USES_VULKANSC
2652 
2653         m_swappedValues = !m_swappedValues;
2654     }
2655 
2656     // Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon3cc04b6f0111::TestConfig2657     uint32_t numIterations() const
2658     {
2659         uint32_t iterations = 0u;
2660 
2661         switch (sequenceOrdering)
2662         {
2663         case SequenceOrdering::TWO_DRAWS_DYNAMIC:
2664         case SequenceOrdering::TWO_DRAWS_STATIC:
2665             iterations = 2u;
2666             break;
2667         default:
2668             iterations = 1u;
2669             break;
2670         }
2671 
2672         return iterations;
2673     }
2674 
2675     // Returns true if we're testing the logic op.
testLogicOpvkt::pipeline::__anon3cc04b6f0111::TestConfig2676     bool testLogicOp() const
2677     {
2678         return static_cast<bool>(logicOpConfig.dynamicValue);
2679     }
2680 
2681     // Returns true if we're testing the logic op enable state.
testLogicOpEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2682     bool testLogicOpEnable() const
2683     {
2684         return static_cast<bool>(logicOpEnableConfig.dynamicValue);
2685     }
2686 
2687     // Returns true if we're testing the patch control points.
testPatchControlPointsvkt::pipeline::__anon3cc04b6f0111::TestConfig2688     bool testPatchControlPoints() const
2689     {
2690         return static_cast<bool>(patchControlPointsConfig.dynamicValue);
2691     }
2692 
2693     // Returns true if we're testing tessellation domain origin.
testTessellationDomainOriginvkt::pipeline::__anon3cc04b6f0111::TestConfig2694     bool testTessellationDomainOrigin() const
2695     {
2696         return static_cast<bool>(tessDomainOriginConfig.dynamicValue);
2697     }
2698 
2699     // Returns true if we're testing primitive restart enable.
testPrimRestartEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2700     bool testPrimRestartEnable() const
2701     {
2702         return static_cast<bool>(primRestartEnableConfig.dynamicValue);
2703     }
2704 
2705     // Returns the topology class.
topologyClassvkt::pipeline::__anon3cc04b6f0111::TestConfig2706     TopologyClass topologyClass() const
2707     {
2708         return getTopologyClass(topologyConfig.staticValue);
2709     }
2710 
2711     // Returns true if the topology class is patches for tessellation.
patchesTopologyvkt::pipeline::__anon3cc04b6f0111::TestConfig2712     bool patchesTopology() const
2713     {
2714         return (topologyClass() == TopologyClass::PATCH);
2715     }
2716 
2717     // Returns true if the test needs tessellation shaders.
needsTessellationvkt::pipeline::__anon3cc04b6f0111::TestConfig2718     bool needsTessellation() const
2719     {
2720         return (testPatchControlPoints() || patchesTopology() || testTessellationDomainOrigin());
2721     }
2722 
2723     // Returns the active line stipple enablement flag.
getActiveLineStippleEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2724     bool getActiveLineStippleEnable() const
2725     {
2726         return ((static_cast<bool>(lineStippleEnableConfig.dynamicValue) && !m_swappedValues) ?
2727                     lineStippleEnableConfig.dynamicValue.get() :
2728                     lineStippleEnableConfig.staticValue);
2729     }
2730 
2731     // Returns the active primitive restart enablement flag.
getActivePrimRestartEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2732     bool getActivePrimRestartEnable() const
2733     {
2734         return ((static_cast<bool>(primRestartEnableConfig.dynamicValue) && !m_swappedValues) ?
2735                     primRestartEnableConfig.dynamicValue.get() :
2736                     primRestartEnableConfig.staticValue);
2737     }
2738 
2739     // Returns the active representative fragment test enablement flag.
getActiveReprFragTestEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2740     bool getActiveReprFragTestEnable() const
2741     {
2742 #ifndef CTS_USES_VULKANSC
2743         return ((static_cast<bool>(reprFragTestEnableConfig.dynamicValue) && !m_swappedValues) ?
2744                     reprFragTestEnableConfig.dynamicValue.get() :
2745                     reprFragTestEnableConfig.staticValue);
2746 #else
2747         return false;
2748 #endif // CTS_USES_VULKANSC
2749     }
2750 
2751     // Returns the active color blend enablement flag.
getActiveColorBlendEnablevkt::pipeline::__anon3cc04b6f0111::TestConfig2752     bool getActiveColorBlendEnable() const
2753     {
2754         return ((static_cast<bool>(colorBlendEnableConfig.dynamicValue) && !m_swappedValues) ?
2755                     colorBlendEnableConfig.dynamicValue.get() :
2756                     colorBlendEnableConfig.staticValue);
2757     }
2758 
2759     // Returns true if the test needs an index buffer.
needsIndexBuffervkt::pipeline::__anon3cc04b6f0111::TestConfig2760     bool needsIndexBuffer() const
2761     {
2762         return ((testPrimRestartEnable() || getActiveLineStippleEnable()) && !useMeshShaders);
2763     }
2764 
2765     // Returns true if the test needs the depth bias clamp feature.
needsDepthBiasClampFeaturevkt::pipeline::__anon3cc04b6f0111::TestConfig2766     bool needsDepthBiasClampFeature() const
2767     {
2768         return (getActiveDepthBiasParams().clamp != 0.0f);
2769     }
2770 
2771     // Returns true if the configuration needs VK_EXT_extended_dynamic_state3.
needsEDS3vkt::pipeline::__anon3cc04b6f0111::TestConfig2772     bool needsEDS3() const
2773     {
2774         return ((!!tessDomainOriginConfig.dynamicValue) || (!!depthClampEnableConfig.dynamicValue) ||
2775                 (!!polygonModeConfig.dynamicValue) || (!!sampleMaskConfig.dynamicValue) ||
2776                 (!!alphaToCoverageConfig.dynamicValue) || (!!alphaToOneConfig.dynamicValue) ||
2777                 (!!colorWriteMaskConfig.dynamicValue) || (!!rasterizationStreamConfig.dynamicValue) ||
2778                 (!!logicOpEnableConfig.dynamicValue) || (!!colorBlendEnableConfig.dynamicValue) ||
2779                 (!!colorBlendEquationConfig.dynamicValue) || (!!provokingVertexConfig.dynamicValue) ||
2780                 (!!negativeOneToOneConfig.dynamicValue) || (!!depthClipEnableConfig.dynamicValue) ||
2781                 (!!lineStippleEnableConfig.dynamicValue) || (!!sampleLocationsEnableConfig.dynamicValue) ||
2782                 (!!conservativeRasterModeConfig.dynamicValue) || (!!extraPrimitiveOverEstConfig.dynamicValue) ||
2783                 (!!lineRasterModeConfig.dynamicValue) || (!!coverageToColorEnableConfig.dynamicValue) ||
2784                 (!!coverageToColorLocationConfig.dynamicValue) || (!!rasterizationSamplesConfig.dynamicValue)
2785 #ifndef CTS_USES_VULKANSC
2786                 || (!!coverageModulationModeConfig.dynamicValue) || (!!coverageModTableEnableConfig.dynamicValue) ||
2787                 (!!coverageModTableConfig.dynamicValue) || (!!coverageReductionModeConfig.dynamicValue) ||
2788                 (!!viewportSwizzleConfig.dynamicValue) || (!!shadingRateImageEnableConfig.dynamicValue) ||
2789                 (!!viewportWScalingEnableConfig.dynamicValue) || (!!reprFragTestEnableConfig.dynamicValue)
2790 #endif // CTS_USES_VULKANSC
2791                 || favorStaticNullPointers);
2792     }
2793 
2794     // Returns the appropriate color image format for the test.
colorFormatvkt::pipeline::__anon3cc04b6f0111::TestConfig2795     vk::VkFormat colorFormat() const
2796     {
2797         // Special case for some tests.
2798         if (forceUnormColorFormat)
2799             return kUnormColorFormat;
2800 
2801         // Pick int color format when testing logic op dynamic states.
2802         if (testLogicOp() || testLogicOpEnable())
2803             return kIntColorFormat;
2804 
2805         // Pick special color format for coverage to color.
2806         if (coverageToColorStruct())
2807             return kIntRedColorFormat;
2808 
2809         return kUnormColorFormat;
2810     }
2811 
2812     // Get used color sample count.
getColorSampleCountvkt::pipeline::__anon3cc04b6f0111::TestConfig2813     vk::VkSampleCountFlagBits getColorSampleCount() const
2814     {
2815         const auto usedColorSampleCount =
2816             ((coverageModulation || coverageReduction) ? colorSampleCount.get() : getActiveSampleCount());
2817         return usedColorSampleCount;
2818     }
2819 
2820     // Returns the list of dynamic states affected by this config.
getDynamicStatesvkt::pipeline::__anon3cc04b6f0111::TestConfig2821     std::vector<vk::VkDynamicState> getDynamicStates() const
2822     {
2823         std::vector<vk::VkDynamicState> dynamicStates;
2824 
2825         if (lineWidthConfig.dynamicValue)
2826             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_WIDTH);
2827         if (depthBiasConfig.dynamicValue)
2828             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS);
2829         if (cullModeConfig.dynamicValue)
2830             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
2831         if (frontFaceConfig.dynamicValue)
2832             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
2833         if (topologyConfig.dynamicValue)
2834             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
2835         if (viewportConfig.dynamicValue)
2836             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
2837         if (scissorConfig.dynamicValue)
2838             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
2839         if (strideConfig.dynamicValue)
2840             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
2841         if (depthTestEnableConfig.dynamicValue)
2842             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
2843         if (depthWriteEnableConfig.dynamicValue)
2844             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
2845         if (depthCompareOpConfig.dynamicValue)
2846             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
2847         if (depthBoundsTestEnableConfig.dynamicValue)
2848             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
2849         if (depthBoundsConfig.dynamicValue)
2850             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS);
2851         if (stencilTestEnableConfig.dynamicValue)
2852             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
2853         if (stencilOpConfig.dynamicValue)
2854             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
2855         if (vertexGenerator.dynamicValue)
2856             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
2857         if (patchControlPointsConfig.dynamicValue)
2858             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
2859         if (rastDiscardEnableConfig.dynamicValue)
2860             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
2861         if (depthBiasEnableConfig.dynamicValue)
2862             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
2863         if (logicOpConfig.dynamicValue)
2864             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
2865         if (primRestartEnableConfig.dynamicValue)
2866             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
2867         if (colorWriteEnableConfig.dynamicValue)
2868             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_ENABLE_EXT);
2869         if (blendConstantsConfig.dynamicValue)
2870             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_BLEND_CONSTANTS);
2871         if (lineStippleParamsConfig.dynamicValue)
2872             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
2873 #ifndef CTS_USES_VULKANSC
2874         if (tessDomainOriginConfig.dynamicValue)
2875             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT);
2876         if (depthClampEnableConfig.dynamicValue)
2877             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
2878         if (polygonModeConfig.dynamicValue)
2879             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_POLYGON_MODE_EXT);
2880         if (sampleMaskConfig.dynamicValue)
2881             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_MASK_EXT);
2882         if (alphaToCoverageConfig.dynamicValue)
2883             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
2884         if (alphaToOneConfig.dynamicValue)
2885             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
2886         if (colorWriteMaskConfig.dynamicValue)
2887             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT);
2888         if (rasterizationStreamConfig.dynamicValue)
2889             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT);
2890         if (logicOpEnableConfig.dynamicValue)
2891             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
2892         if (colorBlendEnableConfig.dynamicValue)
2893             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT);
2894         if (colorBlendEquationConfig.dynamicValue)
2895         {
2896             if (colorBlendBoth || nullStaticColorBlendAttPtr)
2897             {
2898                 dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
2899                 dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT);
2900             }
2901             else
2902             {
2903                 dynamicStates.push_back(colorBlendEquationConfig.staticValue.isAdvanced() ?
2904                                             vk::VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT :
2905                                             vk::VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT);
2906             }
2907         }
2908         if (provokingVertexConfig.dynamicValue)
2909             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT);
2910         if (negativeOneToOneConfig.dynamicValue)
2911             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT);
2912         if (depthClipEnableConfig.dynamicValue)
2913             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT);
2914         if (lineStippleEnableConfig.dynamicValue)
2915             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
2916         if (sampleLocationsEnableConfig.dynamicValue)
2917             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_ENABLE_EXT);
2918         if (conservativeRasterModeConfig.dynamicValue)
2919             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
2920         if (extraPrimitiveOverEstConfig.dynamicValue)
2921             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_EXTRA_PRIMITIVE_OVERESTIMATION_SIZE_EXT);
2922         if (lineRasterModeConfig.dynamicValue)
2923             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
2924         if (rasterizationSamplesConfig.dynamicValue)
2925             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT);
2926         if (coverageToColorEnableConfig.dynamicValue)
2927             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_ENABLE_NV);
2928         if (coverageToColorLocationConfig.dynamicValue)
2929             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_TO_COLOR_LOCATION_NV);
2930         if (coverageModulationModeConfig.dynamicValue)
2931             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_MODE_NV);
2932         if (coverageModTableEnableConfig.dynamicValue)
2933             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_ENABLE_NV);
2934         if (coverageModTableConfig.dynamicValue)
2935             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_MODULATION_TABLE_NV);
2936         if (coverageReductionModeConfig.dynamicValue)
2937             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_COVERAGE_REDUCTION_MODE_NV);
2938         if (viewportSwizzleConfig.dynamicValue)
2939             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_SWIZZLE_NV);
2940         if (shadingRateImageEnableConfig.dynamicValue)
2941             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SHADING_RATE_IMAGE_ENABLE_NV);
2942         if (viewportWScalingEnableConfig.dynamicValue)
2943             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_ENABLE_NV);
2944         if (reprFragTestEnableConfig.dynamicValue)
2945             dynamicStates.push_back(vk::VK_DYNAMIC_STATE_REPRESENTATIVE_FRAGMENT_TEST_ENABLE_NV);
2946 #endif // CTS_USES_VULKANSC
2947 
2948         return dynamicStates;
2949     }
2950 
2951 #ifndef CTS_USES_VULKANSC
2952     // Returns true if the test configuration uses dynamic states which are incompatible with mesh shading pipelines.
badMeshShadingPipelineDynStatevkt::pipeline::__anon3cc04b6f0111::TestConfig2953     bool badMeshShadingPipelineDynState() const
2954     {
2955         const auto states = getDynamicStates();
2956         return std::any_of(begin(states), end(states), isMeshShadingPipelineIncompatible);
2957     }
2958 #endif // CTS_USES_VULKANSC
2959 
testEDSvkt::pipeline::__anon3cc04b6f0111::TestConfig2960     bool testEDS() const
2961     {
2962         return (cullModeConfig.dynamicValue || frontFaceConfig.dynamicValue || topologyConfig.dynamicValue ||
2963                 viewportConfig.dynamicValue || scissorConfig.dynamicValue || strideConfig.dynamicValue ||
2964                 depthTestEnableConfig.dynamicValue || depthWriteEnableConfig.dynamicValue ||
2965                 depthCompareOpConfig.dynamicValue || depthBoundsTestEnableConfig.dynamicValue ||
2966                 stencilTestEnableConfig.dynamicValue || stencilOpConfig.dynamicValue);
2967     }
2968 
testEDS2vkt::pipeline::__anon3cc04b6f0111::TestConfig2969     bool testEDS2() const
2970     {
2971         return (rastDiscardEnableConfig.dynamicValue || depthBiasEnableConfig.dynamicValue ||
2972                 primRestartEnableConfig.dynamicValue || useExtraDynPCPPipeline);
2973     }
2974 
testVertexDynamicvkt::pipeline::__anon3cc04b6f0111::TestConfig2975     bool testVertexDynamic() const
2976     {
2977         return static_cast<bool>(vertexGenerator.dynamicValue);
2978     }
2979 
2980     // Returns the list of extensions needed by this config. Note some other
2981     // requirements are checked with feature structs, which is particularly
2982     // important for extensions which have been partially promoted, like EDS
2983     // and EDS2. Extensions requested here have not been partially promoted.
getRequiredExtensionsvkt::pipeline::__anon3cc04b6f0111::TestConfig2984     std::vector<std::string> getRequiredExtensions() const
2985     {
2986         std::vector<std::string> extensions;
2987 
2988         if (needsEDS3())
2989         {
2990             extensions.push_back("VK_EXT_extended_dynamic_state3");
2991         }
2992 
2993         if (testTessellationDomainOrigin() ||
2994             getActiveTessellationDomainOrigin() != vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT)
2995         {
2996             extensions.push_back("VK_KHR_maintenance2");
2997         }
2998 
2999         if (rasterizationStreamStruct())
3000         {
3001             extensions.push_back("VK_EXT_transform_feedback");
3002         }
3003 
3004         if (provokingVertexStruct())
3005         {
3006             extensions.push_back("VK_EXT_provoking_vertex");
3007         }
3008 
3009         if (negativeOneToOneStruct())
3010         {
3011             extensions.push_back("VK_EXT_depth_clip_control");
3012         }
3013 
3014         if (depthClipEnableStruct())
3015         {
3016             extensions.push_back("VK_EXT_depth_clip_enable");
3017         }
3018 
3019         if (lineRasterizationExt())
3020         {
3021             extensions.push_back("VK_KHR_or_EXT_line_rasterization");
3022         }
3023 
3024         if (colorBlendEquationConfig.staticValue.isAdvanced())
3025         {
3026             extensions.push_back("VK_EXT_blend_operation_advanced");
3027         }
3028 
3029         if (sampleLocationsStruct())
3030         {
3031             extensions.push_back("VK_EXT_sample_locations");
3032         }
3033 
3034         if (coverageToColorStruct())
3035         {
3036             extensions.push_back("VK_NV_fragment_coverage_to_color");
3037         }
3038 
3039         if (conservativeRasterStruct() || static_cast<bool>(maxPrimitiveOverestimationSize))
3040         {
3041             extensions.push_back("VK_EXT_conservative_rasterization");
3042         }
3043 
3044         if (coverageModulation)
3045         {
3046             extensions.push_back("VK_NV_framebuffer_mixed_samples");
3047         }
3048 
3049         if (coverageReduction)
3050         {
3051             extensions.push_back("VK_NV_coverage_reduction_mode");
3052         }
3053 
3054         if (viewportSwizzle)
3055         {
3056             extensions.push_back("VK_NV_viewport_swizzle");
3057         }
3058 
3059         if (shadingRateImage)
3060         {
3061             extensions.push_back("VK_NV_shading_rate_image");
3062         }
3063 
3064         if (viewportWScaling)
3065         {
3066             extensions.push_back("VK_NV_clip_space_w_scaling");
3067         }
3068 
3069         if (representativeFragmentTest)
3070         {
3071             extensions.push_back("VK_NV_representative_fragment_test");
3072         }
3073 
3074         if (useColorWriteEnable)
3075         {
3076             extensions.push_back("VK_EXT_color_write_enable");
3077         }
3078 
3079         return extensions;
3080     }
3081 
getFragDescriptorSetIndexvkt::pipeline::__anon3cc04b6f0111::TestConfig3082     uint32_t getFragDescriptorSetIndex() const
3083     {
3084         return (useMeshShaders ? 1u : 0u);
3085     }
3086 
useFragShaderAtomicsvkt::pipeline::__anon3cc04b6f0111::TestConfig3087     bool useFragShaderAtomics() const
3088     {
3089         return (representativeFragmentTest || forceAtomicCounters);
3090     }
3091 
3092 private:
3093     // Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
3094     // has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
3095     // expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
3096     // pipeline with wrong values and a static one with good values.
3097     //
3098     // Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
3099     // 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
3100     // given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
3101     bool m_swappedValues;
3102 };
3103 
3104 struct PushConstants
3105 {
3106     tcu::Vec4 triangleColor;
3107     float meshDepth;
3108     int32_t viewPortIndex;
3109     float scaleX;
3110     float scaleY;
3111     float offsetX;
3112     float offsetY;
3113     float stripScale;
3114 };
3115 
copy(vk::VkStencilOpState & dst,const StencilOpParams & src)3116 void copy(vk::VkStencilOpState &dst, const StencilOpParams &src)
3117 {
3118     dst.failOp      = src.failOp;
3119     dst.passOp      = src.passOp;
3120     dst.depthFailOp = src.depthFailOp;
3121     dst.compareOp   = src.compareOp;
3122 }
3123 
makeImageCreateInfo(vk::VkFormat format,vk::VkExtent3D extent,vk::VkSampleCountFlagBits sampleCount,vk::VkImageUsageFlags usage,vk::VkImageCreateFlags createFlags)3124 vk::VkImageCreateInfo makeImageCreateInfo(vk::VkFormat format, vk::VkExtent3D extent,
3125                                           vk::VkSampleCountFlagBits sampleCount, vk::VkImageUsageFlags usage,
3126                                           vk::VkImageCreateFlags createFlags)
3127 {
3128     const vk::VkImageCreateInfo imageCreateInfo = {
3129         vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
3130         nullptr,                                 // const void* pNext;
3131         createFlags,                             // VkImageCreateFlags flags;
3132         vk::VK_IMAGE_TYPE_2D,                    // VkImageType imageType;
3133         format,                                  // VkFormat format;
3134         extent,                                  // VkExtent3D extent;
3135         1u,                                      // uint32_t mipLevels;
3136         1u,                                      // uint32_t arrayLayers;
3137         sampleCount,                             // VkSampleCountFlagBits samples;
3138         vk::VK_IMAGE_TILING_OPTIMAL,             // VkImageTiling tiling;
3139         usage,                                   // VkImageUsageFlags usage;
3140         vk::VK_SHARING_MODE_EXCLUSIVE,           // VkSharingMode sharingMode;
3141         0u,                                      // uint32_t queueFamilyIndexCount;
3142         nullptr,                                 // const uint32_t* pQueueFamilyIndices;
3143         vk::VK_IMAGE_LAYOUT_UNDEFINED,           // VkImageLayout initialLayout;
3144     };
3145 
3146     return imageCreateInfo;
3147 }
3148 
3149 class ExtendedDynamicStateTest : public vkt::TestCase
3150 {
3151 public:
3152     ExtendedDynamicStateTest(tcu::TestContext &testCtx, const std::string &name, const TestConfig &testConfig);
~ExtendedDynamicStateTest(void)3153     virtual ~ExtendedDynamicStateTest(void)
3154     {
3155     }
3156 
3157     virtual void checkSupport(Context &context) const;
3158     virtual void initPrograms(vk::SourceCollections &programCollection) const;
3159     virtual TestInstance *createInstance(Context &context) const;
3160 
3161 private:
3162     TestConfig m_testConfig;
3163 };
3164 
3165 class ExtendedDynamicStateInstance : public vkt::TestInstance
3166 {
3167 public:
3168     ExtendedDynamicStateInstance(Context &context, const TestConfig &testConfig);
~ExtendedDynamicStateInstance(void)3169     virtual ~ExtendedDynamicStateInstance(void)
3170     {
3171     }
3172 
3173     virtual tcu::TestStatus iterate(void);
3174 
3175 private:
3176     TestConfig m_testConfig;
3177 };
3178 
ExtendedDynamicStateTest(tcu::TestContext & testCtx,const std::string & name,const TestConfig & testConfig)3179 ExtendedDynamicStateTest::ExtendedDynamicStateTest(tcu::TestContext &testCtx, const std::string &name,
3180                                                    const TestConfig &testConfig)
3181     : vkt::TestCase(testCtx, name)
3182     , m_testConfig(testConfig)
3183 {
3184     const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
3185     DE_UNREF(staticTopologyClass); // For release builds.
3186 
3187     // Matching topology classes.
3188     DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
3189               staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
3190 
3191     // Supported topology classes for these tests.
3192     DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE ||
3193               staticTopologyClass == TopologyClass::PATCH);
3194 
3195     // Make sure these are consistent.
3196     DE_ASSERT(!(m_testConfig.testPatchControlPoints() && !m_testConfig.patchesTopology()));
3197     DE_ASSERT(!(m_testConfig.patchesTopology() && m_testConfig.getActivePatchControlPoints() <= 1u));
3198 
3199     // Do not use an extra dynamic patch control points pipeline if we're not testing them.
3200     DE_ASSERT(!m_testConfig.useExtraDynPCPPipeline || m_testConfig.testPatchControlPoints());
3201 }
3202 
checkSupport(Context & context) const3203 void ExtendedDynamicStateTest::checkSupport(Context &context) const
3204 {
3205     const auto &vki           = context.getInstanceInterface();
3206     const auto physicalDevice = context.getPhysicalDevice();
3207 
3208     // Check feature support.
3209     const auto &baseFeatures = context.getDeviceFeatures();
3210     const auto &edsFeatures  = context.getExtendedDynamicStateFeaturesEXT();
3211     const auto &eds2Features = context.getExtendedDynamicState2FeaturesEXT();
3212     const auto &viFeatures   = context.getVertexInputDynamicStateFeaturesEXT();
3213 #ifndef CTS_USES_VULKANSC
3214     const auto &meshFeatures = context.getMeshShaderFeaturesEXT();
3215 #endif // CTS_USES_VULKANSC
3216 
3217     if (m_testConfig.dualSrcBlend && !baseFeatures.dualSrcBlend)
3218         TCU_THROW(NotSupportedError, "dualSrcBlend is not supported");
3219 
3220     if (m_testConfig.testEDS() && !edsFeatures.extendedDynamicState)
3221         TCU_THROW(NotSupportedError, "extendedDynamicState is not supported");
3222 
3223     if (m_testConfig.testEDS2() && !eds2Features.extendedDynamicState2)
3224         TCU_THROW(NotSupportedError, "extendedDynamicState2 is not supported");
3225 
3226     if (m_testConfig.testLogicOp() && !eds2Features.extendedDynamicState2LogicOp)
3227         TCU_THROW(NotSupportedError, "extendedDynamicState2LogicOp is not supported");
3228 
3229     if ((m_testConfig.testPatchControlPoints() || m_testConfig.useExtraDynPCPPipeline) &&
3230         !eds2Features.extendedDynamicState2PatchControlPoints)
3231         TCU_THROW(NotSupportedError, "extendedDynamicState2PatchControlPoints is not supported");
3232 
3233     if (m_testConfig.testVertexDynamic() && !viFeatures.vertexInputDynamicState)
3234         TCU_THROW(NotSupportedError, "vertexInputDynamicState is not supported");
3235 
3236 #ifndef CTS_USES_VULKANSC
3237     if ((m_testConfig.useMeshShaders || m_testConfig.bindUnusedMeshShadingPipeline) && !meshFeatures.meshShader)
3238         TCU_THROW(NotSupportedError, "meshShader is not supported");
3239 #endif // CTS_USES_VULKANSC
3240 
3241     // Check extension support.
3242     const auto requiredExtensions = m_testConfig.getRequiredExtensions();
3243     for (const auto &extension : requiredExtensions)
3244     {
3245         if (extension == "VK_KHR_or_EXT_line_rasterization")
3246         {
3247             if (!context.isDeviceFunctionalitySupported("VK_KHR_line_rasterization") &&
3248                 !context.isDeviceFunctionalitySupported("VK_EXT_line_rasterization"))
3249             {
3250                 TCU_THROW(NotSupportedError,
3251                           "VK_KHR_line_rasterization and VK_EXT_line_rasterization are not supported");
3252             }
3253         }
3254         else
3255         {
3256             context.requireDeviceFunctionality(extension);
3257         }
3258     }
3259 
3260     // Check support needed for the vertex generators.
3261     m_testConfig.vertexGenerator.staticValue->checkSupport(context);
3262     if (m_testConfig.vertexGenerator.dynamicValue)
3263         m_testConfig.vertexGenerator.dynamicValue.get()->checkSupport(context);
3264 
3265     // Special requirement for rasterizationSamples tests.
3266     // The first iteration of these tests puts the pipeline in a mixed samples state,
3267     // where colorCount != rasterizationSamples.
3268     if (m_testConfig.rasterizationSamplesConfig.dynamicValue &&
3269         (m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
3270          m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC) &&
3271         !context.isDeviceFunctionalitySupported("VK_AMD_mixed_attachment_samples") &&
3272         !context.isDeviceFunctionalitySupported("VK_NV_framebuffer_mixed_samples"))
3273 
3274         TCU_THROW(NotSupportedError,
3275                   "VK_AMD_mixed_attachment_samples or VK_NV_framebuffer_mixed_samples are not supported");
3276 
3277     if (m_testConfig.rasterizationSamplesConfig.dynamicValue &&
3278         (m_testConfig.sequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
3279          m_testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
3280          m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC || m_testConfig.isReversed()) &&
3281         (context.isDeviceFunctionalitySupported("VK_AMD_mixed_attachment_samples") ||
3282          context.isDeviceFunctionalitySupported("VK_NV_framebuffer_mixed_samples")))
3283 
3284         TCU_THROW(NotSupportedError,
3285                   "Test not supported with VK_AMD_mixed_attachment_samples or VK_NV_framebuffer_mixed_samples");
3286 
3287     // Check the number of viewports needed and the corresponding limits.
3288     const auto &viewportConfig = m_testConfig.viewportConfig;
3289     auto numViewports          = viewportConfig.staticValue.size();
3290 
3291     if (viewportConfig.dynamicValue)
3292         numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
3293 
3294     if (numViewports > 1)
3295     {
3296         const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
3297         if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
3298             TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
3299     }
3300 
3301     const auto &dbTestEnable = m_testConfig.depthBoundsTestEnableConfig;
3302     const bool useDepthBounds =
3303         (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
3304 
3305     if (useDepthBounds || m_testConfig.needsGeometryShader() || m_testConfig.needsTessellation() ||
3306         m_testConfig.needsDepthBiasClampFeature())
3307     {
3308         const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
3309 
3310         // Check depth bounds test support.
3311         if (useDepthBounds && !features.depthBounds)
3312             TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
3313 
3314         // Check geometry shader support.
3315         if (m_testConfig.needsGeometryShader() && !features.geometryShader)
3316             TCU_THROW(NotSupportedError, "Geometry shader not supported");
3317 
3318         // Check tessellation support
3319         if (m_testConfig.needsTessellation() && !features.tessellationShader)
3320             TCU_THROW(NotSupportedError, "Tessellation feature not supported");
3321 
3322         // Check depth bias clamp feature.
3323         if (m_testConfig.needsDepthBiasClampFeature() && !features.depthBiasClamp)
3324             TCU_THROW(NotSupportedError, "Depth bias clamp not supported");
3325     }
3326 
3327     // Check color image format support (depth/stencil will be chosen and checked at runtime).
3328     {
3329         const auto colorFormat      = m_testConfig.colorFormat();
3330         const auto colorSampleCount = m_testConfig.getColorSampleCount();
3331         const auto colorImageInfo =
3332             makeImageCreateInfo(colorFormat, kFramebufferExtent, colorSampleCount, kColorUsage, 0u);
3333 
3334         vk::VkImageFormatProperties formatProps;
3335         const auto result = vki.getPhysicalDeviceImageFormatProperties(
3336             physicalDevice, colorImageInfo.format, colorImageInfo.imageType, colorImageInfo.tiling,
3337             colorImageInfo.usage, colorImageInfo.flags, &formatProps);
3338 
3339         if (result != vk::VK_SUCCESS)
3340             TCU_THROW(NotSupportedError, "Required color image features not supported");
3341 
3342         if ((formatProps.sampleCounts & colorSampleCount) != colorSampleCount)
3343             TCU_THROW(NotSupportedError, "Required color sample count not supported");
3344 
3345         // If blending is active, we need to check support explicitly.
3346         if (m_testConfig.getActiveColorBlendEnable())
3347         {
3348             const auto colorFormatProps = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, colorFormat);
3349             DE_ASSERT(colorImageInfo.tiling == vk::VK_IMAGE_TILING_OPTIMAL);
3350             if (!(colorFormatProps.optimalTilingFeatures & vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT))
3351                 TCU_THROW(NotSupportedError, "Color format does not support blending");
3352         }
3353     }
3354 
3355     // Extended dynamic state 3 features.
3356     if (m_testConfig.needsEDS3())
3357     {
3358 #ifndef CTS_USES_VULKANSC
3359         const auto &eds3Features = context.getExtendedDynamicState3FeaturesEXT();
3360 
3361         if (m_testConfig.testTessellationDomainOrigin() && !eds3Features.extendedDynamicState3TessellationDomainOrigin)
3362             TCU_THROW(NotSupportedError, "extendedDynamicState3TessellationDomainOrigin not supported");
3363 
3364         if (m_testConfig.depthClampEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3DepthClampEnable)
3365             TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClampEnable not supported");
3366 
3367         if (m_testConfig.polygonModeConfig.dynamicValue && !eds3Features.extendedDynamicState3PolygonMode)
3368             TCU_THROW(NotSupportedError, "extendedDynamicState3PolygonMode not supported");
3369 
3370         if (m_testConfig.sampleMaskConfig.dynamicValue && !eds3Features.extendedDynamicState3SampleMask)
3371             TCU_THROW(NotSupportedError, "extendedDynamicState3SampleMask not supported");
3372 
3373         if (m_testConfig.alphaToCoverageConfig.dynamicValue && !eds3Features.extendedDynamicState3AlphaToCoverageEnable)
3374             TCU_THROW(NotSupportedError, "extendedDynamicState3AlphaToCoverageEnable not supported");
3375 
3376         if (m_testConfig.alphaToOneConfig.dynamicValue && !eds3Features.extendedDynamicState3AlphaToOneEnable)
3377             TCU_THROW(NotSupportedError, "extendedDynamicState3AlphaToOneEnable not supported");
3378 
3379         if (m_testConfig.colorWriteMaskConfig.dynamicValue && !eds3Features.extendedDynamicState3ColorWriteMask)
3380             TCU_THROW(NotSupportedError, "extendedDynamicState3ColorWriteMask not supported");
3381 
3382         if (m_testConfig.rasterizationStreamConfig.dynamicValue &&
3383             !eds3Features.extendedDynamicState3RasterizationStream)
3384             TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationStream not supported");
3385 
3386         if (m_testConfig.logicOpEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3LogicOpEnable)
3387             TCU_THROW(NotSupportedError, "extendedDynamicState3LogicOpEnable not supported");
3388 
3389         if (m_testConfig.colorBlendEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3ColorBlendEnable)
3390             TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendEnable not supported");
3391 
3392         if (m_testConfig.colorBlendEquationConfig.dynamicValue)
3393         {
3394             const auto isAdvanced = m_testConfig.colorBlendEquationConfig.staticValue.isAdvanced();
3395 
3396             if (isAdvanced || m_testConfig.colorBlendBoth || m_testConfig.nullStaticColorBlendAttPtr)
3397             {
3398                 if (!eds3Features.extendedDynamicState3ColorBlendAdvanced)
3399                     TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendAdvanced not supported");
3400             }
3401 
3402             if (!isAdvanced || m_testConfig.colorBlendBoth)
3403             {
3404                 if (!eds3Features.extendedDynamicState3ColorBlendEquation)
3405                     TCU_THROW(NotSupportedError, "extendedDynamicState3ColorBlendEquation not supported");
3406             }
3407         }
3408 
3409         if (m_testConfig.provokingVertexConfig.dynamicValue && !eds3Features.extendedDynamicState3ProvokingVertexMode)
3410             TCU_THROW(NotSupportedError, "extendedDynamicState3ProvokingVertexMode not supported");
3411 
3412         if (m_testConfig.negativeOneToOneConfig.dynamicValue &&
3413             !eds3Features.extendedDynamicState3DepthClipNegativeOneToOne)
3414             TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClipNegativeOneToOne not supported");
3415 
3416         if (m_testConfig.depthClipEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3DepthClipEnable)
3417             TCU_THROW(NotSupportedError, "extendedDynamicState3DepthClipEnable not supported");
3418 
3419         if (m_testConfig.lineStippleEnableConfig.dynamicValue && !eds3Features.extendedDynamicState3LineStippleEnable)
3420             TCU_THROW(NotSupportedError, "extendedDynamicState3LineStippleEnable not supported");
3421 
3422         if (m_testConfig.sampleLocationsEnableConfig.dynamicValue &&
3423             !eds3Features.extendedDynamicState3SampleLocationsEnable)
3424             TCU_THROW(NotSupportedError, "extendedDynamicState3SampleLocationsEnable not supported");
3425 
3426         if (m_testConfig.conservativeRasterModeConfig.dynamicValue &&
3427             !eds3Features.extendedDynamicState3ConservativeRasterizationMode)
3428             TCU_THROW(NotSupportedError, "extendedDynamicState3ConservativeRasterizationMode not supported");
3429 
3430         if (m_testConfig.extraPrimitiveOverEstConfig.dynamicValue &&
3431             !eds3Features.extendedDynamicState3ExtraPrimitiveOverestimationSize)
3432             TCU_THROW(NotSupportedError, "extendedDynamicState3ExtraPrimitiveOverestimationSize not supported");
3433 
3434         if (m_testConfig.lineRasterModeConfig.dynamicValue && !eds3Features.extendedDynamicState3LineRasterizationMode)
3435             TCU_THROW(NotSupportedError, "extendedDynamicState3LineRasterizationMode not supported");
3436 
3437         if (m_testConfig.coverageToColorEnableConfig.dynamicValue &&
3438             !eds3Features.extendedDynamicState3CoverageToColorEnable)
3439             TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageToColorEnable not supported");
3440 
3441         if (m_testConfig.coverageToColorLocationConfig.dynamicValue &&
3442             !eds3Features.extendedDynamicState3CoverageToColorLocation)
3443             TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageToColorLocation not supported");
3444 
3445         if (m_testConfig.coverageModulationModeConfig.dynamicValue &&
3446             !eds3Features.extendedDynamicState3CoverageModulationMode)
3447             TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationMode not supported");
3448 
3449         if (m_testConfig.coverageModTableEnableConfig.dynamicValue &&
3450             !eds3Features.extendedDynamicState3CoverageModulationTableEnable)
3451             TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationTableEnable not supported");
3452 
3453         if (m_testConfig.coverageModTableConfig.dynamicValue &&
3454             !eds3Features.extendedDynamicState3CoverageModulationTable)
3455             TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageModulationTable not supported");
3456 
3457         if (m_testConfig.coverageReductionModeConfig.dynamicValue)
3458         {
3459             if (!eds3Features.extendedDynamicState3CoverageReductionMode)
3460                 TCU_THROW(NotSupportedError, "extendedDynamicState3CoverageReductionMode not supported");
3461 
3462             uint32_t combinationCount = 0U;
3463             auto result               = vki.getPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(
3464                 physicalDevice, &combinationCount, nullptr);
3465             if (result != vk::VK_SUCCESS || combinationCount == 0U)
3466                 TCU_THROW(
3467                     NotSupportedError,
3468                     "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV supported no combinations");
3469 
3470             const vk::VkFramebufferMixedSamplesCombinationNV defaultCombination = vk::initVulkanStructure();
3471             std::vector<vk::VkFramebufferMixedSamplesCombinationNV> combinations(combinationCount, defaultCombination);
3472             result = vki.getPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(
3473                 physicalDevice, &combinationCount, combinations.data());
3474             if (result != vk::VK_SUCCESS)
3475                 TCU_THROW(
3476                     NotSupportedError,
3477                     "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV supported no combinations");
3478 
3479             auto findCombination = [&](vk::VkCoverageReductionModeNV const coverageReductionMode) -> bool
3480             {
3481                 for (uint32_t i = 0U; i < combinationCount; ++i)
3482                 {
3483                     if (combinations[i].rasterizationSamples == m_testConfig.rasterizationSamplesConfig.staticValue &&
3484                         combinations[i].colorSamples == m_testConfig.getColorSampleCount() &&
3485                         combinations[i].coverageReductionMode == coverageReductionMode)
3486                     {
3487                         return true;
3488                     }
3489                 }
3490                 return false;
3491             };
3492             if (!findCombination(m_testConfig.coverageReductionModeConfig.staticValue) ||
3493                 !findCombination(m_testConfig.coverageReductionModeConfig.dynamicValue.get()))
3494                 TCU_THROW(
3495                     NotSupportedError,
3496                     "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV no matching combination found");
3497         }
3498 
3499         if (m_testConfig.viewportSwizzleConfig.dynamicValue && !eds3Features.extendedDynamicState3ViewportSwizzle)
3500             TCU_THROW(NotSupportedError, "extendedDynamicState3ViewportSwizzle not supported");
3501 
3502         if (m_testConfig.shadingRateImageEnableConfig.dynamicValue &&
3503             !eds3Features.extendedDynamicState3ShadingRateImageEnable)
3504             TCU_THROW(NotSupportedError, "extendedDynamicState3ShadingRateImageEnable not supported");
3505 
3506         if (m_testConfig.viewportWScalingEnableConfig.dynamicValue &&
3507             !eds3Features.extendedDynamicState3ViewportWScalingEnable)
3508             TCU_THROW(NotSupportedError, "extendedDynamicState3ViewportWScalingEnable not supported");
3509 
3510         if (m_testConfig.reprFragTestEnableConfig.dynamicValue &&
3511             !eds3Features.extendedDynamicState3RepresentativeFragmentTestEnable)
3512             TCU_THROW(NotSupportedError, "extendedDynamicState3RepresentativeFragmentTestEnable not supported");
3513 
3514         if (m_testConfig.rasterizationSamplesConfig.dynamicValue &&
3515             !eds3Features.extendedDynamicState3RasterizationSamples)
3516             TCU_THROW(NotSupportedError, "extendedDynamicState3RasterizationSamples not supported");
3517 #else
3518         TCU_THROW(NotSupportedError, "VulkanSC does not support extended dynamic state 3");
3519 #endif // CTS_USES_VULKANSC
3520     }
3521 
3522     if (m_testConfig.getActivePolygonMode() != vk::VK_POLYGON_MODE_FILL)
3523         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FILL_MODE_NON_SOLID);
3524 
3525     if (m_testConfig.getActiveAlphaToOne())
3526         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_ALPHA_TO_ONE);
3527 
3528     if (m_testConfig.rasterizationStreamStruct() || static_cast<bool>(m_testConfig.shaderRasterizationStream))
3529     {
3530 #ifndef CTS_USES_VULKANSC
3531         const auto &xfProperties = context.getTransformFeedbackPropertiesEXT();
3532         if (!xfProperties.transformFeedbackRasterizationStreamSelect)
3533             TCU_THROW(NotSupportedError, "transformFeedbackRasterizationStreamSelect not supported");
3534 
3535         // VUID-RuntimeSpirv-Stream-06312
3536         if (static_cast<bool>(m_testConfig.shaderRasterizationStream))
3537         {
3538             const auto shaderStreamId = m_testConfig.shaderRasterizationStream.get();
3539             if (shaderStreamId >= xfProperties.maxTransformFeedbackStreams)
3540                 TCU_THROW(NotSupportedError,
3541                           "Geometry shader rasterization stream above maxTransformFeedbackStreams limit");
3542         }
3543 
3544         // VUID-VkPipelineRasterizationStateStreamCreateInfoEXT-rasterizationStream-02325
3545         if (static_cast<bool>(m_testConfig.rasterizationStreamConfig.staticValue))
3546         {
3547             const auto staticStreamId = m_testConfig.rasterizationStreamConfig.staticValue.get();
3548             if (staticStreamId >= xfProperties.maxTransformFeedbackStreams)
3549                 TCU_THROW(NotSupportedError, "Static stream number above maxTransformFeedbackStreams limit");
3550         }
3551         if (static_cast<bool>(m_testConfig.rasterizationStreamConfig.dynamicValue &&
3552                               static_cast<bool>(m_testConfig.rasterizationStreamConfig.dynamicValue.get())))
3553         {
3554             const auto dynamicStreamId = m_testConfig.rasterizationStreamConfig.dynamicValue->get();
3555             if (dynamicStreamId >= xfProperties.maxTransformFeedbackStreams)
3556                 TCU_THROW(NotSupportedError, "Dynamic stream number above maxTransformFeedbackStreams limit");
3557         }
3558 #else
3559         TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_transform_feedback");
3560 #endif // CTS_USES_VULKANSC
3561     }
3562 
3563     if (m_testConfig.lineRasterizationExt())
3564     {
3565         // Check the implementation supports some type of stippled line.
3566         const auto &lineRastFeatures = context.getLineRasterizationFeatures();
3567         const auto rasterMode = selectLineRasterizationMode(lineRastFeatures, m_testConfig.lineStippleSupportRequired(),
3568                                                             m_testConfig.lineRasterModeConfig.staticValue);
3569 
3570         if (rasterMode == LineRasterizationMode::NONE)
3571             TCU_THROW(NotSupportedError, "Wanted static line rasterization mode not supported");
3572 
3573         if (static_cast<bool>(m_testConfig.lineRasterModeConfig.dynamicValue) &&
3574             static_cast<bool>(m_testConfig.lineRasterModeConfig.dynamicValue.get()))
3575         {
3576             const auto dynRasterMode =
3577                 selectLineRasterizationMode(lineRastFeatures, m_testConfig.lineStippleSupportRequired(),
3578                                             m_testConfig.lineRasterModeConfig.dynamicValue.get());
3579 
3580             if (dynRasterMode == LineRasterizationMode::NONE)
3581                 TCU_THROW(NotSupportedError, "Wanted dynamic line rasterization mode not supported");
3582         }
3583     }
3584 
3585     const auto hasMaxPrimitiveOverestimationSize = static_cast<bool>(m_testConfig.maxPrimitiveOverestimationSize);
3586 
3587     if (m_testConfig.conservativeRasterStruct() || hasMaxPrimitiveOverestimationSize)
3588     {
3589         const auto &conservativeRasterModeProps = context.getConservativeRasterizationPropertiesEXT();
3590 
3591         if (m_testConfig.getActiveConservativeRasterMode() ==
3592                 vk::VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT &&
3593             !conservativeRasterModeProps.primitiveUnderestimation)
3594             TCU_THROW(NotSupportedError, "primitiveUnderestimation not supported");
3595 
3596         const auto extraSize = m_testConfig.getActiveExtraPrimitiveOverEstSize();
3597         const auto &maxExtra = conservativeRasterModeProps.maxExtraPrimitiveOverestimationSize;
3598 
3599         if (extraSize >= 0.0f && extraSize > maxExtra)
3600         {
3601             std::ostringstream msg;
3602             msg << "Extra primitive overestimation size (" << extraSize
3603                 << ") above maxExtraPrimitiveOverestimationSize (" << maxExtra << ")";
3604             TCU_THROW(NotSupportedError, msg.str());
3605         }
3606 
3607         if (hasMaxPrimitiveOverestimationSize)
3608         {
3609             const auto maxPrimitiveOverestimationSizeVal = m_testConfig.maxPrimitiveOverestimationSize.get();
3610             if (conservativeRasterModeProps.primitiveOverestimationSize > maxPrimitiveOverestimationSizeVal)
3611             {
3612                 std::ostringstream msg;
3613                 msg << "primitiveOverestimationSize (" << conservativeRasterModeProps.primitiveOverestimationSize
3614                     << ") too big for this test (max " << maxPrimitiveOverestimationSizeVal << ")";
3615                 TCU_THROW(NotSupportedError, msg.str());
3616             }
3617         }
3618     }
3619 
3620     if (m_testConfig.useFragShaderAtomics())
3621         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_FRAGMENT_STORES_AND_ATOMICS);
3622 
3623 #ifndef CTS_USES_VULKANSC
3624     if (m_testConfig.depthBiasReprInfo)
3625     {
3626         const auto &reprInfo    = m_testConfig.depthBiasReprInfo.get();
3627         const auto &dbcFeatures = context.getDepthBiasControlFeaturesEXT();
3628 
3629         if (reprInfo.depthBiasExact && !dbcFeatures.depthBiasExact)
3630             TCU_THROW(NotSupportedError, "depthBiasExact not supported");
3631 
3632         if (reprInfo.depthBiasRepresentation ==
3633                 vk::VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT &&
3634             !dbcFeatures.leastRepresentableValueForceUnormRepresentation)
3635         {
3636             TCU_THROW(NotSupportedError, "leastRepresentableValueForceUnormRepresentation not supported");
3637         }
3638 
3639         if (reprInfo.depthBiasRepresentation == vk::VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT &&
3640             !dbcFeatures.floatRepresentation)
3641             TCU_THROW(NotSupportedError, "floatRepresentation not supported");
3642     }
3643 #else
3644     TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_depth_bias_control");
3645 #endif // CTS_USES_VULKANSC
3646 
3647     if (m_testConfig.getActiveLineWidth() != 1.0f)
3648         context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_WIDE_LINES);
3649 
3650     if (m_testConfig.favorStaticNullPointers)
3651     {
3652         if (m_testConfig.primRestartEnableConfig.dynamicValue && m_testConfig.topologyConfig.dynamicValue)
3653         {
3654 #ifndef CTS_USES_VULKANSC
3655             const auto &eds3Properties = context.getExtendedDynamicState3PropertiesEXT();
3656             if (!eds3Properties.dynamicPrimitiveTopologyUnrestricted)
3657                 TCU_THROW(NotSupportedError, "dynamicPrimitiveTopologyUnrestricted not supported");
3658 #else
3659             TCU_THROW(NotSupportedError, "VulkanSC does not support VK_EXT_extended_dynamic_state3");
3660 #endif // CTS_USES_VULKANSC
3661         }
3662     }
3663 
3664     if (m_testConfig.sampleShadingEnable && !baseFeatures.sampleRateShading)
3665         TCU_THROW(NotSupportedError, "sampleRateShading not supported");
3666 
3667     checkPipelineConstructionRequirements(vki, physicalDevice, m_testConfig.pipelineConstructionType);
3668 }
3669 
initPrograms(vk::SourceCollections & programCollection) const3670 void ExtendedDynamicStateTest::initPrograms(vk::SourceCollections &programCollection) const
3671 {
3672     const vk::ShaderBuildOptions meshBuildOptions(programCollection.usedVulkanVersion, vk::SPIRV_VERSION_1_4, 0u, true);
3673 
3674     std::ostringstream pushSource;
3675     std::ostringstream fragOutputLocationStream;
3676     std::ostringstream vertSourceTemplateStream;
3677     std::ostringstream fragSourceTemplateStream;
3678     std::ostringstream geomSource;
3679     std::ostringstream tescSource;
3680     std::ostringstream teseSource;
3681     std::ostringstream meshSourceTemplateStream;
3682 
3683     pushSource << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
3684                << "    vec4  triangleColor;\n"
3685                << "    float depthValue;\n"
3686                << "    int   viewPortIndex;\n"
3687                << "    float scaleX;\n"
3688                << "    float scaleY;\n"
3689                << "    float offsetX;\n"
3690                << "    float offsetY;\n"
3691                << "    float stripScale;\n"
3692                << "} pushConstants;\n";
3693     const auto pushConstants = pushSource.str();
3694 
3695     const bool useAttIndex = m_testConfig.dualSrcBlend;
3696     for (uint32_t refIdx = 0; refIdx < m_testConfig.colorAttachmentCount; ++refIdx)
3697     {
3698         const bool used           = (refIdx == m_testConfig.colorAttachmentCount - 1u);
3699         const std::string attName = (used ? "color" : "unused" + std::to_string(refIdx));
3700         const uint32_t indexCount = (useAttIndex ? 2u : 1u);
3701 
3702         for (uint32_t attIdx = 0u; attIdx < indexCount; ++attIdx)
3703         {
3704             const auto idxStr            = std::to_string(attIdx);
3705             const std::string indexDecl  = (useAttIndex ? (", index=" + idxStr) : "");
3706             const std::string nameSuffix = ((attIdx > 0u) ? idxStr : "");
3707 
3708             fragOutputLocationStream << "layout(location=" << refIdx << indexDecl << ") out ${OUT_COLOR_VTYPE} "
3709                                      << attName << nameSuffix << ";\n";
3710         }
3711     }
3712     const auto fragOutputLocations = fragOutputLocationStream.str();
3713 
3714     // The actual generator, attributes and calculations.
3715     const auto topology    = m_testConfig.topologyClass();
3716     const auto activeGen   = m_testConfig.getActiveVertexGenerator();
3717     const auto attribDecls = activeGen->getAttributeDeclarations();
3718     const auto coordCalcs  = activeGen->getVertexCoordCalc();
3719     const auto descDeclsV =
3720         (m_testConfig.useMeshShaders ? activeGen->getDescriptorDeclarations() : std::vector<std::string>());
3721     const auto descCalcsV =
3722         (m_testConfig.useMeshShaders ? activeGen->getDescriptorCoordCalc(topology) : std::vector<std::string>());
3723     const auto fragInputs = activeGen->getFragInputAttributes();
3724     const auto fragCalcs  = activeGen->getFragOutputCalc();
3725     const auto glslExts   = activeGen->getGLSLExtensions();
3726 
3727     // The static generator, attributes and calculations, for the static pipeline, if needed.
3728     const auto inactiveGen      = m_testConfig.getInactiveVertexGenerator();
3729     const auto staticAttribDec  = inactiveGen->getAttributeDeclarations();
3730     const auto staticCoordCalc  = inactiveGen->getVertexCoordCalc();
3731     const auto staticFragInputs = inactiveGen->getFragInputAttributes();
3732     const auto staticFragCalcs  = inactiveGen->getFragOutputCalc();
3733     const auto staticGlslExts   = inactiveGen->getGLSLExtensions();
3734 
3735     std::ostringstream activeAttribs;
3736     std::ostringstream activeCalcs;
3737     std::ostringstream activeFragInputs;
3738     std::ostringstream activeFragCalcs;
3739     std::ostringstream activeExts;
3740     std::ostringstream inactiveAttribs;
3741     std::ostringstream inactiveCalcs;
3742     std::ostringstream descDecls;
3743     std::ostringstream descCalcs;
3744     std::ostringstream inactiveFragInputs;
3745     std::ostringstream inactiveFragCalcs;
3746     std::ostringstream inactiveExts;
3747 
3748     for (const auto &decl : attribDecls)
3749         activeAttribs << decl << "\n";
3750 
3751     for (const auto &statement : coordCalcs)
3752         activeCalcs << "    " << statement << "\n";
3753 
3754     for (const auto &decl : staticAttribDec)
3755         inactiveAttribs << decl << "\n";
3756 
3757     for (const auto &statement : staticCoordCalc)
3758         inactiveCalcs << "    " << statement << "\n";
3759 
3760     for (const auto &decl : descDeclsV)
3761         descDecls << decl << "\n";
3762 
3763     for (const auto &calc : descCalcsV)
3764         descCalcs << "    " << calc << "\n";
3765 
3766     for (const auto &decl : fragInputs)
3767         activeFragInputs << decl << "\n";
3768 
3769     for (const auto &statement : fragCalcs)
3770         activeFragCalcs << "    " << statement << "\n";
3771 
3772     for (const auto &decl : staticFragInputs)
3773         inactiveFragInputs << decl << "\n";
3774 
3775     for (const auto &statement : staticFragCalcs)
3776         inactiveFragCalcs << "    " << statement << "\n";
3777 
3778     for (const auto &ext : glslExts)
3779         activeExts << ext << "\n";
3780 
3781     for (const auto &ext : staticGlslExts)
3782         inactiveExts << ext << "\n";
3783 
3784     vertSourceTemplateStream
3785         << "#version 450\n"
3786         << "${EXTENSIONS}" << pushConstants << "${ATTRIBUTES}"
3787         << "out gl_PerVertex\n"
3788         << "{\n"
3789         << "    vec4 gl_Position;\n"
3790         << "};\n"
3791         << "void main() {\n"
3792         << "${CALCULATIONS}"
3793         << "    gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * "
3794            "pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
3795         << "    vec2 stripOffset;\n"
3796         << "    switch (gl_VertexIndex) {\n"
3797         << "    case 0: stripOffset = vec2(0.0, 0.0); break;\n"
3798         << "    case 1: stripOffset = vec2(0.0, 1.0); break;\n"
3799         << "    case 2: stripOffset = vec2(1.0, 0.0); break;\n"
3800         << "    case 3: stripOffset = vec2(1.0, 1.0); break;\n"
3801         << "    case 4: stripOffset = vec2(2.0, 0.0); break;\n"
3802         << "    case 5: stripOffset = vec2(2.0, 1.0); break;\n"
3803         << "    default: stripOffset = vec2(-1000.0); break;\n"
3804         << "    }\n"
3805         << "    gl_Position.xy += pushConstants.stripScale * stripOffset;\n"
3806         << "}\n";
3807 
3808     tcu::StringTemplate vertSourceTemplate(vertSourceTemplateStream.str());
3809 
3810     const auto colorFormat  = m_testConfig.colorFormat();
3811     const auto vecType      = (vk::isUnormFormat(colorFormat) ? "vec4" : "uvec4");
3812     const auto fragSetIndex = std::to_string(m_testConfig.getFragDescriptorSetIndex());
3813     const auto fragAtomics  = m_testConfig.useFragShaderAtomics();
3814 
3815     fragSourceTemplateStream
3816         << "#version 450\n"
3817         << (m_testConfig.representativeFragmentTest ? "layout(early_fragment_tests) in;\n" : "")
3818         << (fragAtomics ? "layout(set=" + fragSetIndex +
3819                               ", binding=0, std430) buffer AtomicBlock { uint fragCounter; } counterBuffer;\n" :
3820                           "")
3821         << pushConstants << fragOutputLocations << "${FRAG_INPUTS}"
3822         << "void main() {\n"
3823         << "    color = ${OUT_COLOR_VTYPE}"
3824         << (m_testConfig.dualSrcBlend ? de::toString(kOpaqueWhite) : "(pushConstants.triangleColor)") << ";\n";
3825 
3826     if (m_testConfig.dualSrcBlend)
3827     {
3828         fragSourceTemplateStream << "    color1 = ${OUT_COLOR_VTYPE}(pushConstants.triangleColor);\n";
3829     }
3830 
3831     fragSourceTemplateStream << "${FRAG_CALCULATIONS}"
3832                              << (fragAtomics ? "    atomicAdd(counterBuffer.fragCounter, 1u);\n" : "")
3833                              << (m_testConfig.sampleShadingEnable ?
3834                                      "    uint sampleId = gl_SampleID;\n" :
3835                                      "") // Enable sample shading for shader objects by reading gl_SampleID
3836                              << "}\n";
3837 
3838     tcu::StringTemplate fragSourceTemplate(fragSourceTemplateStream.str());
3839 
3840     std::map<std::string, std::string> activeMap;
3841     std::map<std::string, std::string> inactiveMap;
3842 
3843     activeMap["ATTRIBUTES"]        = activeAttribs.str();
3844     activeMap["CALCULATIONS"]      = activeCalcs.str();
3845     activeMap["FRAG_INPUTS"]       = activeFragInputs.str();
3846     activeMap["FRAG_CALCULATIONS"] = activeFragCalcs.str();
3847     activeMap["EXTENSIONS"]        = activeExts.str();
3848     activeMap["OUT_COLOR_VTYPE"]   = vecType;
3849 
3850     inactiveMap["ATTRIBUTES"]        = inactiveAttribs.str();
3851     inactiveMap["CALCULATIONS"]      = inactiveCalcs.str();
3852     inactiveMap["FRAG_INPUTS"]       = inactiveFragInputs.str();
3853     inactiveMap["FRAG_CALCULATIONS"] = inactiveFragCalcs.str();
3854     inactiveMap["EXTENSIONS"]        = inactiveExts.str();
3855     inactiveMap["OUT_COLOR_VTYPE"]   = vecType;
3856 
3857     const auto activeVertSource   = vertSourceTemplate.specialize(activeMap);
3858     const auto activeFragSource   = fragSourceTemplate.specialize(activeMap);
3859     const auto inactiveVertSource = vertSourceTemplate.specialize(inactiveMap);
3860     const auto inactiveFragSource = fragSourceTemplate.specialize(inactiveMap);
3861 
3862     if (m_testConfig.needsGeometryShader())
3863     {
3864         const auto topologyClass          = getTopologyClass(m_testConfig.topologyConfig.staticValue);
3865         const std::string inputPrimitive  = ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
3866         const uint32_t vertexCount        = ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
3867         const std::string outputPrimitive = ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
3868         const auto selectStream           = static_cast<bool>(m_testConfig.shaderRasterizationStream);
3869         const auto streamNumber           = (selectStream ? m_testConfig.shaderRasterizationStream.get() : 0u);
3870         const auto streamNumberStr        = de::toString(streamNumber);
3871 
3872         geomSource << "#version 450\n"
3873                    << "layout (" << inputPrimitive << ") in;\n"
3874                    << "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
3875                    << (m_testConfig.isMultiViewport() ? pushConstants : "")
3876                    << (selectStream ? "layout (stream=" + streamNumberStr + ") out;\n" : "") << "in gl_PerVertex\n"
3877                    << "{\n"
3878                    << "    vec4 gl_Position;\n"
3879                    << "} gl_in[" << vertexCount << "];\n"
3880                    << "out gl_PerVertex\n"
3881                    << "{\n"
3882                    << "    vec4 gl_Position;\n"
3883                    << "};\n"
3884                    << "void main() {\n"
3885                    << (m_testConfig.isMultiViewport() ? "    gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "");
3886 
3887         for (uint32_t i = 0; i < vertexCount; ++i)
3888         {
3889             geomSource << "    gl_Position = gl_in[" << i << "].gl_Position;\n"
3890                        << "    " << (selectStream ? ("EmitStreamVertex(" + streamNumberStr + ")") : "EmitVertex()")
3891                        << ";\n";
3892         }
3893 
3894         geomSource << "}\n";
3895     }
3896 
3897     if (m_testConfig.needsTessellation())
3898     {
3899         tescSource << "#version 450\n"
3900                    << "#extension GL_EXT_tessellation_shader : require\n"
3901                    << "layout(vertices=3) out;\n"
3902                    << "in gl_PerVertex\n"
3903                    << "{\n"
3904                    << "    vec4 gl_Position;\n"
3905                    << "} gl_in[gl_MaxPatchVertices];\n"
3906                    << "out gl_PerVertex\n"
3907                    << "{\n"
3908                    << "  vec4 gl_Position;\n"
3909                    << "} gl_out[];\n"
3910                    << "void main() {\n"
3911                    << "  gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
3912                    << "  gl_TessLevelOuter[0] = 3.0;\n"
3913                    << "  gl_TessLevelOuter[1] = 3.0;\n"
3914                    << "  gl_TessLevelOuter[2] = 3.0;\n"
3915                    << "  gl_TessLevelInner[0] = 3.0;\n"
3916                    << "}\n";
3917         teseSource << "#version 450\n"
3918                    << "#extension GL_EXT_tessellation_shader : require\n"
3919                    << "layout(triangles) in;\n"
3920                    << "in gl_PerVertex\n"
3921                    << "{\n"
3922                    << "  vec4 gl_Position;\n"
3923                    << "} gl_in[gl_MaxPatchVertices];\n"
3924                    << "out gl_PerVertex\n"
3925                    << "{\n"
3926                    << "  vec4 gl_Position;\n"
3927                    << "};\n"
3928                    << "void main() {\n"
3929                    << "  gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
3930                    << "                 gl_in[1].gl_Position * gl_TessCoord.y + \n"
3931                    << "                 gl_in[2].gl_Position * gl_TessCoord.z);\n"
3932                    << "}\n";
3933     }
3934 
3935 #ifndef CTS_USES_VULKANSC
3936     if (m_testConfig.useMeshShaders)
3937     {
3938         DE_ASSERT(!m_testConfig.needsGeometryShader());
3939         DE_ASSERT(!m_testConfig.needsTessellation());
3940         //DE_ASSERT(!m_testConfig.needsIndexBuffer());
3941 
3942         // Make sure no dynamic states incompatible with mesh shading pipelines are used.
3943         DE_ASSERT(!m_testConfig.badMeshShadingPipelineDynState());
3944 
3945         // Shader below is designed to work with vertex buffers containing triangle strips as used by default.
3946         DE_ASSERT(m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ||
3947                   m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP);
3948         DE_ASSERT(!m_testConfig.singleVertex);
3949 
3950         std::string topologyStr;
3951         std::string indicesBuiltIn;
3952         std::string indicesVal;
3953         uint32_t maxVertices = 0u;
3954 
3955         switch (topology)
3956         {
3957         case TopologyClass::TRIANGLE:
3958             topologyStr    = "triangles";
3959             maxVertices    = 3u;
3960             indicesBuiltIn = "gl_PrimitiveTriangleIndicesEXT";
3961             indicesVal     = "uvec3(0, 1, 2)";
3962             break;
3963         case TopologyClass::LINE:
3964             topologyStr    = "lines";
3965             maxVertices    = 2u;
3966             indicesBuiltIn = "gl_PrimitiveLineIndicesEXT";
3967             indicesVal     = "uvec2(0, 1)";
3968             break;
3969         default:
3970             DE_ASSERT(false);
3971             break;
3972         }
3973 
3974         meshSourceTemplateStream
3975             << "#version 450\n"
3976             << "${EXTENSIONS}"
3977             << "#extension GL_EXT_mesh_shader : enable\n"
3978             << "layout(local_size_x=" << maxVertices << ", local_size_y=1, local_size_z=1) in;\n"
3979             << "layout(" << topologyStr << ") out;\n"
3980             << "layout(max_vertices=" << maxVertices << ", max_primitives=1) out;\n"
3981             << pushConstants
3982             << (m_testConfig.isMultiViewport() ?
3983                     "perprimitiveEXT out gl_MeshPerPrimitiveEXT { int gl_ViewportIndex; } gl_MeshPrimitivesEXT[];\n" :
3984                     "")
3985             << descDecls.str() << "void main() {\n"
3986             << descCalcs.str() << "    SetMeshOutputsEXT(" << maxVertices << "u, 1u);\n"
3987             << "    gl_MeshVerticesEXT[gl_LocalInvocationIndex].gl_Position = vec4(vertexCoords.x * "
3988                "pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + "
3989                "pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
3990             << "    if (gl_LocalInvocationIndex == 0u) {\n"
3991             << "        " << indicesBuiltIn << "[0] = " << indicesVal << ";\n"
3992             << (m_testConfig.isMultiViewport() ?
3993                     "        gl_MeshPrimitivesEXT[0].gl_ViewportIndex = pushConstants.viewPortIndex;\n" :
3994                     "")
3995             << "    }\n"
3996             << "}\n";
3997     }
3998 #endif // CTS_USES_VULKANSC
3999 
4000     // In reversed test configurations, the pipeline with dynamic state needs to have the inactive shader.
4001     const auto kReversed = m_testConfig.isReversed();
4002     programCollection.glslSources.add("dynamicVert")
4003         << glu::VertexSource(kReversed ? inactiveVertSource : activeVertSource);
4004     programCollection.glslSources.add("staticVert")
4005         << glu::VertexSource(kReversed ? activeVertSource : inactiveVertSource);
4006     programCollection.glslSources.add("dynamicFrag")
4007         << glu::FragmentSource(kReversed ? inactiveFragSource : activeFragSource);
4008     programCollection.glslSources.add("staticFrag")
4009         << glu::FragmentSource(kReversed ? activeFragSource : inactiveFragSource);
4010 
4011     if (m_testConfig.needsGeometryShader())
4012         programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
4013     if (m_testConfig.needsTessellation())
4014     {
4015         programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
4016         programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
4017     }
4018     if (m_testConfig.useMeshShaders)
4019     {
4020         tcu::StringTemplate meshSourceTemplate(meshSourceTemplateStream.str());
4021 
4022         const auto activeMeshSource   = meshSourceTemplate.specialize(activeMap);
4023         const auto inactiveMeshSource = meshSourceTemplate.specialize(inactiveMap);
4024 
4025         programCollection.glslSources.add("dynamicMesh")
4026             << glu::MeshSource(kReversed ? inactiveMeshSource : activeMeshSource) << meshBuildOptions;
4027         programCollection.glslSources.add("staticMesh")
4028             << glu::MeshSource(kReversed ? activeMeshSource : inactiveMeshSource) << meshBuildOptions;
4029     }
4030 
4031     if (m_testConfig.bindUnusedMeshShadingPipeline)
4032     {
4033         std::ostringstream meshNoOut;
4034         meshNoOut << "#version 450\n"
4035                   << "#extension GL_EXT_mesh_shader : enable\n"
4036                   << "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
4037                   << "layout(triangles) out;\n"
4038                   << "layout(max_vertices=3, max_primitives=1) out;\n"
4039                   << "void main() {\n"
4040                   << "    SetMeshOutputsEXT(0u, 0u);\n"
4041                   << "}\n";
4042         programCollection.glslSources.add("meshNoOut") << glu::MeshSource(meshNoOut.str()) << meshBuildOptions;
4043     }
4044 
4045     // Extra vert and frag shaders for the extra patch control points pipeline. These draw offscreen.
4046     if (m_testConfig.useExtraDynPCPPipeline || m_testConfig.useExtraDynPipeline)
4047     {
4048         std::ostringstream vertDPCP;
4049         vertDPCP
4050             << "#version 450\n"
4051             << "\n"
4052             << "vec2 positions[3] = vec2[](\n"
4053             << "    vec2(-1.0, -1.0),\n"
4054             << "    vec2( 3.0, -1.0),\n"
4055             << "    vec2(-1.0,  3.0)\n"
4056             << ");\n"
4057             << "\n"
4058             << "void main() {\n"
4059             << "    gl_Position = vec4(positions[gl_VertexIndex] + 10.0 + 1.0 * float(gl_VertexIndex), 0.0, 1.0);\n"
4060             << "}\n";
4061         programCollection.glslSources.add("vertDPCP") << glu::VertexSource(vertDPCP.str());
4062 
4063         std::ostringstream fragDPCP;
4064         fragDPCP << "#version 450\n"
4065                  << "layout(location=0) out " << vecType << " color;\n"
4066                  << "void main() {\n"
4067                  << "    color = " << vecType << "(1.0, 1.0, 1.0, 1.0);\n"
4068                  << "}\n";
4069         programCollection.glslSources.add("fragDPCP") << glu::FragmentSource(fragDPCP.str());
4070     }
4071 }
4072 
createInstance(Context & context) const4073 TestInstance *ExtendedDynamicStateTest::createInstance(Context &context) const
4074 {
4075     return new ExtendedDynamicStateInstance(context, m_testConfig);
4076 }
4077 
ExtendedDynamicStateInstance(Context & context,const TestConfig & testConfig)4078 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context &context, const TestConfig &testConfig)
4079     : vkt::TestInstance(context)
4080     , m_testConfig(testConfig)
4081 {
4082 }
4083 
4084 using BufferWithMemoryPtr = de::MovePtr<vk::BufferWithMemory>;
4085 
4086 struct VertexBufferInfo
4087 {
VertexBufferInfovkt::pipeline::__anon3cc04b6f0111::VertexBufferInfo4088     VertexBufferInfo() : buffer(), offset(0ull), dataSize(0ull)
4089     {
4090     }
4091 
VertexBufferInfovkt::pipeline::__anon3cc04b6f0111::VertexBufferInfo4092     VertexBufferInfo(VertexBufferInfo &&other)
4093         : buffer(other.buffer.release())
4094         , offset(other.offset)
4095         , dataSize(other.dataSize)
4096     {
4097     }
4098 
4099     BufferWithMemoryPtr buffer;
4100     vk::VkDeviceSize offset;
4101     vk::VkDeviceSize dataSize;
4102 };
4103 
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)4104 void logErrors(tcu::TestLog &log, const std::string &setName, const std::string &setDesc,
4105                const tcu::ConstPixelBufferAccess &result, const tcu::ConstPixelBufferAccess &errorMask)
4106 {
4107     log << tcu::TestLog::ImageSet(setName, setDesc) << tcu::TestLog::Image(setName + "Result", "Result image", result)
4108         << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
4109         << tcu::TestLog::EndImageSet;
4110 }
4111 
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)4112 void copyAndFlush(const vk::DeviceInterface &vkd, vk::VkDevice device, vk::BufferWithMemory &buffer, size_t offset,
4113                   const void *src, size_t size)
4114 {
4115     auto &alloc = buffer.getAllocation();
4116     auto dst    = reinterpret_cast<char *>(alloc.getHostPtr());
4117 
4118     deMemcpy(dst + offset, src, size);
4119     vk::flushAlloc(vkd, device, alloc);
4120 }
4121 
4122 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)4123 void setDynamicStates(const TestConfig &testConfig, const vk::DeviceInterface &vkd, vk::VkCommandBuffer cmdBuffer)
4124 {
4125     if (testConfig.lineWidthConfig.dynamicValue)
4126         vkd.cmdSetLineWidth(cmdBuffer, testConfig.lineWidthConfig.dynamicValue.get());
4127 
4128     if (testConfig.depthBoundsConfig.dynamicValue)
4129     {
4130         const auto &minMaxDepth = testConfig.depthBoundsConfig.dynamicValue.get();
4131         vkd.cmdSetDepthBounds(cmdBuffer, minMaxDepth.first, minMaxDepth.second);
4132     }
4133 
4134     if (testConfig.cullModeConfig.dynamicValue)
4135 #ifndef CTS_USES_VULKANSC
4136         vkd.cmdSetCullMode(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
4137 #else
4138         vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
4139 #endif // CTS_USES_VULKANSC
4140 
4141     if (testConfig.frontFaceConfig.dynamicValue)
4142 #ifndef CTS_USES_VULKANSC
4143         vkd.cmdSetFrontFace(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
4144 #else
4145         vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
4146 #endif // CTS_USES_VULKANSC
4147 
4148     if (testConfig.topologyConfig.dynamicValue)
4149 #ifndef CTS_USES_VULKANSC
4150         vkd.cmdSetPrimitiveTopology(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
4151 #else
4152         vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
4153 #endif // CTS_USES_VULKANSC
4154 
4155     if (testConfig.viewportConfig.dynamicValue)
4156     {
4157         const auto &viewports = testConfig.viewportConfig.dynamicValue.get();
4158 #ifndef CTS_USES_VULKANSC
4159         vkd.cmdSetViewportWithCount(cmdBuffer, static_cast<uint32_t>(viewports.size()), viewports.data());
4160 #else
4161         vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<uint32_t>(viewports.size()), viewports.data());
4162 #endif // CTS_USES_VULKANSC
4163     }
4164 
4165     if (testConfig.scissorConfig.dynamicValue)
4166     {
4167         const auto &scissors = testConfig.scissorConfig.dynamicValue.get();
4168 #ifndef CTS_USES_VULKANSC
4169         vkd.cmdSetScissorWithCount(cmdBuffer, static_cast<uint32_t>(scissors.size()), scissors.data());
4170 #else
4171         vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<uint32_t>(scissors.size()), scissors.data());
4172 #endif // CTS_USES_VULKANSC
4173     }
4174 
4175     if (testConfig.depthTestEnableConfig.dynamicValue)
4176 #ifndef CTS_USES_VULKANSC
4177         vkd.cmdSetDepthTestEnable(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
4178 #else
4179         vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
4180 #endif // CTS_USES_VULKANSC
4181 
4182     if (testConfig.depthWriteEnableConfig.dynamicValue)
4183 #ifndef CTS_USES_VULKANSC
4184         vkd.cmdSetDepthWriteEnable(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
4185 #else
4186         vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
4187 #endif // CTS_USES_VULKANSC
4188 
4189     if (testConfig.depthCompareOpConfig.dynamicValue)
4190 #ifndef CTS_USES_VULKANSC
4191         vkd.cmdSetDepthCompareOp(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
4192 #else
4193         vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
4194 #endif // CTS_USES_VULKANSC
4195 
4196     if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
4197 #ifndef CTS_USES_VULKANSC
4198         vkd.cmdSetDepthBoundsTestEnable(cmdBuffer,
4199                                         makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
4200 #else
4201         vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer,
4202                                            makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
4203 #endif // CTS_USES_VULKANSC
4204 
4205     if (testConfig.stencilTestEnableConfig.dynamicValue)
4206 #ifndef CTS_USES_VULKANSC
4207         vkd.cmdSetStencilTestEnable(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
4208 #else
4209         vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
4210 #endif // CTS_USES_VULKANSC
4211 
4212     if (testConfig.depthBiasEnableConfig.dynamicValue)
4213 #ifndef CTS_USES_VULKANSC
4214         vkd.cmdSetDepthBiasEnable(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
4215 #else
4216         vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
4217 #endif // CTS_USES_VULKANSC
4218 
4219     if (testConfig.depthBiasConfig.dynamicValue)
4220     {
4221         const auto &bias = testConfig.depthBiasConfig.dynamicValue.get();
4222 
4223 #ifndef CTS_USES_VULKANSC
4224         if (testConfig.depthBiasReprInfo && !testConfig.isReversed())
4225         {
4226             vk::VkDepthBiasInfoEXT depthBiasInfo  = vk::initVulkanStructureConst(&testConfig.depthBiasReprInfo.get());
4227             depthBiasInfo.depthBiasConstantFactor = bias.constantFactor;
4228             depthBiasInfo.depthBiasClamp          = bias.clamp;
4229 
4230             vkd.cmdSetDepthBias2EXT(cmdBuffer, &depthBiasInfo);
4231         }
4232         else
4233 #endif // CTS_USES_VULKANSC
4234         {
4235             vkd.cmdSetDepthBias(cmdBuffer, bias.constantFactor, bias.clamp, 0.0f);
4236         }
4237     }
4238 
4239     if (testConfig.rastDiscardEnableConfig.dynamicValue)
4240 #ifndef CTS_USES_VULKANSC
4241         vkd.cmdSetRasterizerDiscardEnable(cmdBuffer,
4242                                           makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
4243 #else
4244         vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer,
4245                                              makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
4246 #endif // CTS_USES_VULKANSC
4247 
4248     if (testConfig.primRestartEnableConfig.dynamicValue)
4249 #ifndef CTS_USES_VULKANSC
4250         vkd.cmdSetPrimitiveRestartEnable(cmdBuffer,
4251                                          makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
4252 #else
4253         vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer,
4254                                             makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
4255 #endif // CTS_USES_VULKANSC
4256 
4257     if (testConfig.logicOpConfig.dynamicValue)
4258         vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
4259 
4260     if (testConfig.patchControlPointsConfig.dynamicValue)
4261         vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
4262 
4263     if (testConfig.stencilOpConfig.dynamicValue)
4264     {
4265         for (const auto &params : testConfig.stencilOpConfig.dynamicValue.get())
4266 #ifndef CTS_USES_VULKANSC
4267             vkd.cmdSetStencilOp(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp,
4268                                 params.compareOp);
4269 #else
4270             vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp,
4271                                    params.compareOp);
4272 #endif // CTS_USES_VULKANSC
4273     }
4274 
4275     if (testConfig.vertexGenerator.dynamicValue)
4276     {
4277         const auto generator  = testConfig.vertexGenerator.dynamicValue.get();
4278         const auto bindings   = generator->getBindingDescriptions2(testConfig.strideConfig.staticValue);
4279         const auto attributes = generator->getAttributeDescriptions2();
4280 
4281         vkd.cmdSetVertexInputEXT(cmdBuffer, static_cast<uint32_t>(bindings.size()), de::dataOrNull(bindings),
4282                                  static_cast<uint32_t>(attributes.size()), de::dataOrNull(attributes));
4283     }
4284 
4285     if (testConfig.colorWriteEnableConfig.dynamicValue)
4286     {
4287         const std::vector<vk::VkBool32> colorWriteEnableValues(
4288             testConfig.colorAttachmentCount, makeVkBool32(testConfig.colorWriteEnableConfig.dynamicValue.get()));
4289         vkd.cmdSetColorWriteEnableEXT(cmdBuffer, de::sizeU32(colorWriteEnableValues),
4290                                       de::dataOrNull(colorWriteEnableValues));
4291     }
4292 
4293     if (testConfig.blendConstantsConfig.dynamicValue)
4294         vkd.cmdSetBlendConstants(cmdBuffer, testConfig.blendConstantsConfig.dynamicValue.get().data());
4295 
4296     if (testConfig.lineStippleParamsConfig.dynamicValue &&
4297         static_cast<bool>(testConfig.lineStippleParamsConfig.dynamicValue.get()))
4298     {
4299         const auto &stippleParams = testConfig.lineStippleParamsConfig.dynamicValue->get();
4300         vkd.cmdSetLineStippleKHR(cmdBuffer, stippleParams.factor, stippleParams.pattern);
4301     }
4302 
4303 #ifndef CTS_USES_VULKANSC
4304     if (testConfig.tessDomainOriginConfig.dynamicValue)
4305         vkd.cmdSetTessellationDomainOriginEXT(cmdBuffer, testConfig.tessDomainOriginConfig.dynamicValue.get());
4306 
4307     if (testConfig.depthClampEnableConfig.dynamicValue)
4308         vkd.cmdSetDepthClampEnableEXT(cmdBuffer, testConfig.depthClampEnableConfig.dynamicValue.get());
4309 
4310     if (testConfig.polygonModeConfig.dynamicValue)
4311         vkd.cmdSetPolygonModeEXT(cmdBuffer, testConfig.polygonModeConfig.dynamicValue.get());
4312 
4313     if (testConfig.rasterizationSamplesConfig.dynamicValue)
4314         vkd.cmdSetRasterizationSamplesEXT(cmdBuffer, testConfig.rasterizationSamplesConfig.dynamicValue.get());
4315 
4316     if (testConfig.sampleMaskConfig.dynamicValue)
4317     {
4318         const auto sampleCount =
4319             (static_cast<bool>(testConfig.dynamicSampleMaskCount) ? testConfig.dynamicSampleMaskCount.get() :
4320                                                                     testConfig.getActiveSampleCount());
4321         vkd.cmdSetSampleMaskEXT(cmdBuffer, sampleCount, testConfig.sampleMaskConfig.dynamicValue.get().data());
4322     }
4323 
4324     if (testConfig.alphaToCoverageConfig.dynamicValue)
4325         vkd.cmdSetAlphaToCoverageEnableEXT(cmdBuffer,
4326                                            makeVkBool32(testConfig.alphaToCoverageConfig.dynamicValue.get()));
4327 
4328     if (testConfig.alphaToOneConfig.dynamicValue)
4329         vkd.cmdSetAlphaToOneEnableEXT(cmdBuffer, makeVkBool32(testConfig.alphaToOneConfig.dynamicValue.get()));
4330 
4331     if (testConfig.colorWriteMaskConfig.dynamicValue)
4332     {
4333         const std::vector<vk::VkColorComponentFlags> writeMasks(testConfig.colorAttachmentCount,
4334                                                                 testConfig.colorWriteMaskConfig.dynamicValue.get());
4335         vkd.cmdSetColorWriteMaskEXT(cmdBuffer, 0u, de::sizeU32(writeMasks), de::dataOrNull(writeMasks));
4336     }
4337 
4338     if (testConfig.rasterizationStreamConfig.dynamicValue &&
4339         static_cast<bool>(testConfig.rasterizationStreamConfig.dynamicValue.get()))
4340         vkd.cmdSetRasterizationStreamEXT(cmdBuffer, testConfig.rasterizationStreamConfig.dynamicValue->get());
4341 
4342     if (testConfig.logicOpEnableConfig.dynamicValue)
4343         vkd.cmdSetLogicOpEnableEXT(cmdBuffer, makeVkBool32(testConfig.logicOpEnableConfig.dynamicValue.get()));
4344 
4345     if (testConfig.colorBlendEnableConfig.dynamicValue)
4346     {
4347         const auto colorBlendEnableFlag = makeVkBool32(testConfig.colorBlendEnableConfig.dynamicValue.get());
4348         const std::vector<vk::VkBool32> flags(testConfig.colorAttachmentCount, colorBlendEnableFlag);
4349         vkd.cmdSetColorBlendEnableEXT(cmdBuffer, 0u, de::sizeU32(flags), de::dataOrNull(flags));
4350     }
4351 
4352     if (testConfig.colorBlendEquationConfig.dynamicValue)
4353     {
4354         const auto &configEq  = testConfig.colorBlendEquationConfig.dynamicValue.get();
4355         const auto isAdvanced = testConfig.colorBlendEquationConfig.staticValue.isAdvanced();
4356 
4357         if (isAdvanced || testConfig.colorBlendBoth || testConfig.nullStaticColorBlendAttPtr)
4358         {
4359             const vk::VkColorBlendAdvancedEXT equation = {
4360                 configEq.colorBlendOp,                 // VkBlendOp advancedBlendOp;
4361                 VK_TRUE,                               // VkBool32 srcPremultiplied;
4362                 VK_TRUE,                               // VkBool32 dstPremultiplied;
4363                 vk::VK_BLEND_OVERLAP_UNCORRELATED_EXT, // VkBlendOverlapEXT blendOverlap;
4364                 VK_FALSE,                              // VkBool32 clampResults;
4365             };
4366             const std::vector<vk::VkColorBlendAdvancedEXT> equations(testConfig.colorAttachmentCount, equation);
4367             vkd.cmdSetColorBlendAdvancedEXT(cmdBuffer, 0u, de::sizeU32(equations), de::dataOrNull(equations));
4368         }
4369 
4370         if (!isAdvanced || testConfig.colorBlendBoth ||
4371             vk::isConstructionTypeShaderObject(testConfig.pipelineConstructionType))
4372         {
4373             // VUID-VkColorBlendEquationEXT-colorBlendOp-07361 forbids colorBlendOp and alphaBlendOp to be any advanced operation.
4374             // When the advanced blend op will be set by vkCmdSetColorBlendAdvancedEXT, we use a legal placeholder in this call.
4375             vk::VkBlendOp colorBlendOp = vk::VK_BLEND_OP_ADD;
4376             vk::VkBlendOp alphaBlendOp = vk::VK_BLEND_OP_ADD;
4377 
4378             if (!isAdvanced)
4379             {
4380                 colorBlendOp = configEq.colorBlendOp;
4381                 alphaBlendOp = configEq.alphaBlendOp;
4382             }
4383 
4384             const vk::VkColorBlendEquationEXT equation = {
4385                 configEq.srcColorBlendFactor, // VkBlendFactor srcColorBlendFactor;
4386                 configEq.dstColorBlendFactor, // VkBlendFactor dstColorBlendFactor;
4387                 colorBlendOp,                 // VkBlendOp colorBlendOp;
4388                 configEq.srcAlphaBlendFactor, // VkBlendFactor srcAlphaBlendFactor;
4389                 configEq.dstAlphaBlendFactor, // VkBlendFactor dstAlphaBlendFactor;
4390                 alphaBlendOp,                 // VkBlendOp alphaBlendOp;
4391             };
4392             const std::vector<vk::VkColorBlendEquationEXT> equations(testConfig.colorAttachmentCount, equation);
4393             vkd.cmdSetColorBlendEquationEXT(cmdBuffer, 0u, de::sizeU32(equations), de::dataOrNull(equations));
4394         }
4395     }
4396 
4397     if (testConfig.provokingVertexConfig.dynamicValue &&
4398         static_cast<bool>(testConfig.provokingVertexConfig.dynamicValue.get()))
4399     {
4400         const auto provokingVertexMode = makeProvokingVertexMode(testConfig.provokingVertexConfig.dynamicValue->get());
4401         vkd.cmdSetProvokingVertexModeEXT(cmdBuffer, provokingVertexMode);
4402     }
4403 
4404     if (testConfig.negativeOneToOneConfig.dynamicValue &&
4405         static_cast<bool>(testConfig.negativeOneToOneConfig.dynamicValue.get()))
4406         vkd.cmdSetDepthClipNegativeOneToOneEXT(cmdBuffer,
4407                                                makeVkBool32(testConfig.negativeOneToOneConfig.dynamicValue->get()));
4408 
4409     if (testConfig.depthClipEnableConfig.dynamicValue &&
4410         static_cast<bool>(testConfig.depthClipEnableConfig.dynamicValue.get()))
4411         vkd.cmdSetDepthClipEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthClipEnableConfig.dynamicValue->get()));
4412 
4413     if (testConfig.lineStippleEnableConfig.dynamicValue)
4414         vkd.cmdSetLineStippleEnableEXT(cmdBuffer, makeVkBool32(testConfig.lineStippleEnableConfig.dynamicValue.get()));
4415 
4416     if (testConfig.sampleLocationsEnableConfig.dynamicValue)
4417         vkd.cmdSetSampleLocationsEnableEXT(cmdBuffer,
4418                                            makeVkBool32(testConfig.sampleLocationsEnableConfig.dynamicValue.get()));
4419 
4420     if (testConfig.conservativeRasterModeConfig.dynamicValue)
4421         vkd.cmdSetConservativeRasterizationModeEXT(cmdBuffer,
4422                                                    testConfig.conservativeRasterModeConfig.dynamicValue.get());
4423 
4424     if (testConfig.extraPrimitiveOverEstConfig.dynamicValue)
4425         vkd.cmdSetExtraPrimitiveOverestimationSizeEXT(cmdBuffer,
4426                                                       testConfig.extraPrimitiveOverEstConfig.dynamicValue.get());
4427 
4428     if (testConfig.lineRasterModeConfig.dynamicValue &&
4429         static_cast<bool>(testConfig.lineRasterModeConfig.dynamicValue.get()))
4430         vkd.cmdSetLineRasterizationModeEXT(
4431             cmdBuffer, makeLineRasterizationMode(testConfig.lineRasterModeConfig.dynamicValue->get()));
4432 
4433     if (testConfig.coverageToColorEnableConfig.dynamicValue)
4434         vkd.cmdSetCoverageToColorEnableNV(cmdBuffer,
4435                                           makeVkBool32(testConfig.coverageToColorEnableConfig.dynamicValue.get()));
4436 
4437     if (testConfig.coverageToColorLocationConfig.dynamicValue)
4438         vkd.cmdSetCoverageToColorLocationNV(cmdBuffer, testConfig.coverageToColorLocationConfig.dynamicValue.get());
4439 
4440     if (testConfig.coverageModulationModeConfig.dynamicValue)
4441         vkd.cmdSetCoverageModulationModeNV(cmdBuffer, testConfig.coverageModulationModeConfig.dynamicValue.get());
4442 
4443     if (testConfig.coverageModTableEnableConfig.dynamicValue)
4444         vkd.cmdSetCoverageModulationTableEnableNV(
4445             cmdBuffer, makeVkBool32(testConfig.coverageModTableEnableConfig.dynamicValue.get()));
4446 
4447     if (testConfig.coverageModTableConfig.dynamicValue)
4448     {
4449         const auto &tableVec = testConfig.coverageModTableConfig.dynamicValue.get();
4450         vkd.cmdSetCoverageModulationTableNV(cmdBuffer, static_cast<uint32_t>(tableVec.size()),
4451                                             de::dataOrNull(tableVec));
4452     }
4453 
4454     if (testConfig.coverageReductionModeConfig.dynamicValue)
4455         vkd.cmdSetCoverageReductionModeNV(cmdBuffer, testConfig.coverageReductionModeConfig.dynamicValue.get());
4456 
4457     if (testConfig.viewportSwizzleConfig.dynamicValue)
4458     {
4459         const auto &viewportSwizzleVec = testConfig.viewportSwizzleConfig.dynamicValue.get();
4460         vkd.cmdSetViewportSwizzleNV(cmdBuffer, 0u, static_cast<uint32_t>(viewportSwizzleVec.size()),
4461                                     de::dataOrNull(viewportSwizzleVec));
4462     }
4463 
4464     if (testConfig.shadingRateImageEnableConfig.dynamicValue)
4465         vkd.cmdSetShadingRateImageEnableNV(cmdBuffer,
4466                                            makeVkBool32(testConfig.shadingRateImageEnableConfig.dynamicValue.get()));
4467 
4468     if (testConfig.viewportWScalingEnableConfig.dynamicValue)
4469         vkd.cmdSetViewportWScalingEnableNV(cmdBuffer,
4470                                            makeVkBool32(testConfig.viewportWScalingEnableConfig.dynamicValue.get()));
4471 
4472     if (testConfig.reprFragTestEnableConfig.dynamicValue)
4473         vkd.cmdSetRepresentativeFragmentTestEnableNV(
4474             cmdBuffer, makeVkBool32(testConfig.reprFragTestEnableConfig.dynamicValue.get()));
4475 
4476 #endif // CTS_USES_VULKANSC
4477 }
4478 
4479 // Bind the appropriate vertex buffers using dynamic strides if the test configuration needs a dynamic stride.
4480 // Return true if the vertex buffer was bound.
maybeBindVertexBufferDynStride(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,size_t meshIdx,const std::vector<VertexBufferInfo> & vertBuffers,const std::vector<VertexBufferInfo> & rvertBuffers)4481 bool maybeBindVertexBufferDynStride(const TestConfig &testConfig, const vk::DeviceInterface &vkd,
4482                                     vk::VkCommandBuffer cmdBuffer, size_t meshIdx,
4483                                     const std::vector<VertexBufferInfo> &vertBuffers,
4484                                     const std::vector<VertexBufferInfo> &rvertBuffers)
4485 {
4486     if (!testConfig.strideConfig.dynamicValue)
4487         return false;
4488 
4489     DE_ASSERT(!testConfig.useMeshShaders);
4490 
4491     const auto &viewportVec = testConfig.getActiveViewportVec();
4492     DE_UNREF(viewportVec); // For release builds.
4493 
4494     // When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
4495     // orderings if we have several viewports or meshes.
4496     DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u) ||
4497               testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW ||
4498               testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
4499 
4500     // Split buffers, offsets, sizes and strides into their own vectors for the call.
4501     std::vector<vk::VkBuffer> buffers;
4502     std::vector<vk::VkDeviceSize> offsets;
4503     std::vector<vk::VkDeviceSize> sizes;
4504     const auto strides = testConfig.strideConfig.dynamicValue.get();
4505 
4506     const auto &chosenBuffers = (testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers);
4507 
4508     buffers.reserve(chosenBuffers.size());
4509     offsets.reserve(chosenBuffers.size());
4510     sizes.reserve(chosenBuffers.size());
4511     DE_ASSERT(chosenBuffers.size() == strides.size());
4512 
4513     for (const auto &vertBuffer : chosenBuffers)
4514     {
4515         buffers.push_back(vertBuffer.buffer->get());
4516         offsets.push_back(vertBuffer.offset);
4517         sizes.push_back(vertBuffer.dataSize);
4518     }
4519 
4520 #ifndef CTS_USES_VULKANSC
4521     vkd.cmdBindVertexBuffers2(cmdBuffer, 0u, static_cast<uint32_t>(chosenBuffers.size()), buffers.data(),
4522                               offsets.data(), sizes.data(), strides.data());
4523 #else
4524     vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, static_cast<uint32_t>(chosenBuffers.size()), buffers.data(),
4525                                  offsets.data(), sizes.data(), strides.data());
4526 #endif // CTS_USES_VULKANSC
4527 
4528     return true;
4529 }
4530 
4531 // Bind the given vertex buffers with the non-dynamic call. Similar to maybeBindVertexBufferDynStride but simpler.
bindVertexBuffers(const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,const std::vector<VertexBufferInfo> & vertexBuffers)4532 void bindVertexBuffers(const vk::DeviceInterface &vkd, vk::VkCommandBuffer cmdBuffer,
4533                        const std::vector<VertexBufferInfo> &vertexBuffers)
4534 {
4535     std::vector<vk::VkBuffer> buffers;
4536     std::vector<vk::VkDeviceSize> offsets;
4537 
4538     buffers.reserve(vertexBuffers.size());
4539     offsets.reserve(vertexBuffers.size());
4540 
4541     for (const auto &vertBuffer : vertexBuffers)
4542     {
4543         buffers.push_back(vertBuffer.buffer->get());
4544         offsets.push_back(vertBuffer.offset);
4545     }
4546 
4547     vkd.cmdBindVertexBuffers(cmdBuffer, 0u, static_cast<uint32_t>(vertexBuffers.size()), buffers.data(),
4548                              offsets.data());
4549 }
4550 
4551 // Create a vector of VertexBufferInfo elements using the given vertex generator and set of vertices.
prepareVertexBuffers(std::vector<VertexBufferInfo> & buffers,const vk::DeviceInterface & vkd,vk::VkDevice device,vk::Allocator & allocator,const VertexGenerator * generator,const std::vector<tcu::Vec2> & vertices,uint32_t dataOffset,uint32_t trailingSize,bool ssbos)4552 void prepareVertexBuffers(std::vector<VertexBufferInfo> &buffers, const vk::DeviceInterface &vkd, vk::VkDevice device,
4553                           vk::Allocator &allocator, const VertexGenerator *generator,
4554                           const std::vector<tcu::Vec2> &vertices, uint32_t dataOffset, uint32_t trailingSize,
4555                           bool ssbos)
4556 {
4557     const uint32_t paddingBytes = 0xDEADBEEFu;
4558     const auto vertexData =
4559         generator->createVertexData(vertices, dataOffset, trailingSize, &paddingBytes, sizeof(paddingBytes));
4560 
4561     for (const auto &bufferBytes : vertexData)
4562     {
4563         const auto bufferSize = static_cast<vk::VkDeviceSize>(de::dataSize(bufferBytes));
4564         const auto extraSize  = static_cast<vk::VkDeviceSize>(dataOffset + trailingSize);
4565         DE_ASSERT(bufferSize > extraSize);
4566         const auto dataSize = bufferSize - extraSize;
4567 
4568         // Create a full-size buffer but remember the data size and offset for it.
4569         const auto createInfo = vk::makeBufferCreateInfo(
4570             bufferSize, (ssbos ? vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT : vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT));
4571 
4572         VertexBufferInfo bufferInfo;
4573         bufferInfo.buffer = BufferWithMemoryPtr(
4574             new vk::BufferWithMemory(vkd, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
4575         bufferInfo.offset   = static_cast<vk::VkDeviceSize>(dataOffset);
4576         bufferInfo.dataSize = dataSize;
4577         buffers.emplace_back(std::move(bufferInfo));
4578 
4579         // Copy the whole contents to the full buffer.
4580         copyAndFlush(vkd, device, *buffers.back().buffer, 0, bufferBytes.data(), de::dataSize(bufferBytes));
4581     }
4582 }
4583 
4584 // Device helper: this is needed in some tests when we create custom devices.
4585 class DeviceHelper
4586 {
4587 public:
~DeviceHelper()4588     virtual ~DeviceHelper()
4589     {
4590     }
4591     virtual const vk::DeviceInterface &getDeviceInterface(void) const       = 0;
4592     virtual vk::VkDevice getDevice(void) const                              = 0;
4593     virtual uint32_t getQueueFamilyIndex(void) const                        = 0;
4594     virtual vk::VkQueue getQueue(void) const                                = 0;
4595     virtual vk::Allocator &getAllocator(void) const                         = 0;
4596     virtual const std::vector<std::string> &getDeviceExtensions(void) const = 0;
4597 };
4598 
4599 // This one just reuses the default device from the context.
4600 class ContextDeviceHelper : public DeviceHelper
4601 {
4602 public:
ContextDeviceHelper(Context & context)4603     ContextDeviceHelper(Context &context)
4604         : m_deviceInterface(context.getDeviceInterface())
4605         , m_device(context.getDevice())
4606         , m_queueFamilyIndex(context.getUniversalQueueFamilyIndex())
4607         , m_queue(context.getUniversalQueue())
4608         , m_allocator(context.getDefaultAllocator())
4609         , m_extensions(context.getDeviceExtensions())
4610     {
4611     }
4612 
~ContextDeviceHelper()4613     virtual ~ContextDeviceHelper()
4614     {
4615     }
4616 
getDeviceInterface(void) const4617     const vk::DeviceInterface &getDeviceInterface(void) const override
4618     {
4619         return m_deviceInterface;
4620     }
getDevice(void) const4621     vk::VkDevice getDevice(void) const override
4622     {
4623         return m_device;
4624     }
getQueueFamilyIndex(void) const4625     uint32_t getQueueFamilyIndex(void) const override
4626     {
4627         return m_queueFamilyIndex;
4628     }
getQueue(void) const4629     vk::VkQueue getQueue(void) const override
4630     {
4631         return m_queue;
4632     }
getAllocator(void) const4633     vk::Allocator &getAllocator(void) const override
4634     {
4635         return m_allocator;
4636     }
getDeviceExtensions(void) const4637     const std::vector<std::string> &getDeviceExtensions(void) const override
4638     {
4639         return m_extensions;
4640     }
4641 
4642 protected:
4643     const vk::DeviceInterface &m_deviceInterface;
4644     const vk::VkDevice m_device;
4645     const uint32_t m_queueFamilyIndex;
4646     const vk::VkQueue m_queue;
4647     vk::Allocator &m_allocator;
4648     std::vector<std::string> m_extensions;
4649 };
4650 
4651 // A non-default device helper that can create a custom device with some options that can be specify in the constructor.
4652 class CustomizedDeviceHelper : public DeviceHelper
4653 {
4654 public:
4655     // Options, chosen so that a default value of false gives the default device.
4656     struct Options
4657     {
4658         bool shadingRateImage;  // Enable VK_NV_shading_rate_image.
4659         bool disableAlphaToOne; // Forcefully disable alphaToOne.
4660         bool disableAdvBlendingCoherentOps;
4661 
4662         // We need to sort these options in a map below, so we need operator< and the boilerplate below.
operator <vkt::pipeline::__anon3cc04b6f0111::CustomizedDeviceHelper::Options4663         bool operator<(const Options &other) const
4664         {
4665             return (this->toVec() < other.toVec());
4666         }
4667 
4668     private:
toVecvkt::pipeline::__anon3cc04b6f0111::CustomizedDeviceHelper::Options4669         std::vector<bool> toVec(void) const
4670         {
4671             return std::vector<bool>{shadingRateImage, disableAlphaToOne, disableAdvBlendingCoherentOps};
4672         }
4673     };
4674 
CustomizedDeviceHelper(Context & context,const Options & options)4675     CustomizedDeviceHelper(Context &context, const Options &options)
4676     {
4677         const auto &vkp           = context.getPlatformInterface();
4678         const auto &vki           = context.getInstanceInterface();
4679         const auto instance       = context.getInstance();
4680         const auto physicalDevice = context.getPhysicalDevice();
4681         const auto queuePriority  = 1.0f;
4682 
4683         // Queue index first.
4684         m_queueFamilyIndex = context.getUniversalQueueFamilyIndex();
4685 
4686         // Create a universal queue that supports graphics and compute.
4687         const vk::VkDeviceQueueCreateInfo queueParams = {
4688             vk::VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, // VkStructureType sType;
4689             DE_NULL,                                        // const void* pNext;
4690             0u,                                             // VkDeviceQueueCreateFlags flags;
4691             m_queueFamilyIndex,                             // uint32_t queueFamilyIndex;
4692             1u,                                             // uint32_t queueCount;
4693             &queuePriority                                  // const float* pQueuePriorities;
4694         };
4695 
4696 #ifndef CTS_USES_VULKANSC
4697         const auto &contextMeshFeatures  = context.getMeshShaderFeaturesEXT();
4698         const auto &contextGPLFeatures   = context.getGraphicsPipelineLibraryFeaturesEXT();
4699         const auto &contextDBCFeatures   = context.getDepthBiasControlFeaturesEXT();
4700         const auto &contextSOFeatures    = context.getShaderObjectFeaturesEXT();
4701         const auto &contextBlendFeatures = context.getBlendOperationAdvancedFeaturesEXT();
4702 
4703         const bool meshShaderSupport    = contextMeshFeatures.meshShader;
4704         const bool gplSupport           = contextGPLFeatures.graphicsPipelineLibrary;
4705         const bool dbcSupport           = contextDBCFeatures.depthBiasControl;
4706         const bool shaderObjectSupport  = contextSOFeatures.shaderObject;
4707         const bool eds3Support          = context.isDeviceFunctionalitySupported("VK_EXT_extended_dynamic_state3");
4708         const bool blendFeaturesSupport = contextBlendFeatures.advancedBlendCoherentOperations;
4709 
4710         // Mandatory.
4711         vk::VkPhysicalDeviceFeatures2 features2 = vk::initVulkanStructure();
4712 
4713         // Optional.
4714         vk::VkPhysicalDeviceExtendedDynamicState3FeaturesEXT eds3Features               = vk::initVulkanStructure();
4715         vk::VkPhysicalDeviceShadingRateImageFeaturesNV shadingRateImageFeatures         = vk::initVulkanStructure();
4716         vk::VkPhysicalDeviceDepthBiasControlFeaturesEXT dbcFeatures                     = vk::initVulkanStructure();
4717         vk::VkPhysicalDeviceMeshShaderFeaturesEXT meshFeatures                          = vk::initVulkanStructure();
4718         vk::VkPhysicalDeviceMultiviewFeatures multiviewFeatures                         = vk::initVulkanStructure();
4719         vk::VkPhysicalDeviceGraphicsPipelineLibraryFeaturesEXT gplFeatures              = vk::initVulkanStructure();
4720         vk::VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures                = vk::initVulkanStructure();
4721         vk::VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures           = vk::initVulkanStructure();
4722         vk::VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT blendOperationAdvFeatures = vk::initVulkanStructure();
4723         vk::VkPhysicalDeviceFragmentShadingRateFeaturesKHR fragmentShadingRateFeatures  = vk::initVulkanStructure();
4724 
4725         const auto addFeatures = vk::makeStructChainAdder(&features2);
4726 
4727         if (eds3Support)
4728             addFeatures(&eds3Features);
4729 
4730         if (options.shadingRateImage)
4731             addFeatures(&shadingRateImageFeatures);
4732 
4733         if (meshShaderSupport)
4734         {
4735             addFeatures(&meshFeatures);
4736 
4737             if (contextMeshFeatures.multiviewMeshShader)
4738                 addFeatures(&multiviewFeatures);
4739         }
4740 
4741         if (gplSupport)
4742             addFeatures(&gplFeatures);
4743 
4744         if (dbcSupport)
4745             addFeatures(&dbcFeatures);
4746 
4747         if (shaderObjectSupport)
4748         {
4749             addFeatures(&shaderObjectFeatures);
4750             addFeatures(&dynamicRenderingFeatures);
4751         }
4752 
4753         if (options.disableAdvBlendingCoherentOps && blendFeaturesSupport)
4754             addFeatures(&blendOperationAdvFeatures);
4755 
4756         vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
4757 
4758         if (options.shadingRateImage)
4759         {
4760             // [VUID-VkDeviceCreateInfo-shadingRateImage-04479]
4761             // If the shadingRateImage feature is enabled primitiveFragmentShadingRate must not be enabled
4762             //
4763             // [VUID-VkPhysicalDeviceMeshShaderFeaturesEXT-primitiveFragmentShadingRateMeshShader-07033]
4764             // If primitiveFragmentShadingRateMeshShader is enabled then
4765             // VkPhysicalDeviceFragmentShadingRateFeaturesKHR::primitiveFragmentShadingRate must also be enabled
4766             meshFeatures.primitiveFragmentShadingRateMeshShader = VK_FALSE;
4767         }
4768         else if (meshFeatures.primitiveFragmentShadingRateMeshShader)
4769         {
4770             addFeatures(&fragmentShadingRateFeatures);
4771             fragmentShadingRateFeatures.primitiveFragmentShadingRate = VK_TRUE;
4772         }
4773 
4774         // Disable alpha-to-one if requested by options.
4775         if (options.disableAlphaToOne)
4776             features2.features.alphaToOne = VK_FALSE;
4777 
4778         // Disable robust buffer access and advanced color blend operations explicitly.
4779         features2.features.robustBufferAccess                     = VK_FALSE;
4780         blendOperationAdvFeatures.advancedBlendCoherentOperations = VK_FALSE;
4781 
4782 #endif // CTS_USES_VULKANSC
4783 
4784         std::vector<const char *> extensions;
4785 
4786 #ifndef CTS_USES_VULKANSC
4787         if (options.shadingRateImage)
4788             extensions.push_back("VK_NV_shading_rate_image");
4789         else if (meshFeatures.primitiveFragmentShadingRateMeshShader)
4790             extensions.push_back("VK_KHR_fragment_shading_rate");
4791 
4792         if (eds3Support)
4793             extensions.push_back("VK_EXT_extended_dynamic_state3");
4794 
4795         if (meshShaderSupport)
4796         {
4797             extensions.push_back("VK_EXT_mesh_shader");
4798             if (contextMeshFeatures.multiviewMeshShader)
4799                 extensions.push_back("VK_KHR_multiview");
4800         }
4801 
4802         if (gplSupport)
4803         {
4804             extensions.push_back("VK_KHR_pipeline_library");
4805             extensions.push_back("VK_EXT_graphics_pipeline_library");
4806         }
4807 
4808         if (dbcSupport)
4809             extensions.push_back("VK_EXT_depth_bias_control");
4810 
4811         if (shaderObjectSupport)
4812         {
4813             extensions.push_back("VK_KHR_dynamic_rendering");
4814             extensions.push_back("VK_EXT_shader_object");
4815         }
4816 
4817         if (options.disableAdvBlendingCoherentOps && blendFeaturesSupport)
4818             extensions.push_back("VK_EXT_blend_operation_advanced");
4819 #endif // CTS_USES_VULKANSC
4820 
4821         for (const auto &ext : extensions)
4822             m_extensions.push_back(ext);
4823 
4824         const vk::VkDeviceCreateInfo deviceCreateInfo = {
4825             vk::VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, //sType;
4826 #ifndef CTS_USES_VULKANSC
4827             &features2, //pNext;
4828 #else
4829             nullptr,
4830 #endif                                  // CTS_USES_VULKANSC
4831             0u,                         //flags
4832             1u,                         //queueRecordCount;
4833             &queueParams,               //pRequestedQueues;
4834             0u,                         //layerCount;
4835             nullptr,                    //ppEnabledLayerNames;
4836             de::sizeU32(extensions),    // uint32_t enabledExtensionCount;
4837             de::dataOrNull(extensions), // const char* const* ppEnabledExtensionNames;
4838             nullptr,                    //pEnabledFeatures;
4839         };
4840 
4841         m_device = createCustomDevice(context.getTestContext().getCommandLine().isValidationEnabled(), vkp, instance,
4842                                       vki, physicalDevice, &deviceCreateInfo);
4843         m_vkd.reset(new vk::DeviceDriver(vkp, instance, m_device.get(), context.getUsedApiVersion(),
4844                                          context.getTestContext().getCommandLine()));
4845         m_queue = getDeviceQueue(*m_vkd, *m_device, m_queueFamilyIndex, 0u);
4846         m_allocator.reset(
4847             new vk::SimpleAllocator(*m_vkd, m_device.get(), getPhysicalDeviceMemoryProperties(vki, physicalDevice)));
4848 
4849 #ifdef CTS_USES_VULKANSC
4850         DE_UNREF(options);
4851 #endif // CTS_USES_VULKANSC
4852     }
4853 
~CustomizedDeviceHelper()4854     virtual ~CustomizedDeviceHelper()
4855     {
4856     }
4857 
getDeviceInterface(void) const4858     const vk::DeviceInterface &getDeviceInterface(void) const override
4859     {
4860         return *m_vkd;
4861     }
getDevice(void) const4862     vk::VkDevice getDevice(void) const override
4863     {
4864         return m_device.get();
4865     }
getQueueFamilyIndex(void) const4866     uint32_t getQueueFamilyIndex(void) const override
4867     {
4868         return m_queueFamilyIndex;
4869     }
getQueue(void) const4870     vk::VkQueue getQueue(void) const override
4871     {
4872         return m_queue;
4873     }
getAllocator(void) const4874     vk::Allocator &getAllocator(void) const override
4875     {
4876         return *m_allocator;
4877     }
getDeviceExtensions(void) const4878     const std::vector<std::string> &getDeviceExtensions(void) const override
4879     {
4880         return m_extensions;
4881     }
4882 
4883 protected:
4884     vk::Move<vk::VkDevice> m_device;
4885     std::unique_ptr<vk::DeviceDriver> m_vkd;
4886     uint32_t m_queueFamilyIndex;
4887     vk::VkQueue m_queue;
4888     std::unique_ptr<vk::SimpleAllocator> m_allocator;
4889     std::vector<std::string> m_extensions;
4890 };
4891 
4892 using DeviceHelperPtr = std::unique_ptr<DeviceHelper>;
4893 std::map<CustomizedDeviceHelper::Options, DeviceHelperPtr> g_deviceHelpers;
4894 
getDeviceHelper(Context & context,const TestConfig & testConfig)4895 DeviceHelper &getDeviceHelper(Context &context, const TestConfig &testConfig)
4896 {
4897     const CustomizedDeviceHelper::Options deviceOptions{
4898         testConfig.shadingRateImage,
4899         testConfig.disableAlphaToOneFeature,
4900         testConfig.disableAdvBlendingCoherentOps,
4901     };
4902 
4903     auto itr = g_deviceHelpers.find(deviceOptions);
4904     if (itr == g_deviceHelpers.end())
4905     {
4906         using MapValueType = decltype(g_deviceHelpers)::value_type;
4907 
4908         // Using the default options results in a non-custom device from the context. Otherwise a custom device is created.
4909         const bool defaultOptions = (!deviceOptions.shadingRateImage && !deviceOptions.disableAlphaToOne &&
4910                                      !deviceOptions.disableAdvBlendingCoherentOps);
4911         DeviceHelperPtr ptr       = DeviceHelperPtr(
4912             defaultOptions ? static_cast<DeviceHelper *>(new ContextDeviceHelper(context)) :
4913                              static_cast<DeviceHelper *>(new CustomizedDeviceHelper(context, deviceOptions)));
4914         MapValueType mapValue(std::move(deviceOptions), std::move(ptr));
4915 
4916         itr = g_deviceHelpers.insert(std::move(mapValue)).first;
4917     }
4918     return *itr->second;
4919 }
4920 
cleanupDevices()4921 void cleanupDevices()
4922 {
4923     for (auto &keyValue : g_deviceHelpers)
4924         keyValue.second.reset(nullptr);
4925     g_deviceHelpers.clear();
4926 }
4927 
getChannelClass(const tcu::TextureFormat & format)4928 tcu::TextureChannelClass getChannelClass(const tcu::TextureFormat &format)
4929 {
4930     const auto generalClass = getTextureChannelClass(format.type);
4931     // Workaround for VK_FORMAT_X8_D24_UNORM_PACK32.
4932     return ((generalClass == tcu::TEXTURECHANNELCLASS_LAST) ? tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT :
4933                                                               generalClass);
4934 }
4935 
iterate(void)4936 tcu::TestStatus ExtendedDynamicStateInstance::iterate(void)
4937 {
4938     using ImageWithMemoryVec = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
4939     using ImageViewVec       = std::vector<vk::Move<vk::VkImageView>>;
4940     using RenderPassVec      = std::vector<vk::RenderPassWrapper>;
4941 
4942     const auto &vki           = m_context.getInstanceInterface();
4943     const auto physicalDevice = m_context.getPhysicalDevice();
4944     const auto &deviceHelper  = getDeviceHelper(m_context, m_testConfig);
4945     const auto &vkd           = deviceHelper.getDeviceInterface();
4946     const auto device         = deviceHelper.getDevice();
4947     auto &allocator           = deviceHelper.getAllocator();
4948     const auto queue          = deviceHelper.getQueue();
4949     const auto queueIndex     = deviceHelper.getQueueFamilyIndex();
4950     auto &log                 = m_context.getTestContext().getLog();
4951 
4952     const auto kReversed          = m_testConfig.isReversed();
4953     const auto kBindStaticFirst   = m_testConfig.bindStaticFirst();
4954     const auto kUseStaticPipeline = m_testConfig.useStaticPipeline();
4955     const auto kNumIterations     = m_testConfig.numIterations();
4956     const auto kColorAttCount     = m_testConfig.colorAttachmentCount;
4957     const auto kSequenceOrdering  = m_testConfig.sequenceOrdering;
4958 
4959     const auto kDSCreateFlags =
4960         (m_testConfig.sampleLocationsStruct() ?
4961              static_cast<vk::VkImageCreateFlags>(vk::VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT) :
4962              0u);
4963     const auto colorFormat       = m_testConfig.colorFormat();
4964     const auto colorSampleCount  = m_testConfig.getColorSampleCount();
4965     const auto activeSampleCount = m_testConfig.getActiveSampleCount();
4966     const bool vertDataAsSSBO    = m_testConfig.useMeshShaders;
4967     const auto pipelineBindPoint = vk::VK_PIPELINE_BIND_POINT_GRAPHICS;
4968     const bool kUseResolveAtt    = (colorSampleCount != kSingleSampleCount);
4969     const bool kMultisampleDS    = (activeSampleCount != kSingleSampleCount);
4970     const bool kFragAtomics      = m_testConfig.useFragShaderAtomics();
4971 
4972     // Choose depth/stencil format.
4973     const DepthStencilFormat *dsFormatInfo = nullptr;
4974 
4975     for (const auto &kDepthStencilFormat : kDepthStencilFormats)
4976     {
4977         // This is how we'll attempt to create images later.
4978         const auto dsImageInfo = makeImageCreateInfo(kDepthStencilFormat.imageFormat, kFramebufferExtent,
4979                                                      activeSampleCount, kDSUsage, kDSCreateFlags);
4980 
4981         vk::VkImageFormatProperties formatProps;
4982         const auto result = vki.getPhysicalDeviceImageFormatProperties(
4983             physicalDevice, dsImageInfo.format, dsImageInfo.imageType, dsImageInfo.tiling, dsImageInfo.usage,
4984             dsImageInfo.flags, &formatProps);
4985 
4986         // Format not supported.
4987         if (result != vk::VK_SUCCESS)
4988             continue;
4989 
4990         // Extent not big enough.
4991         const auto &maxExtent = formatProps.maxExtent;
4992         if (maxExtent.width < kFramebufferExtent.width || maxExtent.height < kFramebufferExtent.height ||
4993             maxExtent.depth < kFramebufferExtent.depth)
4994             continue;
4995 
4996         // Sample count not supported.
4997         if ((formatProps.sampleCounts & activeSampleCount) != activeSampleCount)
4998             continue;
4999 
5000         if (m_testConfig.neededDepthChannelClass != tcu::TEXTURECHANNELCLASS_LAST)
5001         {
5002             const auto tcuDSFormat  = vk::getDepthCopyFormat(kDepthStencilFormat.imageFormat);
5003             const auto channelClass = getChannelClass(tcuDSFormat);
5004 
5005             if (channelClass != m_testConfig.neededDepthChannelClass)
5006                 continue;
5007         }
5008 
5009         dsFormatInfo = &kDepthStencilFormat;
5010         break;
5011     }
5012 
5013     // Note: Not Supported insted of Fail because some features are not mandatory.
5014     if (!dsFormatInfo)
5015         TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
5016     log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat
5017         << tcu::TestLog::EndMessage;
5018     log << tcu::TestLog::Message << "Chosen color format: " << colorFormat << tcu::TestLog::EndMessage;
5019 
5020     // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
5021     // where we will bind the static pipeline last before drawing.
5022     if (kReversed)
5023         m_testConfig.swapValues();
5024 
5025     // Create color and depth/stencil images.
5026     ImageWithMemoryVec colorImages;
5027     ImageWithMemoryVec dsImages;
5028     ImageWithMemoryVec resolveImages;
5029 
5030     const auto colorImageInfo = makeImageCreateInfo(colorFormat, kFramebufferExtent, colorSampleCount, kColorUsage, 0u);
5031     for (uint32_t i = 0u; i < kNumIterations * kColorAttCount; ++i)
5032         colorImages.emplace_back(
5033             new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
5034 
5035     const auto dsImageInfo =
5036         makeImageCreateInfo(dsFormatInfo->imageFormat, kFramebufferExtent, activeSampleCount, kDSUsage, kDSCreateFlags);
5037     for (uint32_t i = 0u; i < kNumIterations; ++i)
5038         dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
5039 
5040     if (kUseResolveAtt)
5041     {
5042         const auto resolveImageInfo =
5043             makeImageCreateInfo(colorFormat, kFramebufferExtent, kSingleSampleCount, kColorUsage, 0u);
5044         for (uint32_t i = 0u; i < kNumIterations * kColorAttCount; ++i)
5045             resolveImages.emplace_back(
5046                 new vk::ImageWithMemory(vkd, device, allocator, resolveImageInfo, vk::MemoryRequirement::Any));
5047     }
5048 
5049     const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
5050     const auto dsSubresourceRange    = vk::makeImageSubresourceRange(
5051         (vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
5052 
5053     ImageViewVec colorImageViews;
5054     ImageViewVec dsImageViews;
5055     ImageViewVec resolveImageViews;
5056 
5057     for (const auto &img : colorImages)
5058         colorImageViews.emplace_back(
5059             vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
5060 
5061     for (const auto &img : dsImages)
5062         dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D,
5063                                                     dsFormatInfo->imageFormat, dsSubresourceRange));
5064 
5065     for (const auto &img : resolveImages)
5066         resolveImageViews.emplace_back(
5067             vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
5068 
5069     // Vertex buffer.
5070     const auto topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
5071     std::vector<uint32_t> indices;
5072     std::vector<tcu::Vec2> vertices;
5073 
5074     if (m_testConfig.oversizedTriangle || m_testConfig.offCenterTriangle)
5075     {
5076         DE_ASSERT(topologyClass == TopologyClass::TRIANGLE);
5077         DE_ASSERT(!m_testConfig.singleVertex);
5078     }
5079 
5080     if (m_testConfig.obliqueLine)
5081         DE_ASSERT(topologyClass == TopologyClass::LINE);
5082 
5083     if (topologyClass == TopologyClass::TRIANGLE)
5084     {
5085         DE_ASSERT(!m_testConfig.needsIndexBuffer());
5086 
5087         if (m_testConfig.oversizedTriangle)
5088         {
5089             vertices.reserve(3u);
5090             vertices.push_back(tcu::Vec2(-2.0f, -2.0f));
5091             vertices.push_back(tcu::Vec2(-2.0f, 6.0f));
5092             vertices.push_back(tcu::Vec2(6.0f, -2.0f));
5093         }
5094         else if (m_testConfig.offCenterTriangle)
5095         {
5096             // Triangle covering the whole screen, except for the first row and column, which may not be covered by all samples.
5097             const float horOffset = 2.0f / static_cast<float>(kFramebufferWidth) * m_testConfig.offCenterProportion.x();
5098             const float vertOffset =
5099                 2.0f / static_cast<float>(kFramebufferHeight) * m_testConfig.offCenterProportion.y();
5100 
5101             vertices.reserve(3u);
5102             vertices.push_back(tcu::Vec2(-1.0f + horOffset, -1.0f + vertOffset));
5103             vertices.push_back(tcu::Vec2(-1.0f + horOffset, 4.0f));
5104             vertices.push_back(tcu::Vec2(4.0f, -1.0f + vertOffset));
5105         }
5106         else
5107         {
5108             // Full-screen triangle strip with 6 vertices.
5109             //
5110             // 0        2        4
5111             //  +-------+-------+
5112             //  |      XX      X|
5113             //  |     X X     X |
5114             //  |    X  X    X  |
5115             //  |   X   X   X   |
5116             //  |  X    X  X    |
5117             //  | X     X X     |
5118             //  |X      XX      |
5119             //  +-------+-------+
5120             // 1        3       5
5121             vertices.reserve(6u);
5122             vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
5123             vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
5124             vertices.push_back(tcu::Vec2(0.0f, -1.0f));
5125             vertices.push_back(tcu::Vec2(0.0f, 1.0f));
5126             vertices.push_back(tcu::Vec2(1.0f, -1.0f));
5127             vertices.push_back(tcu::Vec2(1.0f, 1.0f));
5128         }
5129     }
5130     else if (topologyClass == TopologyClass::PATCH)
5131     {
5132         DE_ASSERT(!m_testConfig.needsIndexBuffer());
5133         DE_ASSERT(m_testConfig.getActivePatchControlPoints() > 1u);
5134 
5135         // 2 triangles making a quad
5136         vertices.reserve(6u);
5137         vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
5138         vertices.push_back(tcu::Vec2(1.0f, 1.0f));
5139         vertices.push_back(tcu::Vec2(1.0f, -1.0f));
5140         vertices.push_back(tcu::Vec2(1.0f, -1.0f));
5141         vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
5142         vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
5143     }
5144     else // TopologyClass::LINE
5145     {
5146         const float pixelHeight = 2.0f / static_cast<float>(kFramebufferHeight);
5147         const float pixelWidth  = 2.0f / static_cast<float>(kFramebufferWidth);
5148 
5149         if (m_testConfig.obliqueLine)
5150         {
5151             // The starting point of the oblique line is located in the top left pixel, in a position below and slightly to the left
5152             // of the pixel center. The ending point is in the middle of the right side of the framebuffer. Those coordinates make
5153             // sure that a bresenham-style line covers the center of the top left pixel, because the left edge of the line goes up
5154             // vertically from that point. However, a rectangular line misses it by a small delta because its edge goes up and to
5155             // the right, leaving the pixel center to its left. So the top left pixel itself may be covered or not depending on the
5156             // active line rasterization mode.
5157             //
5158             // Note: results may also be affected by multisample and sample locations if those are used.
5159             vertices.reserve(2u);
5160             vertices.push_back(tcu::Vec2(pixelWidth * 7.0f / 16.0f - 1.0f, pixelHeight * 12.0f / 16.0f - 1.0f));
5161             vertices.push_back(tcu::Vec2(1.0f, 0.0f));
5162         }
5163         else
5164         {
5165             DE_ASSERT(m_testConfig.getActivePrimRestartEnable());
5166 
5167             // 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.
5168             vertices.reserve(kFramebufferHeight * 4u);
5169 
5170             const auto indicesPerRow = (m_testConfig.extraLineRestarts ? 6u : 5u);
5171             if (m_testConfig.needsIndexBuffer())
5172                 indices.reserve(kFramebufferHeight * indicesPerRow);
5173 
5174             for (uint32_t rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
5175             {
5176                 // Offset of 0.5 pixels + one pixel per row, from -1 to 1.
5177                 const float yCoord = (pixelHeight / 2.0f) + pixelHeight * static_cast<float>(rowIdx) - 1.0f;
5178                 vertices.push_back(tcu::Vec2(-1.0f, yCoord));
5179                 vertices.push_back(tcu::Vec2(-0.5f, yCoord));
5180                 vertices.push_back(tcu::Vec2(0.5f, yCoord));
5181                 vertices.push_back(tcu::Vec2(1.0f, yCoord));
5182 
5183                 if (m_testConfig.needsIndexBuffer())
5184                 {
5185                     indices.push_back(4u * rowIdx + 0u);
5186                     indices.push_back(4u * rowIdx + 1u);
5187 
5188                     // When using extra line restarts, insert a primitive restart index in the middle, which will result in the
5189                     // center strip being skipped, as if the topology was a line list instead of a strip.
5190                     if (m_testConfig.extraLineRestarts)
5191                         indices.push_back(0xFFFFFFFFu);
5192 
5193                     indices.push_back(4u * rowIdx + 2u);
5194                     indices.push_back(4u * rowIdx + 3u);
5195                     indices.push_back(0xFFFFFFFFu); // Restart line strip.
5196                 }
5197             }
5198         }
5199     }
5200 
5201     if (m_testConfig.singleVertex)
5202     {
5203         DE_ASSERT(!m_testConfig.needsIndexBuffer());
5204         vertices.resize(1);
5205     }
5206 
5207     // Reversed vertices order in triangle strip (1, 0, 3, 2, 5, 4)
5208     std::vector<tcu::Vec2> rvertices;
5209     if (topologyClass == TopologyClass::TRIANGLE)
5210     {
5211         DE_ASSERT(!vertices.empty());
5212         if (m_testConfig.singleVertex)
5213             rvertices.push_back(vertices[0]);
5214         else if (m_testConfig.oversizedTriangle || m_testConfig.offCenterTriangle)
5215         {
5216             rvertices.reserve(3u);
5217             rvertices.push_back(vertices[0]);
5218             rvertices.push_back(vertices[2]);
5219             rvertices.push_back(vertices[1]);
5220         }
5221         else
5222         {
5223             rvertices.reserve(6u);
5224             rvertices.push_back(vertices[1]);
5225             rvertices.push_back(vertices[0]);
5226             rvertices.push_back(vertices[3]);
5227             rvertices.push_back(vertices[2]);
5228             rvertices.push_back(vertices[5]);
5229             rvertices.push_back(vertices[4]);
5230         }
5231     }
5232 
5233     if (topologyClass != TopologyClass::TRIANGLE)
5234     {
5235         for (const auto &mesh : m_testConfig.meshParams)
5236         {
5237             DE_UNREF(mesh); // For release builds.
5238             DE_ASSERT(!mesh.reversed);
5239         }
5240     }
5241 
5242     // Buffers with vertex data for the different bindings.
5243     std::vector<VertexBufferInfo> vertBuffers;
5244     std::vector<VertexBufferInfo> rvertBuffers;
5245 
5246     {
5247         const auto dataOffset   = static_cast<uint32_t>(m_testConfig.vertexDataOffset);
5248         const auto trailingSize = static_cast<uint32_t>(m_testConfig.vertexDataExtraBytes);
5249         const auto generator    = m_testConfig.getActiveVertexGenerator();
5250         prepareVertexBuffers(vertBuffers, vkd, device, allocator, generator, vertices, dataOffset, trailingSize,
5251                              vertDataAsSSBO);
5252         if (topologyClass == TopologyClass::TRIANGLE)
5253             prepareVertexBuffers(rvertBuffers, vkd, device, allocator, generator, rvertices, dataOffset, trailingSize,
5254                                  vertDataAsSSBO);
5255     }
5256 
5257     // Index buffer.
5258     BufferWithMemoryPtr indexBuffer;
5259     if (!indices.empty())
5260     {
5261         const auto indexDataSize   = static_cast<vk::VkDeviceSize>(de::dataSize(indices));
5262         const auto indexBufferInfo = vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
5263 
5264         indexBuffer = BufferWithMemoryPtr(
5265             new vk::BufferWithMemory(vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible));
5266         copyAndFlush(vkd, device, *indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
5267     }
5268 
5269     // Fragment counter buffer.
5270     BufferWithMemoryPtr counterBuffer;
5271     const auto counterBufferSize = static_cast<vk::VkDeviceSize>(sizeof(uint32_t));
5272 
5273     if (kFragAtomics)
5274     {
5275         const auto counterBufferInfo =
5276             vk::makeBufferCreateInfo(counterBufferSize, vk::VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
5277         const uint32_t initialValue = 0u;
5278 
5279         counterBuffer = BufferWithMemoryPtr(
5280             new vk::BufferWithMemory(vkd, device, allocator, counterBufferInfo, vk::MemoryRequirement::HostVisible));
5281         copyAndFlush(vkd, device, *counterBuffer, 0u, &initialValue, static_cast<size_t>(counterBufferSize));
5282     }
5283 
5284     // Frag shader descriptor set layout.
5285     vk::Move<vk::VkDescriptorSetLayout> fragSetLayout;
5286     {
5287         vk::DescriptorSetLayoutBuilder layoutBuilder;
5288         if (kFragAtomics)
5289             layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, vk::VK_SHADER_STAGE_FRAGMENT_BIT);
5290         fragSetLayout = layoutBuilder.build(vkd, device);
5291     }
5292 
5293     // Descriptor pool and set.
5294     vk::Move<vk::VkDescriptorPool> fragDescriptorPool;
5295     vk::Move<vk::VkDescriptorSet> fragDescriptorSet;
5296 
5297     if (kFragAtomics)
5298     {
5299         vk::DescriptorPoolBuilder poolBuilder;
5300         poolBuilder.addType(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
5301         fragDescriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
5302         fragDescriptorSet  = vk::makeDescriptorSet(vkd, device, fragDescriptorPool.get(), fragSetLayout.get());
5303 
5304         vk::DescriptorSetUpdateBuilder updateBuilder;
5305         const auto location = vk::DescriptorSetUpdateBuilder::Location::binding(0u);
5306         const auto descInfo = vk::makeDescriptorBufferInfo(counterBuffer->get(), 0ull, counterBufferSize);
5307         updateBuilder.writeSingle(fragDescriptorSet.get(), location, vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &descInfo);
5308         updateBuilder.update(vkd, device);
5309     }
5310 
5311     // Push constant stages (matches SSBO stages if used).
5312     vk::VkShaderStageFlags pushConstantStageFlags = ((m_testConfig.useMeshShaders
5313 #ifndef CTS_USES_VULKANSC
5314                                                           ?
5315                                                           vk::VK_SHADER_STAGE_MESH_BIT_EXT
5316 #else
5317                                                           ?
5318                                                           0
5319 #endif // CTS_USES_VULKANSC
5320                                                           :
5321                                                           vk::VK_SHADER_STAGE_VERTEX_BIT) |
5322                                                      vk::VK_SHADER_STAGE_FRAGMENT_BIT);
5323 
5324     if (m_testConfig.needsGeometryShader())
5325         pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
5326 
5327     // Mesh descriptor set layout.
5328     vk::Move<vk::VkDescriptorSetLayout> meshSetLayout;
5329     if (vertDataAsSSBO)
5330     {
5331         vk::DescriptorSetLayoutBuilder layoutBuilder;
5332         for (size_t i = 0; i < vertBuffers.size(); ++i)
5333             layoutBuilder.addSingleBinding(vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, pushConstantStageFlags);
5334         meshSetLayout = layoutBuilder.build(vkd, device);
5335     }
5336 
5337     // Descriptor pool and set if needed.
5338     vk::Move<vk::VkDescriptorPool> meshDescriptorPool;
5339     vk::Move<vk::VkDescriptorSet> meshDescriptorSet;
5340     vk::Move<vk::VkDescriptorSet> meshDescriptorSetRev;
5341 
5342     if (vertDataAsSSBO)
5343     {
5344         const auto hasReversed = (rvertBuffers.size() > 0u);
5345         const auto descType    = vk::VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
5346         vk::DescriptorPoolBuilder poolBuilder;
5347         poolBuilder.addType(descType, static_cast<uint32_t>(vertBuffers.size()) * 2u);
5348 
5349         meshDescriptorPool = poolBuilder.build(vkd, device, vk::VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 2u);
5350         meshDescriptorSet  = vk::makeDescriptorSet(vkd, device, meshDescriptorPool.get(), meshSetLayout.get());
5351 
5352         if (hasReversed)
5353             meshDescriptorSetRev = vk::makeDescriptorSet(vkd, device, meshDescriptorPool.get(), meshSetLayout.get());
5354 
5355         std::vector<vk::VkDescriptorBufferInfo> descBufferInfos;
5356         std::vector<vk::VkDescriptorBufferInfo> descBufferInfosRev;
5357         descBufferInfos.reserve(vertBuffers.size());
5358         if (hasReversed)
5359             descBufferInfosRev.reserve(rvertBuffers.size());
5360 
5361         vk::DescriptorSetUpdateBuilder updateBuilder;
5362 
5363         DE_ASSERT(vertBuffers.size() == rvertBuffers.size() || !hasReversed);
5364         for (size_t i = 0; i < vertBuffers.size(); ++i)
5365         {
5366             const auto binding = vk::DescriptorSetUpdateBuilder::Location::binding(static_cast<uint32_t>(i));
5367 
5368             descBufferInfos.push_back(vk::makeDescriptorBufferInfo(vertBuffers[i].buffer->get(), vertBuffers[i].offset,
5369                                                                    vertBuffers[i].dataSize));
5370             updateBuilder.writeSingle(meshDescriptorSet.get(), binding, descType, &descBufferInfos.back());
5371 
5372             if (hasReversed)
5373             {
5374                 descBufferInfosRev.push_back(vk::makeDescriptorBufferInfo(
5375                     rvertBuffers[i].buffer->get(), rvertBuffers[i].offset, rvertBuffers[i].dataSize));
5376                 updateBuilder.writeSingle(meshDescriptorSetRev.get(), binding, descType, &descBufferInfosRev.back());
5377             }
5378         }
5379 
5380         updateBuilder.update(vkd, device);
5381     }
5382 
5383     // The frag shader descriptor set is the second one if both exist. See getFragDescriptorSetIndex().
5384     std::vector<vk::VkDescriptorSetLayout> rawSetLayouts;
5385 
5386     if (meshSetLayout.get() != VK_NULL_HANDLE)
5387         rawSetLayouts.push_back(meshSetLayout.get());
5388 
5389     if (fragSetLayout.get() != VK_NULL_HANDLE)
5390         rawSetLayouts.push_back(fragSetLayout.get());
5391 
5392     // Pipeline layout.
5393     const vk::VkPushConstantRange pushConstantRange = {
5394         pushConstantStageFlags,                       // VkShaderStageFlags stageFlags;
5395         0u,                                           // uint32_t offset;
5396         static_cast<uint32_t>(sizeof(PushConstants)), // uint32_t size;
5397     };
5398 
5399     const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
5400         vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
5401         nullptr,                                           // const void* pNext;
5402         0u,                                                // VkPipelineLayoutCreateFlags flags;
5403         de::sizeU32(rawSetLayouts),                        // uint32_t setLayoutCount;
5404         de::dataOrNull(rawSetLayouts),                     // const VkDescriptorSetLayout* pSetLayouts;
5405         1u,                                                // uint32_t pushConstantRangeCount;
5406         &pushConstantRange,                                // const VkPushConstantRange* pPushConstantRanges;
5407     };
5408     const vk::PipelineLayoutWrapper pipelineLayout(m_testConfig.pipelineConstructionType, vkd, device,
5409                                                    &pipelineLayoutCreateInfo);
5410 
5411     // Render pass with single subpass. Attachment order:
5412     // 1) Color attachments (kColorAttCount items).
5413     // 2) DS attachment.
5414     // 3) [optional] Resolve attachments (kColorAttCount).
5415 
5416     DE_ASSERT(kColorAttCount > 0u);
5417 
5418     std::vector<vk::VkAttachmentReference> colorAttachments;
5419     std::vector<vk::VkAttachmentReference> resolveAttachments;
5420 
5421     for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
5422     {
5423         colorAttachments.push_back(
5424             vk::makeAttachmentReference(colorAttIdx, vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
5425         if (kUseResolveAtt)
5426             resolveAttachments.push_back(vk::makeAttachmentReference(kColorAttCount + 1u + colorAttIdx,
5427                                                                      vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL));
5428     }
5429 
5430     const vk::VkAttachmentReference dsAttachmentReference = {
5431         kColorAttCount,                                       // uint32_t attachment;
5432         vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
5433     };
5434 
5435     const vk::VkSubpassDescription subpassDescription = {
5436         0u,                                 // VkSubpassDescriptionFlags flags;
5437         pipelineBindPoint,                  // VkPipelineBindPoint pipelineBindPoint;
5438         0u,                                 // uint32_t inputAttachmentCount;
5439         nullptr,                            // const VkAttachmentReference* pInputAttachments;
5440         kColorAttCount,                     // uint32_t colorAttachmentCount;
5441         de::dataOrNull(colorAttachments),   // const VkAttachmentReference* pColorAttachments;
5442         de::dataOrNull(resolveAttachments), // const VkAttachmentReference* pResolveAttachments;
5443         &dsAttachmentReference,             // const VkAttachmentReference* pDepthStencilAttachment;
5444         0u,                                 // uint32_t preserveAttachmentCount;
5445         nullptr,                            // const uint32_t* pPreserveAttachments;
5446     };
5447 
5448     std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
5449 
5450     // For multisample, we care about the resolve attachment, not the color one.
5451     const auto colorAttachmentStoreOp =
5452         (kUseResolveAtt ? vk::VK_ATTACHMENT_STORE_OP_DONT_CARE : vk::VK_ATTACHMENT_STORE_OP_STORE);
5453 
5454     for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
5455     {
5456         attachmentDescriptions.push_back(vk::VkAttachmentDescription{
5457             0u,                                           // VkAttachmentDescriptionFlags flags;
5458             colorFormat,                                  // VkFormat format;
5459             colorSampleCount,                             // VkSampleCountFlagBits samples;
5460             vk::VK_ATTACHMENT_LOAD_OP_CLEAR,              // VkAttachmentLoadOp loadOp;
5461             colorAttachmentStoreOp,                       // VkAttachmentStoreOp storeOp;
5462             vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
5463             vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
5464             vk::VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
5465             vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
5466         });
5467     }
5468 
5469     attachmentDescriptions.push_back(vk::VkAttachmentDescription{
5470         0u,                                                   // VkAttachmentDescriptionFlags flags;
5471         dsFormatInfo->imageFormat,                            // VkFormat format;
5472         activeSampleCount,                                    // VkSampleCountFlagBits samples;
5473         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp loadOp;
5474         vk::VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp storeOp;
5475         vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                      // VkAttachmentLoadOp stencilLoadOp;
5476         vk::VK_ATTACHMENT_STORE_OP_STORE,                     // VkAttachmentStoreOp stencilStoreOp;
5477         vk::VK_IMAGE_LAYOUT_UNDEFINED,                        // VkImageLayout initialLayout;
5478         vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
5479     });
5480 
5481     if (kUseResolveAtt)
5482     {
5483         // Resolve attachments.
5484         for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
5485         {
5486             attachmentDescriptions.push_back(vk::VkAttachmentDescription{
5487                 0u,                                           // VkAttachmentDescriptionFlags flags;
5488                 colorFormat,                                  // VkFormat format;
5489                 kSingleSampleCount,                           // VkSampleCountFlagBits samples;
5490                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp loadOp;
5491                 vk::VK_ATTACHMENT_STORE_OP_STORE,             // VkAttachmentStoreOp storeOp;
5492                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,          // VkAttachmentLoadOp stencilLoadOp;
5493                 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,         // VkAttachmentStoreOp stencilStoreOp;
5494                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                // VkImageLayout initialLayout;
5495                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
5496             });
5497         }
5498     }
5499 
5500     // Render pass and framebuffers.
5501     RenderPassVec renderPassFramebuffers;
5502 
5503     const vk::VkRenderPassCreateInfo renderPassCreateInfo = {
5504         vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,        // VkStructureType sType;
5505         nullptr,                                              // const void* pNext;
5506         0u,                                                   // VkRenderPassCreateFlags flags;
5507         static_cast<uint32_t>(attachmentDescriptions.size()), // uint32_t attachmentCount;
5508         attachmentDescriptions.data(),                        // const VkAttachmentDescription* pAttachments;
5509         1u,                                                   // uint32_t subpassCount;
5510         &subpassDescription,                                  // const VkSubpassDescription* pSubpasses;
5511         0u,                                                   // uint32_t dependencyCount;
5512         nullptr,                                              // const VkSubpassDependency* pDependencies;
5513     };
5514 
5515     DE_ASSERT(colorImageViews.size() == dsImageViews.size() * kColorAttCount);
5516 
5517     if (kUseResolveAtt)
5518         DE_ASSERT(colorImageViews.size() == resolveImageViews.size());
5519 
5520     for (size_t iterIdx = 0; iterIdx < dsImageViews.size(); ++iterIdx)
5521     {
5522         std::vector<vk::VkImage> images;
5523         std::vector<vk::VkImageView> attachments;
5524 
5525         for (uint32_t colorAttIdx = 0u; colorAttIdx < kColorAttCount; ++colorAttIdx)
5526         {
5527             const auto colorViewIdx = iterIdx * kColorAttCount + colorAttIdx;
5528             images.push_back(colorImages[colorViewIdx].get()->get());
5529             attachments.push_back(colorImageViews[colorViewIdx].get());
5530         }
5531 
5532         images.push_back(dsImages[iterIdx].get()->get());
5533         attachments.push_back(dsImageViews[iterIdx].get());
5534 
5535         if (kUseResolveAtt)
5536         {
5537             for (uint32_t resolveAttIdx = 0u; resolveAttIdx < kColorAttCount; ++resolveAttIdx)
5538             {
5539                 const auto resolveViewIdx = iterIdx * kColorAttCount + resolveAttIdx;
5540                 images.push_back(resolveImages[resolveViewIdx].get()->get());
5541                 attachments.push_back(resolveImageViews[resolveViewIdx].get());
5542             }
5543         }
5544 
5545         renderPassFramebuffers.emplace_back(m_testConfig.pipelineConstructionType, vkd, device, &renderPassCreateInfo);
5546 
5547         const vk::VkFramebufferCreateInfo framebufferCreateInfo = {
5548             vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
5549             nullptr,                                       // const void* pNext;
5550             0u,                                            // VkFramebufferCreateFlags flags;
5551             renderPassFramebuffers[iterIdx].get(),         // VkRenderPass renderPass;
5552             static_cast<uint32_t>(attachments.size()),     // uint32_t attachmentCount;
5553             attachments.data(),                            // const VkImageView* pAttachments;
5554             kFramebufferWidth,                             // uint32_t width;
5555             kFramebufferHeight,                            // uint32_t height;
5556             1u,                                            // uint32_t layers;
5557         };
5558 
5559         renderPassFramebuffers[iterIdx].createFramebuffer(vkd, device, &framebufferCreateInfo, images);
5560     }
5561 
5562     // Shader modules.
5563     const auto &binaries         = m_context.getBinaryCollection();
5564     const auto dynamicVertModule = vk::ShaderWrapper(vkd, device, binaries.get("dynamicVert"));
5565     const auto staticVertModule  = vk::ShaderWrapper(vkd, device, binaries.get("staticVert"));
5566     const auto dynamicFragModule =
5567         vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("dynamicFrag"), 0u);
5568     const auto staticFragModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("staticFrag"), 0u);
5569     const auto geomModule = (m_testConfig.needsGeometryShader() ? vk::ShaderWrapper(vkd, device, binaries.get("geom")) :
5570                                                                   vk::ShaderWrapper());
5571     const auto tescModule =
5572         (m_testConfig.needsTessellation() ? vk::ShaderWrapper(vkd, device, binaries.get("tesc")) : vk::ShaderWrapper());
5573     const auto teseModule =
5574         (m_testConfig.needsTessellation() ? vk::ShaderWrapper(vkd, device, binaries.get("tese")) : vk::ShaderWrapper());
5575     const auto dynamicMeshModule =
5576         (m_testConfig.useMeshShaders ? vk::ShaderWrapper(vkd, device, binaries.get("dynamicMesh")) :
5577                                        vk::ShaderWrapper());
5578     const auto staticMeshModule =
5579         (m_testConfig.useMeshShaders ? vk::ShaderWrapper(vkd, device, binaries.get("staticMesh")) :
5580                                        vk::ShaderWrapper());
5581     const auto meshNoOutModule =
5582         (m_testConfig.bindUnusedMeshShadingPipeline ? vk::ShaderWrapper(vkd, device, binaries.get("meshNoOut")) :
5583                                                       vk::ShaderWrapper());
5584 
5585     vk::ShaderWrapper vertDPCPModule;
5586     vk::ShaderWrapper fragDPCPModule;
5587 
5588     // Input state.
5589     const auto vertexBindings =
5590         m_testConfig.vertexGenerator.staticValue->getBindingDescriptions(m_testConfig.strideConfig.staticValue);
5591     const auto vertexAttributes = m_testConfig.vertexGenerator.staticValue->getAttributeDescriptions();
5592 
5593     const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
5594         vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
5595         nullptr,                                                       // const void* pNext;
5596         0u,                                                            // VkPipelineVertexInputStateCreateFlags flags;
5597         static_cast<uint32_t>(vertexBindings.size()),                  // uint32_t vertexBindingDescriptionCount;
5598         vertexBindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
5599         static_cast<uint32_t>(vertexAttributes.size()), // uint32_t vertexAttributeDescriptionCount;
5600         vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
5601     };
5602 
5603     // Input assembly.
5604     const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
5605         vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
5606         nullptr,                                                         // const void* pNext;
5607         0u,                                      // VkPipelineInputAssemblyStateCreateFlags flags;
5608         m_testConfig.topologyConfig.staticValue, // VkPrimitiveTopology topology;
5609         makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue), // VkBool32 primitiveRestartEnable;
5610     };
5611 
5612     // Viewport state.
5613     if (m_testConfig.viewportConfig.dynamicValue)
5614         DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
5615     else
5616         DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
5617 
5618     if (m_testConfig.scissorConfig.dynamicValue)
5619         DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
5620     else
5621         DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
5622 
5623     // Rasterization state.
5624     void *multisamplePnext   = nullptr;
5625     void *rasterizationPnext = nullptr;
5626     void *viewportPnext      = nullptr;
5627 
5628     const bool staticStreamInfo           = static_cast<bool>(m_testConfig.rasterizationStreamConfig.staticValue);
5629     const bool staticProvokingVtxInfo     = static_cast<bool>(m_testConfig.provokingVertexConfig.staticValue);
5630     const bool staticDepthClipEnableInfo  = static_cast<bool>(m_testConfig.depthClipEnableConfig.staticValue);
5631     const bool staticDepthClipControlInfo = static_cast<bool>(m_testConfig.negativeOneToOneConfig.staticValue);
5632 #ifndef CTS_USES_VULKANSC
5633     using RastStreamInfoPtr    = de::MovePtr<vk::VkPipelineRasterizationStateStreamCreateInfoEXT>;
5634     using ProvokingVtxModePtr  = de::MovePtr<vk::VkPipelineRasterizationProvokingVertexStateCreateInfoEXT>;
5635     using DepthClipControlPtr  = de::MovePtr<vk::VkPipelineViewportDepthClipControlCreateInfoEXT>;
5636     using DepthClipEnablePtr   = de::MovePtr<vk::VkPipelineRasterizationDepthClipStateCreateInfoEXT>;
5637     using ConservativeRastPtr  = de::MovePtr<vk::VkPipelineRasterizationConservativeStateCreateInfoEXT>;
5638     using DepthBiasReprInfoPtr = de::MovePtr<vk::VkDepthBiasRepresentationInfoEXT>;
5639 
5640     RastStreamInfoPtr pRasterizationStreamInfo;
5641 
5642     if (staticStreamInfo)
5643     {
5644         pRasterizationStreamInfo = RastStreamInfoPtr(
5645             new vk::VkPipelineRasterizationStateStreamCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
5646         pRasterizationStreamInfo->rasterizationStream = m_testConfig.rasterizationStreamConfig.staticValue.get();
5647         rasterizationPnext                            = pRasterizationStreamInfo.get();
5648     }
5649 
5650     ProvokingVtxModePtr pProvokingVertexModeInfo;
5651 
5652     if (staticProvokingVtxInfo)
5653     {
5654         pProvokingVertexModeInfo = ProvokingVtxModePtr(new vk::VkPipelineRasterizationProvokingVertexStateCreateInfoEXT(
5655             vk::initVulkanStructure(rasterizationPnext)));
5656         pProvokingVertexModeInfo->provokingVertexMode =
5657             makeProvokingVertexMode(m_testConfig.provokingVertexConfig.staticValue.get());
5658         rasterizationPnext = pProvokingVertexModeInfo.get();
5659     }
5660 
5661     DepthClipEnablePtr pDepthClipEnableInfo;
5662 
5663     if (staticDepthClipEnableInfo)
5664     {
5665         pDepthClipEnableInfo = DepthClipEnablePtr(
5666             new vk::VkPipelineRasterizationDepthClipStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
5667         pDepthClipEnableInfo->depthClipEnable = makeVkBool32(m_testConfig.depthClipEnableConfig.staticValue.get());
5668         rasterizationPnext                    = pDepthClipEnableInfo.get();
5669     }
5670 
5671     DepthClipControlPtr pDepthClipControlInfo;
5672 
5673     if (staticDepthClipControlInfo)
5674     {
5675         pDepthClipControlInfo = DepthClipControlPtr(
5676             new vk::VkPipelineViewportDepthClipControlCreateInfoEXT(vk::initVulkanStructure(viewportPnext)));
5677         pDepthClipControlInfo->negativeOneToOne = makeVkBool32(m_testConfig.negativeOneToOneConfig.staticValue.get());
5678         viewportPnext                           = pDepthClipControlInfo.get();
5679     }
5680 
5681     ConservativeRastPtr pConservativeRasterModeInfo;
5682 
5683     if (m_testConfig.conservativeRasterStruct())
5684     {
5685         pConservativeRasterModeInfo = ConservativeRastPtr(
5686             new vk::VkPipelineRasterizationConservativeStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
5687         rasterizationPnext = pConservativeRasterModeInfo.get();
5688 
5689         pConservativeRasterModeInfo->conservativeRasterizationMode =
5690             m_testConfig.conservativeRasterModeConfig.staticValue;
5691         pConservativeRasterModeInfo->extraPrimitiveOverestimationSize =
5692             m_testConfig.extraPrimitiveOverEstConfig.staticValue;
5693     }
5694 
5695     DepthBiasReprInfoPtr pDepthBiasReprInfo;
5696 
5697     if (m_testConfig.depthBiasReprInfo && (!m_testConfig.depthBiasConfig.dynamicValue || kReversed))
5698     {
5699         // Representation info will be passed statically.
5700         pDepthBiasReprInfo =
5701             DepthBiasReprInfoPtr(new vk::VkDepthBiasRepresentationInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
5702         rasterizationPnext = pDepthBiasReprInfo.get();
5703 
5704         const auto &reprInfo                        = m_testConfig.depthBiasReprInfo.get();
5705         pDepthBiasReprInfo->depthBiasRepresentation = reprInfo.depthBiasRepresentation;
5706         pDepthBiasReprInfo->depthBiasExact          = reprInfo.depthBiasExact;
5707     }
5708 #else
5709     DE_ASSERT(!staticStreamInfo);
5710     DE_ASSERT(!staticProvokingVtxInfo);
5711     DE_ASSERT(!staticDepthClipEnableInfo);
5712     DE_ASSERT(!staticDepthClipControlInfo);
5713     DE_ASSERT(!m_testConfig.conservativeRasterStruct());
5714     DE_UNREF(staticStreamInfo);
5715     DE_UNREF(staticProvokingVtxInfo);
5716     DE_UNREF(staticDepthClipEnableInfo);
5717     DE_UNREF(staticDepthClipControlInfo);
5718 #endif // CTS_USES_VULKANSC
5719 
5720     using LineRasterModePtr = de::MovePtr<vk::VkPipelineRasterizationLineStateCreateInfoEXT>;
5721     LineRasterModePtr pLineRasterModeInfo;
5722 
5723     if (m_testConfig.lineRasterStruct())
5724     {
5725         DE_ASSERT(static_cast<bool>(m_testConfig.lineStippleParamsConfig.staticValue));
5726 
5727         pLineRasterModeInfo = LineRasterModePtr(
5728             new vk::VkPipelineRasterizationLineStateCreateInfoEXT(vk::initVulkanStructure(rasterizationPnext)));
5729         rasterizationPnext = pLineRasterModeInfo.get();
5730 
5731         const auto &lineRasterFeatures = m_context.getLineRasterizationFeatures();
5732         const auto lineRasterMode =
5733             selectLineRasterizationMode(lineRasterFeatures, m_testConfig.lineStippleSupportRequired(),
5734                                         m_testConfig.lineRasterModeConfig.staticValue);
5735         const auto &staticParams = m_testConfig.lineStippleParamsConfig.staticValue.get();
5736 
5737         pLineRasterModeInfo->stippledLineEnable    = m_testConfig.lineStippleEnableConfig.staticValue;
5738         pLineRasterModeInfo->lineRasterizationMode = makeLineRasterizationMode(lineRasterMode);
5739         pLineRasterModeInfo->lineStippleFactor     = staticParams.factor;
5740         pLineRasterModeInfo->lineStipplePattern    = staticParams.pattern;
5741     }
5742 
5743     const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = {
5744         vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
5745         rasterizationPnext,                                             // const void* pNext;
5746         0u,                                                            // VkPipelineRasterizationStateCreateFlags flags;
5747         makeVkBool32(m_testConfig.depthClampEnableConfig.staticValue), // VkBool32 depthClampEnable;
5748         makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue), // VkBool32 rasterizerDiscardEnable;
5749         m_testConfig.polygonModeConfig.staticValue,                     // VkPolygonMode polygonMode;
5750         m_testConfig.cullModeConfig.staticValue,                        // VkCullModeFlags cullMode;
5751         m_testConfig.frontFaceConfig.staticValue,                       // VkFrontFace frontFace;
5752         makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue),   // VkBool32 depthBiasEnable;
5753         m_testConfig.depthBiasConfig.staticValue.constantFactor,        // float depthBiasConstantFactor;
5754         m_testConfig.depthBiasConfig.staticValue.clamp,                 // float depthBiasClamp;
5755         0.0f,                                                           // float depthBiasSlopeFactor;
5756         m_testConfig.lineWidthConfig.staticValue,                       // float lineWidth;
5757     };
5758 
5759     using SampleLocationsPtr = de::MovePtr<vk::VkPipelineSampleLocationsStateCreateInfoEXT>;
5760     SampleLocationsPtr pSampleLocations;
5761     std::vector<vk::VkSampleLocationEXT> sampleLocationCoords;
5762 
5763 #ifndef CTS_USES_VULKANSC
5764     using CoverageToColorPtr = de::MovePtr<vk::VkPipelineCoverageToColorStateCreateInfoNV>;
5765     CoverageToColorPtr pCoverageToColor;
5766 
5767     using CoverageModulationPtr = de::MovePtr<vk::VkPipelineCoverageModulationStateCreateInfoNV>;
5768     CoverageModulationPtr pCoverageModulation;
5769 
5770     using CoverageReductionPtr = de::MovePtr<vk::VkPipelineCoverageReductionStateCreateInfoNV>;
5771     CoverageReductionPtr pCoverageReduction;
5772 
5773     using ViewportSwizzlePtr = de::MovePtr<vk::VkPipelineViewportSwizzleStateCreateInfoNV>;
5774     ViewportSwizzlePtr pViewportSwizzle;
5775 
5776     using ShadingRateImagePtr = de::MovePtr<vk::VkPipelineViewportShadingRateImageStateCreateInfoNV>;
5777     ShadingRateImagePtr pShadingRateImage;
5778 
5779     using ViewportWScalingPtr = de::MovePtr<vk::VkPipelineViewportWScalingStateCreateInfoNV>;
5780     ViewportWScalingPtr pViewportWScaling;
5781 
5782     using ReprFragmentPtr = de::MovePtr<vk::VkPipelineRepresentativeFragmentTestStateCreateInfoNV>;
5783     ReprFragmentPtr pReprFragment;
5784 #endif // CTS_USES_VULKANSC
5785 
5786     if (m_testConfig.sampleLocationsStruct())
5787     {
5788         pSampleLocations = SampleLocationsPtr(
5789             new vk::VkPipelineSampleLocationsStateCreateInfoEXT(vk::initVulkanStructure(multisamplePnext)));
5790         multisamplePnext = pSampleLocations.get();
5791 
5792         pSampleLocations->sampleLocationsEnable = makeVkBool32(m_testConfig.sampleLocationsEnableConfig.staticValue);
5793         pSampleLocations->sampleLocationsInfo   = vk::initVulkanStructure();
5794         pSampleLocations->sampleLocationsInfo.sampleLocationsPerPixel = activeSampleCount;
5795         pSampleLocations->sampleLocationsInfo.sampleLocationGridSize  = vk::makeExtent2D(1u, 1u);
5796         pSampleLocations->sampleLocationsInfo.sampleLocationsCount    = static_cast<uint32_t>(activeSampleCount);
5797 
5798         sampleLocationCoords.reserve(pSampleLocations->sampleLocationsInfo.sampleLocationsCount);
5799         for (uint32_t i = 0; i < pSampleLocations->sampleLocationsInfo.sampleLocationsCount; ++i)
5800             sampleLocationCoords.push_back(
5801                 vk::VkSampleLocationEXT{m_testConfig.sampleLocations.x(), m_testConfig.sampleLocations.y()});
5802 
5803         pSampleLocations->sampleLocationsInfo.pSampleLocations = sampleLocationCoords.data();
5804     }
5805 
5806 #ifndef CTS_USES_VULKANSC
5807     if (m_testConfig.coverageToColorStruct())
5808     {
5809         pCoverageToColor = CoverageToColorPtr(
5810             new vk::VkPipelineCoverageToColorStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
5811         multisamplePnext = pCoverageToColor.get();
5812 
5813         pCoverageToColor->coverageToColorEnable   = makeVkBool32(m_testConfig.coverageToColorEnableConfig.staticValue);
5814         pCoverageToColor->coverageToColorLocation = m_testConfig.coverageToColorLocationConfig.staticValue;
5815     }
5816 
5817     if (m_testConfig.coverageModulation)
5818     {
5819         pCoverageModulation = CoverageModulationPtr(
5820             new vk::VkPipelineCoverageModulationStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
5821         multisamplePnext = pCoverageModulation.get();
5822 
5823         pCoverageModulation->coverageModulationMode = m_testConfig.coverageModulationModeConfig.staticValue;
5824         pCoverageModulation->coverageModulationTableEnable =
5825             makeVkBool32(m_testConfig.coverageModTableEnableConfig.staticValue);
5826         pCoverageModulation->coverageModulationTableCount =
5827             static_cast<uint32_t>(m_testConfig.coverageModTableConfig.staticValue.size());
5828         pCoverageModulation->pCoverageModulationTable = de::dataOrNull(m_testConfig.coverageModTableConfig.staticValue);
5829     }
5830 
5831     if (m_testConfig.coverageReduction)
5832     {
5833         pCoverageReduction = CoverageReductionPtr(
5834             new vk::VkPipelineCoverageReductionStateCreateInfoNV(vk::initVulkanStructure(multisamplePnext)));
5835         multisamplePnext = pCoverageReduction.get();
5836 
5837         pCoverageReduction->coverageReductionMode = m_testConfig.coverageReductionModeConfig.staticValue;
5838     }
5839 
5840     if (m_testConfig.viewportSwizzle)
5841     {
5842         pViewportSwizzle = ViewportSwizzlePtr(
5843             new vk::VkPipelineViewportSwizzleStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
5844         viewportPnext = pViewportSwizzle.get();
5845 
5846         const auto &swizzleVec              = m_testConfig.viewportSwizzleConfig.staticValue;
5847         pViewportSwizzle->viewportCount     = static_cast<uint32_t>(swizzleVec.size());
5848         pViewportSwizzle->pViewportSwizzles = de::dataOrNull(swizzleVec);
5849     }
5850 
5851     const vk::VkShadingRatePaletteEntryNV defaultShadingRatePaletteEntry =
5852         vk::VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV;
5853     const auto defaultShadingRatePalette = vk::makeShadingRatePaletteNV(1u, &defaultShadingRatePaletteEntry);
5854     std::vector<vk::VkShadingRatePaletteNV> shadingRatePaletteVec;
5855 
5856     const auto defaultViewportWScalingFactors = vk::makeViewportWScalingNV(-1.0f, -1.0f);
5857     std::vector<vk::VkViewportWScalingNV> viewportWScalingVec;
5858 
5859     if (m_testConfig.shadingRateImage)
5860     {
5861         pShadingRateImage = ShadingRateImagePtr(
5862             new vk::VkPipelineViewportShadingRateImageStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
5863         viewportPnext = pShadingRateImage.get();
5864 
5865         const auto &viewportVec                   = m_testConfig.getActiveViewportVec();
5866         pShadingRateImage->shadingRateImageEnable = makeVkBool32(m_testConfig.shadingRateImageEnableConfig.staticValue);
5867         pShadingRateImage->viewportCount          = de::sizeU32(viewportVec);
5868 
5869         shadingRatePaletteVec.resize(viewportVec.size(), defaultShadingRatePalette);
5870         pShadingRateImage->pShadingRatePalettes = shadingRatePaletteVec.data();
5871     }
5872 
5873     if (m_testConfig.viewportWScaling)
5874     {
5875         pViewportWScaling = ViewportWScalingPtr(
5876             new vk::VkPipelineViewportWScalingStateCreateInfoNV(vk::initVulkanStructure(viewportPnext)));
5877         viewportPnext = pViewportWScaling.get();
5878 
5879         const auto &viewportVec                   = m_testConfig.getActiveViewportVec();
5880         pViewportWScaling->viewportWScalingEnable = makeVkBool32(m_testConfig.viewportWScalingEnableConfig.staticValue);
5881         pViewportWScaling->viewportCount          = de::sizeU32(viewportVec);
5882 
5883         viewportWScalingVec.resize(viewportVec.size(), defaultViewportWScalingFactors);
5884         pViewportWScaling->pViewportWScalings = viewportWScalingVec.data();
5885     }
5886 
5887     if (m_testConfig.representativeFragmentTest)
5888     {
5889         pReprFragment =
5890             ReprFragmentPtr(new vk::VkPipelineRepresentativeFragmentTestStateCreateInfoNV(vk::initVulkanStructure()));
5891         pReprFragment->representativeFragmentTestEnable =
5892             makeVkBool32(m_testConfig.reprFragTestEnableConfig.staticValue);
5893     }
5894 #endif // CTS_USES_VULKANSC
5895 
5896     // Multisample state.
5897     const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{
5898         vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
5899         multisamplePnext,                                             // const void* pNext;
5900         0u,                                                           // VkPipelineMultisampleStateCreateFlags flags;
5901         m_testConfig.rasterizationSamplesConfig.staticValue,          // VkSampleCountFlagBits rasterizationSamples;
5902         makeVkBool32(m_testConfig.sampleShadingEnable),               // VkBool32 sampleShadingEnable;
5903         m_testConfig.minSampleShading,                                // float minSampleShading;
5904         de::dataOrNull(m_testConfig.sampleMaskConfig.staticValue),    // const VkSampleMask* pSampleMask;
5905         makeVkBool32(m_testConfig.alphaToCoverageConfig.staticValue), // VkBool32 alphaToCoverageEnable;
5906         makeVkBool32(m_testConfig.alphaToOneConfig.staticValue),      // VkBool32 alphaToOneEnable;
5907     };
5908 
5909     // Depth/stencil state.
5910     vk::VkStencilOpState staticFrontStencil;
5911     vk::VkStencilOpState staticBackStencil;
5912     bool staticFrontStencilSet = false;
5913     bool staticBackStencilSet  = false;
5914 
5915     // Common setup for the front and back operations.
5916     staticFrontStencil.compareMask = 0xFFu;
5917     staticFrontStencil.writeMask   = 0xFFu;
5918     staticFrontStencil.reference   = m_testConfig.referenceStencil;
5919     staticBackStencil              = staticFrontStencil;
5920 
5921     for (const auto &op : m_testConfig.stencilOpConfig.staticValue)
5922     {
5923         if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
5924         {
5925             copy(staticFrontStencil, op);
5926             staticFrontStencilSet = true;
5927         }
5928         if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
5929         {
5930             copy(staticBackStencil, op);
5931             staticBackStencilSet = true;
5932         }
5933     }
5934 
5935     // Default values for the static part.
5936     if (!staticFrontStencilSet)
5937         copy(staticFrontStencil, kDefaultStencilOpParams);
5938     if (!staticBackStencilSet)
5939         copy(staticBackStencil, kDefaultStencilOpParams);
5940 
5941     const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
5942         vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
5943         nullptr,                                                        // const void* pNext;
5944         0u,                                                             // VkPipelineDepthStencilStateCreateFlags flags;
5945         makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),   // VkBool32 depthTestEnable;
5946         makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),  // VkBool32 depthWriteEnable;
5947         m_testConfig.depthCompareOpConfig.staticValue,                  // VkCompareOp depthCompareOp;
5948         makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue), // VkBool32 depthBoundsTestEnable;
5949         makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),     // VkBool32 stencilTestEnable;
5950         staticFrontStencil,                                                 // VkStencilOpState front;
5951         staticBackStencil,                                                  // VkStencilOpState back;
5952         m_testConfig.depthBoundsConfig.staticValue.first,                   // float minDepthBounds;
5953         m_testConfig.depthBoundsConfig.staticValue.second,                  // float maxDepthBounds;
5954     };
5955 
5956     // Dynamic state. Here we will set all states which have a dynamic value.
5957     const auto dynamicStates = m_testConfig.getDynamicStates();
5958 
5959     const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo = {
5960         vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
5961         nullptr,                                                  // const void* pNext;
5962         0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
5963         static_cast<uint32_t>(dynamicStates.size()),              // uint32_t dynamicStateCount;
5964         de::dataOrNull(dynamicStates),                            // const VkDynamicState* pDynamicStates;
5965     };
5966 
5967     const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
5968         makeVkBool32(m_testConfig.colorBlendEnableConfig.staticValue), // VkBool32                 blendEnable
5969         m_testConfig.colorBlendEquationConfig.staticValue
5970             .srcColorBlendFactor, // VkBlendFactor            srcColorBlendFactor
5971         m_testConfig.colorBlendEquationConfig.staticValue
5972             .dstColorBlendFactor,                                       // VkBlendFactor            dstColorBlendFactor
5973         m_testConfig.colorBlendEquationConfig.staticValue.colorBlendOp, // VkBlendOp                colorBlendOp
5974         m_testConfig.colorBlendEquationConfig.staticValue
5975             .srcAlphaBlendFactor, // VkBlendFactor            srcAlphaBlendFactor
5976         m_testConfig.colorBlendEquationConfig.staticValue
5977             .dstAlphaBlendFactor,                                       // VkBlendFactor            dstAlphaBlendFactor
5978         m_testConfig.colorBlendEquationConfig.staticValue.alphaBlendOp, // VkBlendOp                alphaBlendOp
5979         m_testConfig.colorWriteMaskConfig.staticValue,                  // VkColorComponentFlags    colorWriteMask
5980     };
5981     const std::vector<vk::VkPipelineColorBlendAttachmentState> colorBlendAttachmentStateVec(kColorAttCount,
5982                                                                                             colorBlendAttachmentState);
5983 
5984     void *colorBlendPnext = nullptr;
5985 
5986     using ColorBlendAdvancedPtr = de::MovePtr<vk::VkPipelineColorBlendAdvancedStateCreateInfoEXT>;
5987     ColorBlendAdvancedPtr pColorBlendAdvanced;
5988 
5989     if (m_testConfig.colorBlendEquationConfig.staticValue.isAdvanced())
5990     {
5991         pColorBlendAdvanced = ColorBlendAdvancedPtr(
5992             new vk::VkPipelineColorBlendAdvancedStateCreateInfoEXT(vk::initVulkanStructure(colorBlendPnext)));
5993         pColorBlendAdvanced->srcPremultiplied = VK_TRUE;
5994         pColorBlendAdvanced->dstPremultiplied = VK_TRUE;
5995         pColorBlendAdvanced->blendOverlap     = vk::VK_BLEND_OVERLAP_UNCORRELATED_EXT;
5996         colorBlendPnext                       = pColorBlendAdvanced.get();
5997     }
5998 
5999     const std::vector<vk::VkBool32> colorWriteValues(colorBlendAttachmentStateVec.size(),
6000                                                      m_testConfig.colorWriteEnableConfig.staticValue);
6001 
6002     using ColorWriteEnablePtr = de::MovePtr<vk::VkPipelineColorWriteCreateInfoEXT>;
6003     ColorWriteEnablePtr pColorWriteEnable;
6004 
6005     if (m_testConfig.useColorWriteEnable)
6006     {
6007         pColorWriteEnable =
6008             ColorWriteEnablePtr(new vk::VkPipelineColorWriteCreateInfoEXT(vk::initVulkanStructure(colorBlendPnext)));
6009         pColorWriteEnable->attachmentCount    = de::sizeU32(colorWriteValues);
6010         pColorWriteEnable->pColorWriteEnables = de::dataOrNull(colorWriteValues);
6011         colorBlendPnext                       = pColorWriteEnable.get();
6012     }
6013 
6014     if (m_testConfig.nullStaticColorBlendAttPtr || m_testConfig.colorBlendAttCnt0)
6015     {
6016         DE_ASSERT(static_cast<bool>(m_testConfig.colorBlendEnableConfig.dynamicValue));
6017         DE_ASSERT(static_cast<bool>(m_testConfig.colorBlendEquationConfig.dynamicValue));
6018         DE_ASSERT(static_cast<bool>(m_testConfig.colorWriteMaskConfig.dynamicValue));
6019     }
6020 
6021     const auto attachmentCount = m_testConfig.colorBlendAttCnt0 ? 0u : de::sizeU32(colorBlendAttachmentStateVec);
6022     const auto attachments =
6023         m_testConfig.nullStaticColorBlendAttPtr ? nullptr : de::dataOrNull(colorBlendAttachmentStateVec);
6024 
6025     const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = {
6026         vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType                               sType
6027         colorBlendPnext,                              // const void*                                   pNext
6028         0u,                                           // VkPipelineColorBlendStateCreateFlags          flags
6029         m_testConfig.logicOpEnableConfig.staticValue, // VkBool32                                      logicOpEnable
6030         m_testConfig.logicOpConfig.staticValue,       // VkLogicOp                                     logicOp
6031         attachmentCount,                              // uint32_t                                      attachmentCount
6032         attachments,                                  // const VkPipelineColorBlendAttachmentState*    pAttachments
6033         {
6034             // float                                         blendConstants[4]
6035             m_testConfig.blendConstantsConfig.staticValue[0],
6036             m_testConfig.blendConstantsConfig.staticValue[1],
6037             m_testConfig.blendConstantsConfig.staticValue[2],
6038             m_testConfig.blendConstantsConfig.staticValue[3],
6039         },
6040     };
6041 
6042     vk::GraphicsPipelineWrapper staticPipeline(vki, vkd, physicalDevice, device, deviceHelper.getDeviceExtensions(),
6043                                                m_testConfig.pipelineConstructionType);
6044 
6045     // Create extra dynamic patch control points pipeline if needed.
6046     vk::GraphicsPipelineWrapper extraDynPCPPipeline(
6047         vki, vkd, physicalDevice, device, deviceHelper.getDeviceExtensions(), m_testConfig.pipelineConstructionType);
6048 
6049     if (m_testConfig.useExtraDynPCPPipeline)
6050     {
6051         vertDPCPModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vertDPCP"));
6052         fragDPCPModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("fragDPCP"));
6053 
6054         const vk::VkPipelineVertexInputStateCreateInfo extraDPCPInputState = vk::initVulkanStructure();
6055         const vk::VkDynamicState extraDynamicState = vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT;
6056         const vk::VkPipelineDynamicStateCreateInfo extraDynamicStateInfo = {
6057             vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
6058             nullptr,                                                  // const void* pNext;
6059             0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
6060             1u,                                                       // uint32_t dynamicStateCount;
6061             &extraDynamicState,                                       // const VkDynamicState* pDynamicStates;
6062         };
6063 
6064         const vk::PipelineLayoutWrapper extraPipelineLayout(m_testConfig.pipelineConstructionType, vkd, device);
6065 
6066         const auto viewports = m_testConfig.viewportConfig.staticValue;
6067         const auto scissors  = m_testConfig.scissorConfig.staticValue;
6068 
6069         extraDynPCPPipeline.setDynamicState(&extraDynamicStateInfo)
6070             .setDefaultTopology(vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
6071             .setDefaultColorBlendState()
6072             .setDefaultMultisampleState()
6073             .setupVertexInputState(&extraDPCPInputState)
6074             .setupPreRasterizationShaderState(viewports, scissors, extraPipelineLayout, *renderPassFramebuffers[0], 0u,
6075                                               vertDPCPModule, &rasterizationStateCreateInfo)
6076             .setupFragmentShaderState(extraPipelineLayout, *renderPassFramebuffers[0], 0u, fragDPCPModule,
6077                                       &depthStencilStateCreateInfo)
6078             .setupFragmentOutputState(*renderPassFramebuffers[0], 0u)
6079             .setMonolithicPipelineLayout(extraPipelineLayout)
6080             .buildPipeline();
6081     }
6082     else if (m_testConfig.useExtraDynPipeline)
6083     {
6084         vertDPCPModule = vk::ShaderWrapper(vkd, device, m_context.getBinaryCollection().get("vertDPCP"));
6085     }
6086 
6087     // Create static pipeline when needed.
6088     if (kUseStaticPipeline)
6089     {
6090         auto viewports = m_testConfig.viewportConfig.staticValue;
6091         auto scissors  = m_testConfig.scissorConfig.staticValue;
6092 
6093         // The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
6094         const auto minStaticCount = static_cast<uint32_t>(
6095             std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
6096         viewports.resize(minStaticCount);
6097         scissors.resize(minStaticCount);
6098 
6099         staticPipeline.setDefaultPatchControlPoints(m_testConfig.patchControlPointsConfig.staticValue)
6100             .setViewportStatePnext(viewportPnext)
6101             .setDefaultTessellationDomainOrigin(m_testConfig.tessDomainOriginConfig.staticValue);
6102 
6103         // The pAttachments pointer must never be null for the static pipeline.
6104         vk::VkPipelineColorBlendStateCreateInfo staticCBStateInfo = colorBlendStateCreateInfo;
6105         if (m_testConfig.nullStaticColorBlendAttPtr)
6106             staticCBStateInfo.pAttachments = de::dataOrNull(colorBlendAttachmentStateVec);
6107 
6108         // The attachment count must never be 0 for the static pipeline.
6109         if (m_testConfig.colorBlendAttCnt0)
6110             staticCBStateInfo.attachmentCount = de::sizeU32(colorBlendAttachmentStateVec);
6111 
6112 #ifndef CTS_USES_VULKANSC
6113         if (m_testConfig.useMeshShaders)
6114         {
6115             staticPipeline.setupPreRasterizationMeshShaderState(viewports, scissors, pipelineLayout,
6116                                                                 *renderPassFramebuffers[0], 0u, vk::ShaderWrapper(),
6117                                                                 staticMeshModule, &rasterizationStateCreateInfo);
6118         }
6119         else
6120 #endif // CTS_USES_VULKANSC
6121         {
6122             staticPipeline.setupVertexInputState(&vertexInputStateCreateInfo, &inputAssemblyStateCreateInfo)
6123                 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPassFramebuffers[0], 0u,
6124                                                   staticVertModule, &rasterizationStateCreateInfo, tescModule,
6125                                                   teseModule, geomModule);
6126         }
6127 
6128         vk::ShaderWrapper emptyFrag{};
6129         const vk::ShaderWrapper &fragForStatic =
6130             m_testConfig.rastDiscardEnableConfig.staticValue ? emptyFrag : staticFragModule;
6131 
6132         staticPipeline
6133 #ifndef CTS_USES_VULKANSC
6134             .setRepresentativeFragmentTestState(pReprFragment.get())
6135 #endif // CTS_USES_VULKANSC
6136             .setupFragmentShaderState(pipelineLayout, *renderPassFramebuffers[0], 0u, fragForStatic,
6137                                       &depthStencilStateCreateInfo, &multisampleStateCreateInfo)
6138             .setupFragmentOutputState(*renderPassFramebuffers[0], 0u, &staticCBStateInfo, &multisampleStateCreateInfo)
6139             .setMonolithicPipelineLayout(pipelineLayout)
6140             .buildPipeline();
6141     }
6142 
6143     // Create dynamic pipeline.
6144     vk::GraphicsPipelineWrapper graphicsPipeline(vki, vkd, physicalDevice, device, deviceHelper.getDeviceExtensions(),
6145                                                  m_testConfig.pipelineConstructionType);
6146     vk::GraphicsPipelineWrapper extraDynPipeline(vki, vkd, physicalDevice, device, deviceHelper.getDeviceExtensions(),
6147                                                  m_testConfig.pipelineConstructionType);
6148     {
6149         auto viewports = m_testConfig.viewportConfig.staticValue;
6150         auto scissors  = m_testConfig.scissorConfig.staticValue;
6151 
6152         const auto finalDynamicViewportCount =
6153             (m_testConfig.viewportConfig.dynamicValue ? m_testConfig.viewportConfig.dynamicValue.get().size() :
6154                                                         m_testConfig.viewportConfig.staticValue.size());
6155 
6156         const auto finalDynamicScissorCount =
6157             (m_testConfig.scissorConfig.dynamicValue ? m_testConfig.scissorConfig.dynamicValue.get().size() :
6158                                                        m_testConfig.scissorConfig.staticValue.size());
6159 
6160         const auto minDynamicCount =
6161             static_cast<uint32_t>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
6162 
6163         // The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
6164         if (m_testConfig.viewportConfig.dynamicValue)
6165         {
6166             graphicsPipeline.setDefaultViewportsCount();
6167             if (m_testConfig.useExtraDynPipeline)
6168                 extraDynPipeline.setDefaultViewportsCount();
6169             viewports = std::vector<vk::VkViewport>();
6170         }
6171         else
6172             viewports.resize(minDynamicCount);
6173 
6174         if (m_testConfig.scissorConfig.dynamicValue)
6175         {
6176             graphicsPipeline.setDefaultScissorsCount();
6177             if (m_testConfig.useExtraDynPipeline)
6178                 extraDynPipeline.setDefaultScissorsCount();
6179             scissors = std::vector<vk::VkRect2D>();
6180         }
6181         else
6182             scissors.resize(minDynamicCount);
6183 
6184         // Setting patch control points to std::numeric_limits<uint32_t>::max() will force null tessellation state pointer.
6185         const auto patchControlPoints =
6186             ((m_testConfig.favorStaticNullPointers && m_testConfig.patchControlPointsConfig.dynamicValue) ?
6187                  std::numeric_limits<uint32_t>::max() :
6188                  m_testConfig.patchControlPointsConfig.staticValue);
6189 
6190         const auto disableViewportState =
6191             (m_testConfig.favorStaticNullPointers && m_testConfig.viewportConfig.dynamicValue &&
6192              m_testConfig.scissorConfig.dynamicValue);
6193 
6194         graphicsPipeline.setDynamicState(&dynamicStateCreateInfo)
6195             .setDefaultPatchControlPoints(patchControlPoints)
6196             .setViewportStatePnext(viewportPnext)
6197             .setDefaultTessellationDomainOrigin(m_testConfig.tessDomainOriginConfig.staticValue)
6198             .disableViewportState(disableViewportState);
6199         if (m_testConfig.useExtraDynPipeline)
6200             extraDynPipeline.setDynamicState(&dynamicStateCreateInfo)
6201                 .setDefaultPatchControlPoints(patchControlPoints)
6202                 .setViewportStatePnext(viewportPnext)
6203                 .setDefaultTessellationDomainOrigin(m_testConfig.tessDomainOriginConfig.staticValue)
6204                 .disableViewportState(disableViewportState);
6205 
6206         const auto staticRasterizationStateCreateInfo =
6207             ((m_testConfig.favorStaticNullPointers && m_testConfig.depthClampEnableConfig.dynamicValue &&
6208               m_testConfig.rastDiscardEnableConfig.dynamicValue && m_testConfig.polygonModeConfig.dynamicValue &&
6209               m_testConfig.cullModeConfig.dynamicValue && m_testConfig.frontFaceConfig.dynamicValue &&
6210               m_testConfig.depthBiasEnableConfig.dynamicValue && m_testConfig.depthBiasConfig.dynamicValue &&
6211               m_testConfig.lineWidthConfig.dynamicValue) ?
6212                  nullptr :
6213                  &rasterizationStateCreateInfo);
6214 
6215         DE_ASSERT(!m_testConfig.useExtraDynPipeline || !m_testConfig.useMeshShaders);
6216 
6217         const vk::VkPipelineVertexInputStateCreateInfo emptyVertexInputStateCreateInfo = {
6218             vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
6219             DE_NULL,                                                       // const void* pNext;
6220             0u,      // VkPipelineVertexInputStateCreateFlags flags;
6221             0u,      // uint32_t vertexBindingDescriptionCount;
6222             DE_NULL, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
6223             0u,      // uint32_t vertexAttributeDescriptionCount;
6224             DE_NULL, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
6225         };
6226 
6227 #ifndef CTS_USES_VULKANSC
6228         if (m_testConfig.useMeshShaders)
6229         {
6230             graphicsPipeline.setupPreRasterizationMeshShaderState(
6231                 viewports, scissors, pipelineLayout, *renderPassFramebuffers[0], 0u, vk::ShaderWrapper(),
6232                 dynamicMeshModule, staticRasterizationStateCreateInfo);
6233         }
6234         else
6235 #endif // CTS_USES_VULKANSC
6236         {
6237             const auto staticVertexInputStateCreateInfo =
6238                 ((m_testConfig.favorStaticNullPointers && m_testConfig.testVertexDynamic()) ?
6239                      nullptr :
6240                      &vertexInputStateCreateInfo);
6241 
6242             const auto staticInputAssemblyStateCreateInfo =
6243                 ((m_testConfig.favorStaticNullPointers && m_testConfig.primRestartEnableConfig.dynamicValue &&
6244                   m_testConfig.topologyConfig.dynamicValue) ?
6245                      nullptr :
6246                      &inputAssemblyStateCreateInfo);
6247 
6248             graphicsPipeline
6249                 .setupVertexInputState(staticVertexInputStateCreateInfo, staticInputAssemblyStateCreateInfo,
6250                                        VK_NULL_HANDLE, vk::PipelineCreationFeedbackCreateInfoWrapper(),
6251                                        m_testConfig.favorStaticNullPointers)
6252                 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPassFramebuffers[0], 0u,
6253                                                   dynamicVertModule, staticRasterizationStateCreateInfo, tescModule,
6254                                                   teseModule, geomModule);
6255 
6256             if (m_testConfig.useExtraDynPipeline)
6257                 extraDynPipeline
6258                     .setupVertexInputState(&emptyVertexInputStateCreateInfo, staticInputAssemblyStateCreateInfo,
6259                                            VK_NULL_HANDLE, vk::PipelineCreationFeedbackCreateInfoWrapper(),
6260                                            m_testConfig.favorStaticNullPointers)
6261                     .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPassFramebuffers[0],
6262                                                       0u, vertDPCPModule, staticRasterizationStateCreateInfo);
6263         }
6264 
6265         const auto staticMultisampleStateCreateInfo =
6266             ((m_testConfig.favorStaticNullPointers && m_testConfig.rasterizationSamplesConfig.dynamicValue &&
6267               m_testConfig.sampleMaskConfig.dynamicValue && m_testConfig.alphaToCoverageConfig.dynamicValue &&
6268               (m_testConfig.alphaToOneConfig.dynamicValue || m_testConfig.disableAlphaToOneFeature)) ?
6269                  nullptr :
6270                  &multisampleStateCreateInfo);
6271 
6272         const auto staticDepthStencilStateCreateInfo =
6273             ((m_testConfig.favorStaticNullPointers && m_testConfig.depthTestEnableConfig.dynamicValue &&
6274               m_testConfig.depthWriteEnableConfig.dynamicValue && m_testConfig.depthCompareOpConfig.dynamicValue &&
6275               m_testConfig.depthBoundsTestEnableConfig.dynamicValue &&
6276               m_testConfig.stencilTestEnableConfig.dynamicValue && m_testConfig.stencilOpConfig.dynamicValue &&
6277               m_testConfig.depthBoundsConfig.dynamicValue) ?
6278                  nullptr :
6279                  &depthStencilStateCreateInfo);
6280 
6281         const auto staticColorBlendStateCreateInfo =
6282             ((m_testConfig.favorStaticNullPointers && m_testConfig.logicOpEnableConfig.dynamicValue &&
6283               m_testConfig.logicOpConfig.dynamicValue && m_testConfig.colorBlendEnableConfig.dynamicValue &&
6284               m_testConfig.colorBlendEquationConfig.dynamicValue &&
6285               (m_testConfig.colorBlendBoth || !m_testConfig.colorBlendEquationConfig.staticValue.isAdvanced()) &&
6286               m_testConfig.colorWriteMaskConfig.dynamicValue && m_testConfig.blendConstantsConfig.dynamicValue) ?
6287                  nullptr :
6288                  &colorBlendStateCreateInfo);
6289         graphicsPipeline
6290 #ifndef CTS_USES_VULKANSC
6291             .setRepresentativeFragmentTestState(pReprFragment.get())
6292 #endif // CTS_USES_VULKANSC
6293             .setupFragmentShaderState(pipelineLayout, *renderPassFramebuffers[0], 0u, dynamicFragModule,
6294                                       staticDepthStencilStateCreateInfo, staticMultisampleStateCreateInfo)
6295             .setupFragmentOutputState(*renderPassFramebuffers[0], 0u, staticColorBlendStateCreateInfo,
6296                                       staticMultisampleStateCreateInfo)
6297             .setMonolithicPipelineLayout(pipelineLayout)
6298             .buildPipeline();
6299         if (m_testConfig.useExtraDynPipeline)
6300             extraDynPipeline
6301 #ifndef CTS_USES_VULKANSC
6302                 .setRepresentativeFragmentTestState(pReprFragment.get())
6303 #endif // CTS_USES_VULKANSC
6304                 .setupFragmentShaderState(pipelineLayout, *renderPassFramebuffers[0], 0u, dynamicFragModule,
6305                                           staticDepthStencilStateCreateInfo, staticMultisampleStateCreateInfo)
6306                 .setupFragmentOutputState(*renderPassFramebuffers[0], 0u, staticColorBlendStateCreateInfo,
6307                                           staticMultisampleStateCreateInfo)
6308                 .setMonolithicPipelineLayout(pipelineLayout)
6309                 .buildPipeline();
6310     }
6311 
6312     vk::GraphicsPipelineWrapper meshNoOutPipeline(vki, vkd, physicalDevice, device, deviceHelper.getDeviceExtensions(),
6313                                                   m_testConfig.pipelineConstructionType);
6314 
6315 #ifndef CTS_USES_VULKANSC
6316     if (m_testConfig.bindUnusedMeshShadingPipeline)
6317     {
6318         // Remove dynamic states which are not compatible with mesh shading pipelines.
6319         std::vector<vk::VkDynamicState> meshNoOutDynamicStates;
6320         std::copy_if(begin(dynamicStates), end(dynamicStates), std::back_inserter(meshNoOutDynamicStates),
6321                      isMeshShadingPipelineCompatible);
6322 
6323         const vk::VkPipelineDynamicStateCreateInfo meshNoOutDynamicStateInfo = {
6324             vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
6325             nullptr,                                                  // const void* pNext;
6326             0u,                                                       // VkPipelineDynamicStateCreateFlags flags;
6327             de::sizeU32(meshNoOutDynamicStates),                      // uint32_t dynamicStateCount;
6328             de::dataOrNull(meshNoOutDynamicStates),                   // const VkDynamicState* pDynamicStates;
6329         };
6330 
6331         // Provide a viewport state similar to the static pipeline.
6332         auto viewports = m_testConfig.viewportConfig.staticValue;
6333         auto scissors  = m_testConfig.scissorConfig.staticValue;
6334 
6335         const auto minStaticCount = static_cast<uint32_t>(
6336             std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
6337         viewports.resize(minStaticCount);
6338         scissors.resize(minStaticCount);
6339 
6340         meshNoOutPipeline.setDynamicState(&meshNoOutDynamicStateInfo)
6341             .setDefaultPatchControlPoints(m_testConfig.patchControlPointsConfig.staticValue)
6342             .setupPreRasterizationMeshShaderState(viewports, scissors, pipelineLayout, *renderPassFramebuffers[0], 0u,
6343                                                   vk::ShaderWrapper(), meshNoOutModule, &rasterizationStateCreateInfo)
6344             .setupFragmentShaderState(pipelineLayout, *renderPassFramebuffers[0], 0u, vk::ShaderWrapper(),
6345                                       &depthStencilStateCreateInfo, &multisampleStateCreateInfo)
6346             .setupFragmentOutputState(*renderPassFramebuffers[0], 0u, &colorBlendStateCreateInfo,
6347                                       &multisampleStateCreateInfo)
6348             .setMonolithicPipelineLayout(pipelineLayout)
6349             .buildPipeline();
6350     }
6351 #endif // CTS_USES_VULKANSC
6352 
6353     // Command buffer.
6354     const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
6355     const auto cmdBufferPtr =
6356         vk::allocateCommandBuffer(vkd, device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
6357     const auto cmdBuffer = cmdBufferPtr.get();
6358 
6359     // Clear values, clear to green for dynamic logicOp
6360     std::vector<vk::VkClearValue> clearValues(kColorAttCount, m_testConfig.clearColorValue);
6361     clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
6362 
6363     // Record command buffer.
6364     vk::beginCommandBuffer(vkd, cmdBuffer);
6365 
6366     for (uint32_t iteration = 0u; iteration < kNumIterations; ++iteration)
6367     {
6368         // Track in-advance vertex buffer binding.
6369         bool boundInAdvance = false;
6370 
6371         // Maybe set extended dynamic state here.
6372         if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
6373         {
6374             setDynamicStates(m_testConfig, vkd, cmdBuffer);
6375             boundInAdvance =
6376                 maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
6377         }
6378 
6379         // Begin render pass.
6380         renderPassFramebuffers[iteration].begin(vkd, cmdBuffer, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight),
6381                                                 static_cast<uint32_t>(clearValues.size()), clearValues.data());
6382 
6383         // Bind a static pipeline first if needed.
6384         if (kBindStaticFirst && iteration == 0u)
6385             staticPipeline.bind(cmdBuffer);
6386 
6387         // Maybe set extended dynamic state here.
6388         if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
6389         {
6390             setDynamicStates(m_testConfig, vkd, cmdBuffer);
6391             boundInAdvance =
6392                 maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
6393         }
6394 
6395         // Bind dynamic pipeline.
6396         if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
6397              kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
6398             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
6399             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
6400         {
6401             if (m_testConfig.bindUnusedMeshShadingPipeline)
6402             {
6403                 DE_ASSERT(kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START);
6404                 meshNoOutPipeline.bind(cmdBuffer);
6405             }
6406 
6407             if (m_testConfig.useExtraDynPCPPipeline)
6408             {
6409                 extraDynPCPPipeline.bind(cmdBuffer);
6410 
6411                 // In these two sequence orderings, the right dynamic state value will have been set before and we would be
6412                 // setting it to a wrong value here, resulting in test failures. We keep the right value instead.
6413                 if (kSequenceOrdering != SequenceOrdering::CMD_BUFFER_START &&
6414                     kSequenceOrdering != SequenceOrdering::BETWEEN_PIPELINES)
6415                     vkd.cmdSetPatchControlPointsEXT(cmdBuffer, m_testConfig.patchControlPointsConfig.staticValue);
6416 
6417                 vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
6418             }
6419 
6420             if (m_testConfig.useExtraDynPipeline)
6421             {
6422                 extraDynPipeline.bind(cmdBuffer);
6423 
6424                 if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW ||
6425                     kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
6426                     kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC)
6427                     setDynamicStates(m_testConfig, vkd, cmdBuffer);
6428 
6429                 vkd.cmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
6430             }
6431 
6432             graphicsPipeline.bind(cmdBuffer);
6433 
6434             // When shader objects are used vkCmdSetVertexInput() will overwrite vkCmdBindBuffers2 so we have to call it again
6435             if (boundInAdvance && vk::isConstructionTypeShaderObject(m_testConfig.pipelineConstructionType))
6436                 maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
6437         }
6438 
6439         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
6440             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
6441             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
6442         {
6443             setDynamicStates(m_testConfig, vkd, cmdBuffer);
6444             boundInAdvance =
6445                 maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
6446         }
6447 
6448         // Bind a static pipeline last if needed.
6449         if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
6450             (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
6451         {
6452             staticPipeline.bind(cmdBuffer);
6453         }
6454 
6455         const auto &viewportVec = m_testConfig.getActiveViewportVec();
6456         for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
6457         {
6458             for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
6459             {
6460                 // Push constants.
6461                 PushConstants pushConstants = {
6462                     m_testConfig.meshParams[meshIdx].color,      // tcu::Vec4 triangleColor;
6463                     m_testConfig.meshParams[meshIdx].depth,      // float meshDepth;
6464                     static_cast<int32_t>(viewportIdx),           // int32_t viewPortIndex;
6465                     m_testConfig.meshParams[meshIdx].scaleX,     // float scaleX;
6466                     m_testConfig.meshParams[meshIdx].scaleY,     // float scaleY;
6467                     m_testConfig.meshParams[meshIdx].offsetX,    // float offsetX;
6468                     m_testConfig.meshParams[meshIdx].offsetY,    // float offsetY;
6469                     m_testConfig.meshParams[meshIdx].stripScale, // float stripScale;
6470                 };
6471                 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u,
6472                                      static_cast<uint32_t>(sizeof(pushConstants)), &pushConstants);
6473 
6474                 // Track vertex bounding state for this mesh.
6475                 bool boundBeforeDraw = false;
6476 
6477                 // Maybe set extended dynamic state here.
6478                 if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW ||
6479                     kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
6480                 {
6481                     setDynamicStates(m_testConfig, vkd, cmdBuffer);
6482                     boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffers,
6483                                                                      rvertBuffers);
6484                 }
6485 
6486                 // Bind vertex buffer with static stride if needed and draw.
6487                 if (!(boundInAdvance || boundBeforeDraw) && !m_testConfig.useMeshShaders)
6488                 {
6489                     bindVertexBuffers(vkd, cmdBuffer,
6490                                       (m_testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers));
6491                     if (m_testConfig.needsIndexBuffer())
6492                     {
6493                         const auto indexType = vk::VK_INDEX_TYPE_UINT32;
6494                         vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer->get(), 0, indexType);
6495                     }
6496                 }
6497 
6498                 if (vertDataAsSSBO)
6499                 {
6500                     if (topologyClass == TopologyClass::LINE)
6501                         DE_ASSERT(!m_testConfig.meshParams[meshIdx].reversed);
6502 
6503                     const auto boundSet = (m_testConfig.meshParams[meshIdx].reversed ? meshDescriptorSetRev.get() :
6504                                                                                        meshDescriptorSet.get());
6505                     vkd.cmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, pipelineLayout.get(), 0u, 1u, &boundSet, 0u,
6506                                               nullptr);
6507                 }
6508 
6509 #ifndef CTS_USES_VULKANSC
6510                 // Shading rate image if enabled (we'll use a null handle to simplify, which is valid).
6511                 if (m_testConfig.shadingRateImage)
6512                     vkd.cmdBindShadingRateImageNV(cmdBuffer, VK_NULL_HANDLE, vk::VK_IMAGE_LAYOUT_GENERAL);
6513 #endif // CTS_USES_VULKANSC
6514 
6515                 if (kFragAtomics)
6516                     vkd.cmdBindDescriptorSets(cmdBuffer, pipelineBindPoint, pipelineLayout.get(),
6517                                               m_testConfig.getFragDescriptorSetIndex(), 1u, &fragDescriptorSet.get(),
6518                                               0u, nullptr);
6519 
6520                 // Draw mesh.
6521                 if (m_testConfig.needsIndexBuffer())
6522                 {
6523                     uint32_t numIndices = static_cast<uint32_t>(indices.size());
6524                     // For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
6525                     // So, draw without using the invalid index, the second draw with primitive restart enabled will replace the results
6526                     // using all indices.
6527                     if (iteration == 0u && m_testConfig.testPrimRestartEnable() &&
6528                         (m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
6529                          m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
6530                     {
6531                         numIndices = 2u;
6532                     }
6533                     vkd.cmdDrawIndexed(cmdBuffer, numIndices, m_testConfig.instanceCount, 0u, 0u, 0u);
6534                 }
6535 #ifndef CTS_USES_VULKANSC
6536                 else if (m_testConfig.useMeshShaders)
6537                 {
6538                     // Make sure drawing this way makes sense.
6539                     const auto minVertCount = ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
6540                     DE_UNREF(minVertCount); // For release builds.
6541                     DE_ASSERT(vertices.size() >= minVertCount);
6542                     DE_ASSERT(m_testConfig.instanceCount == 1u);
6543                     DE_ASSERT(!m_testConfig.topologyConfig.dynamicValue);
6544 
6545                     uint32_t numPrimitives = 0u;
6546 
6547                     if (topologyClass == TopologyClass::TRIANGLE)
6548                     {
6549                         DE_ASSERT(m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
6550                         numPrimitives = de::sizeU32(vertices) - 2u;
6551                     }
6552                     else if (topologyClass == TopologyClass::LINE)
6553                     {
6554                         DE_ASSERT(m_testConfig.topologyConfig.staticValue == vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP);
6555                         const auto vertsPerRow = 4u;
6556                         const auto linesPerRow = 3u;
6557                         const auto vertexCount = de::sizeU32(vertices);
6558                         const auto rowCount    = vertexCount / vertsPerRow;
6559                         numPrimitives          = rowCount * linesPerRow;
6560 
6561                         if (m_testConfig.obliqueLine)
6562                             numPrimitives = 1u;
6563                         else
6564                             DE_ASSERT(vertexCount % vertsPerRow == 0u);
6565                     }
6566                     else
6567                         DE_ASSERT(false);
6568 
6569                     vkd.cmdDrawMeshTasksEXT(cmdBuffer, numPrimitives, 1u, 1u);
6570                 }
6571 #endif // CTS_USES_VULKANSC
6572                 else
6573                 {
6574                     uint32_t vertexCount = static_cast<uint32_t>(vertices.size());
6575                     if (m_testConfig.singleVertex)
6576                         vertexCount = m_testConfig.singleVertexDrawCount;
6577                     vkd.cmdDraw(cmdBuffer, vertexCount, m_testConfig.instanceCount, 0u, 0u);
6578                 }
6579             }
6580         }
6581 
6582         renderPassFramebuffers[iteration].end(vkd, cmdBuffer);
6583     }
6584 
6585     if (kFragAtomics)
6586     {
6587         const auto bufferBarrier = vk::makeMemoryBarrier(vk::VK_ACCESS_SHADER_WRITE_BIT, vk::VK_ACCESS_HOST_READ_BIT);
6588         vk::cmdPipelineMemoryBarrier(vkd, cmdBuffer, vk::VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
6589                                      vk::VK_PIPELINE_STAGE_HOST_BIT, &bufferBarrier);
6590     }
6591 
6592     vk::endCommandBuffer(vkd, cmdBuffer);
6593 
6594     // Submit commands.
6595     vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
6596 
6597     // Read result image aspects from the last used framebuffer.
6598     using LevelPtr = de::MovePtr<tcu::TextureLevel>;
6599 
6600     const tcu::UVec2 renderSize(kFramebufferWidth, kFramebufferHeight);
6601 
6602     const auto colorResultImg = (kUseResolveAtt ? resolveImages.back()->get() : colorImages.back()->get());
6603     const auto colorBuffer =
6604         readColorAttachment(vkd, device, queue, queueIndex, allocator, colorResultImg, colorFormat, renderSize);
6605     const auto colorAccess = colorBuffer->getAccess();
6606 
6607     LevelPtr depthBuffer;
6608     LevelPtr stencilBuffer;
6609     tcu::PixelBufferAccess depthAccess;
6610     tcu::PixelBufferAccess stencilAccess;
6611 
6612     if (!kMultisampleDS)
6613     {
6614         depthBuffer = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(),
6615                                           dsFormatInfo->imageFormat, renderSize);
6616         stencilBuffer =
6617             readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(),
6618                                   dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
6619         depthAccess   = depthBuffer->getAccess();
6620         stencilAccess = stencilBuffer->getAccess();
6621     }
6622 
6623     const int kWidth  = static_cast<int>(kFramebufferWidth);
6624     const int kHeight = static_cast<int>(kFramebufferHeight);
6625 
6626     // Generate reference color buffer.
6627     const auto tcuColorFormat = vk::mapVkFormat(colorFormat);
6628     tcu::TextureLevel referenceColorLevel(tcuColorFormat, kWidth, kHeight);
6629     tcu::PixelBufferAccess referenceColorAccess = referenceColorLevel.getAccess();
6630     (*m_testConfig.referenceColor)(referenceColorAccess);
6631 
6632     const tcu::TextureFormat errorFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
6633     tcu::TextureLevel colorError(errorFormat, kWidth, kHeight);
6634     tcu::TextureLevel depthError(errorFormat, kWidth, kHeight);
6635     tcu::TextureLevel stencilError(errorFormat, kWidth, kHeight);
6636     const auto colorErrorAccess   = colorError.getAccess();
6637     const auto depthErrorAccess   = depthError.getAccess();
6638     const auto stencilErrorAccess = stencilError.getAccess();
6639     const tcu::Vec4 kGood(0.0f, 1.0f, 0.0f, 1.0f);
6640     const tcu::Vec4 kBad(1.0f, 0.0f, 0.0f, 1.0f);
6641 
6642     // Check expected values.
6643     const bool hasCustomVerif = static_cast<bool>(m_testConfig.colorVerificator);
6644     const auto minDepth = m_testConfig.expectedDepth - dsFormatInfo->depthThreshold - m_testConfig.extraDepthThreshold;
6645     const auto maxDepth = m_testConfig.expectedDepth + dsFormatInfo->depthThreshold + m_testConfig.extraDepthThreshold;
6646     bool colorMatch     = true;
6647     bool depthMatch     = true;
6648     bool stencilMatch   = true;
6649     bool match;
6650 
6651     if (hasCustomVerif)
6652         colorMatch = (*m_testConfig.colorVerificator)(colorAccess, referenceColorAccess, colorErrorAccess);
6653 
6654     for (int y = 0; y < kHeight; ++y)
6655         for (int x = 0; x < kWidth; ++x)
6656         {
6657             if (!hasCustomVerif)
6658             {
6659                 if (vk::isUnormFormat(colorFormat))
6660                 {
6661                     const auto colorPixel    = colorAccess.getPixel(x, y);
6662                     const auto expectedPixel = referenceColorAccess.getPixel(x, y);
6663                     match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kUnormColorThreshold));
6664                 }
6665                 else
6666                 {
6667                     DE_ASSERT(vk::isUintFormat(colorFormat));
6668                     const auto colorPixel    = colorAccess.getPixelUint(x, y);
6669                     const auto expectedPixel = referenceColorAccess.getPixelUint(x, y);
6670                     match                    = (colorPixel == expectedPixel);
6671                 }
6672 
6673                 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
6674                 if (!match)
6675                     colorMatch = false;
6676             }
6677 
6678             if (!kMultisampleDS)
6679             {
6680                 const auto depthPixel = depthAccess.getPixDepth(x, y);
6681                 match                 = de::inRange(depthPixel, minDepth, maxDepth);
6682                 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
6683                 if (!match)
6684                     depthMatch = false;
6685 
6686                 const auto stencilPixel = static_cast<uint32_t>(stencilAccess.getPixStencil(x, y));
6687                 match                   = (stencilPixel == m_testConfig.expectedStencil);
6688                 stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
6689                 if (!match)
6690                     stencilMatch = false;
6691             }
6692         }
6693 
6694     if (!(colorMatch && depthMatch && stencilMatch))
6695     {
6696         if (!colorMatch)
6697             logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
6698 
6699         if (!depthMatch)
6700             logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
6701 
6702         if (!stencilMatch)
6703             logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
6704 
6705         if (!(colorMatch && depthMatch && stencilMatch))
6706             return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
6707     }
6708 
6709     // Check storage buffer if used.
6710     uint32_t fragCounter = 0u;
6711 
6712     if (kFragAtomics)
6713     {
6714         DE_ASSERT(m_testConfig.oversizedTriangle);
6715         DE_ASSERT(m_testConfig.meshParams.size() == 1u);
6716         DE_ASSERT(!m_testConfig.depthWriteEnableConfig.dynamicValue); // No dynamic value for depth writes.
6717         DE_ASSERT(!m_testConfig.depthWriteEnableConfig.staticValue);  // No depth writes.
6718 
6719         auto &counterBufferAlloc = counterBuffer->getAllocation();
6720         void *counterBufferData  = counterBufferAlloc.getHostPtr();
6721         vk::invalidateAlloc(vkd, device, counterBufferAlloc);
6722 
6723         deMemcpy(&fragCounter, counterBufferData, sizeof(fragCounter));
6724     }
6725 
6726     if (m_testConfig.representativeFragmentTest)
6727     {
6728         DE_ASSERT(!m_testConfig.rasterizationSamplesConfig.dynamicValue);
6729 
6730         // The expected number of invocations depends on how many draws are performed with the test enabled.
6731         // Draws with the test disabled should always result in kFramebufferHeight * kFramebufferWidth invocations.
6732         // Draws with the test enabled should result in at least 1 invocation, maybe more.
6733         uint32_t minValue = 0u;
6734 
6735         const uint32_t minInvocations[] = {
6736             (kFramebufferHeight * kFramebufferWidth *
6737              static_cast<uint32_t>(m_testConfig.rasterizationSamplesConfig.staticValue)),
6738             1u,
6739         };
6740 
6741         if (kNumIterations == 1u)
6742         {
6743             const auto testEnabled = m_testConfig.getActiveReprFragTestEnable();
6744             minValue += minInvocations[testEnabled];
6745         }
6746         else if (kNumIterations == 2u)
6747         {
6748             for (uint32_t i = 0u; i < kNumIterations; ++i)
6749             {
6750                 bool testEnabled = false;
6751 
6752 #ifndef CTS_USES_VULKANSC
6753                 // Actually varies depending on TWO_DRAWS_STATIC/_DYNAMIC, but does not affect results.
6754                 const bool staticDraw = (i == 0u);
6755 
6756                 if (staticDraw)
6757                     testEnabled = m_testConfig.reprFragTestEnableConfig.staticValue;
6758                 else
6759                 {
6760                     testEnabled = (m_testConfig.reprFragTestEnableConfig.dynamicValue ?
6761                                        m_testConfig.reprFragTestEnableConfig.dynamicValue.get() :
6762                                        m_testConfig.reprFragTestEnableConfig.staticValue);
6763                 }
6764 #endif // CTS_USES_VULKANSC
6765 
6766                 minValue += minInvocations[testEnabled];
6767             }
6768         }
6769         else
6770         {
6771             DE_ASSERT(false);
6772         }
6773 
6774         log << tcu::TestLog::Message << "Fragment counter minimum value: " << minValue << tcu::TestLog::EndMessage;
6775         log << tcu::TestLog::Message << "Fragment counter: " << fragCounter << tcu::TestLog::EndMessage;
6776 
6777         if (fragCounter < minValue)
6778         {
6779             std::ostringstream msg;
6780             msg << "Fragment shader invocation counter lower than expected: found " << fragCounter
6781                 << " and expected at least " << minValue;
6782             return tcu::TestStatus::fail(msg.str());
6783         }
6784     }
6785     else if (kFragAtomics)
6786     {
6787         // The expected number of invocations depends on how many draws are performed and the sample count of each one.
6788         // Draws with the test disabled should always result in kFramebufferHeight * kFramebufferWidth invocations.
6789         // Draws with the test enabled should result in at least 1 invocation, maybe more.
6790         uint32_t sampleCount = 0u;
6791 
6792         if (kNumIterations == 1u)
6793         {
6794             sampleCount += static_cast<uint32_t>(m_testConfig.getActiveSampleCount());
6795         }
6796         else if (kNumIterations == 2u)
6797         {
6798             for (uint32_t i = 0u; i < kNumIterations; ++i)
6799             {
6800                 // Actually varies depending on TWO_DRAWS_STATIC/_DYNAMIC, but does not affect results.
6801                 const bool staticDraw = (i == 0u);
6802 
6803                 if (staticDraw)
6804                     sampleCount += static_cast<uint32_t>(m_testConfig.rasterizationSamplesConfig.staticValue);
6805                 else
6806                 {
6807                     sampleCount +=
6808                         static_cast<uint32_t>(m_testConfig.rasterizationSamplesConfig.dynamicValue ?
6809                                                   m_testConfig.rasterizationSamplesConfig.dynamicValue.get() :
6810                                                   m_testConfig.rasterizationSamplesConfig.staticValue);
6811                 }
6812             }
6813         }
6814         else
6815         {
6816             DE_ASSERT(false);
6817         }
6818 
6819         const uint32_t expectedValue = sampleCount * kFramebufferWidth * kFramebufferHeight;
6820 
6821         if (fragCounter != expectedValue)
6822         {
6823             std::ostringstream msg;
6824             msg << "Fragment shader invocation count does not match expected value: found " << fragCounter
6825                 << " and expected " << expectedValue;
6826             return tcu::TestStatus::fail(msg.str());
6827         }
6828     }
6829 
6830     return tcu::TestStatus::pass("Pass");
6831 }
6832 
stencilPasses(vk::VkCompareOp op,uint8_t storedValue,uint8_t referenceValue)6833 bool stencilPasses(vk::VkCompareOp op, uint8_t storedValue, uint8_t referenceValue)
6834 {
6835     switch (op)
6836     {
6837     case vk::VK_COMPARE_OP_NEVER:
6838         return false;
6839     case vk::VK_COMPARE_OP_LESS:
6840         return (referenceValue < storedValue);
6841     case vk::VK_COMPARE_OP_EQUAL:
6842         return (referenceValue == storedValue);
6843     case vk::VK_COMPARE_OP_LESS_OR_EQUAL:
6844         return (referenceValue <= storedValue);
6845     case vk::VK_COMPARE_OP_GREATER:
6846         return (referenceValue > storedValue);
6847     case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:
6848         return (referenceValue >= storedValue);
6849     case vk::VK_COMPARE_OP_ALWAYS:
6850         return true;
6851     default:
6852         DE_ASSERT(false);
6853         return false;
6854     }
6855 
6856     return false; // Unreachable.
6857 }
6858 
stencilResult(vk::VkStencilOp op,uint8_t storedValue,uint8_t referenceValue,uint8_t min,uint8_t max)6859 uint8_t stencilResult(vk::VkStencilOp op, uint8_t storedValue, uint8_t referenceValue, uint8_t min, uint8_t max)
6860 {
6861     uint8_t result = storedValue;
6862 
6863     switch (op)
6864     {
6865     case vk::VK_STENCIL_OP_KEEP:
6866         break;
6867     case vk::VK_STENCIL_OP_ZERO:
6868         result = 0;
6869         break;
6870     case vk::VK_STENCIL_OP_REPLACE:
6871         result = referenceValue;
6872         break;
6873     case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:
6874         result = ((result == max) ? result : static_cast<uint8_t>(result + 1));
6875         break;
6876     case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:
6877         result = ((result == min) ? result : static_cast<uint8_t>(result - 1));
6878         break;
6879     case vk::VK_STENCIL_OP_INVERT:
6880         result = static_cast<uint8_t>(~result);
6881         break;
6882     case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:
6883         result = ((result == max) ? min : static_cast<uint8_t>(result + 1));
6884         break;
6885     case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:
6886         result = ((result == min) ? max : static_cast<uint8_t>(result - 1));
6887         break;
6888     default:
6889         DE_ASSERT(false);
6890         break;
6891     }
6892 
6893     return result;
6894 }
6895 
6896 class TestGroupWithClean : public tcu::TestCaseGroup
6897 {
6898 public:
TestGroupWithClean(tcu::TestContext & testCtx,const char * name)6899     TestGroupWithClean(tcu::TestContext &testCtx, const char *name) : tcu::TestCaseGroup(testCtx, name)
6900     {
6901     }
6902 
deinit(void)6903     void deinit(void) override
6904     {
6905         cleanupDevices();
6906     }
6907 };
6908 
6909 using GroupPtr = de::MovePtr<tcu::TestCaseGroup>;
6910 
6911 } // anonymous namespace
6912 
createExtendedDynamicStateTests(tcu::TestContext & testCtx,vk::PipelineConstructionType pipelineConstructionType)6913 tcu::TestCaseGroup *createExtendedDynamicStateTests(tcu::TestContext &testCtx,
6914                                                     vk::PipelineConstructionType pipelineConstructionType)
6915 {
6916     GroupPtr extendedDynamicStateGroup(new TestGroupWithClean(testCtx, "extended_dynamic_state"));
6917     GroupPtr meshShaderGroup(new tcu::TestCaseGroup(testCtx, "mesh_shader"));
6918 
6919     // Auxiliar constants.
6920     const uint32_t kHalfWidthU = kFramebufferWidth / 2u;
6921     const int32_t kHalfWidthI  = static_cast<int32_t>(kHalfWidthU);
6922     const float kHalfWidthF    = static_cast<float>(kHalfWidthU);
6923     const float kWidthF        = static_cast<float>(kFramebufferWidth);
6924     const float kHeightF       = static_cast<float>(kFramebufferHeight);
6925 
6926     static const struct
6927     {
6928         SequenceOrdering ordering;
6929         std::string name;
6930     } kOrderingCases[] = {
6931         // Dynamic state set after command buffer start
6932         {SequenceOrdering::CMD_BUFFER_START, "cmd_buffer_start"},
6933         // Dynamic state set just before drawing
6934         {SequenceOrdering::BEFORE_DRAW, "before_draw"},
6935         // Dynamic after a pipeline with static states has been bound and before a pipeline with dynamic states has been bound
6936         {SequenceOrdering::BETWEEN_PIPELINES, "between_pipelines"},
6937         // Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound
6938         {SequenceOrdering::AFTER_PIPELINES, "after_pipelines"},
6939         // Dynamic state set after a dynamic pipeline has been bound and before a second static-state pipeline with the right values has been bound
6940         {SequenceOrdering::BEFORE_GOOD_STATIC, "before_good_static"},
6941         // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again
6942         {SequenceOrdering::TWO_DRAWS_DYNAMIC, "two_draws_dynamic"},
6943         // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again
6944         {SequenceOrdering::TWO_DRAWS_STATIC, "two_draws_static"},
6945     };
6946 
6947     static const struct
6948     {
6949         bool useMeshShaders;
6950         std::string groupName;
6951     } kMeshShadingCases[] = {
6952         {false, ""},
6953 #ifndef CTS_USES_VULKANSC
6954         {true, "mesh_shader"},
6955 #endif // CTS_USES_VULKANSC
6956     };
6957 
6958     static const struct
6959     {
6960         bool bindUnusedMeshShadingPipeline;
6961         std::string nameSuffix;
6962     } kBindUnusedCases[] = {
6963         {false, ""},
6964 #ifndef CTS_USES_VULKANSC
6965         {true, "_bind_unused_ms"},
6966 #endif // CTS_USES_VULKANSC
6967     };
6968 
6969     static const std::vector<ColorBlendSubCase> cbSubCases{
6970         ColorBlendSubCase::EQ_ONLY,
6971         ColorBlendSubCase::ALL_CB,
6972         ColorBlendSubCase::ALL_BUT_LO,
6973     };
6974 
6975     for (const auto &kMeshShadingCase : kMeshShadingCases)
6976         for (const auto &kOrderingCase : kOrderingCases)
6977         {
6978             if (vk::isConstructionTypeShaderObject(pipelineConstructionType) &&
6979                 (kOrderingCase.ordering == SequenceOrdering::BETWEEN_PIPELINES ||
6980                  kOrderingCase.ordering == SequenceOrdering::AFTER_PIPELINES))
6981                 continue;
6982 
6983             const auto &kUseMeshShaders = kMeshShadingCase.useMeshShaders;
6984             const auto &kOrdering       = kOrderingCase.ordering;
6985 
6986             GroupPtr orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str()));
6987 
6988             // Cull modes.
6989             {
6990                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6991                 config.cullModeConfig.staticValue  = vk::VK_CULL_MODE_FRONT_BIT;
6992                 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
6993                 // Dynamically set cull mode to none
6994                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", config));
6995             }
6996             {
6997                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
6998                 config.cullModeConfig.staticValue  = vk::VK_CULL_MODE_FRONT_AND_BACK;
6999                 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
7000                 // Dynamically set cull mode to back
7001                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", config));
7002             }
7003             {
7004                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7005                 // Make triangles look back.
7006                 config.meshParams[0].reversed      = true;
7007                 config.cullModeConfig.staticValue  = vk::VK_CULL_MODE_BACK_BIT;
7008                 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
7009                 // Dynamically set cull mode to front
7010                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", config));
7011             }
7012             {
7013                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7014                 config.cullModeConfig.staticValue  = vk::VK_CULL_MODE_NONE;
7015                 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
7016                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7017                 // Dynamically set cull mode to front and back
7018                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", config));
7019             }
7020 
7021             // Front face.
7022             {
7023                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7024                 config.cullModeConfig.staticValue   = vk::VK_CULL_MODE_BACK_BIT;
7025                 config.frontFaceConfig.staticValue  = vk::VK_FRONT_FACE_CLOCKWISE;
7026                 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
7027                 // Dynamically set front face to clockwise
7028                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", config));
7029             }
7030             {
7031                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7032                 // Pass triangles in clockwise order.
7033                 config.meshParams[0].reversed       = true;
7034                 config.cullModeConfig.staticValue   = vk::VK_CULL_MODE_BACK_BIT;
7035                 config.frontFaceConfig.staticValue  = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
7036                 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
7037                 // Dynamically set front face to counter-clockwise
7038                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", config));
7039             }
7040             {
7041                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7042                 config.cullModeConfig.staticValue   = vk::VK_CULL_MODE_BACK_BIT;
7043                 config.frontFaceConfig.staticValue  = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
7044                 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
7045                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7046                 // Dynamically set front face to clockwise with a counter-clockwise mesh
7047                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", config));
7048             }
7049             {
7050                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7051                 // Pass triangles in clockwise order.
7052                 config.meshParams[0].reversed       = true;
7053                 config.cullModeConfig.staticValue   = vk::VK_CULL_MODE_BACK_BIT;
7054                 config.frontFaceConfig.staticValue  = vk::VK_FRONT_FACE_CLOCKWISE;
7055                 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
7056                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7057                 // Dynamically set front face to counter-clockwise with a clockwise mesh
7058                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", config));
7059             }
7060 
7061             // Rasterizer discard
7062             {
7063                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7064                 config.rastDiscardEnableConfig.staticValue  = false;
7065                 config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
7066                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7067                 // Dynamically disable rasterizer
7068                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", config));
7069             }
7070             {
7071                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7072                 config.rastDiscardEnableConfig.staticValue  = true;
7073                 config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
7074                 // Dynamically enable rasterizer
7075                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", config));
7076             }
7077 
7078             // Logic op
7079             {
7080                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7081 
7082                 config.logicOpEnableConfig.staticValue = true;
7083                 config.logicOpConfig.staticValue       = vk::VK_LOGIC_OP_CLEAR;
7084                 config.logicOpConfig.dynamicValue      = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
7085 
7086                 // Clear to green, paint in blue, expect cyan due to logic op.
7087                 config.meshParams[0].color = kLogicOpTriangleColorFl;
7088                 config.clearColorValue     = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(),
7089                                                                         kGreenClearColor.z(), kGreenClearColor.w());
7090                 config.referenceColor.reset(new SingleColorGenerator(kLogicOpFinalColor));
7091 
7092                 // Dynamically change logic op to VK_LOGIC_OP_OR
7093                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", config));
7094             }
7095 
7096             // Logic op enable.
7097             {
7098                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7099 
7100                 config.logicOpEnableConfig.staticValue  = false;
7101                 config.logicOpEnableConfig.dynamicValue = true;
7102                 config.logicOpConfig.staticValue        = vk::VK_LOGIC_OP_OR;
7103 
7104                 // Clear to green, paint in blue, expect cyan due to logic op.
7105                 config.meshParams[0].color = kLogicOpTriangleColorFl;
7106                 config.clearColorValue     = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(),
7107                                                                         kGreenClearColor.z(), kGreenClearColor.w());
7108                 config.referenceColor.reset(new SingleColorGenerator(kLogicOpFinalColor));
7109 
7110                 // Dynamically enable logic OP
7111                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_enable", config));
7112             }
7113             {
7114                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7115 
7116                 config.logicOpEnableConfig.staticValue  = true;
7117                 config.logicOpEnableConfig.dynamicValue = false;
7118                 config.logicOpConfig.staticValue        = vk::VK_LOGIC_OP_OR;
7119 
7120                 // Clear to green, paint in blue, expect cyan due to logic op.
7121                 config.meshParams[0].color = kLogicOpTriangleColorFl;
7122                 config.clearColorValue     = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(),
7123                                                                         kGreenClearColor.z(), kGreenClearColor.w());
7124                 config.referenceColor.reset(new SingleColorGenerator(kLogicOpTriangleColor));
7125 
7126                 // Dynamically disable logic OP
7127                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_disable", config));
7128             }
7129 
7130             // Color blend enable.
7131             {
7132                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7133 
7134                 // The equation picks the old color instead of the new one if blending is enabled.
7135                 config.colorBlendEquationConfig.staticValue =
7136                     ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
7137                                  vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
7138 
7139                 config.colorBlendEnableConfig.staticValue  = false;
7140                 config.colorBlendEnableConfig.dynamicValue = true;
7141                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7142 
7143                 // Dynamically enable color blending
7144                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_enable", config));
7145             }
7146             {
7147                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7148 
7149                 // The equation picks the old color instead of the new one if blending is enabled.
7150                 config.colorBlendEquationConfig.staticValue =
7151                     ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
7152                                  vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
7153 
7154                 config.colorBlendEnableConfig.staticValue  = true;
7155                 config.colorBlendEnableConfig.dynamicValue = false;
7156 
7157                 // Dynamically disable color blending
7158                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "color_blend_disable", config));
7159             }
7160 
7161             // Color blend equation.
7162             {
7163                 for (const auto &cbSubCase : cbSubCases)
7164                 {
7165                     const bool onlyEq       = (cbSubCase == ColorBlendSubCase::EQ_ONLY);
7166                     const bool allCBDynamic = (cbSubCase == ColorBlendSubCase::ALL_CB);
7167 
7168                     // Skip two-draws variants as this will use dynamic logic op and force UNORM color attachments, which would result in illegal operations.
7169                     if (allCBDynamic && (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC ||
7170                                          kOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC))
7171                         continue;
7172 
7173                     for (int j = 0; j < 2; ++j)
7174                     {
7175                         const bool enableStateValue = (j > 0);
7176 
7177                         // Do not test statically disabling color blend.
7178                         if (onlyEq && !enableStateValue)
7179                             continue;
7180 
7181                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7182 
7183                         // The equation picks the old color instead of the new one if blending is enabled.
7184                         config.colorBlendEquationConfig.staticValue =
7185                             ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
7186                                          vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
7187 
7188                         // The dynamic value picks the new color.
7189                         config.colorBlendEquationConfig.dynamicValue =
7190                             ColorBlendEq(vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD,
7191                                          vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD);
7192 
7193                         if (!onlyEq)
7194                         {
7195                             config.colorBlendEnableConfig.staticValue  = !enableStateValue;
7196                             config.colorBlendEnableConfig.dynamicValue = enableStateValue;
7197                             config.colorWriteMaskConfig.staticValue    = (0 | 0 | 0 | 0);
7198                             config.colorWriteMaskConfig.dynamicValue   = (CR | CG | CB | CA);
7199                             config.blendConstantsConfig.staticValue    = BlendConstArray{1.0f, 1.0f, 1.0f, 1.0f};
7200                             config.blendConstantsConfig.dynamicValue   = BlendConstArray{0.0f, 0.0f, 0.0f, 0.0f};
7201                             // Note we don't set a dynamic value for alpha to coverage.
7202 
7203                             config.useColorWriteEnable                 = true;
7204                             config.colorWriteEnableConfig.staticValue  = false;
7205                             config.colorWriteEnableConfig.dynamicValue = true;
7206 
7207                             if (allCBDynamic)
7208                             {
7209                                 config.forceUnormColorFormat            = true;
7210                                 config.logicOpEnableConfig.staticValue  = true;
7211                                 config.logicOpEnableConfig.dynamicValue = false;
7212                                 config.logicOpConfig.staticValue        = vk::VK_LOGIC_OP_COPY;
7213                                 config.logicOpConfig.dynamicValue       = vk::VK_LOGIC_OP_CLEAR;
7214                             }
7215                         }
7216                         else
7217                         {
7218                             config.colorBlendEnableConfig.staticValue = enableStateValue;
7219                         }
7220 
7221                         const std::string stateStr = (enableStateValue ? "enable" : "disable");
7222                         const std::string nameSuffix =
7223                             (onlyEq ?
7224                                  "" :
7225                                  (allCBDynamic ? ("_dynamic_" + stateStr) : ("_dynamic_but_logic_op_" + stateStr)));
7226 
7227                         // Dynamically set a color equation that picks the mesh color
7228                         orderingGroup->addChild(new ExtendedDynamicStateTest(
7229                             testCtx, "color_blend_equation_new_color" + nameSuffix, config));
7230 
7231                         config.colorBlendEquationConfig.swapValues();
7232                         config.referenceColor.reset(
7233                             new SingleColorGenerator(enableStateValue ? kDefaultClearColor : kDefaultTriangleColor));
7234 
7235                         // Dynamically set a color equation that picks the clear color
7236                         orderingGroup->addChild(new ExtendedDynamicStateTest(
7237                             testCtx, "color_blend_equation_old_color" + nameSuffix, config));
7238                     }
7239                 }
7240             }
7241 
7242             // Color blend advanced.
7243             {
7244                 for (const auto &cbSubCase : cbSubCases)
7245                 {
7246                     const bool onlyEq       = (cbSubCase == ColorBlendSubCase::EQ_ONLY);
7247                     const bool allCBDynamic = (cbSubCase == ColorBlendSubCase::ALL_CB);
7248 
7249                     // Skip two-draws variants as this will use dynamic logic op and force UNORM color attachments, which would result in illegal operations.
7250                     if (allCBDynamic && (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC ||
7251                                          kOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC))
7252                         continue;
7253 
7254                     for (int j = 0; j < 2; ++j)
7255                     {
7256                         const bool enableStateValue = (j > 0);
7257 
7258                         // Do not test statically disabling color blend.
7259                         if (onlyEq && !enableStateValue)
7260                             continue;
7261 
7262                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7263 
7264                         // This static value picks the old color instead of the new one.
7265                         config.colorBlendEquationConfig.staticValue =
7266                             ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_DARKEN_EXT,
7267                                          vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_DARKEN_EXT);
7268 
7269                         // The dynamic value picks the new color.
7270                         config.colorBlendEquationConfig.dynamicValue = ColorBlendEq(
7271                             vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_LIGHTEN_EXT,
7272                             vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_LIGHTEN_EXT);
7273 
7274                         if (!onlyEq)
7275                         {
7276                             config.colorBlendEnableConfig.staticValue  = !enableStateValue;
7277                             config.colorBlendEnableConfig.dynamicValue = enableStateValue;
7278                             config.colorWriteMaskConfig.staticValue    = (0 | 0 | 0 | 0);
7279                             config.colorWriteMaskConfig.dynamicValue   = (CR | CG | CB | CA);
7280                             config.blendConstantsConfig.staticValue    = BlendConstArray{1.0f, 1.0f, 1.0f, 1.0f};
7281                             config.blendConstantsConfig.dynamicValue   = BlendConstArray{0.0f, 0.0f, 0.0f, 0.0f};
7282                             // Note we don't set a dynamic value for alpha to coverage.
7283 
7284                             config.useColorWriteEnable                 = true;
7285                             config.colorWriteEnableConfig.staticValue  = false;
7286                             config.colorWriteEnableConfig.dynamicValue = true;
7287 
7288                             if (allCBDynamic)
7289                             {
7290                                 config.forceUnormColorFormat            = true;
7291                                 config.logicOpEnableConfig.staticValue  = true;
7292                                 config.logicOpEnableConfig.dynamicValue = false;
7293                                 config.logicOpConfig.staticValue        = vk::VK_LOGIC_OP_COPY;
7294                                 config.logicOpConfig.dynamicValue       = vk::VK_LOGIC_OP_CLEAR;
7295                             }
7296                         }
7297                         else
7298                         {
7299                             config.colorBlendEnableConfig.staticValue = true;
7300                         }
7301 
7302                         const std::string stateStr = (enableStateValue ? "enable" : "disable");
7303                         const std::string nameSuffix =
7304                             (onlyEq ?
7305                                  "" :
7306                                  (allCBDynamic ? ("_dynamic_" + stateStr) : ("_dynamic_but_logic_op_" + stateStr)));
7307 
7308                         // Dynamically set an advanced color equation that picks the mesh color
7309                         orderingGroup->addChild(new ExtendedDynamicStateTest(
7310                             testCtx, "color_blend_equation_advanced_new_color" + nameSuffix, config));
7311 
7312                         config.colorBlendEquationConfig.swapValues();
7313                         config.referenceColor.reset(
7314                             new SingleColorGenerator(enableStateValue ? kDefaultClearColor : kDefaultTriangleColor));
7315 
7316                         // Dynamically set an advanced color equation that picks the clear color
7317                         orderingGroup->addChild(new ExtendedDynamicStateTest(
7318                             testCtx, "color_blend_equation_advanced_old_color" + nameSuffix, config));
7319                     }
7320                 }
7321             }
7322 
7323             // All color blend as dynamic, including both blend equations.
7324             {
7325                 for (int i = 0; i < 2; ++i)
7326                 {
7327                     for (int j = 0; j < 2; ++j)
7328                     {
7329                         const bool swapEquation         = (j > 0);
7330                         const bool picksNew             = (!swapEquation);
7331                         const auto colorBlendResultName = (picksNew ? "new" : "old");
7332 
7333                         const bool colorBlendEnableDyn    = (i > 0);
7334                         const bool colorBlendEnableStatic = !colorBlendEnableDyn;
7335                         const auto colorBlendStateName    = (colorBlendEnableDyn ? "enabled" : "disabled");
7336 
7337                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7338 
7339                         // We need to apply both color blending equation states instead of deciding if it's advanced or not.
7340                         config.colorBlendBoth = true;
7341 
7342                         config.colorBlendEnableConfig.staticValue  = colorBlendEnableStatic;
7343                         config.colorBlendEnableConfig.dynamicValue = colorBlendEnableDyn;
7344 
7345                         config.colorWriteMaskConfig.staticValue  = (0 | 0 | 0 | 0);
7346                         config.colorWriteMaskConfig.dynamicValue = (CR | CG | CB | CA);
7347                         config.blendConstantsConfig.staticValue  = BlendConstArray{1.0f, 1.0f, 1.0f, 1.0f};
7348                         config.blendConstantsConfig.dynamicValue = BlendConstArray{0.0f, 0.0f, 0.0f, 0.0f};
7349 
7350                         config.useColorWriteEnable                 = true;
7351                         config.colorWriteEnableConfig.staticValue  = false;
7352                         config.colorWriteEnableConfig.dynamicValue = true;
7353 
7354                         config.forceUnormColorFormat            = true;
7355                         config.logicOpEnableConfig.staticValue  = true;
7356                         config.logicOpEnableConfig.dynamicValue = false;
7357                         config.logicOpConfig.staticValue        = vk::VK_LOGIC_OP_COPY;
7358                         config.logicOpConfig.dynamicValue       = vk::VK_LOGIC_OP_CLEAR;
7359 
7360                         // This static value picks the new color.
7361                         config.colorBlendEquationConfig.staticValue = ColorBlendEq(
7362                             vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_LIGHTEN_EXT,
7363                             vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_LIGHTEN_EXT);
7364 
7365                         // The dynamic value picks the old color instead of the new one.
7366                         config.colorBlendEquationConfig.dynamicValue =
7367                             ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_DARKEN_EXT,
7368                                          vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_DARKEN_EXT);
7369 
7370                         if (swapEquation)
7371                             config.colorBlendEquationConfig.swapValues();
7372 
7373                         // Expected result.
7374                         const auto expectGeomColor = (!colorBlendEnableDyn || swapEquation);
7375                         config.referenceColor.reset(
7376                             new SingleColorGenerator(expectGeomColor ? kDefaultTriangleColor : kDefaultClearColor));
7377 
7378                         const auto testName = std::string("color_blend_all_") + colorBlendStateName + "_" +
7379                                               colorBlendResultName + "_color";
7380                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7381                     }
7382                 }
7383             }
7384 
7385             // Dynamic color blend equation with dual blending.
7386             {
7387                 // Two equations: one picks index 0 and the other one picks index 1.
7388                 const struct
7389                 {
7390                     const ColorBlendEq equation;
7391                     const tcu::Vec4 expectedColor;
7392                 } dualSrcCases[] = {
7393                     {
7394                         ColorBlendEq(vk::VK_BLEND_FACTOR_SRC_COLOR, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD,
7395                                      vk::VK_BLEND_FACTOR_SRC_ALPHA, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD),
7396                         // This matches our logic in the frag shader for the first color index.
7397                         kOpaqueWhite,
7398                     },
7399                     {
7400                         ColorBlendEq(vk::VK_BLEND_FACTOR_SRC1_COLOR, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD,
7401                                      vk::VK_BLEND_FACTOR_SRC1_ALPHA, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD),
7402                         // This matches our logic in the frag shader for color1.
7403                         kDefaultTriangleColor,
7404                     },
7405                 };
7406 
7407                 for (size_t dynamicPick = 0u; dynamicPick < de::arrayLength(dualSrcCases); ++dynamicPick)
7408                 {
7409                     DE_ASSERT(de::arrayLength(dualSrcCases) == size_t{2});
7410 
7411                     const auto &dynamicEq = dualSrcCases[dynamicPick].equation;
7412                     const auto &staticEq  = dualSrcCases[size_t{1} - dynamicPick].equation;
7413 
7414                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7415 
7416                     config.dualSrcBlend                          = true;
7417                     config.colorBlendEnableConfig.staticValue    = true;
7418                     config.colorBlendEquationConfig.staticValue  = staticEq;
7419                     config.colorBlendEquationConfig.dynamicValue = dynamicEq;
7420                     config.referenceColor.reset(new SingleColorGenerator(dualSrcCases[dynamicPick].expectedColor));
7421 
7422                     const auto indexStr = std::to_string(dynamicPick);
7423                     // Dynamically change dual source blending equation to pick color index
7424                     orderingGroup->addChild(
7425                         new ExtendedDynamicStateTest(testCtx, "color_blend_dual_index_" + indexStr, config));
7426                 }
7427             }
7428 
7429             // Null color blend pipeline pAttachments pointer with all structure contents as dynamic states.
7430             {
7431                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7432 
7433                 // The equation picks the old color instead of the new one if blending is enabled.
7434                 config.colorBlendEquationConfig.staticValue =
7435                     ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
7436                                  vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
7437 
7438                 // The dynamic value picks the new color.
7439                 config.colorBlendEquationConfig.dynamicValue =
7440                     ColorBlendEq(vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD,
7441                                  vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD);
7442 
7443                 config.colorBlendEnableConfig.staticValue  = false;
7444                 config.colorBlendEnableConfig.dynamicValue = true;
7445 
7446                 config.colorWriteMaskConfig.staticValue  = (0 | 0 | 0 | 0);
7447                 config.colorWriteMaskConfig.dynamicValue = (CR | CG | CB | CA);
7448 
7449                 config.nullStaticColorBlendAttPtr = true; // What this test is about.
7450 
7451                 const char *testName = "null_color_blend_att_ptr";
7452                 // Set all VkPipelineColorBlendAttachmentState substates as dynamic and pass a null pointer in VkPipelineColorBlendStateCreateInfo::pAttachments
7453                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7454             }
7455 
7456             // Full dynamic blending with attachment count set to 0 and/or pAttachments set to null
7457             {
7458                 TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
7459 
7460                 // The equation picks the old color instead of the new one if blending is enabled.
7461                 baseConfig.colorBlendEquationConfig.staticValue =
7462                     ColorBlendEq(vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
7463                                  vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
7464 
7465                 // The dynamic value picks the new color.
7466                 baseConfig.colorBlendEquationConfig.dynamicValue =
7467                     ColorBlendEq(vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD,
7468                                  vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ZERO, vk::VK_BLEND_OP_ADD);
7469 
7470                 baseConfig.colorBlendEnableConfig.staticValue  = false;
7471                 baseConfig.colorBlendEnableConfig.dynamicValue = true;
7472 
7473                 baseConfig.colorWriteMaskConfig.staticValue  = (0 | 0 | 0 | 0);
7474                 baseConfig.colorWriteMaskConfig.dynamicValue = (CR | CG | CB | CA);
7475 
7476                 baseConfig.colorBlendAttCnt0 = true;
7477 
7478                 // VkPipelineColorBlendStateCreateInfo::attachmentCount = 0 and VkPipelineColorBlendStateCreateInfo::pAttachments may not be null
7479                 // DS3 advanced blending required
7480                 {
7481                     TestConfig config(baseConfig);
7482                     config.disableAdvBlendingCoherentOps = false;
7483                     config.colorBlendBoth                = true;
7484 
7485                     const char *testName = "color_blend_att_count_0_adv";
7486                     // Set all VkPipelineColorBlendAttachmentState substates as dynamic and set VkPipelineColorBlendStateCreateInfo::attachmentCount to 0 when DS3 advanced blending is supported
7487                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7488                 }
7489 
7490                 // VkPipelineColorBlendStateCreateInfo::attachmentCount = 0 and VkPipelineColorBlendStateCreateInfo::pAttachments may not be null
7491                 // DS3 advanced blending not required
7492                 // Advanced blending extension disabled if enabled/supported by default
7493                 {
7494                     TestConfig config(baseConfig);
7495                     config.disableAdvBlendingCoherentOps = true;
7496                     config.colorBlendBoth                = false;
7497 
7498                     const char *testName = "color_blend_att_count_0";
7499                     // Set all VkPipelineColorBlendAttachmentState substates as dynamic and set VkPipelineColorBlendStateCreateInfo::attachmentCount to 0
7500                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7501                 }
7502 
7503                 // VkPipelineColorBlendStateCreateInfo::attachmentCount = 0 and VkPipelineColorBlendStateCreateInfo::pAttachments = nullptr
7504                 // DS3 advanced blending required
7505                 {
7506                     TestConfig config(baseConfig);
7507                     config.disableAdvBlendingCoherentOps = false;
7508                     config.nullStaticColorBlendAttPtr    = true;
7509 
7510                     const char *testName = "color_blend_no_attachments";
7511                     // Set all VkPipelineColorBlendAttachmentState substates as dynamic and set VkPipelineColorBlendStateCreateInfo::attachmentCount to 0 and VkPipelineColorBlendStateCreateInfo::pAttachments to null
7512                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7513                 }
7514             }
7515 
7516             // Dynamically enable primitive restart
7517             if (!kUseMeshShaders)
7518             {
7519                 for (const auto &bindUnusedCase : kBindUnusedCases)
7520                 {
7521                     if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
7522                         continue;
7523 
7524                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7525                     config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7526                     config.extraLineRestarts                    = true;
7527                     config.primRestartEnableConfig.staticValue  = false;
7528                     config.primRestartEnableConfig.dynamicValue = tcu::just(true);
7529                     config.bindUnusedMeshShadingPipeline        = bindUnusedCase.bindUnusedMeshShadingPipeline;
7530                     config.referenceColor.reset(new CenterStripGenerator(kDefaultTriangleColor, kDefaultClearColor));
7531                     // Dynamically enable primitiveRestart
7532                     orderingGroup->addChild(new ExtendedDynamicStateTest(
7533                         testCtx, std::string("prim_restart_enable") + bindUnusedCase.nameSuffix, config));
7534                 }
7535             }
7536 
7537             // Dynamically change the number of primitive control points
7538             if (!kUseMeshShaders)
7539             {
7540                 for (const auto &bindUnusedCase : kBindUnusedCases)
7541                 {
7542                     if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
7543                         continue;
7544 
7545                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7546                     config.topologyConfig.staticValue            = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7547                     config.patchControlPointsConfig.staticValue  = 1;
7548                     config.patchControlPointsConfig.dynamicValue = 3;
7549                     config.bindUnusedMeshShadingPipeline         = bindUnusedCase.bindUnusedMeshShadingPipeline;
7550                     // Dynamically change patch control points
7551                     orderingGroup->addChild(new ExtendedDynamicStateTest(
7552                         testCtx, "patch_control_points" + bindUnusedCase.nameSuffix, config));
7553                 }
7554 
7555                 {
7556                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7557                     config.topologyConfig.staticValue            = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7558                     config.patchControlPointsConfig.staticValue  = 1;
7559                     config.patchControlPointsConfig.dynamicValue = 3;
7560                     config.useExtraDynPCPPipeline                = true;
7561 
7562                     const auto testName = "patch_control_points_extra_pipeline";
7563                     // Dynamically change patch control points and draw first with a pipeline using the state and no tessellation shaders
7564                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
7565                 }
7566             }
7567 
7568             // Test tessellation domain origin.
7569             if (!kUseMeshShaders)
7570             {
7571                 {
7572                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7573                     config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7574                     config.patchControlPointsConfig.staticValue = 3;
7575                     config.tessDomainOriginConfig.staticValue   = vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT;
7576                     config.tessDomainOriginConfig.dynamicValue  = vk::VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
7577                     config.cullModeConfig.staticValue           = vk::VK_CULL_MODE_BACK_BIT;
7578 
7579                     // Dynamically set the right domain origin to lower left
7580                     orderingGroup->addChild(
7581                         new ExtendedDynamicStateTest(testCtx, "tess_domain_origin_lower_left", config));
7582                 }
7583                 {
7584                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7585                     config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
7586                     config.patchControlPointsConfig.staticValue = 3;
7587                     config.tessDomainOriginConfig.staticValue   = vk::VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT;
7588                     config.tessDomainOriginConfig.dynamicValue  = vk::VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT;
7589                     config.cullModeConfig.staticValue           = vk::VK_CULL_MODE_FRONT_BIT;
7590 
7591                     // Dynamically set the right domain origin to upper left
7592                     orderingGroup->addChild(
7593                         new ExtendedDynamicStateTest(testCtx, "tess_domain_origin_upper_left", config));
7594                 }
7595             }
7596 
7597             // Dynamic topology.
7598             if (!kUseMeshShaders)
7599             {
7600                 TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
7601 
7602                 for (int i = 0; i < 2; ++i)
7603                 {
7604                     const bool forceGeometryShader = (i > 0);
7605 
7606                     static const struct
7607                     {
7608                         vk::VkPrimitiveTopology staticVal;
7609                         vk::VkPrimitiveTopology dynamicVal;
7610                     } kTopologyCases[] = {
7611                         {vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP},
7612                         {vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP},
7613                         {vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST},
7614                     };
7615 
7616                     for (const auto &kTopologyCase : kTopologyCases)
7617                     {
7618                         const auto topologyClass = getTopologyClass(kTopologyCase.staticVal);
7619 
7620                         for (const auto &bindUnusedCase : kBindUnusedCases)
7621                         {
7622                             if (bindUnusedCase.bindUnusedMeshShadingPipeline &&
7623                                 kOrdering != SequenceOrdering::CMD_BUFFER_START)
7624                                 continue;
7625 
7626                             TestConfig config(baseConfig);
7627                             config.forceGeometryShader        = forceGeometryShader;
7628                             config.topologyConfig.staticValue = kTopologyCase.staticVal;
7629                             config.topologyConfig.dynamicValue =
7630                                 tcu::just<vk::VkPrimitiveTopology>(kTopologyCase.dynamicVal);
7631                             config.primRestartEnableConfig.staticValue  = (topologyClass == TopologyClass::LINE);
7632                             config.patchControlPointsConfig.staticValue = (config.needsTessellation() ? 3u : 1u);
7633                             config.bindUnusedMeshShadingPipeline        = bindUnusedCase.bindUnusedMeshShadingPipeline;
7634 
7635                             const std::string className = topologyClassName(topologyClass);
7636                             const std::string name = "topology_" + className + (forceGeometryShader ? "_geom" : "") +
7637                                                      bindUnusedCase.nameSuffix;
7638                             // Dynamically switch primitive topologies
7639                             orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, config));
7640                         }
7641                     }
7642                 }
7643             }
7644 
7645             // Line stipple enable.
7646             {
7647                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7648 
7649                 config.primRestartEnableConfig.staticValue  = true;
7650                 config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7651                 config.lineStippleEnableConfig.staticValue  = true;
7652                 config.lineStippleEnableConfig.dynamicValue = false;
7653                 config.lineStippleParamsConfig.staticValue  = LineStippleParams{1u, 0x5555u};
7654 
7655                 // Dynamically disable line stipple
7656                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_disable", config));
7657 
7658                 config.lineStippleEnableConfig.swapValues();
7659                 config.referenceColor.reset(
7660                     new VerticalStripesGenerator(kDefaultTriangleColor, kDefaultClearColor, 1u));
7661 
7662                 // Dynamycally enable line stipple
7663                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_enable", config));
7664             }
7665 
7666             // Line stipple params.
7667             {
7668                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7669 
7670                 config.primRestartEnableConfig.staticValue  = true;
7671                 config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7672                 config.lineStippleEnableConfig.staticValue  = true;
7673                 config.lineStippleParamsConfig.staticValue  = LineStippleParams{1u, 0x5555u};
7674                 config.lineStippleParamsConfig.dynamicValue = LineStippleParams{2u, 0x3333u};
7675                 config.referenceColor.reset(
7676                     new VerticalStripesGenerator(kDefaultTriangleColor, kDefaultClearColor, 4u));
7677 
7678                 // Dynamically change the line stipple parameters
7679                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_stipple_params", config));
7680             }
7681 
7682             // Line rasterization mode.
7683             {
7684                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7685 
7686                 config.topologyConfig.staticValue          = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7687                 config.obliqueLine                         = true;
7688                 config.colorVerificator                    = verifyTopLeftCornerExactly;
7689                 config.lineStippleEnableConfig.staticValue = false;
7690                 config.lineStippleParamsConfig.staticValue = LineStippleParams{0u, 0u};
7691                 config.lineRasterModeConfig.staticValue    = LineRasterizationMode::RECTANGULAR;
7692                 config.lineRasterModeConfig.dynamicValue   = LineRasterizationMode::BRESENHAM;
7693 
7694                 // Dynamically set line rasterization mode to bresenham
7695                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_raster_mode_bresenham", config));
7696 
7697                 config.lineRasterModeConfig.swapValues();
7698                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7699                 // Dynamically set line rasterization mode to rectangular
7700                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_raster_mode_rectangular", config));
7701             }
7702             {
7703                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7704 
7705                 config.topologyConfig.staticValue          = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
7706                 config.obliqueLine                         = true;
7707                 config.colorVerificator                    = verifyTopLeftCornerWithPartialAlpha;
7708                 config.lineStippleEnableConfig.staticValue = false;
7709                 config.lineStippleParamsConfig.staticValue = LineStippleParams{0u, 0u};
7710                 config.lineRasterModeConfig.staticValue    = LineRasterizationMode::BRESENHAM;
7711                 config.lineRasterModeConfig.dynamicValue   = LineRasterizationMode::SMOOTH;
7712 
7713                 // Dynamically set line rasterization mode to smooth
7714                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "line_raster_mode_smooth", config));
7715             }
7716 
7717             // Viewport.
7718             {
7719                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7720                 // 2 scissors, bad static single viewport.
7721                 config.scissorConfig.staticValue =
7722                     ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight),
7723                                vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
7724                 config.viewportConfig.staticValue  = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
7725                 config.viewportConfig.dynamicValue = ViewportVec{
7726                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7727                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7728                 };
7729                 // Dynamically set 2 viewports
7730                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", config));
7731             }
7732             {
7733                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7734                 // Bad static reduced viewport.
7735                 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
7736                 config.viewportConfig.staticValue =
7737                     ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
7738                 // Dynamically set viewport to cover full framebuffer
7739                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", config));
7740             }
7741             {
7742                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7743                 // 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
7744                 config.scissorConfig.staticValue =
7745                     ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight),
7746                                vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
7747                 config.viewportConfig.staticValue = ViewportVec{
7748                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
7749                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),        // Left.
7750                 };
7751                 config.viewportConfig.dynamicValue =
7752                     ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
7753                 // Dynamically switch the order with 2 viewports
7754                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", config));
7755             }
7756             {
7757                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7758                 // 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
7759                 config.scissorConfig.staticValue =
7760                     ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight),
7761                                vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
7762                 config.viewportConfig.staticValue = ViewportVec{
7763                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),        // Left.
7764                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
7765                 };
7766                 config.viewportConfig.dynamicValue =
7767                     ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
7768                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7769                 // Dynamically switch the order with 2 viewports resulting in clean image
7770                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", config));
7771             }
7772 
7773             // Scissor.
7774             {
7775                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7776                 // 2 viewports, bad static single scissor.
7777                 config.viewportConfig.staticValue = ViewportVec{
7778                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7779                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7780                 };
7781                 config.scissorConfig.staticValue =
7782                     ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
7783                 config.scissorConfig.dynamicValue = ScissorVec{
7784                     vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
7785                     vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
7786                 };
7787                 // Dynamically set 2 scissors
7788                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", config));
7789             }
7790             {
7791                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7792                 // 1 viewport, bad static single scissor.
7793                 config.scissorConfig.staticValue =
7794                     ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
7795                 config.scissorConfig.dynamicValue =
7796                     ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
7797                 // Dynamically set scissor to cover full framebuffer
7798                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", config));
7799             }
7800             {
7801                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7802                 // 2 viewports, 2 reversed scissors that need fixing.
7803                 config.viewportConfig.staticValue = ViewportVec{
7804                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7805                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7806                 };
7807                 config.scissorConfig.staticValue = ScissorVec{
7808                     vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
7809                     vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
7810                 };
7811                 config.scissorConfig.dynamicValue =
7812                     ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
7813                 // Dynamically switch the order with 2 scissors
7814                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", config));
7815             }
7816             {
7817                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7818                 // 2 viewports, 2 scissors switched to prevent drawing.
7819                 config.viewportConfig.staticValue = ViewportVec{
7820                     vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7821                     vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
7822                 };
7823                 config.scissorConfig.staticValue = ScissorVec{
7824                     vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
7825                     vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
7826                 };
7827                 config.scissorConfig.dynamicValue =
7828                     ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
7829                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7830                 // Dynamically switch the order with 2 scissors to avoid drawing
7831                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", config));
7832             }
7833 
7834             // Stride.
7835             if (!kUseMeshShaders)
7836             {
7837                 struct
7838                 {
7839                     const VertexGenerator *factory;
7840                     const std::string prefix;
7841                 } strideCases[] = {
7842                     {getVertexWithPaddingGenerator(), "stride"},
7843                     {getVertexWithExtraAttributesGenerator(), "large_stride"},
7844                 };
7845 
7846                 for (const auto &strideCase : strideCases)
7847                 {
7848                     const auto factory       = strideCase.factory;
7849                     const auto &prefix       = strideCase.prefix;
7850                     const auto vertexStrides = factory->getVertexDataStrides();
7851                     StrideVec halfStrides;
7852 
7853                     halfStrides.reserve(vertexStrides.size());
7854                     for (const auto &stride : vertexStrides)
7855                         halfStrides.push_back(stride / 2u);
7856 
7857                     if (factory == getVertexWithExtraAttributesGenerator() &&
7858                         kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
7859                     {
7860                         // This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
7861                         // stride being less than the extent of the binding for the second attribute.
7862                         continue;
7863                     }
7864 
7865                     for (const auto &bindUnusedCase : kBindUnusedCases)
7866                     {
7867                         if (bindUnusedCase.bindUnusedMeshShadingPipeline &&
7868                             kOrdering != SequenceOrdering::CMD_BUFFER_START)
7869                             continue;
7870 
7871                         {
7872                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
7873                             config.strideConfig.staticValue      = halfStrides;
7874                             config.strideConfig.dynamicValue     = vertexStrides;
7875                             config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
7876                             // Dynamically set stride
7877                             orderingGroup->addChild(
7878                                 new ExtendedDynamicStateTest(testCtx, prefix + bindUnusedCase.nameSuffix, config));
7879                         }
7880                         {
7881                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
7882                             config.strideConfig.staticValue      = halfStrides;
7883                             config.strideConfig.dynamicValue     = vertexStrides;
7884                             config.vertexDataOffset              = vertexStrides[0];
7885                             config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
7886                             // Dynamically set stride using a nonzero vertex data offset
7887                             orderingGroup->addChild(new ExtendedDynamicStateTest(
7888                                 testCtx, prefix + "_with_offset" + bindUnusedCase.nameSuffix, config));
7889                         }
7890                         {
7891                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, factory);
7892                             config.strideConfig.staticValue      = halfStrides;
7893                             config.strideConfig.dynamicValue     = vertexStrides;
7894                             config.vertexDataOffset              = vertexStrides[0];
7895                             config.vertexDataExtraBytes          = config.vertexDataOffset;
7896                             config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
7897 
7898                             // 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.
7899                             config.referenceColor.reset(
7900                                 new HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor));
7901                             config.meshParams[0].scaleY  = 0.5f;
7902                             config.meshParams[0].offsetY = -0.5f;
7903 
7904                             // Dynamically set stride using a nonzero vertex data offset and extra bytes
7905                             orderingGroup->addChild(new ExtendedDynamicStateTest(
7906                                 testCtx, prefix + "_with_offset_and_padding" + bindUnusedCase.nameSuffix, config));
7907                         }
7908                     }
7909                 }
7910 
7911                 // Dynamic stride of 0
7912                 //
7913                 // The "two_draws" variants are invalid because the non-zero vertex stride will cause out-of-bounds access
7914                 // when drawing more than one vertex.
7915                 if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC && kOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC)
7916                 {
7917                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders,
7918                                       getVertexWithExtraAttributesGenerator());
7919                     config.strideConfig.staticValue  = config.getActiveVertexGenerator()->getVertexDataStrides();
7920                     config.strideConfig.dynamicValue = {0};
7921                     config.vertexDataOffset          = 4;
7922                     config.singleVertex              = true;
7923                     config.singleVertexDrawCount     = 6;
7924 
7925                     // Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
7926                     // offscreen vertex and draw something in the bottom half.
7927                     config.referenceColor.reset(
7928                         new HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor));
7929                     config.meshParams[0].scaleY  = 0.5f;
7930                     config.meshParams[0].offsetY = -0.5f;
7931 
7932                     // Use strip scale to synthesize a strip from a vertex attribute which remains constant over the draw call.
7933                     config.meshParams[0].stripScale = 1.0f;
7934 
7935                     // Dynamically set zero stride using a nonzero vertex data offset
7936                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "zero_stride_with_offset", config));
7937                 }
7938             }
7939 
7940             // Depth test enable.
7941             {
7942                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7943                 config.depthTestEnableConfig.staticValue  = false;
7944                 config.depthTestEnableConfig.dynamicValue = tcu::just(true);
7945                 // By default, the depth test never passes when enabled.
7946                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
7947                 // Dynamically enable depth test
7948                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", config));
7949             }
7950             {
7951                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7952                 config.depthTestEnableConfig.staticValue  = true;
7953                 config.depthTestEnableConfig.dynamicValue = tcu::just(false);
7954                 // Dynamically disable depth test
7955                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", config));
7956             }
7957 
7958             // Depth write enable.
7959             {
7960                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7961 
7962                 // Enable depth test and set values so it passes.
7963                 config.depthTestEnableConfig.staticValue = true;
7964                 config.depthCompareOpConfig.staticValue  = vk::VK_COMPARE_OP_LESS;
7965                 config.clearDepthValue                   = 0.5f;
7966                 config.meshParams[0].depth               = 0.25f;
7967 
7968                 // Enable writes and expect the mesh value.
7969                 config.depthWriteEnableConfig.staticValue  = false;
7970                 config.depthWriteEnableConfig.dynamicValue = tcu::just(true);
7971                 config.expectedDepth                       = 0.25f;
7972 
7973                 // Dynamically enable writes to the depth buffer
7974                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", config));
7975             }
7976             {
7977                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7978 
7979                 // Enable depth test and set values so it passes.
7980                 config.depthTestEnableConfig.staticValue = true;
7981                 config.depthCompareOpConfig.staticValue  = vk::VK_COMPARE_OP_LESS;
7982                 config.clearDepthValue                   = 0.5f;
7983                 config.meshParams[0].depth               = 0.25f;
7984 
7985                 // But disable writing dynamically and expect the clear value.
7986                 config.depthWriteEnableConfig.staticValue  = true;
7987                 config.depthWriteEnableConfig.dynamicValue = tcu::just(false);
7988                 config.expectedDepth                       = 0.5f;
7989 
7990                 // Dynamically disable writes to the depth buffer
7991                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", config));
7992             }
7993 
7994             // Depth clamp enable.
7995             {
7996                 // Without clamping, the mesh depth fails the depth test after applying the viewport transform.
7997                 // With clamping, it should pass thanks to the viewport.
7998                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
7999 
8000                 config.meshParams[0].depth                = 1.5f;
8001                 config.clearDepthValue                    = 0.625f;
8002                 config.depthTestEnableConfig.staticValue  = true;
8003                 config.depthWriteEnableConfig.staticValue = true;
8004                 config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_LESS;
8005                 config.viewportConfig.staticValue =
8006                     ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.0f, 0.5f));
8007                 config.expectedDepth = 0.5f;
8008 
8009                 config.depthClampEnableConfig.staticValue  = false;
8010                 config.depthClampEnableConfig.dynamicValue = true;
8011 
8012                 // Dynamically enable depth clamp
8013                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_enable", config));
8014             }
8015             {
8016                 // Reverse situation.
8017                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8018 
8019                 config.meshParams[0].depth                = 1.5f;
8020                 config.clearDepthValue                    = 0.625f;
8021                 config.depthTestEnableConfig.staticValue  = true;
8022                 config.depthWriteEnableConfig.staticValue = true;
8023                 config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_LESS;
8024                 config.viewportConfig.staticValue =
8025                     ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.0f, 0.5f));
8026                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8027                 config.expectedDepth = 0.625f;
8028 
8029                 config.depthClampEnableConfig.staticValue  = true;
8030                 config.depthClampEnableConfig.dynamicValue = false;
8031 
8032                 // Dynamically disable depth clamp
8033                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_disable", config));
8034             }
8035 
8036 #if 0
8037         // "If the depth clamping state is changed dynamically, and the pipeline was not created with
8038         // VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT enabled, then depth clipping is enabled when depth clamping is disabled and vice
8039         // versa"
8040         //
8041         // Try to verify the implementation ignores the static depth clipping state. We cannot test the following sequence orderings for this:
8042         // - BEFORE_GOOD_STATIC and TWO_DRAWS_STATIC because they use static-state pipelines, but for this specific case we need dynamic state as per the spec.
8043         // - TWO_DRAWS_DYNAMIC because the first draw may modify the framebuffer with undesired side-effects.
8044         if (kOrdering != SequenceOrdering::BEFORE_GOOD_STATIC && kOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC && kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
8045         {
8046             {
8047                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8048 
8049                 config.meshParams[0].depth = -0.5f;
8050                 config.clearDepthValue = 1.0f;
8051                 config.depthTestEnableConfig.staticValue = true;
8052                 config.depthWriteEnableConfig.staticValue = true;
8053                 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
8054                 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.5f, 1.0f));
8055                 config.expectedDepth = 0.5f; // Geometry will be clamped to this value.
8056 
8057                 config.depthClampEnableConfig.staticValue = false;
8058                 config.depthClampEnableConfig.dynamicValue = true;
8059 
8060                 // Dynamically enable depth clamp while making sure depth clip is disabled
8061                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_enable_no_clip", config));
8062             }
8063             {
8064                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8065 
8066                 config.meshParams[0].depth = -0.5f;
8067                 config.clearDepthValue = 1.0f;
8068                 config.depthTestEnableConfig.staticValue = true;
8069                 config.depthWriteEnableConfig.staticValue = true;
8070                 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
8071                 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.5f, 1.0f));
8072                 config.expectedDepth = 1.0f; // Geometry should be clipped in this case.
8073                 config.referenceColor.reset                    (new SingleColorGenerator(kDefaultClearColor));
8074 
8075                 // Enable clamping dynamically, with clipping enabled statically.
8076                 config.depthClampEnableConfig.staticValue = false;
8077                 config.depthClampEnableConfig.dynamicValue = true;
8078                 config.depthClipEnableConfig.staticValue = OptBoolean(true);
8079 
8080                 // Dynamically enable depth clamp while keeping depth clip enabled statically
8081                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_enable_with_clip", config));
8082             }
8083             {
8084                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8085 
8086                 config.meshParams[0].depth = -0.5f;
8087                 config.clearDepthValue = 1.0f;
8088                 config.depthTestEnableConfig.staticValue = true;
8089                 config.depthWriteEnableConfig.staticValue = true;
8090                 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
8091                 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.5f, 1.0f));
8092                 config.expectedDepth = 1.0f; // Geometry should be clipped in this case.
8093                 config.referenceColor.reset                    (new SingleColorGenerator(kDefaultClearColor));
8094 
8095                 config.depthClampEnableConfig.staticValue = true;
8096                 config.depthClampEnableConfig.dynamicValue = false;
8097                 if (vk::isConstructionTypeShaderObject(pipelineConstructionType))
8098                     config.depthClipEnableConfig.staticValue = OptBoolean(true);
8099 
8100                 // Dynamically disable depth clamp making sure depth clipping is enabled
8101                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_clamp_disable_with_clip", config));
8102             }
8103             // Note: the combination of depth clamp disabled and depth clip disabled cannot be tested because if Zf falls outside
8104             // [Zmin,Zmax] from the viewport, then the value of Zf is undefined during the depth test.
8105         }
8106 #endif
8107 
8108             // Polygon mode.
8109             {
8110                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8111 
8112                 config.polygonModeConfig.staticValue  = vk::VK_POLYGON_MODE_FILL;
8113                 config.polygonModeConfig.dynamicValue = vk::VK_POLYGON_MODE_POINT;
8114                 config.oversizedTriangle              = true;
8115                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8116 
8117                 // Dynamically set polygon draw mode to points
8118                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "polygon_mode_point", config));
8119             }
8120             {
8121                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8122 
8123                 config.polygonModeConfig.staticValue  = vk::VK_POLYGON_MODE_POINT;
8124                 config.polygonModeConfig.dynamicValue = vk::VK_POLYGON_MODE_FILL;
8125                 config.oversizedTriangle              = true;
8126 
8127                 // Dynamically set polygon draw mode to fill
8128                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "polygon_mode_fill", config));
8129             }
8130 
8131             for (int i = 0; i < 2; ++i)
8132             {
8133                 const bool multisample         = (i > 0);
8134                 const auto activeSampleCount   = (multisample ? kMultiSampleCount : kSingleSampleCount);
8135                 const auto inactiveSampleCount = (multisample ? kSingleSampleCount : kMultiSampleCount);
8136                 const std::string namePrefix   = (multisample ? "multi_sample_" : "single_sample_");
8137                 const std::string descSuffix   = (multisample ? " in multisample mode" : " in single sample mode");
8138 
8139                 // Sample count.
8140                 {
8141                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8142 
8143                     // The static pipeline would be illegal due to VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853.
8144                     if (!config.useStaticPipeline())
8145                     {
8146                         config.rasterizationSamplesConfig.staticValue  = inactiveSampleCount;
8147                         config.rasterizationSamplesConfig.dynamicValue = activeSampleCount;
8148                         // Dynamically set the rasterization sample count
8149                         orderingGroup->addChild(
8150                             new ExtendedDynamicStateTest(testCtx, namePrefix + "rasterization_samples", config));
8151                     }
8152                 }
8153 
8154                 // Sample mask
8155                 {
8156                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8157                     config.rasterizationSamplesConfig    = activeSampleCount;
8158                     config.sampleMaskConfig.staticValue  = SampleMaskVec(1u, 0u);
8159                     config.sampleMaskConfig.dynamicValue = SampleMaskVec(1u, 0xFFu);
8160 
8161                     // Dynamically set a sample mask that allows drawing
8162                     orderingGroup->addChild(
8163                         new ExtendedDynamicStateTest(testCtx, namePrefix + "sample_mask_enable", config));
8164                 }
8165                 {
8166                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8167                     config.rasterizationSamplesConfig    = activeSampleCount;
8168                     config.sampleMaskConfig.staticValue  = SampleMaskVec(1u, 0xFFu);
8169                     config.sampleMaskConfig.dynamicValue = SampleMaskVec(1u, 0u);
8170                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8171 
8172                     // Dynamically set a sample mask that prevents drawing
8173                     orderingGroup->addChild(
8174                         new ExtendedDynamicStateTest(testCtx, namePrefix + "sample_mask_disable", config));
8175                 }
8176 
8177                 // Alpha to coverage.
8178                 {
8179                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8180 
8181                     config.rasterizationSamplesConfig         = activeSampleCount;
8182                     config.meshParams[0].color                = kTransparentColor;
8183                     config.alphaToCoverageConfig.staticValue  = false;
8184                     config.alphaToCoverageConfig.dynamicValue = true;
8185                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8186 
8187                     // Dynamically enable alpha to coverage
8188                     orderingGroup->addChild(
8189                         new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_coverage_enable", config));
8190                 }
8191                 {
8192                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8193 
8194                     config.rasterizationSamplesConfig         = activeSampleCount;
8195                     config.meshParams[0].color                = kTransparentColor;
8196                     config.alphaToCoverageConfig.staticValue  = true;
8197                     config.alphaToCoverageConfig.dynamicValue = false;
8198                     config.referenceColor.reset(new SingleColorGenerator(kTransparentColor));
8199 
8200                     // Dynamically disable alpha to coverage
8201                     orderingGroup->addChild(
8202                         new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_coverage_disable", config));
8203                 }
8204 
8205                 // Alpha to one.
8206                 {
8207                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8208 
8209                     config.rasterizationSamplesConfig    = activeSampleCount;
8210                     config.meshParams[0].color           = kTransparentColor;
8211                     config.alphaToOneConfig.staticValue  = false;
8212                     config.alphaToOneConfig.dynamicValue = true;
8213                     config.referenceColor.reset(new SingleColorGenerator(kDefaultTriangleColor));
8214 
8215                     // Dynamically enable alpha to one
8216                     orderingGroup->addChild(
8217                         new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_one_enable", config));
8218                 }
8219                 {
8220                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8221 
8222                     config.rasterizationSamplesConfig    = activeSampleCount;
8223                     config.meshParams[0].color           = kTransparentColor;
8224                     config.alphaToOneConfig.staticValue  = true;
8225                     config.alphaToOneConfig.dynamicValue = false;
8226                     config.referenceColor.reset(new SingleColorGenerator(kTransparentColor));
8227 
8228                     // Dynamically disable alpha to one
8229                     orderingGroup->addChild(
8230                         new ExtendedDynamicStateTest(testCtx, namePrefix + "alpha_to_one_disable", config));
8231                 }
8232             }
8233 
8234             // Special sample mask case: make sure the dynamic sample mask count does not overwrite the actual sample mask.
8235             {
8236                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8237 
8238                 // There's guaranteed support for 1 sample and 4 samples. So the official pipeline sample count will be 1 sample, and
8239                 // the one we'll use in the dynamic sample mask call will be 4.
8240                 //
8241                 // When using 4 samples, sample 3 uses a Y offset of 0.875 pixels, so we'll use an off-center triangle to try to trick
8242                 // the implementation into having that one covered by using a Y offset of 0.75.
8243                 config.dynamicSampleMaskCount        = tcu::just(kMultiSampleCount);
8244                 config.sampleMaskConfig.staticValue  = SampleMaskVec(1u, 0u);
8245                 config.sampleMaskConfig.dynamicValue = SampleMaskVec(1u, 0xFFu);
8246                 config.offCenterTriangle             = true;
8247                 config.offCenterProportion           = tcu::Vec2(0.0f, 0.75f);
8248                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultTriangleColor,
8249                                                                        kDefaultClearColor, kDefaultClearColor));
8250 
8251                 // Dynamically set sample mask with slightly different sample count
8252                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_mask_count", config));
8253             }
8254 
8255             // Special rasterization samples case: make sure rasterization samples is taken from the dynamic value, but provide a larger mask.
8256             {
8257                 const auto kLargeRasterizationSampleCount = vk::VK_SAMPLE_COUNT_64_BIT;
8258                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8259 
8260                 // We cannot create a static pipeline with the configuration below because the render pass attachments will have a
8261                 // sample count of kMultiSampleCount and VUID-VkGraphicsPipelineCreateInfo-multisampledRenderToSingleSampled-06853
8262                 // applies here.
8263                 if (!config.useStaticPipeline())
8264                 {
8265                     config.rasterizationSamplesConfig.staticValue  = kLargeRasterizationSampleCount;
8266                     config.rasterizationSamplesConfig.dynamicValue = kMultiSampleCount;
8267                     config.sampleMaskConfig.staticValue = SampleMaskVec{0xFFFFFFF0u, 0xFFFFFFFFu}; // Last 4 bits off.
8268                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8269 
8270                     // Dynamically set the rasterization samples to a low value while disabling bits corresponding to the dynamic sample count
8271                     orderingGroup->addChild(
8272                         new ExtendedDynamicStateTest(testCtx, "large_static_rasterization_samples_off", config));
8273 
8274                     config.sampleMaskConfig.staticValue = SampleMaskVec{0xFu, 0u}; // Last 4 bits on.
8275                     config.referenceColor.reset(new SingleColorGenerator(kDefaultTriangleColor));
8276 
8277                     // Dynamically set the rasterization samples to a low value while enabling bits corresponding to the dynamic sample count
8278                     orderingGroup->addChild(
8279                         new ExtendedDynamicStateTest(testCtx, "large_static_rasterization_samples_on", config));
8280                 }
8281             }
8282 
8283             // Color write mask.
8284             {
8285                 const struct
8286                 {
8287                     vk::VkColorComponentFlags staticVal;
8288                     vk::VkColorComponentFlags dynamicVal;
8289                 } colorComponentCases[] = {
8290                     {(CR | CG | CB | CA), (CR | 0 | 0 | 0)}, {(CR | CG | CB | CA), (0 | CG | 0 | 0)},
8291                     {(CR | CG | CB | CA), (0 | 0 | CB | 0)}, {(CR | CG | CB | CA), (0 | 0 | 0 | CA)},
8292                     {(CR | CG | CB | CA), (0 | 0 | 0 | 0)},  {(0 | 0 | 0 | 0), (CR | 0 | 0 | 0)},
8293                     {(0 | 0 | 0 | 0), (0 | CG | 0 | 0)},     {(0 | 0 | 0 | 0), (0 | 0 | CB | 0)},
8294                     {(0 | 0 | 0 | 0), (0 | 0 | 0 | CA)},     {(0 | 0 | 0 | 0), (CR | CG | CB | CA)},
8295                 };
8296 
8297                 for (const auto &colorCompCase : colorComponentCases)
8298                 {
8299                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8300 
8301                     config.clearColorValue                   = vk::makeClearValueColor(kTransparentClearColor);
8302                     config.meshParams[0].color               = kOpaqueWhite;
8303                     config.colorWriteMaskConfig.staticValue  = colorCompCase.staticVal;
8304                     config.colorWriteMaskConfig.dynamicValue = colorCompCase.dynamicVal;
8305                     config.referenceColor.reset(new SingleColorGenerator(
8306                         filterColor(kTransparentClearColor, kOpaqueWhite, colorCompCase.dynamicVal)));
8307 
8308                     const auto staticCode  = componentCodes(colorCompCase.staticVal);
8309                     const auto dynamicCode = componentCodes(colorCompCase.dynamicVal);
8310                     const auto testName    = "color_write_mask_" + staticCode + "_to_" + dynamicCode;
8311                     // Dynamically set color write mask
8312                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
8313                 }
8314             }
8315 
8316             // Rasterization stream selection.
8317             if (!kUseMeshShaders)
8318             {
8319                 const struct
8320                 {
8321                     OptRastStream shaderStream; // Stream in the geometry shader.
8322                     OptRastStream staticVal;    // Static value for the extension struct.
8323                     OptRastStream dynamicVal;   // Dynamic value for the setter.
8324                     const bool expectDraw;      // Match between actual stream and active selected value?
8325                     const char *name;
8326                 } rastStreamCases[] = {
8327                     {tcu::just(1u), tcu::Nothing, tcu::just(1u), true, "none_to_one"},
8328                     {tcu::just(1u), tcu::just(0u), tcu::just(1u), true, "zero_to_one"},
8329                     {tcu::Nothing, tcu::just(1u), tcu::just(0u), true, "one_to_zero"},
8330                     {tcu::just(0u), tcu::just(1u), tcu::just(0u), true, "one_to_zero_explicit"},
8331                     {tcu::just(0u), tcu::Nothing, tcu::just(1u), false, "none_to_one_mismatch"},
8332                     {tcu::just(0u), tcu::just(0u), tcu::just(1u), false, "zero_to_one_mismatch"},
8333                     {tcu::Nothing, tcu::Nothing, tcu::just(1u), false, "none_to_one_mismatch_implicit"},
8334                     {tcu::Nothing, tcu::just(0u), tcu::just(1u), false, "zero_to_one_mismatch_implicit"},
8335                 };
8336 
8337                 for (const auto &rastStreamCase : rastStreamCases)
8338                 {
8339                     // In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
8340                     // calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
8341                     // must be set if the used pipeline contains the dynamic state.
8342                     if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC && !static_cast<bool>(rastStreamCase.staticVal))
8343                         continue;
8344 
8345                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8346 
8347                     config.rasterizationStreamConfig.staticValue  = rastStreamCase.staticVal;
8348                     config.rasterizationStreamConfig.dynamicValue = rastStreamCase.dynamicVal;
8349                     config.shaderRasterizationStream              = rastStreamCase.shaderStream;
8350                     config.referenceColor.reset(new SingleColorGenerator(
8351                         rastStreamCase.expectDraw ? kDefaultTriangleColor : kDefaultClearColor));
8352 
8353                     const auto testName = std::string("rasterization_stream_") + rastStreamCase.name;
8354 
8355                     // Dynamically switch rasterization streams
8356                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
8357                 }
8358             }
8359 
8360             // Provoking vertex mode.
8361             {
8362                 const struct
8363                 {
8364                     OptBoolean staticVal;
8365                     OptBoolean dynamicVal;
8366                     const char *name;
8367                 } provokingVtxCases[] = {
8368                     // Dynamically switch provoking vertex mode from none (first) to last
8369                     {tcu::Nothing, tcu::just(true), "provoking_vertex_first_to_last_implicit"},
8370                     // Dynamically switch provoking vertex mode from first to last
8371                     {tcu::just(false), tcu::just(true), "provoking_vertex_first_to_last_explicit"},
8372                     // Dynamically switch provoking vertex mode from last to first
8373                     {tcu::just(true), tcu::just(false), "provoking_vertex_last_to_first"},
8374                 };
8375 
8376                 for (const auto &provokingVtxCase : provokingVtxCases)
8377                 {
8378                     // In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
8379                     // calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
8380                     // must be set if the used pipeline contains the dynamic state.
8381                     if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC &&
8382                         !static_cast<bool>(provokingVtxCase.staticVal))
8383                         continue;
8384 
8385                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders,
8386                                       getProvokingVertexWithPaddingGenerator(provokingVtxCase.dynamicVal.get()));
8387                     config.provokingVertexConfig.staticValue  = provokingVtxCase.staticVal;
8388                     config.provokingVertexConfig.dynamicValue = provokingVtxCase.dynamicVal;
8389                     config.oversizedTriangle                  = true;
8390 
8391                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, provokingVtxCase.name, config));
8392                 }
8393             }
8394 
8395             // Depth clip negative one to one.
8396             {
8397                 const struct
8398                 {
8399                     OptBoolean staticVal;
8400                     OptBoolean dynamicVal;
8401                     const char *name;
8402                 } negativeOneToOneCases[] = {
8403                     // Dynamically switch negative one to one mode from none (false) to true
8404                     {tcu::Nothing, tcu::just(true), "negative_one_to_one_false_to_true_implicit"},
8405                     // Dynamically switch negative one to one mode from false to true
8406                     {tcu::just(false), tcu::just(true), "negative_one_to_one_false_to_true_explicit"},
8407                     // Dynamically switch negative one to one mode from true to false
8408                     {tcu::just(true), tcu::just(false), "negative_one_to_one_true_to_false"},
8409                 };
8410 
8411                 for (const auto &negOneToOneCase : negativeOneToOneCases)
8412                 {
8413                     // In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
8414                     // calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
8415                     // must be set if the used pipeline contains the dynamic state.
8416                     if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC &&
8417                         !static_cast<bool>(negOneToOneCase.staticVal))
8418                         continue;
8419 
8420                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8421                     config.negativeOneToOneConfig.staticValue  = negOneToOneCase.staticVal;
8422                     config.negativeOneToOneConfig.dynamicValue = negOneToOneCase.dynamicVal;
8423 
8424                     // Enable depth test and set values so it passes.
8425                     config.depthTestEnableConfig.staticValue  = true;
8426                     config.depthWriteEnableConfig.staticValue = true;
8427                     config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_LESS;
8428                     config.meshParams[0].depth                = 0.5f;
8429                     config.expectedDepth = (config.getActiveNegativeOneToOneValue() ? 0.75f : 0.5f);
8430 
8431                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, negOneToOneCase.name, config));
8432                 }
8433             }
8434 
8435             // Depth clip enable.
8436             {
8437                 const struct
8438                 {
8439                     OptBoolean staticVal;
8440                     OptBoolean dynamicVal;
8441                     const char *name;
8442                 } depthClipEnableCases[] = {
8443                     // Dynamically switch negative one to one mode from none (true) to false
8444                     {tcu::Nothing, tcu::just(false), "depth_clip_enable_true_to_false_implicit"},
8445                     // Dynamically switch negative one to one mode from true to false
8446                     {tcu::just(true), tcu::just(false), "depth_clip_enable_true_to_false_explicit"},
8447                     // Dynamically switch negative one to one mode from false to true
8448                     {tcu::just(false), tcu::just(true), "depth_clip_enable_true_to_false"},
8449                 };
8450 
8451                 for (const auto &depthClipEnableCase : depthClipEnableCases)
8452                 {
8453                     // In TWO_DRAWS_STATIC sequence ordering, the bad dynamic value may be tcu::Nothing, which is equivalent to not
8454                     // calling the state-setting function, but the pipeline will be used to draw. This is illegal. The dynamic value
8455                     // must be set if the used pipeline contains the dynamic state.
8456                     if (kOrdering == SequenceOrdering::TWO_DRAWS_STATIC &&
8457                         !static_cast<bool>(depthClipEnableCase.staticVal))
8458                         continue;
8459 
8460                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8461                     config.depthClipEnableConfig.staticValue  = depthClipEnableCase.staticVal;
8462                     config.depthClipEnableConfig.dynamicValue = depthClipEnableCase.dynamicVal;
8463 
8464                     const bool depthClipActive = config.getActiveDepthClipEnable();
8465 
8466                     // Enable depth test and set values so it passes.
8467                     config.depthTestEnableConfig.staticValue  = true;
8468                     config.depthWriteEnableConfig.staticValue = true;
8469                     config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_LESS;
8470                     config.meshParams[0].depth                = -0.5f;
8471                     config.viewportConfig.staticValue =
8472                         ViewportVec(1u, vk::makeViewport(0.0f, 0.0f, kWidthF, kHeightF, 0.5f, 1.0f));
8473                     config.expectedDepth = (depthClipActive ? 1.0f : 0.25f);
8474                     config.referenceColor.reset(
8475                         new SingleColorGenerator(depthClipActive ? kDefaultClearColor : kDefaultTriangleColor));
8476 
8477                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, depthClipEnableCase.name, config));
8478                 }
8479             }
8480 
8481             // Sample locations enablement.
8482             {
8483                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8484                 config.rasterizationSamplesConfig = kMultiSampleCount;
8485                 config.offCenterTriangle          = true;
8486                 config.offCenterProportion        = tcu::Vec2(0.90625f, 0.90625f);
8487 
8488                 // Push sample locations towards the bottom right corner so they're able to sample the off-center triangle.
8489                 config.sampleLocations = tcu::Vec2(1.0f, 1.0f);
8490 
8491                 config.sampleLocationsEnableConfig.staticValue  = false;
8492                 config.sampleLocationsEnableConfig.dynamicValue = true;
8493 
8494                 // Dynamically enable sample locations
8495                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_locations_enable", config));
8496 
8497                 config.sampleLocationsEnableConfig.swapValues();
8498                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor,
8499                                                                        kDefaultClearColor, kDefaultClearColor));
8500 
8501                 // Dynamically disable sample locations
8502                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_locations_disable", config));
8503             }
8504 
8505             // Coverage to color enable.
8506             {
8507                 for (int i = 0; i < 2; ++i)
8508                 {
8509                     const bool multisample = (i > 0);
8510 
8511                     for (int j = 0; j < 2; ++j)
8512                     {
8513                         const bool covToColor = (j > 0);
8514                         const uint32_t referenceRed =
8515                             ((covToColor ? (multisample ? 15u : 1u) : 48u /*matches meshParams[0].color*/));
8516 
8517                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8518 
8519                         config.oversizedTriangle          = true; // This avoids partial coverages in fragments.
8520                         config.rasterizationSamplesConfig = (multisample ? kMultiSampleCount : kSingleSampleCount);
8521                         config.coverageToColorEnableConfig.staticValue  = !covToColor;
8522                         config.coverageToColorEnableConfig.dynamicValue = covToColor;
8523                         config.meshParams[0].color =
8524                             tcu::Vec4(48.0f, 0.0f, 0.0f, 1.0f); // Distinct value, does not match any coverage mask.
8525                         config.referenceColor.reset(new SingleColorGenerator(tcu::UVec4(referenceRed, 0u, 0u, 1u)));
8526 
8527                         const std::string finalState = (covToColor ? "enable" : "disable");
8528                         const auto testName =
8529                             "coverage_to_color_" + finalState + "_" + (multisample ? "multisample" : "single_sample");
8530 
8531                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
8532                     }
8533                 }
8534             }
8535 
8536             // Coverage to color location.
8537             {
8538                 for (int i = 0; i < 2; ++i)
8539                 {
8540                     const bool multisample = (i > 0);
8541 
8542                     for (int j = 0; j < 2; ++j)
8543                     {
8544                         const bool locationLast      = (j > 0);
8545                         const uint32_t colorAttCount = 4u;
8546                         const uint32_t covToColorLoc = (locationLast ? colorAttCount - 1u : 0u);
8547                         const uint32_t referenceRed =
8548                             ((locationLast ? (multisample ? 15u : 1u) : 48u /*matches meshParams[0].color*/));
8549 
8550                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8551 
8552                         config.oversizedTriangle          = true; // This avoids partial coverages in fragments.
8553                         config.rasterizationSamplesConfig = (multisample ? kMultiSampleCount : kSingleSampleCount);
8554                         config.colorAttachmentCount       = colorAttCount;
8555                         config.coverageToColorEnableConfig.staticValue    = true;
8556                         config.coverageToColorLocationConfig.staticValue  = (locationLast ? 0u : colorAttCount - 1u);
8557                         config.coverageToColorLocationConfig.dynamicValue = covToColorLoc;
8558                         config.meshParams[0].color =
8559                             tcu::Vec4(48.0f, 0.0f, 0.0f, 1.0f); // Distinct value, does not match any coverage mask.
8560                         config.referenceColor.reset(new SingleColorGenerator(tcu::UVec4(referenceRed, 0u, 0u, 1u)));
8561 
8562                         const auto locName  = std::to_string(covToColorLoc);
8563                         const auto testName = "coverage_to_color_location_" + locName + "_" +
8564                                               (multisample ? "multisample" : "single_sample");
8565                         // Dynamically enable coverage to color in location
8566                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
8567                     }
8568                 }
8569             }
8570 
8571 #ifndef CTS_USES_VULKANSC
8572             // Coverage modulation mode.
8573             {
8574                 const struct
8575                 {
8576                     vk::VkCoverageModulationModeNV staticVal;
8577                     vk::VkCoverageModulationModeNV dynamicVal;
8578                     tcu::Vec4 partialCovFactor; // This will match the expected coverage proportion. See below.
8579                     const char *name;
8580                 } modulationModeCases[] = {
8581                     {vk::VK_COVERAGE_MODULATION_MODE_NONE_NV, vk::VK_COVERAGE_MODULATION_MODE_RGB_NV,
8582                      tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f), "rgb"},
8583                     {vk::VK_COVERAGE_MODULATION_MODE_NONE_NV, vk::VK_COVERAGE_MODULATION_MODE_ALPHA_NV,
8584                      tcu::Vec4(1.0f, 1.0f, 1.0f, 0.25f), "alpha"},
8585                     {vk::VK_COVERAGE_MODULATION_MODE_NONE_NV, vk::VK_COVERAGE_MODULATION_MODE_RGBA_NV,
8586                      tcu::Vec4(0.25f, 0.25f, 0.25f, 0.25f), "rgba"},
8587                     {vk::VK_COVERAGE_MODULATION_MODE_RGBA_NV, vk::VK_COVERAGE_MODULATION_MODE_NONE_NV,
8588                      tcu::Vec4(1.0f, 1.0f, 1.0f, 1.0f), "none"},
8589                 };
8590 
8591                 for (const auto &modulationModeCase : modulationModeCases)
8592                 {
8593                     TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8594 
8595                     config.coverageModulation         = true;
8596                     config.rasterizationSamplesConfig = kMultiSampleCount;
8597                     config.colorSampleCount           = kSingleSampleCount;
8598 
8599                     // With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
8600                     // * Leave the corner pixel uncovered.
8601                     // * Cover the top border with sample 3 (1/4 the samples = 0.25).
8602                     // * Cover the left border with sample 1 (1/4 the samples = 0.25).
8603                     config.offCenterProportion = tcu::Vec2(0.6875f, 0.6875f);
8604                     config.offCenterTriangle   = true;
8605 
8606                     config.coverageModulationModeConfig.staticValue  = modulationModeCase.staticVal;
8607                     config.coverageModulationModeConfig.dynamicValue = modulationModeCase.dynamicVal;
8608 
8609                     const auto &partialCoverageColor = kDefaultTriangleColor * modulationModeCase.partialCovFactor;
8610                     config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, partialCoverageColor,
8611                                                                            kDefaultClearColor, partialCoverageColor));
8612 
8613                     const auto testName = std::string("coverage_modulation_mode_") + modulationModeCase.name;
8614                     // Dynamically set coverage modulation mode
8615                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, config));
8616                 }
8617             }
8618 
8619             // Coverage modulation table enable.
8620             {
8621                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8622 
8623                 config.coverageModulation         = true;
8624                 config.rasterizationSamplesConfig = kMultiSampleCount;
8625                 config.colorSampleCount           = kSingleSampleCount;
8626 
8627                 // With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
8628                 // * Leave the corner pixel uncovered.
8629                 // * Cover the top border with sample 3 (1/4 the samples = 0.25).
8630                 // * Cover the left border with sample 1 (1/4 the samples = 0.25).
8631                 config.offCenterProportion = tcu::Vec2(0.6875f, 0.6875f);
8632                 config.offCenterTriangle   = true;
8633 
8634                 const CovModTableVec table{0.75f, 1.0f, 1.0f, 1.0f};
8635                 config.coverageModulationModeConfig.staticValue = vk::VK_COVERAGE_MODULATION_MODE_RGB_NV;
8636                 config.coverageModTableConfig.staticValue       = table;
8637 
8638                 config.coverageModTableEnableConfig.staticValue  = false;
8639                 config.coverageModTableEnableConfig.dynamicValue = true;
8640 
8641                 const auto tableCoverFactor           = tcu::Vec4(0.75f, 0.75f, 0.75f, 1.0f);
8642                 const auto &tablePartialCoverageColor = kDefaultTriangleColor * tableCoverFactor;
8643 
8644                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, tablePartialCoverageColor,
8645                                                                        kDefaultClearColor, tablePartialCoverageColor));
8646 
8647                 // Dynamically enable coverage modulation table
8648                 orderingGroup->addChild(
8649                     new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_enable", config));
8650 
8651                 // Reverse situation, fall back to the default modulation factor.
8652                 config.coverageModTableEnableConfig.swapValues();
8653                 const auto noTableCoverFactor           = tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f);
8654                 const auto &noTablePartialCoverageColor = kDefaultTriangleColor * noTableCoverFactor;
8655                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor,
8656                                                                        noTablePartialCoverageColor, kDefaultClearColor,
8657                                                                        noTablePartialCoverageColor));
8658 
8659                 // Dynamically disable coverage modulation table
8660                 orderingGroup->addChild(
8661                     new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_disable", config));
8662             }
8663 
8664             // Coverage modulation table.
8665             {
8666                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8667 
8668                 config.coverageModulation         = true;
8669                 config.rasterizationSamplesConfig = kMultiSampleCount;
8670                 config.colorSampleCount           = kSingleSampleCount;
8671 
8672                 // With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
8673                 // * Cover the corner pixel with 1 sample (0.25).
8674                 // * Cover the top border with 2 samples (0.5).
8675                 // * Cover the left border with 2 samples (0.5).
8676                 config.offCenterProportion = tcu::Vec2(0.5f, 0.5f);
8677                 config.offCenterTriangle   = true;
8678 
8679                 config.coverageModulationModeConfig.staticValue = vk::VK_COVERAGE_MODULATION_MODE_RGB_NV;
8680                 config.coverageModTableEnableConfig.staticValue = true;
8681 
8682                 //                                    corner    border    unused        main
8683                 const CovModTableVec goodTable{0.75f, 0.25f, 0.0f, 0.5f};
8684                 const CovModTableVec badTable{0.5f, 0.75f, 1.0f, 0.25f};
8685 
8686                 config.coverageModTableConfig.staticValue  = badTable;
8687                 config.coverageModTableConfig.dynamicValue = goodTable;
8688 
8689                 // VK_COVERAGE_MODULATION_MODE_RGB_NV, factors for RGB according to goodTable, alpha untouched.
8690                 const auto cornerFactor = tcu::Vec4(0.75f, 0.75f, 0.75f, 1.0f);
8691                 const auto borderFactor = tcu::Vec4(0.25f, 0.25f, 0.25f, 1.0f);
8692                 const auto mainFactor   = tcu::Vec4(0.5f, 0.5f, 0.5f, 1.0f);
8693 
8694                 const auto &cornerColor = kDefaultTriangleColor * cornerFactor;
8695                 const auto &borderColor = kDefaultTriangleColor * borderFactor;
8696                 const auto &mainColor   = kDefaultTriangleColor * mainFactor;
8697 
8698                 config.referenceColor.reset(
8699                     new TopLeftBorderGenerator(mainColor, borderColor, cornerColor, borderColor));
8700 
8701                 // Dynamically change coverage modulation table
8702                 orderingGroup->addChild(
8703                     new ExtendedDynamicStateTest(testCtx, "coverage_modulation_table_change", config));
8704             }
8705 
8706             // Coverage reduction mode.
8707             {
8708                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8709 
8710                 config.coverageReduction          = true;
8711                 config.rasterizationSamplesConfig = kMultiSampleCount;
8712                 config.colorSampleCount           = kSingleSampleCount;
8713 
8714                 // With VK_SAMPLE_COUNT_4_BIT and the standard sample locations, this pixel offset will:
8715                 // * Leave the corner pixel uncovered.
8716                 // * Cover the top border with sample 3 (1/4 the samples = 0.25).
8717                 // * Cover the left border with sample 1 (1/4 the samples = 0.25).
8718                 config.offCenterProportion = tcu::Vec2(0.6875f, 0.6875f);
8719                 config.offCenterTriangle   = true;
8720 
8721                 config.coverageReductionModeConfig.staticValue  = vk::VK_COVERAGE_REDUCTION_MODE_MERGE_NV;
8722                 config.coverageReductionModeConfig.dynamicValue = vk::VK_COVERAGE_REDUCTION_MODE_TRUNCATE_NV;
8723 
8724                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor,
8725                                                                        kDefaultClearColor, kDefaultClearColor));
8726                 // Dynamically set coverage reduction truncate mode
8727                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_reduction_truncate", config));
8728 
8729                 // In merge mode, the only pixel without coverage should be the corner. However, the spec is a bit ambiguous in this
8730                 // case:
8731                 //
8732                 //    VK_COVERAGE_REDUCTION_MODE_MERGE_NV specifies that each color sample will be associated with an
8733                 //    implementation-dependent subset of samples in the pixel coverage. If any of those associated samples are covered,
8734                 //    the color sample is covered.
8735                 //
8736                 // We cannot be 100% sure the single color sample will be associated with the whole set of 4 rasterization samples, but
8737                 // the test appears to pass in existing HW.
8738                 config.coverageReductionModeConfig.swapValues();
8739                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultTriangleColor,
8740                                                                        kDefaultClearColor, kDefaultTriangleColor));
8741                 // Dynamically set coverage reduction merge mode
8742                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "coverage_reduction_merge", config));
8743             }
8744 
8745             // Viewport swizzle.
8746             {
8747                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8748 
8749                 config.viewportSwizzle            = true;
8750                 config.oversizedTriangle          = true;
8751                 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
8752 
8753                 const vk::VkViewportSwizzleNV idSwizzle{
8754                     vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV,
8755                     vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV,
8756                     vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV,
8757                     vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV,
8758                 };
8759 
8760                 const vk::VkViewportSwizzleNV
8761                     yxSwizzle // Switches Y and X coordinates, makes the oversized triangle clockwise.
8762                     {
8763                         vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV, // <--
8764                         vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV, // <--
8765                         vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV,
8766                         vk::VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV,
8767                     };
8768 
8769                 config.viewportSwizzleConfig.staticValue  = ViewportSwzVec(1u, idSwizzle);
8770                 config.viewportSwizzleConfig.dynamicValue = ViewportSwzVec(1u, yxSwizzle);
8771                 config.frontFaceConfig.staticValue        = vk::VK_FRONT_FACE_CLOCKWISE;
8772 
8773                 // Dynamically set a viewport swizzle with X and Y switched around
8774                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "viewport_swizzle_yx", config));
8775 
8776                 config.viewportSwizzleConfig.swapValues();
8777                 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
8778                 // Dynamically set the viewport identity swizzle
8779                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "viewport_swizzle_xy", config));
8780             }
8781 
8782             // Shading rate image enable.
8783             // VK_NV_shading_rate_image is disabled when using shader objects due to interaction with VK_KHR_fragment_shading_rate
8784             if (!vk::isConstructionTypeShaderObject(pipelineConstructionType))
8785             {
8786                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8787 
8788                 for (int i = 0; i < 2; ++i)
8789                 {
8790                     const bool sriEnable        = (i > 0);
8791                     const std::string enableStr = (sriEnable ? "enable" : "disable");
8792 
8793                     config.shadingRateImage                          = true;
8794                     config.shadingRateImageEnableConfig.staticValue  = !sriEnable;
8795                     config.shadingRateImageEnableConfig.dynamicValue = sriEnable;
8796                     config.referenceColor.reset(
8797                         new SingleColorGenerator(sriEnable ? kDefaultClearColor : kDefaultTriangleColor));
8798 
8799                     orderingGroup->addChild(
8800                         new ExtendedDynamicStateTest(testCtx, "shading_rate_image_" + enableStr, config));
8801                 }
8802             }
8803 
8804             // Viewport W Scaling enable.
8805             {
8806                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8807 
8808                 for (int i = 0; i < 2; ++i)
8809                 {
8810                     const bool wScalingEnable   = (i > 0);
8811                     const std::string enableStr = (wScalingEnable ? "enable" : "disable");
8812 
8813                     config.colorVerificator                          = verifyTopLeftCornerExactly;
8814                     config.viewportWScaling                          = true;
8815                     config.viewportWScalingEnableConfig.staticValue  = !wScalingEnable;
8816                     config.viewportWScalingEnableConfig.dynamicValue = wScalingEnable;
8817                     config.referenceColor.reset(
8818                         new SingleColorGenerator(wScalingEnable ? kDefaultClearColor : kDefaultTriangleColor));
8819 
8820                     orderingGroup->addChild(
8821                         new ExtendedDynamicStateTest(testCtx, "viewport_w_scaling_" + enableStr, config));
8822                 }
8823             }
8824 
8825             // Representative fragment test state.
8826             {
8827                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8828 
8829                 for (int i = 0; i < 2; ++i)
8830                 {
8831                     const bool reprFragTestEnable = (i > 0);
8832                     const std::string enableStr   = (reprFragTestEnable ? "enable" : "disable");
8833 
8834                     config.depthTestEnableConfig.staticValue = true;
8835                     config.depthCompareOpConfig.staticValue  = vk::VK_COMPARE_OP_LESS;
8836                     config.colorWriteMaskConfig.staticValue  = 0u; // Disable color writes.
8837                     config.oversizedTriangle                 = true;
8838                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
8839 
8840                     config.representativeFragmentTest            = true;
8841                     config.reprFragTestEnableConfig.staticValue  = !reprFragTestEnable;
8842                     config.reprFragTestEnableConfig.dynamicValue = reprFragTestEnable;
8843 
8844                     orderingGroup->addChild(
8845                         new ExtendedDynamicStateTest(testCtx, "repr_frag_test_" + enableStr, config));
8846                 }
8847             }
8848 #endif // CTS_USES_VULKANSC
8849 
8850             // Conservative rasterization mode.
8851             {
8852                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8853                 config.offCenterTriangle = true;
8854 
8855                 // Single-sampling at the pixel center should not cover this, but overestimation should result in coverage.
8856                 config.offCenterProportion                      = tcu::Vec2(0.75f, 0.75f);
8857                 config.extraPrimitiveOverEstConfig.staticValue  = 0.0f;
8858                 config.conservativeRasterModeConfig.staticValue = vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
8859                 config.conservativeRasterModeConfig.dynamicValue =
8860                     vk::VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
8861 
8862                 // Dynamically set conservative rasterization mode to overestimation
8863                 orderingGroup->addChild(
8864                     new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_overestimate", config));
8865 
8866                 config.conservativeRasterModeConfig.swapValues();
8867                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor,
8868                                                                        kDefaultClearColor, kDefaultClearColor));
8869                 // Dynamically set conservative rasterization mode to disabled
8870                 orderingGroup->addChild(
8871                     new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_disabled", config));
8872             }
8873             {
8874                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8875                 config.offCenterTriangle = true;
8876 
8877                 // Single-sampling at the pixel center should cover this, but underestimation should result in lack of coverage.
8878                 config.offCenterProportion                      = tcu::Vec2(0.25f, 0.25f);
8879                 config.extraPrimitiveOverEstConfig.staticValue  = 0.0f;
8880                 config.conservativeRasterModeConfig.staticValue = vk::VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT;
8881                 config.conservativeRasterModeConfig.dynamicValue =
8882                     vk::VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT;
8883                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor,
8884                                                                        kDefaultClearColor, kDefaultClearColor));
8885 
8886                 // Dynamically set conservative rasterization mode to underestimation
8887                 orderingGroup->addChild(
8888                     new ExtendedDynamicStateTest(testCtx, "conservative_rasterization_mode_underestimate", config));
8889             }
8890 
8891             // Extra primitive overestimation size.
8892             // Notes as of 2022-08-12 and gpuinfo.org:
8893             //    * primitiveOverestimationSize is typically 0.0, 0.001953125 or 0.00195313 (i.e. very small).
8894             //    * maxExtraPrimitiveOverestimationSize is typically 0.0 or 0.75 (no other values).
8895             //    * extraPrimitiveOverestimationSizeGranularity is typically 0.0 or 0.25 (no other values).
8896             {
8897                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8898                 config.offCenterTriangle = true;
8899 
8900                 // Move the triangle by more than one pixel, then use an extra overestimation of 0.75 to cover the border pixels too.
8901                 config.offCenterProportion = tcu::Vec2(1.125f, 1.125f);
8902                 config.maxPrimitiveOverestimationSize =
8903                     0.5f; // Otherwise the base overestimation size will be enough. This should never trigger.
8904                 config.conservativeRasterModeConfig.staticValue =
8905                     vk::VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT;
8906                 config.extraPrimitiveOverEstConfig.staticValue = 0.0f;
8907                 config.extraPrimitiveOverEstConfig.dynamicValue =
8908                     0.75f; // Large enough to reach the center of the border pixel.
8909 
8910                 // Dynamically set the extra overestimation size to a large value
8911                 orderingGroup->addChild(
8912                     new ExtendedDynamicStateTest(testCtx, "extra_overestimation_size_large", config));
8913 
8914                 config.extraPrimitiveOverEstConfig.swapValues();
8915                 config.referenceColor.reset(new TopLeftBorderGenerator(kDefaultTriangleColor, kDefaultClearColor,
8916                                                                        kDefaultClearColor, kDefaultClearColor));
8917 
8918                 // Dynamically set the extra overestimation size to zero
8919                 orderingGroup->addChild(
8920                     new ExtendedDynamicStateTest(testCtx, "extra_overestimation_size_none", config));
8921             }
8922 
8923             // Depth bias enable with static or dynamic depth bias parameters.
8924             {
8925                 const DepthBiasParams kAlternativeDepthBiasParams = {2e7f, 0.25f};
8926 
8927                 for (int dynamicBiasIter = 0; dynamicBiasIter < 2; ++dynamicBiasIter)
8928                 {
8929                     const bool useDynamicBias = (dynamicBiasIter > 0);
8930 
8931                     {
8932                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8933 
8934                         // Enable depth test and write 1.0f
8935                         config.depthTestEnableConfig.staticValue  = true;
8936                         config.depthWriteEnableConfig.staticValue = true;
8937                         config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_ALWAYS;
8938                         // Clear depth buffer to 0.25f
8939                         config.clearDepthValue = 0.25f;
8940                         // Write depth to 0.5f
8941                         config.meshParams[0].depth = 0.5f;
8942 
8943                         // Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
8944                         if (useDynamicBias)
8945                         {
8946                             config.depthBiasConfig.staticValue  = kNoDepthBiasParams;
8947                             config.depthBiasConfig.dynamicValue = kAlternativeDepthBiasParams;
8948                         }
8949                         else
8950                         {
8951                             config.depthBiasConfig.staticValue = kAlternativeDepthBiasParams;
8952                         }
8953 
8954                         config.depthBiasEnableConfig.staticValue  = false;
8955                         config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
8956                         config.expectedDepth                      = 0.75f;
8957 
8958                         std::string caseName = "depth_bias_enable";
8959 
8960                         if (useDynamicBias)
8961                         {
8962                             caseName += "_dynamic_bias_params";
8963                         }
8964 
8965                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, config));
8966                     }
8967                     {
8968                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
8969 
8970                         // Enable depth test and write 1.0f
8971                         config.depthTestEnableConfig.staticValue  = true;
8972                         config.depthWriteEnableConfig.staticValue = true;
8973                         config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_ALWAYS;
8974                         // Clear depth buffer to 0.25f
8975                         config.clearDepthValue = 0.25f;
8976                         // Write depth to 0.5f
8977                         config.meshParams[0].depth = 0.5f;
8978 
8979                         // Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
8980                         if (useDynamicBias)
8981                         {
8982                             config.depthBiasConfig.staticValue  = kNoDepthBiasParams;
8983                             config.depthBiasConfig.dynamicValue = kAlternativeDepthBiasParams;
8984                         }
8985                         else
8986                         {
8987                             config.depthBiasConfig.staticValue = kAlternativeDepthBiasParams;
8988                         }
8989 
8990                         config.depthBiasEnableConfig.staticValue  = true;
8991                         config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
8992                         config.expectedDepth                      = 0.5f;
8993 
8994                         std::string caseName = "depth_bias_disable";
8995 
8996                         if (useDynamicBias)
8997                         {
8998                             caseName += "_dynamic_bias_params";
8999                         }
9000 
9001                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, config));
9002                     }
9003                 }
9004             }
9005 
9006 #ifndef CTS_USES_VULKANSC
9007             // Depth bias representation info.
9008             {
9009                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9010 
9011                 // Enable depth test and writes.
9012                 config.depthTestEnableConfig.staticValue  = true;
9013                 config.depthWriteEnableConfig.staticValue = true;
9014                 config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_ALWAYS;
9015                 config.clearDepthValue                    = 0.0f;
9016                 config.meshParams[0].depth                = 0.125f;
9017                 const double targetBias                   = 0.5f;
9018                 config.expectedDepth                      = 0.625f; // mesh depth + target bias
9019 
9020                 vk::VkDepthBiasRepresentationInfoEXT depthBiasReprInfo = vk::initVulkanStructure();
9021                 depthBiasReprInfo.depthBiasRepresentation =
9022                     vk::VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT;
9023                 depthBiasReprInfo.depthBiasExact = VK_TRUE;
9024                 config.depthBiasReprInfo         = depthBiasReprInfo;
9025                 config.neededDepthChannelClass   = tcu::TEXTURECHANNELCLASS_FLOATING_POINT;
9026 
9027                 // We will choose a format with floating point representation, but force a UNORM exact depth bias representation.
9028                 // With this, the value of R should be 2^(-N), with N being the number of mantissa bits plus one (2^(-24) for D32_SFLOAT).
9029                 // To reach our target bias, the constant factor must be calculated based on it and the value of R.
9030                 //
9031                 // If the VkDepthBiasRepresentationInfoEXT is not taken into account, the value of R would be 2^(E-N), such that:
9032                 // E is the maximum exponent in the range of Z values that the primitive uses (-3 for our mesh depth of 0.125).
9033                 // N is the number of mantissa bits in the floating point format (23 in our case)
9034                 // R would be wrongly calculated as 2^(-26) (1/4th of the intended value).
9035                 const double minR           = 1.0 / static_cast<double>(1u << 24u);
9036                 const double constantFactor = targetBias / minR;
9037 
9038                 const DepthBiasParams kPositiveBias{static_cast<float>(constantFactor), 0.0f};
9039                 config.depthBiasEnableConfig.staticValue = true;
9040                 config.depthBiasConfig.staticValue       = kNoDepthBiasParams;
9041                 config.depthBiasConfig.dynamicValue      = kPositiveBias;
9042                 config.extraDepthThreshold               = static_cast<float>(minR);
9043 
9044                 const char *caseName = "depth_bias_repr_info";
9045                 // Dynamically set the depth bias representation information
9046                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, config));
9047             }
9048             {
9049                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9050 
9051                 // Enable depth test and writes.
9052                 config.depthTestEnableConfig.staticValue  = true;
9053                 config.depthWriteEnableConfig.staticValue = true;
9054                 config.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_ALWAYS;
9055                 config.clearDepthValue                    = 0.25f; // Clear depth buffer to 0.25.
9056                 config.meshParams[0].depth                = 0.5f;  // Set mesh depth to 0.5 as a base.
9057 
9058                 // Enable dynamic depth bias to add a 0.25 bias to the mesh depth (using float representation), expecting the final
9059                 // depth to be 0.75.
9060                 vk::VkDepthBiasRepresentationInfoEXT depthBiasReprInfo = vk::initVulkanStructure();
9061                 depthBiasReprInfo.depthBiasRepresentation              = vk::VK_DEPTH_BIAS_REPRESENTATION_FLOAT_EXT;
9062                 depthBiasReprInfo.depthBiasExact                       = VK_FALSE;
9063                 config.depthBiasReprInfo                               = depthBiasReprInfo;
9064 
9065                 const DepthBiasParams kPositiveBias{0.25f, 0.0f};
9066                 config.depthBiasEnableConfig.staticValue = true;
9067                 config.depthBiasConfig.staticValue       = kNoDepthBiasParams;
9068                 config.depthBiasConfig.dynamicValue      = kPositiveBias;
9069                 config.expectedDepth                     = 0.75f;
9070 
9071                 const char *caseName = "depth_bias_repr_info_float";
9072                 // Dynamically set the depth bias representation information to float representation
9073                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, config));
9074             }
9075 #endif // CTS_USES_VULKANSC
9076 
9077             // Depth compare op.
9078             {
9079                 TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
9080                 const tcu::Vec4 kAlternativeColor(0.0f, 0.0f, 0.5f, 1.0f);
9081                 baseConfig.depthTestEnableConfig.staticValue  = true;
9082                 baseConfig.depthWriteEnableConfig.staticValue = true;
9083                 baseConfig.depthCompareOpConfig.staticValue   = vk::VK_COMPARE_OP_NEVER;
9084                 baseConfig.clearDepthValue                    = 0.5f;
9085 
9086                 {
9087                     TestConfig config                        = baseConfig;
9088                     config.depthCompareOpConfig.staticValue  = vk::VK_COMPARE_OP_ALWAYS;
9089                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NEVER;
9090                     config.meshParams[0].depth               = 0.25f;
9091                     config.expectedDepth                     = 0.5f;
9092                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
9093                     // Dynamically set the depth compare operator to NEVER
9094                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", config));
9095                 }
9096                 {
9097                     TestConfig config                        = baseConfig;
9098                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS;
9099                     config.meshParams[0].depth               = 0.25f;
9100                     config.expectedDepth                     = 0.25f;
9101                     // Dynamically set the depth compare operator to LESS
9102                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", config));
9103                 }
9104                 {
9105                     TestConfig config                        = baseConfig;
9106                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER;
9107                     config.meshParams[0].depth               = 0.75f;
9108                     config.expectedDepth                     = 0.75f;
9109                     // Dynamically set the depth compare operator to GREATER
9110                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", config));
9111                 }
9112                 {
9113                     TestConfig config                        = baseConfig;
9114                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_EQUAL;
9115                     config.meshParams[0].depth               = 0.5f;
9116                     config.meshParams[0].color               = kAlternativeColor;
9117                     // Draw another mesh in front to verify it does not pass the equality test.
9118                     config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
9119                     config.expectedDepth = 0.5f;
9120                     config.referenceColor.reset(new SingleColorGenerator(kAlternativeColor));
9121                     // Dynamically set the depth compare operator to EQUAL
9122                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", config));
9123                 }
9124                 {
9125                     TestConfig config                        = baseConfig;
9126                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
9127                     config.meshParams[0].depth               = 0.25f;
9128                     config.expectedDepth                     = 0.25f;
9129                     // Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with smaller depth
9130                     orderingGroup->addChild(
9131                         new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less", config));
9132                 }
9133                 {
9134                     TestConfig config                        = baseConfig;
9135                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
9136                     config.meshParams[0].depth               = 0.5f;
9137                     config.expectedDepth                     = 0.5f;
9138                     // Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with equal depth
9139                     orderingGroup->addChild(
9140                         new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_equal", config));
9141                 }
9142                 {
9143                     TestConfig config                        = baseConfig;
9144                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
9145                     config.meshParams[0].depth               = 0.25f;
9146                     // Draw another mesh with the same depth in front of it.
9147                     config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
9148                     config.expectedDepth = 0.25f;
9149                     config.referenceColor.reset(new SingleColorGenerator(kAlternativeColor));
9150                     // Dynamically set the depth compare operator to LESS_OR_EQUAL and draw two meshes with less and equal depth
9151                     orderingGroup->addChild(
9152                         new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less_then_equal", config));
9153                 }
9154                 {
9155                     TestConfig config                        = baseConfig;
9156                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
9157                     config.meshParams[0].depth               = 0.75f;
9158                     config.expectedDepth                     = 0.75f;
9159                     // Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with greater depth
9160                     orderingGroup->addChild(
9161                         new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_greater", config));
9162                 }
9163                 {
9164                     TestConfig config                        = baseConfig;
9165                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
9166                     config.meshParams[0].depth               = 0.5f;
9167                     config.expectedDepth                     = 0.5f;
9168                     // Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with equal depth
9169                     orderingGroup->addChild(
9170                         new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_equal", config));
9171                 }
9172                 {
9173                     TestConfig config                        = baseConfig;
9174                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
9175                     config.meshParams[0].depth               = 0.75f;
9176                     // Draw another mesh with the same depth in front of it.
9177                     config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
9178                     config.expectedDepth = 0.75f;
9179                     config.referenceColor.reset(new SingleColorGenerator(kAlternativeColor));
9180                     // Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw two meshes with greater and equal depth
9181                     orderingGroup->addChild(new ExtendedDynamicStateTest(
9182                         testCtx, "depth_compare_greater_equal_greater_then_equal", config));
9183                 }
9184                 {
9185                     TestConfig config                        = baseConfig;
9186                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NOT_EQUAL;
9187 
9188                     // Draw first mesh in front.
9189                     config.meshParams[0].depth = 0.25f;
9190                     // Draw another mesh in the back, this should pass too.
9191                     config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
9192                     // Finally a new mesh with the same depth. This should not pass.
9193                     config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
9194 
9195                     config.referenceColor.reset(new SingleColorGenerator(kAlternativeColor));
9196                     config.expectedDepth = 0.5f;
9197                     // Dynamically set the depth compare operator to NOT_EQUAL
9198                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", config));
9199                 }
9200                 {
9201                     TestConfig config                        = baseConfig;
9202                     config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_ALWAYS;
9203 
9204                     config.meshParams[0].depth = 0.5f;
9205                     config.expectedDepth       = 0.5f;
9206                     // Dynamically set the depth compare operator to ALWAYS and draw with equal depth
9207                     orderingGroup->addChild(
9208                         new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", config));
9209 
9210                     config.meshParams[0].depth = 0.25f;
9211                     config.expectedDepth       = 0.25f;
9212                     // Dynamically set the depth compare operator to ALWAYS and draw with less depth
9213                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", config));
9214 
9215                     config.meshParams[0].depth = 0.75f;
9216                     config.expectedDepth       = 0.75f;
9217                     // Dynamically set the depth compare operator to ALWAYS and draw with greater depth
9218                     orderingGroup->addChild(
9219                         new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", config));
9220                 }
9221             }
9222 
9223             // Depth bounds test.
9224             {
9225                 TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
9226                 baseConfig.depthBoundsConfig.staticValue = std::make_pair(0.25f, 0.75f);
9227                 baseConfig.meshParams[0].depth           = 0.0f;
9228 
9229                 {
9230                     TestConfig config                               = baseConfig;
9231                     config.depthBoundsTestEnableConfig.staticValue  = false;
9232                     config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(true);
9233                     config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
9234                     // Dynamically enable the depth bounds test
9235                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", config));
9236                 }
9237                 {
9238                     TestConfig config                               = baseConfig;
9239                     config.depthBoundsTestEnableConfig.staticValue  = true;
9240                     config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(false);
9241                     // Dynamically disable the depth bounds test
9242                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", config));
9243                 }
9244             }
9245 
9246             // Stencil test enable.
9247             {
9248                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9249                 config.stencilTestEnableConfig.staticValue           = false;
9250                 config.stencilTestEnableConfig.dynamicValue          = tcu::just(true);
9251                 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
9252                 config.referenceColor.reset(new SingleColorGenerator(kDefaultClearColor));
9253                 // Dynamically enable the stencil test
9254                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", config));
9255             }
9256             {
9257                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9258                 config.stencilTestEnableConfig.staticValue           = true;
9259                 config.stencilTestEnableConfig.dynamicValue          = tcu::just(false);
9260                 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
9261                 // Dynamically disable the stencil test
9262                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", config));
9263             }
9264 
9265             // Stencil operation. Many combinations are possible.
9266             {
9267                 static const struct
9268                 {
9269                     vk::VkStencilFaceFlags face;
9270                     std::string name;
9271                 } kFaces[] = {
9272                     {vk::VK_STENCIL_FACE_FRONT_BIT, "face_front"},
9273                     {vk::VK_STENCIL_FACE_FRONT_AND_BACK, "face_both_single"},
9274                     {vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM, "face_both_dual"}, // MAX_ENUM is a placeholder.
9275                 };
9276 
9277                 static const struct
9278                 {
9279                     vk::VkCompareOp compareOp;
9280                     std::string name;
9281                 } kCompare[] = {
9282                     {vk::VK_COMPARE_OP_LESS, "lt"},
9283                     {vk::VK_COMPARE_OP_GREATER, "gt"},
9284                 };
9285 
9286                 using u8vec = std::vector<uint8_t>;
9287 
9288                 static const auto kMinVal  = std::numeric_limits<uint8_t>::min();
9289                 static const auto kMaxVal  = std::numeric_limits<uint8_t>::max();
9290                 static const auto kMinValI = static_cast<int>(kMinVal);
9291                 static const auto kMaxValI = static_cast<int>(kMaxVal);
9292 
9293                 static const struct
9294                 {
9295                     vk::VkStencilOp stencilOp;
9296                     std::string name;
9297                     u8vec clearValues; // One test per clear value interesting for this operation.
9298                     vk::VkStencilOp
9299                         incompatibleOp; // Alternative operation giving incompatible results for the given values.
9300                 } kStencilOps[] = {
9301                     {vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP, "inc_clamp", u8vec{kMaxVal - 1, kMaxVal},
9302                      vk::VK_STENCIL_OP_ZERO},
9303                     {vk::VK_STENCIL_OP_DECREMENT_AND_WRAP, "dec_wrap", u8vec{kMinVal + 1, kMinVal},
9304                      vk::VK_STENCIL_OP_KEEP},
9305                 };
9306 
9307                 for (const auto &face : kFaces)
9308                     for (const auto &compare : kCompare)
9309                         for (const auto &op : kStencilOps)
9310                         {
9311                             // Try clearing the stencil value with different values.
9312                             for (const auto clearVal : op.clearValues)
9313                             {
9314                                 // Use interesting values as the reference stencil value.
9315                                 for (const auto delta : {-1, 1})
9316                                 {
9317                                     const int refVal = clearVal + delta;
9318                                     if (refVal < kMinValI || refVal > kMaxValI)
9319                                         continue;
9320 
9321                                     const auto refValU8  = static_cast<uint8_t>(refVal);
9322                                     const auto refValU32 = static_cast<uint32_t>(refVal);
9323 
9324                                     // Calculate outcome of the stencil test itself.
9325                                     const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
9326 
9327                                     // If the test passes, use an additional variant for the depthFail operation.
9328                                     const int subCases = (wouldPass ? 2 : 1);
9329 
9330                                     for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
9331                                     {
9332                                         for (int extraPipelineIter = 0; extraPipelineIter < 2; ++extraPipelineIter)
9333                                         {
9334                                             const bool useExtraPipeline =
9335                                                 (extraPipelineIter >
9336                                                  0); // Bind and draw with another pipeline using the same dynamic states.
9337 
9338                                             if (useExtraPipeline && (kOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
9339                                                                      kOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
9340                                                 continue;
9341 
9342                                             if (useExtraPipeline && kUseMeshShaders)
9343                                                 continue;
9344 
9345                                             const bool depthFail =
9346                                                 (subCaseIdx > 0); // depthFail would be the second variant.
9347                                             const bool globalPass =
9348                                                 (wouldPass && !depthFail); // Global result of the stencil+depth test.
9349 
9350                                             // Start tuning test parameters.
9351                                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9352 
9353                                             // No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
9354                                             if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
9355                                             {
9356                                                 // Default parameters are OK.
9357                                             }
9358                                             else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
9359                                             {
9360                                                 // Reverse the mesh so it applies the back operation.
9361                                                 config.meshParams[0].reversed = true;
9362                                             }
9363                                             else // Front and back.
9364                                             {
9365                                                 // Draw both a front and a back-facing mesh so both are applied.
9366                                                 // The first mesh will be drawn in the top half and the second mesh in the bottom half.
9367 
9368                                                 // Make the second mesh a reversed copy of the first mesh.
9369                                                 config.meshParams.push_back(config.meshParams.front());
9370                                                 config.meshParams.back().reversed = true;
9371 
9372                                                 // Apply scale and offset to the top mesh.
9373                                                 config.meshParams.front().scaleY  = 0.5f;
9374                                                 config.meshParams.front().offsetY = -0.5f;
9375 
9376                                                 // Apply scale and offset to the bottom mesh.
9377                                                 config.meshParams.back().scaleY  = 0.5f;
9378                                                 config.meshParams.back().offsetY = 0.5f;
9379                                             }
9380 
9381                                             // Enable the stencil test.
9382                                             config.stencilTestEnableConfig.staticValue = true;
9383 
9384                                             // Set dynamic configuration.
9385                                             StencilOpParams dynamicStencilConfig;
9386                                             dynamicStencilConfig.faceMask    = face.face;
9387                                             dynamicStencilConfig.compareOp   = compare.compareOp;
9388                                             dynamicStencilConfig.failOp      = vk::VK_STENCIL_OP_MAX_ENUM;
9389                                             dynamicStencilConfig.passOp      = vk::VK_STENCIL_OP_MAX_ENUM;
9390                                             dynamicStencilConfig.depthFailOp = vk::VK_STENCIL_OP_MAX_ENUM;
9391 
9392                                             // Set operations so only the appropriate operation for this case gives the right result.
9393                                             vk::VkStencilOp *activeOp       = nullptr;
9394                                             vk::VkStencilOp *inactiveOps[2] = {nullptr, nullptr};
9395                                             if (wouldPass)
9396                                             {
9397                                                 if (depthFail)
9398                                                 {
9399                                                     activeOp       = &dynamicStencilConfig.depthFailOp;
9400                                                     inactiveOps[0] = &dynamicStencilConfig.passOp;
9401                                                     inactiveOps[1] = &dynamicStencilConfig.failOp;
9402                                                 }
9403                                                 else
9404                                                 {
9405                                                     activeOp       = &dynamicStencilConfig.passOp;
9406                                                     inactiveOps[0] = &dynamicStencilConfig.depthFailOp;
9407                                                     inactiveOps[1] = &dynamicStencilConfig.failOp;
9408                                                 }
9409                                             }
9410                                             else
9411                                             {
9412                                                 activeOp       = &dynamicStencilConfig.failOp;
9413                                                 inactiveOps[0] = &dynamicStencilConfig.passOp;
9414                                                 inactiveOps[1] = &dynamicStencilConfig.depthFailOp;
9415                                             }
9416 
9417                                             *activeOp       = op.stencilOp;
9418                                             *inactiveOps[0] = op.incompatibleOp;
9419                                             *inactiveOps[1] = op.incompatibleOp;
9420 
9421                                             // Make sure all ops have been configured properly.
9422                                             DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
9423                                             DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
9424                                             DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
9425 
9426                                             // Set an incompatible static operation too.
9427                                             auto &staticStencilConfig    = config.stencilOpConfig.staticValue.front();
9428                                             staticStencilConfig.faceMask = face.face;
9429                                             staticStencilConfig.compareOp =
9430                                                 (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
9431                                             staticStencilConfig.passOp      = op.incompatibleOp;
9432                                             staticStencilConfig.failOp      = op.incompatibleOp;
9433                                             staticStencilConfig.depthFailOp = op.incompatibleOp;
9434 
9435                                             // Set dynamic configuration.
9436                                             StencilOpVec stencilOps;
9437                                             stencilOps.push_back(dynamicStencilConfig);
9438 
9439                                             if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
9440                                             {
9441                                                 // This is the dual case. We will set the front and back face values with two separate calls.
9442                                                 stencilOps.push_back(stencilOps.front());
9443                                                 stencilOps.front().faceMask  = vk::VK_STENCIL_FACE_FRONT_BIT;
9444                                                 stencilOps.back().faceMask   = vk::VK_STENCIL_FACE_BACK_BIT;
9445                                                 staticStencilConfig.faceMask = vk::VK_STENCIL_FACE_FRONT_AND_BACK;
9446                                             }
9447 
9448                                             config.stencilOpConfig.dynamicValue = tcu::just(stencilOps);
9449                                             config.clearStencilValue            = clearVal;
9450                                             config.referenceStencil             = refValU32;
9451 
9452                                             if (depthFail)
9453                                             {
9454                                                 // Enable depth test and make it fail.
9455                                                 config.depthTestEnableConfig.staticValue = true;
9456                                                 config.clearDepthValue                   = 0.5f;
9457                                                 config.depthCompareOpConfig.staticValue  = vk::VK_COMPARE_OP_LESS;
9458 
9459                                                 for (auto &meshPar : config.meshParams)
9460                                                     meshPar.depth = 0.75f;
9461                                             }
9462 
9463                                             // Set expected outcome.
9464                                             config.referenceColor.reset(new SingleColorGenerator(
9465                                                 globalPass ? kDefaultTriangleColor : kDefaultClearColor));
9466                                             config.expectedDepth =
9467                                                 config.clearDepthValue; // No depth writing by default.
9468                                             config.expectedStencil =
9469                                                 stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
9470 
9471                                             config.useExtraDynPipeline = useExtraPipeline;
9472 
9473                                             const std::string testName =
9474                                                 std::string("stencil_state") +
9475                                                 ((useExtraPipeline) ? "_extra_pipeline" : "") + "_" + face.name + "_" +
9476                                                 compare.name + "_" + op.name + "_clear_" +
9477                                                 de::toString(static_cast<int>(clearVal)) + "_ref_" +
9478                                                 de::toString(refVal) + "_" +
9479                                                 (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
9480 
9481                                             // Dynamically configure stencil test
9482                                             orderingGroup->addChild(
9483                                                 new ExtendedDynamicStateTest(testCtx, testName, config));
9484                                         }
9485                                     }
9486                                 }
9487                             }
9488                         }
9489             }
9490 
9491             // Vertex input.
9492             if (!kUseMeshShaders)
9493             {
9494                 for (const auto &bindUnusedCase : kBindUnusedCases)
9495                 {
9496                     if (bindUnusedCase.bindUnusedMeshShadingPipeline && kOrdering != SequenceOrdering::CMD_BUFFER_START)
9497                         continue;
9498 
9499                     // TWO_DRAWS_STATIC would be invalid because it violates VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the
9500                     // dynamic stride being less than the extent of the binding for the second attribute.
9501                     if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
9502                     {
9503                         {
9504                             const auto staticGen   = getVertexWithPaddingGenerator();
9505                             const auto dynamicGen  = getVertexWithExtraAttributesGenerator();
9506                             const auto goodStrides = dynamicGen->getVertexDataStrides();
9507                             StrideVec badStrides;
9508 
9509                             badStrides.reserve(goodStrides.size());
9510                             for (const auto &stride : goodStrides)
9511                                 badStrides.push_back(stride / 2u);
9512 
9513                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, staticGen,
9514                                               dynamicGen);
9515                             config.strideConfig.staticValue      = badStrides;
9516                             config.strideConfig.dynamicValue     = goodStrides;
9517                             config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
9518                             orderingGroup->addChild(new ExtendedDynamicStateTest(
9519                                 testCtx, "vertex_input" + bindUnusedCase.nameSuffix, config));
9520                         }
9521                         {
9522                             const auto staticGen   = getVertexWithInstanceDataGenerator();
9523                             const auto goodStrides = staticGen->getVertexDataStrides();
9524                             StrideVec badStrides;
9525 
9526                             DE_ASSERT(goodStrides.size() == 2u);
9527                             badStrides.reserve(2u);
9528                             badStrides.push_back(goodStrides.at(0u));
9529                             badStrides.push_back(goodStrides.at(1u) / 2u); // Halve instance rate stride.
9530 
9531                             TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders, staticGen);
9532                             config.strideConfig.staticValue      = badStrides;
9533                             config.strideConfig.dynamicValue     = goodStrides;
9534                             config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
9535                             config.instanceCount                 = 2u;
9536                             // Dynamically set instance rate stride
9537                             orderingGroup->addChild(new ExtendedDynamicStateTest(
9538                                 testCtx, "instance_rate_stride" + bindUnusedCase.nameSuffix, config));
9539                         }
9540                     }
9541 
9542                     {
9543                         // Variant without mixing in the stride config.
9544                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders,
9545                                           getVertexWithPaddingGenerator(), getVertexWithExtraAttributesGenerator());
9546                         config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
9547                         // Dynamically set vertex input without using dynamic strides
9548                         orderingGroup->addChild(new ExtendedDynamicStateTest(
9549                             testCtx, "vertex_input_no_dyn_stride" + bindUnusedCase.nameSuffix, config));
9550                     }
9551 
9552                     {
9553                         // Variant using multiple bindings.
9554                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders,
9555                                           getVertexWithExtraAttributesGenerator(),
9556                                           getVertexWithMultipleBindingsGenerator());
9557                         config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
9558                         // Dynamically set vertex input with multiple bindings
9559                         orderingGroup->addChild(new ExtendedDynamicStateTest(
9560                             testCtx, "vertex_input_multiple_bindings" + bindUnusedCase.nameSuffix, config));
9561                     }
9562 
9563                     {
9564                         // Variant checking dynamic vertex inputs with 16-bit floats.
9565                         TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders,
9566                                           getVertexWithPaddingGenerator(), getVertexWithPadding16Generator());
9567                         config.bindUnusedMeshShadingPipeline = bindUnusedCase.bindUnusedMeshShadingPipeline;
9568                         // Dynamically set vertex input with float16 inputs
9569                         orderingGroup->addChild(new ExtendedDynamicStateTest(
9570                             testCtx, "vertex_input_float16" + bindUnusedCase.nameSuffix, config));
9571                     }
9572                 }
9573             }
9574 
9575             // Null state pointers. These do not make sense for shader objects.
9576             if (!vk::isConstructionTypeShaderObject(pipelineConstructionType))
9577             {
9578                 TestConfig baseConfig(pipelineConstructionType, kOrdering, kUseMeshShaders);
9579                 baseConfig.favorStaticNullPointers = true;
9580 
9581                 if (!kUseMeshShaders)
9582                 {
9583                     TestConfig config(pipelineConstructionType, kOrdering, false, getVertexWithPaddingGenerator(),
9584                                       getVertexWithExtraAttributesGenerator());
9585                     config.favorStaticNullPointers = true;
9586                     // Use null pVertexInputState
9587                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_vertex_input_state", config));
9588                 }
9589 
9590                 if (!kUseMeshShaders)
9591                 {
9592                     TestConfig config(baseConfig);
9593                     config.topologyConfig.staticValue           = vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
9594                     config.topologyConfig.dynamicValue          = vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
9595                     config.extraLineRestarts                    = true;
9596                     config.primRestartEnableConfig.staticValue  = false;
9597                     config.primRestartEnableConfig.dynamicValue = tcu::just(true);
9598                     config.referenceColor.reset(new CenterStripGenerator(kDefaultTriangleColor, kDefaultClearColor));
9599                     // Use null pVertexInputState
9600                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_input_assembly_state", config));
9601                 }
9602 
9603                 if (!kUseMeshShaders)
9604                 {
9605                     TestConfig config(baseConfig);
9606                     config.topologyConfig.staticValue            = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
9607                     config.patchControlPointsConfig.staticValue  = 1;
9608                     config.patchControlPointsConfig.dynamicValue = 3;
9609                     // Use null pTessellationState
9610                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_tessellation_state", config));
9611                 }
9612 
9613                 {
9614                     TestConfig config(baseConfig);
9615 
9616                     config.viewportConfig.staticValue = ViewportVec{
9617                         vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
9618                         vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),        // Left.
9619                     };
9620 
9621                     config.scissorConfig.staticValue = ScissorVec{
9622                         vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
9623                         vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
9624                     };
9625 
9626                     config.scissorConfig.dynamicValue =
9627                         ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
9628                     config.viewportConfig.dynamicValue = ViewportVec{config.viewportConfig.staticValue.back(),
9629                                                                      config.viewportConfig.staticValue.front()};
9630 
9631                     // Use null pViewportState
9632                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_viewport_state", config));
9633                 }
9634 
9635                 {
9636                     TestConfig config(baseConfig);
9637                     config.depthClampEnableConfig.staticValue   = true;
9638                     config.depthClampEnableConfig.dynamicValue  = false;
9639                     config.rastDiscardEnableConfig.staticValue  = true;
9640                     config.rastDiscardEnableConfig.dynamicValue = false;
9641                     config.polygonModeConfig.staticValue        = vk::VK_POLYGON_MODE_POINT;
9642                     config.polygonModeConfig.dynamicValue       = vk::VK_POLYGON_MODE_FILL;
9643                     config.cullModeConfig.staticValue           = vk::VK_CULL_MODE_FRONT_AND_BACK;
9644                     config.cullModeConfig.dynamicValue          = vk::VK_CULL_MODE_NONE;
9645                     config.frontFaceConfig.staticValue          = vk::VK_FRONT_FACE_CLOCKWISE;
9646                     config.frontFaceConfig.dynamicValue         = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
9647                     config.depthBiasEnableConfig.staticValue    = true;
9648                     config.depthBiasEnableConfig.dynamicValue   = false;
9649                     config.depthBiasConfig.staticValue          = DepthBiasParams{1.0f, 1.0f};
9650                     config.depthBiasConfig.dynamicValue         = kNoDepthBiasParams;
9651                     config.lineWidthConfig.staticValue          = 0.0f;
9652                     config.lineWidthConfig.dynamicValue         = 1.0f;
9653                     // Use null pRasterizationState
9654                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_rasterization_state", config));
9655                 }
9656 
9657                 {
9658                     TestConfig config(baseConfig);
9659                     config.rasterizationSamplesConfig.staticValue  = kMultiSampleCount;
9660                     config.rasterizationSamplesConfig.dynamicValue = kSingleSampleCount;
9661                     config.sampleMaskConfig.staticValue            = SampleMaskVec(1u, 0u);
9662                     config.sampleMaskConfig.dynamicValue           = SampleMaskVec(1u, 0xFFu);
9663                     config.alphaToCoverageConfig.staticValue       = true;
9664                     config.alphaToCoverageConfig.dynamicValue      = false;
9665                     config.alphaToOneConfig.staticValue            = true;
9666                     config.alphaToOneConfig.dynamicValue           = false;
9667                     // Use null pMultisampleState
9668                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_multisample_state", config));
9669                 }
9670 
9671                 {
9672                     TestConfig config(baseConfig);
9673                     config.rasterizationSamplesConfig.staticValue  = kMultiSampleCount;
9674                     config.rasterizationSamplesConfig.dynamicValue = kSingleSampleCount;
9675                     config.sampleMaskConfig.staticValue            = SampleMaskVec(1u, 0u);
9676                     config.sampleMaskConfig.dynamicValue           = SampleMaskVec(1u, 0xFFu);
9677                     config.alphaToCoverageConfig.staticValue       = true;
9678                     config.alphaToCoverageConfig.dynamicValue      = false;
9679                     config.disableAlphaToOneFeature                = true;
9680                     // Use null pMultisampleState
9681                     orderingGroup->addChild(
9682                         new ExtendedDynamicStateTest(testCtx, "null_multisample_state_no_alpha_to_one", config));
9683                 }
9684 
9685                 {
9686                     TestConfig config(baseConfig);
9687                     config.depthTestEnableConfig.staticValue        = true;
9688                     config.depthTestEnableConfig.dynamicValue       = false;
9689                     config.depthWriteEnableConfig.staticValue       = true;
9690                     config.depthWriteEnableConfig.dynamicValue      = false;
9691                     config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_NEVER;
9692                     config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_ALWAYS;
9693                     config.depthBoundsTestEnableConfig.staticValue  = true;
9694                     config.depthBoundsTestEnableConfig.dynamicValue = false;
9695                     config.stencilTestEnableConfig.staticValue      = true;
9696                     config.stencilTestEnableConfig.dynamicValue     = false;
9697                     config.stencilOpConfig.staticValue =
9698                         StencilOpVec(1u, StencilOpParams{vk::VK_STENCIL_FACE_FRONT_AND_BACK, vk::VK_STENCIL_OP_INVERT,
9699                                                          vk::VK_STENCIL_OP_INVERT, vk::VK_STENCIL_OP_INVERT,
9700                                                          vk::VK_COMPARE_OP_NEVER});
9701                     config.stencilOpConfig.dynamicValue = StencilOpVec(
9702                         1u, StencilOpParams{vk::VK_STENCIL_FACE_FRONT_AND_BACK, vk::VK_STENCIL_OP_KEEP,
9703                                             vk::VK_STENCIL_OP_KEEP, vk::VK_STENCIL_OP_KEEP, vk::VK_COMPARE_OP_ALWAYS});
9704                     config.depthBoundsConfig.staticValue  = std::make_pair(1.0f, 1.0f);
9705                     config.depthBoundsConfig.dynamicValue = std::make_pair(0.0f, 0.0f);
9706                     // Use null pDepthStencilState
9707                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_depth_stencil_state", config));
9708                 }
9709 
9710                 {
9711                     TestConfig config(baseConfig);
9712                     config.forceUnormColorFormat                = true;
9713                     config.logicOpEnableConfig.staticValue      = true;
9714                     config.logicOpEnableConfig.dynamicValue     = false;
9715                     config.logicOpConfig.staticValue            = vk::VK_LOGIC_OP_CLEAR;
9716                     config.logicOpConfig.dynamicValue           = vk::VK_LOGIC_OP_COPY;
9717                     config.colorBlendEnableConfig.staticValue   = true;
9718                     config.colorBlendEnableConfig.dynamicValue  = false;
9719                     config.colorBlendEquationConfig.staticValue = ColorBlendEq();
9720                     config.colorBlendEquationConfig.dynamicValue =
9721                         ColorBlendEq(vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD,
9722                                      vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_FACTOR_ONE, vk::VK_BLEND_OP_ADD);
9723                     config.colorWriteMaskConfig.staticValue  = 0u;
9724                     config.colorWriteMaskConfig.dynamicValue = (CR | CG | CB | CA);
9725                     config.blendConstantsConfig.staticValue  = BlendConstArray{1.0f, 1.0f, 1.0f, 1.0f};
9726                     config.blendConstantsConfig.dynamicValue = BlendConstArray{0.0f, 0.0f, 0.0f, 0.0f};
9727                     // Use null pColorBlendState
9728                     orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "null_color_blend_state", config));
9729                 }
9730             }
9731 
9732             {
9733                 TestConfig config(pipelineConstructionType, kOrdering, kUseMeshShaders);
9734                 config.sampleShadingEnable                     = true;
9735                 config.minSampleShading                        = 1.0f;
9736                 config.forceAtomicCounters                     = true;
9737                 config.oversizedTriangle                       = true;
9738                 config.rasterizationSamplesConfig.staticValue  = kSingleSampleCount;
9739                 config.rasterizationSamplesConfig.dynamicValue = kMultiSampleCount;
9740                 // Test number of frag shader invocations with sample shading enabled and dynamic sample counts
9741                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "sample_shading_sample_count", config));
9742             }
9743 
9744             tcu::TestCaseGroup *group = (kUseMeshShaders ? meshShaderGroup.get() : extendedDynamicStateGroup.get());
9745             group->addChild(orderingGroup.release());
9746         }
9747 
9748     extendedDynamicStateGroup->addChild(meshShaderGroup.release());
9749     extendedDynamicStateGroup->addChild(createExtendedDynamicStateMiscTests(testCtx, pipelineConstructionType));
9750     return extendedDynamicStateGroup.release();
9751 }
9752 
9753 } // namespace pipeline
9754 } // namespace vkt
9755