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