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