90131f68c48875dd91fc57e9757923cdf5842ae5
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / pipeline / vktPipelineExtendedDynamicStateTests.cpp
1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *      http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*
21  * \file
22  * \brief Extended dynamic state tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktPipelineExtendedDynamicStateTests.hpp"
26 #include "vktPipelineImageUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkCmdUtil.hpp"
37
38 #include "tcuVector.hpp"
39 #include "tcuMaybe.hpp"
40 #include "tcuTestLog.hpp"
41 #include "tcuVectorUtil.hpp"
42
43 #include "deUniquePtr.hpp"
44 #include "deStringUtil.hpp"
45
46 #include <vector>
47 #include <sstream>
48 #include <algorithm>
49 #include <iterator>
50 #include <string>
51 #include <limits>
52
53 namespace vkt
54 {
55 namespace pipeline
56 {
57
58 namespace
59 {
60
61 inline vk::VkBool32 makeVkBool32(bool value)
62 {
63         return (value ? VK_TRUE : VK_FALSE);
64 }
65
66 // Framebuffer size.
67 constexpr deUint32      kFramebufferWidth       = 64u;
68 constexpr deUint32      kFramebufferHeight      = 64u;
69
70 // Image formats.
71 constexpr       vk::VkFormat    kColorFormat            = vk::VK_FORMAT_R8G8B8A8_UNORM;
72 constexpr       vk::VkFormat    kDepthStencilFormat     = vk::VK_FORMAT_D32_SFLOAT_S8_UINT;
73 const           tcu::Vec4               kColorThreshold         (0.005f); // 1/255 < 0.005 < 2/255.
74
75 // Vertices in buffers will have 2 components and a padding to properly test the stride.
76 struct GeometryVertex
77 {
78         tcu::Vec2 coords;
79         tcu::Vec2 padding;
80
81         GeometryVertex (const tcu::Vec2& coords_)
82                 : coords        (coords_)
83                 , padding       (0.0f)
84         {
85         }
86 };
87
88 constexpr auto kVertexStride    = static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex));
89 constexpr auto kCoordsSize              = static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex::coords));
90
91 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
92 struct StencilOpParams
93 {
94         vk::VkStencilFaceFlags  faceMask;
95         vk::VkStencilOp         failOp;
96         vk::VkStencilOp         passOp;
97         vk::VkStencilOp         depthFailOp;
98         vk::VkCompareOp         compareOp;
99 };
100
101 const StencilOpParams kDefaultStencilOpParams =
102 {
103         vk::VK_STENCIL_FACE_FRONT_AND_BACK,
104         vk::VK_STENCIL_OP_KEEP,
105         vk::VK_STENCIL_OP_KEEP,
106         vk::VK_STENCIL_OP_KEEP,
107         vk::VK_COMPARE_OP_ALWAYS
108 };
109
110 using ViewportVec       = std::vector<vk::VkViewport>;
111 using ScissorVec        = std::vector<vk::VkRect2D>;
112 using StencilOpVec      = std::vector<StencilOpParams>;
113
114 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
115 template<typename T>
116 struct StaticAndDynamicPair
117 {
118         T                               staticValue;
119         tcu::Maybe<T>   dynamicValue;
120
121         // Helper constructor to set a static value and no dynamic value.
122         StaticAndDynamicPair (const T& value)
123                 : staticValue   (value)
124                 , dynamicValue  (tcu::nothing<T>())
125         {
126         }
127
128         // Helper constructor to set both.
129         StaticAndDynamicPair (const T& sVal, const T& dVal)
130                 : staticValue   (sVal)
131                 , dynamicValue  (tcu::just<T>(dVal))
132         {
133         }
134 };
135
136 // For anything boolean, see below.
137 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
138
139 // Configuration for every aspect of the extended dynamic state.
140 using CullModeConfig                            = StaticAndDynamicPair<vk::VkCullModeFlags>;
141 using FrontFaceConfig                           = StaticAndDynamicPair<vk::VkFrontFace>;
142 using TopologyConfig                            = StaticAndDynamicPair<vk::VkPrimitiveTopology>;
143 using ViewportConfig                            = StaticAndDynamicPair<ViewportVec>;    // At least one element.
144 using ScissorConfig                                     = StaticAndDynamicPair<ScissorVec>;             // At least one element.
145 using StrideConfig                                      = StaticAndDynamicPair<vk::VkDeviceSize>;
146 using DepthTestEnableConfig                     = BooleanFlagConfig;
147 using DepthWriteEnableConfig            = BooleanFlagConfig;
148 using DepthCompareOpConfig                      = StaticAndDynamicPair<vk::VkCompareOp>;
149 using DepthBoundsTestEnableConfig       = BooleanFlagConfig;
150 using StencilTestEnableConfig           = BooleanFlagConfig;
151 using StencilOpConfig                           = StaticAndDynamicPair<StencilOpVec>;   // At least one element.
152
153 const tcu::Vec4 kDefaultTriangleColor   (0.0f, 0.0f, 1.0f, 1.0f);       // Opaque blue.
154 const tcu::Vec4 kDefaultClearColor              (0.0f, 0.0f, 0.0f, 1.0f);       // Opaque black.
155
156 struct MeshParams
157 {
158         tcu::Vec4       color;
159         float           depth;
160         bool            reversed;
161         float           scaleX;
162         float           scaleY;
163         float           offsetX;
164         float           offsetY;
165
166         MeshParams (const tcu::Vec4&    color_          = kDefaultTriangleColor,
167                                 float                           depth_          = 0.0f,
168                                 bool                            reversed_       = false,
169                                 float                           scaleX_         = 1.0f,
170                                 float                           scaleY_         = 1.0f,
171                                 float                           offsetX_        = 0.0f,
172                                 float                           offsetY_        = 0.0f)
173                 : color         (color_)
174                 , depth         (depth_)
175                 , reversed      (reversed_)
176                 , scaleX        (scaleX_)
177                 , scaleY        (scaleY_)
178                 , offsetX       (offsetX_)
179                 , offsetY       (offsetY_)
180         {}
181 };
182
183 enum class SequenceOrdering
184 {
185         CMD_BUFFER_START        = 0,    // Set state at the start of the command buffer.
186         BEFORE_DRAW                     = 1,    // After binding dynamic pipeline and just before drawing.
187         BETWEEN_PIPELINES       = 2,    // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
188         AFTER_PIPELINES         = 3,    // After a static state pipeline and a second dynamic state pipeline have been bound.
189 };
190
191 struct TestConfig
192 {
193         // Main sequence ordering.
194         SequenceOrdering                        sequenceOrdering;
195
196         // Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
197         std::vector<MeshParams>         meshParams;                     // Mesh parameters for each full-screen layer of geometry.
198         deUint32                                        referenceStencil;       // Reference stencil value.
199
200         // Clearing parameters for the framebuffer.
201         tcu::Vec4                                       clearColorValue;
202         float                                           clearDepthValue;
203         deUint32                                        clearStencilValue;
204
205         // Expected output in the attachments.
206         tcu::Vec4                                       expectedColor;
207         float                                           expectedDepth;
208         deUint32                                        expectedStencil;
209
210         // Depth bounds parameters for the pipeline.
211         float                                           minDepthBounds;
212         float                                           maxDepthBounds;
213
214         // Include passthrough geometry shader or not.
215         bool                                            useGeometryShader;
216
217         // Static and dynamic pipeline configuration.
218         CullModeConfig                          cullModeConfig;
219         FrontFaceConfig                         frontFaceConfig;
220         TopologyConfig                          topologyConfig;
221         ViewportConfig                          viewportConfig;
222         ScissorConfig                           scissorConfig;
223         StrideConfig                            strideConfig;
224         DepthTestEnableConfig           depthTestEnableConfig;
225         DepthWriteEnableConfig          depthWriteEnableConfig;
226         DepthCompareOpConfig            depthCompareOpConfig;
227         DepthBoundsTestEnableConfig     depthBoundsTestEnableConfig;
228         StencilTestEnableConfig         stencilTestEnableConfig;
229         StencilOpConfig                         stencilOpConfig;
230
231         // Sane defaults.
232         TestConfig (SequenceOrdering ordering)
233                 : sequenceOrdering                              (ordering)
234                 , meshParams                                    (1u, MeshParams())
235                 , referenceStencil                              (0u)
236                 , clearColorValue                               (kDefaultClearColor)
237                 , clearDepthValue                               (1.0f)
238                 , clearStencilValue                             (0u)
239                 , expectedColor                                 (kDefaultTriangleColor)
240                 , expectedDepth                                 (1.0f)
241                 , expectedStencil                               (0u)
242                 , minDepthBounds                                (0.0f)
243                 , maxDepthBounds                                (1.0f)
244                 , useGeometryShader                             (false)
245                 , cullModeConfig                                (static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
246                 , frontFaceConfig                               (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
247                 // By default we will use a triangle fan with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
248                 , topologyConfig                                (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
249                 , viewportConfig                                (ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
250                 , scissorConfig                                 (ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
251                 , strideConfig                                  (kVertexStride)
252                 , depthTestEnableConfig                 (false)
253                 , depthWriteEnableConfig                (false)
254                 , depthCompareOpConfig                  (vk::VK_COMPARE_OP_NEVER)
255                 , depthBoundsTestEnableConfig   (false)
256                 , stencilTestEnableConfig               (false)
257                 , stencilOpConfig                               (StencilOpVec(1u, kDefaultStencilOpParams))
258         {
259         }
260 };
261
262 struct PushConstants
263 {
264         tcu::Vec4       triangleColor;
265         float           meshDepth;
266         deInt32         viewPortIndex;
267         float           scaleX;
268         float           scaleY;
269         float           offsetX;
270         float           offsetY;
271 };
272
273 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
274 {
275         dst.failOp              = src.failOp;
276         dst.passOp              = src.passOp;
277         dst.depthFailOp = src.depthFailOp;
278         dst.compareOp   = src.compareOp;
279 }
280
281 enum class TopologyClass
282 {
283         POINT,
284         LINE,
285         TRIANGLE,
286         PATCH,
287         INVALID,
288 };
289
290 std::string topologyClassName (TopologyClass tclass)
291 {
292         switch (tclass)
293         {
294         case TopologyClass::POINT:              return "point";
295         case TopologyClass::LINE:               return "line";
296         case TopologyClass::TRIANGLE:   return "triangle";
297         case TopologyClass::PATCH:              return "patch";
298         default:
299                 break;
300         }
301
302         DE_ASSERT(false);
303         return "";
304 }
305
306 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
307 {
308         switch (topology)
309         {
310         case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
311                 return TopologyClass::POINT;
312         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
313         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
314         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
315         case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
316                 return TopologyClass::LINE;
317         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
318         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
319         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
320         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
321         case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
322                 return TopologyClass::TRIANGLE;
323         case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
324                 return TopologyClass::PATCH;
325         default:
326                 break;
327         }
328
329         DE_ASSERT(false);
330         return TopologyClass::INVALID;
331 }
332
333 class ExtendedDynamicStateTest : public vkt::TestCase
334 {
335 public:
336                                                         ExtendedDynamicStateTest                (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
337         virtual                                 ~ExtendedDynamicStateTest               (void) {}
338
339         virtual void                    checkSupport                                    (Context& context) const;
340         virtual void                    initPrograms                                    (vk::SourceCollections& programCollection) const;
341         virtual TestInstance*   createInstance                                  (Context& context) const;
342
343 private:
344         TestConfig                              m_testConfig;
345 };
346
347 class ExtendedDynamicStateInstance : public vkt::TestInstance
348 {
349 public:
350                                                                 ExtendedDynamicStateInstance    (Context& context, const TestConfig& testConfig);
351         virtual                                         ~ExtendedDynamicStateInstance   (void) {}
352
353         virtual tcu::TestStatus         iterate                                                 (void);
354
355 private:
356         TestConfig                                      m_testConfig;
357 };
358
359 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
360         : vkt::TestCase (testCtx, name, description)
361         , m_testConfig  (testConfig)
362 {
363         const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
364         DE_UNREF(staticTopologyClass); // For release builds.
365
366         // Matching topology classes.
367         DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
368                           staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
369
370         // Supported topology classes for these tests.
371         DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE);
372 }
373
374 void ExtendedDynamicStateTest::checkSupport (Context& context) const
375 {
376         const auto&     vki                             = context.getInstanceInterface();
377         const auto      physicalDevice  = context.getPhysicalDevice();
378
379         // This is always required.
380         context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
381
382         // Check the number of viewports needed and the corresponding limits.
383         const auto&     viewportConfig  = m_testConfig.viewportConfig;
384         auto            numViews                = viewportConfig.staticValue.size();
385
386         if (viewportConfig.dynamicValue)
387                 numViews = std::max(numViews, viewportConfig.dynamicValue.get().size());
388
389         if (numViews > 1)
390         {
391                 context.requireDeviceFunctionality("VK_KHR_multiview");
392                 const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
393                 if (numViews > static_cast<decltype(numViews)>(properties.limits.maxViewports))
394                         TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViews) + ")");
395         }
396
397         const auto&     dbTestEnable    = m_testConfig.depthBoundsTestEnableConfig;
398         const bool      useDepthBounds  = (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
399         if (useDepthBounds || m_testConfig.useGeometryShader)
400         {
401                 const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
402
403                 // Check depth bounds test support.
404                 if (useDepthBounds && !features.depthBounds)
405                         TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
406
407                 // Check geometry shader support.
408                 if (m_testConfig.useGeometryShader && !features.geometryShader)
409                         TCU_THROW(NotSupportedError, "Geometry shader not supported");
410         }
411
412         // Check image format support.
413         const vk::VkFormatFeatureFlags kColorFeatures   = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
414         const vk::VkFormatFeatureFlags kDSFeatures              = (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
415
416         const auto colorProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kColorFormat);
417         if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
418                 TCU_THROW(NotSupportedError, "Required color image features not supported");
419
420         const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormat);
421         if ((dsProperties.optimalTilingFeatures & kDSFeatures) != kDSFeatures)
422                 TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
423 }
424
425 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
426 {
427         std::ostringstream pushSource;
428         std::ostringstream vertSource;
429         std::ostringstream fragSource;
430         std::ostringstream geomSource;
431
432         pushSource
433                 << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
434                 << "    vec4  triangleColor;\n"
435                 << "    float depthValue;\n"
436                 << "    int   viewPortIndex;\n"
437                 << "    float scaleX;\n"
438                 << "    float scaleY;\n"
439                 << "    float offsetX;\n"
440                 << "    float offsetY;\n"
441                 << "} pushConstants;\n"
442                 ;
443         const auto pushConstants = pushSource.str();
444
445         vertSource
446                 << "#version 450\n"
447                 << "#extension GL_ARB_shader_viewport_layer_array : require\n"
448                 << pushConstants
449                 << "layout(location=0) in vec2 position;\n"
450                 << "out gl_PerVertex\n"
451                 << "{\n"
452                 << "    vec4 gl_Position;\n"
453                 << "};\n"
454                 << "void main() {\n"
455                 << "    gl_Position = vec4(position.x * pushConstants.scaleX + pushConstants.offsetX, position.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
456                 << "    gl_ViewportIndex = pushConstants.viewPortIndex;\n"
457                 << "}\n"
458                 ;
459
460         fragSource
461                 << "#version 450\n"
462                 << pushConstants
463                 << "layout(location=0) out vec4 color;\n"
464                 << "void main() {\n"
465                 << "    color = pushConstants.triangleColor;\n"
466                 << "}\n"
467                 ;
468
469         if (m_testConfig.useGeometryShader)
470         {
471                 const auto                      topologyClass   = getTopologyClass(m_testConfig.topologyConfig.staticValue);
472                 const std::string       inputPrimitive  = ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
473                 const deUint32          vertexCount             = ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
474                 const std::string       outputPrimitive = ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
475
476                 geomSource
477                         << "#version 450\n"
478                         << "layout (" << inputPrimitive << ") in;\n"
479                         << "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
480                         << "in gl_PerVertex\n"
481                         << "{\n"
482                         << "    vec4 gl_Position;\n"
483                         << "} gl_in[" << vertexCount << "];\n"
484                         << "out gl_PerVertex\n"
485                         << "{\n"
486                         << "    vec4 gl_Position;\n"
487                         << "};\n"
488                         << "void main() {\n"
489                         ;
490
491                 for (deUint32 i = 0; i < vertexCount; ++i)
492                 {
493                         geomSource
494                                 << "    gl_Position = gl_in[" << i << "].gl_Position;\n"
495                                 << "    EmitVertex();\n"
496                                 ;
497                 }
498
499                 geomSource
500                         << "}\n"
501                         ;
502         }
503
504         programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
505         programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
506         if (m_testConfig.useGeometryShader)
507                 programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
508 }
509
510 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
511 {
512         return new ExtendedDynamicStateInstance(context, m_testConfig);
513 }
514
515 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
516         : vkt::TestInstance     (context)
517         , m_testConfig          (testConfig)
518 {
519 }
520
521 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
522 {
523         log << tcu::TestLog::ImageSet(setName, setDesc)
524                 << tcu::TestLog::Image(setName + "Result", "Result image", result)
525                 << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
526                 << tcu::TestLog::EndImageSet;
527 }
528
529 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, const void* src, size_t size)
530 {
531         auto& alloc     = buffer.getAllocation();
532         void* dst       = alloc.getHostPtr();
533
534         deMemcpy(dst, src, size);
535         vk::flushAlloc(vkd, device, alloc);
536 }
537
538 // Sets values for dynamic states if needed according to the test configuration.
539 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
540 {
541         if (testConfig.cullModeConfig.dynamicValue)
542                 vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
543
544         if (testConfig.frontFaceConfig.dynamicValue)
545                 vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
546
547         if (testConfig.topologyConfig.dynamicValue)
548                 vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
549
550         if (testConfig.viewportConfig.dynamicValue)
551         {
552                 const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
553                 vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
554         }
555
556         if (testConfig.scissorConfig.dynamicValue)
557         {
558                 const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
559                 vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
560         }
561
562         if (testConfig.depthTestEnableConfig.dynamicValue)
563                 vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
564
565         if (testConfig.depthWriteEnableConfig.dynamicValue)
566                 vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
567
568         if (testConfig.depthCompareOpConfig.dynamicValue)
569                 vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
570
571         if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
572                 vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
573
574         if (testConfig.stencilTestEnableConfig.dynamicValue)
575                 vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
576
577         if (testConfig.stencilOpConfig.dynamicValue)
578         {
579                 for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
580                         vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
581         }
582 }
583
584 // Get the proper viewport vector according to the test config.
585 const ViewportVec& getActiveViewportVec(const TestConfig& testConfig)
586 {
587         return (testConfig.viewportConfig.dynamicValue ? testConfig.viewportConfig.dynamicValue.get() : testConfig.viewportConfig.staticValue);
588 }
589
590 // Bind the appropriate vertex buffer with a dynamic stride if the test configuration needs a dynamic stride.
591 // Return true if the vertex buffer was bound.
592 bool maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, vk::VkBuffer vertBuffer, vk::VkBuffer rvertBuffer, vk::VkDeviceSize vertBufferSize, vk::VkDeviceSize vertBufferOffset)
593 {
594         if (testConfig.strideConfig.dynamicValue)
595         {
596                 const auto& viewportVec = getActiveViewportVec(testConfig);
597                 DE_UNREF(viewportVec); // For release builds.
598
599                 // When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
600                 // orderings when we have several viewports or meshes.
601                 DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
602                                         || testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
603                                         || testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
604
605                 vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, 1u, (testConfig.meshParams[meshIdx].reversed ? &rvertBuffer : &vertBuffer), &vertBufferOffset, &vertBufferSize, &testConfig.strideConfig.dynamicValue.get());
606                 return true;
607         }
608
609         return false;
610 }
611
612 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
613 {
614         const auto&     vkd                                     = m_context.getDeviceInterface();
615         const auto      device                          = m_context.getDevice();
616         auto&           allocator                       = m_context.getDefaultAllocator();
617         const auto      queue                           = m_context.getUniversalQueue();
618         const auto      queueIndex                      = m_context.getUniversalQueueFamilyIndex();
619
620         const auto                                      kFramebufferExtent      = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
621         const vk::VkImageUsageFlags kColorUsage                 = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
622         const vk::VkImageUsageFlags kDSUsage                    = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
623
624         // Create color and depth/stencil images.
625         const vk::VkImageCreateInfo colorImageInfo =
626         {
627                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,        //      VkStructureType                 sType;
628                 nullptr,                                                                        //      const void*                             pNext;
629                 0u,                                                                                     //      VkImageCreateFlags              flags;
630                 vk::VK_IMAGE_TYPE_2D,                                           //      VkImageType                             imageType;
631                 kColorFormat,                                                           //      VkFormat                                format;
632                 kFramebufferExtent,                                                     //      VkExtent3D                              extent;
633                 1u,                                                                                     //      deUint32                                mipLevels;
634                 1u,                                                                                     //      deUint32                                arrayLayers;
635                 vk::VK_SAMPLE_COUNT_1_BIT,                                      //      VkSampleCountFlagBits   samples;
636                 vk::VK_IMAGE_TILING_OPTIMAL,                            //      VkImageTiling                   tiling;
637                 kColorUsage,                                                            //      VkImageUsageFlags               usage;
638                 vk::VK_SHARING_MODE_EXCLUSIVE,                          //      VkSharingMode                   sharingMode;
639                 1u,                                                                                     //      deUint32                                queueFamilyIndexCount;
640                 &queueIndex,                                                            //      const deUint32*                 pQueueFamilyIndices;
641                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                          //      VkImageLayout                   initialLayout;
642         };
643         vk::ImageWithMemory colorImage(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any);
644
645         const vk::VkImageCreateInfo dsImageInfo =
646         {
647                 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,        //      VkStructureType                 sType;
648                 nullptr,                                                                        //      const void*                             pNext;
649                 0u,                                                                                     //      VkImageCreateFlags              flags;
650                 vk::VK_IMAGE_TYPE_2D,                                           //      VkImageType                             imageType;
651                 kDepthStencilFormat,                                            //      VkFormat                                format;
652                 kFramebufferExtent,                                                     //      VkExtent3D                              extent;
653                 1u,                                                                                     //      deUint32                                mipLevels;
654                 1u,                                                                                     //      deUint32                                arrayLayers;
655                 vk::VK_SAMPLE_COUNT_1_BIT,                                      //      VkSampleCountFlagBits   samples;
656                 vk::VK_IMAGE_TILING_OPTIMAL,                            //      VkImageTiling                   tiling;
657                 kDSUsage,                                                                       //      VkImageUsageFlags               usage;
658                 vk::VK_SHARING_MODE_EXCLUSIVE,                          //      VkSharingMode                   sharingMode;
659                 1u,                                                                                     //      deUint32                                queueFamilyIndexCount;
660                 &queueIndex,                                                            //      const deUint32*                 pQueueFamilyIndices;
661                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                          //      VkImageLayout                   initialLayout;
662         };
663         vk::ImageWithMemory dsImage(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any);
664
665         const auto colorSubresourceRange        = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
666         const auto colorImageView                       = vk::makeImageView(vkd, device, colorImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kColorFormat, colorSubresourceRange);
667         const auto dsSubresourceRange           = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
668         const auto dsImageView                          = vk::makeImageView(vkd, device, dsImage.get(), vk::VK_IMAGE_VIEW_TYPE_2D, kDepthStencilFormat, dsSubresourceRange);
669
670         // Vertex buffer.
671         const auto                                      topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
672         std::vector<GeometryVertex>     vertices;
673
674         if (topologyClass == TopologyClass::TRIANGLE)
675         {
676                 // Full-scren triangle fan with 6 vertices.
677                 //
678                 // 4        3        2
679                 //  +-------+-------+
680                 //  |X      X      X|
681                 //  | X     X     X |
682                 //  |  X    X    X  |
683                 //  |   X   X   X   |
684                 //  |    X  X  X    |
685                 //  |     X X X     |
686                 //  |      XXX      |
687                 //  +-------+-------+
688                 // 5        0        1
689                 vertices.push_back(GeometryVertex(tcu::Vec2( 0.0f,  1.0f)));
690                 vertices.push_back(GeometryVertex(tcu::Vec2( 1.0f,  1.0f)));
691                 vertices.push_back(GeometryVertex(tcu::Vec2( 1.0f, -1.0f)));
692                 vertices.push_back(GeometryVertex(tcu::Vec2( 0.0f, -1.0f)));
693                 vertices.push_back(GeometryVertex(tcu::Vec2(-1.0f, -1.0f)));
694                 vertices.push_back(GeometryVertex(tcu::Vec2(-1.0f,  1.0f)));
695         }
696         else // TopologyClass::LINE
697         {
698                 // 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.
699                 const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
700                 for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
701                 {
702                         // Offset of 0.5 pixels + one line per row from -1 to 1.
703                         const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
704                         vertices.push_back(GeometryVertex(tcu::Vec2(-1.0f, yCoord)));
705                         vertices.push_back(GeometryVertex(tcu::Vec2(-0.5f, yCoord)));
706                         vertices.push_back(GeometryVertex(tcu::Vec2( 0.5f, yCoord)));
707                         vertices.push_back(GeometryVertex(tcu::Vec2( 1.0f, yCoord)));
708                 }
709         }
710
711         // Reversed vertices, except for the first one (0, 5, 4, 3, 2, 1): clockwise mesh for triangles. Not to be used with lines.
712         std::vector<GeometryVertex> reversedVertices(1u, vertices[0]);
713         std::copy_n(vertices.rbegin(), vertices.size() - 1u, std::back_inserter(reversedVertices));
714
715         if (topologyClass == TopologyClass::LINE)
716         {
717                 for (const auto& mesh : m_testConfig.meshParams)
718                 {
719                         DE_UNREF(mesh); // For release builds.
720                         DE_ASSERT(!mesh.reversed);
721                 }
722         }
723
724         const auto vertBufferSize = static_cast<vk::VkDeviceSize>(vertices.size() * sizeof(decltype(vertices)::value_type));
725         const auto vertBufferInfo = vk::makeBufferCreateInfo(vertBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
726         vk::BufferWithMemory vertBuffer         (vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
727         vk::BufferWithMemory rvertBuffer        (vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
728
729         // Copy data to vertex buffers and flush allocations.
730         copyAndFlush(vkd, device, vertBuffer, vertices.data(), static_cast<size_t>(vertBufferSize));
731         copyAndFlush(vkd, device, rvertBuffer, reversedVertices.data(), static_cast<size_t>(vertBufferSize));
732         const vk::VkDeviceSize vertBufferOffset = 0ull;
733
734         // Descriptor set layout.
735         vk::DescriptorSetLayoutBuilder layoutBuilder;
736         const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
737
738         // Pipeline layout.
739         const vk::VkShaderStageFlags    pushConstantStageFlags  = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
740         const vk::VkPushConstantRange   pushConstantRange               =
741         {
742                 pushConstantStageFlags,                                                 //      VkShaderStageFlags      stageFlags;
743                 0u,                                                                                             //      deUint32                        offset;
744                 static_cast<deUint32>(sizeof(PushConstants)),   //      deUint32                        size;
745         };
746
747         const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
748         {
749                 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,      //      VkStructureType                                 sType;
750                 nullptr,                                                                                        //      const void*                                             pNext;
751                 0u,                                                                                                     //      VkPipelineLayoutCreateFlags             flags;
752                 1u,                                                                                                     //      deUint32                                                setLayoutCount;
753                 &descriptorSetLayout.get(),                                                     //      const VkDescriptorSetLayout*    pSetLayouts;
754                 1u,                                                                                                     //      deUint32                                                pushConstantRangeCount;
755                 &pushConstantRange,                                                                     //      const VkPushConstantRange*              pPushConstantRanges;
756         };
757         const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
758
759         // Render pass with single subpass.
760         const vk::VkAttachmentReference colorAttachmentReference =
761         {
762                 0u,                                                                                             //      deUint32                attachment;
763                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   //      VkImageLayout   layout;
764         };
765
766         const vk::VkAttachmentReference dsAttachmentReference =
767         {
768                 1u,                                                                                                             //      deUint32                attachment;
769                 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,   //      VkImageLayout   layout;
770         };
771
772         const vk::VkSubpassDescription subpassDescription =
773         {
774                 0u,                                                                             //      VkSubpassDescriptionFlags               flags;
775                 vk::VK_PIPELINE_BIND_POINT_GRAPHICS,    //      VkPipelineBindPoint                             pipelineBindPoint;
776                 0u,                                                                             //      deUint32                                                inputAttachmentCount;
777                 nullptr,                                                                //      const VkAttachmentReference*    pInputAttachments;
778                 1u,                                                                             //      deUint32                                                colorAttachmentCount;
779                 &colorAttachmentReference,                              //      const VkAttachmentReference*    pColorAttachments;
780                 nullptr,                                                                //      const VkAttachmentReference*    pResolveAttachments;
781                 &dsAttachmentReference,                                 //      const VkAttachmentReference*    pDepthStencilAttachment;
782                 0u,                                                                             //      deUint32                                                preserveAttachmentCount;
783                 nullptr,                                                                //      const deUint32*                                 pPreserveAttachments;
784         };
785
786         std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
787
788         attachmentDescriptions.push_back(vk::VkAttachmentDescription
789         {
790                 0u,                                                                                             //      VkAttachmentDescriptionFlags    flags;
791                 kColorFormat,                                                                   //      VkFormat                                                format;
792                 vk::VK_SAMPLE_COUNT_1_BIT,                                              //      VkSampleCountFlagBits                   samples;
793                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                //      VkAttachmentLoadOp                              loadOp;
794                 vk::VK_ATTACHMENT_STORE_OP_STORE,                               //      VkAttachmentStoreOp                             storeOp;
795                 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE,                    //      VkAttachmentLoadOp                              stencilLoadOp;
796                 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE,                   //      VkAttachmentStoreOp                             stencilStoreOp;
797                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                                  //      VkImageLayout                                   initialLayout;
798                 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   //      VkImageLayout                                   finalLayout;
799         });
800
801         attachmentDescriptions.push_back(vk::VkAttachmentDescription
802         {
803                 0u,                                                                                                             //      VkAttachmentDescriptionFlags    flags;
804                 kDepthStencilFormat,                                                                    //      VkFormat                                                format;
805                 vk::VK_SAMPLE_COUNT_1_BIT,                                                              //      VkSampleCountFlagBits                   samples;
806                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                //      VkAttachmentLoadOp                              loadOp;
807                 vk::VK_ATTACHMENT_STORE_OP_STORE,                                               //      VkAttachmentStoreOp                             storeOp;
808                 vk::VK_ATTACHMENT_LOAD_OP_CLEAR,                                                //      VkAttachmentLoadOp                              stencilLoadOp;
809                 vk::VK_ATTACHMENT_STORE_OP_STORE,                                               //      VkAttachmentStoreOp                             stencilStoreOp;
810                 vk::VK_IMAGE_LAYOUT_UNDEFINED,                                                  //      VkImageLayout                                   initialLayout;
811                 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,   //      VkImageLayout                                   finalLayout;
812         });
813
814         const vk::VkRenderPassCreateInfo renderPassCreateInfo =
815         {
816                 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,                  //      VkStructureType                                 sType;
817                 nullptr,                                                                                                //      const void*                                             pNext;
818                 0u,                                                                                                             //      VkRenderPassCreateFlags                 flags;
819                 static_cast<deUint32>(attachmentDescriptions.size()),   //      deUint32                                                attachmentCount;
820                 attachmentDescriptions.data(),                                                  //      const VkAttachmentDescription*  pAttachments;
821                 1u,                                                                                                             //      deUint32                                                subpassCount;
822                 &subpassDescription,                                                                    //      const VkSubpassDescription*             pSubpasses;
823                 0u,                                                                                                             //      deUint32                                                dependencyCount;
824                 nullptr,                                                                                                //      const VkSubpassDependency*              pDependencies;
825         };
826         const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
827
828         // Framebuffer.
829         std::vector<vk::VkImageView> attachments;
830         attachments.push_back(colorImageView.get());
831         attachments.push_back(dsImageView.get());
832
833         const vk::VkFramebufferCreateInfo framebufferCreateInfo =
834         {
835                 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,  //      VkStructureType                         sType;
836                 nullptr,                                                                                //      const void*                                     pNext;
837                 0u,                                                                                             //      VkFramebufferCreateFlags        flags;
838                 renderPass.get(),                                                               //      VkRenderPass                            renderPass;
839                 static_cast<deUint32>(attachments.size()),              //      deUint32                                        attachmentCount;
840                 attachments.data(),                                                             //      const VkImageView*                      pAttachments;
841                 kFramebufferWidth,                                                              //      deUint32                                        width;
842                 kFramebufferHeight,                                                             //      deUint32                                        height;
843                 1u,                                                                                             //      deUint32                                        layers;
844         };
845         const auto framebuffer = vk::createFramebuffer(vkd, device, &framebufferCreateInfo);
846
847         // Shader modules.
848         const auto                                              vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
849         const auto                                              fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
850         vk::Move<vk::VkShaderModule>    geomModule;
851
852         if (m_testConfig.useGeometryShader)
853                 geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
854
855         // Shader stages.
856         std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
857
858         vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
859         {
860                 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,        //      VkStructureType                                         sType;
861                 nullptr,                                                                                                        //      const void*                                                     pNext;
862                 0u,                                                                                                                     //      VkPipelineShaderStageCreateFlags        flags;
863                 vk::VK_SHADER_STAGE_VERTEX_BIT,                                                         //      VkShaderStageFlagBits                           stage;
864                 vertModule.get(),                                                                                       //      VkShaderModule                                          module;
865                 "main",                                                                                                         //      const char*                                                     pName;
866                 nullptr,                                                                                                        //      const VkSpecializationInfo*                     pSpecializationInfo;
867         };
868
869         shaderStages.push_back(shaderStageCreateInfo);
870         shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
871         shaderStageCreateInfo.module = fragModule.get();
872         shaderStages.push_back(shaderStageCreateInfo);
873
874         if (m_testConfig.useGeometryShader)
875         {
876                 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
877                 shaderStageCreateInfo.module = geomModule.get();
878                 shaderStages.push_back(shaderStageCreateInfo);
879         }
880
881         // Input state.
882         const auto vertexBinding        = vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(m_testConfig.strideConfig.staticValue), vk::VK_VERTEX_INPUT_RATE_VERTEX);
883         const auto vertexAttribute      = vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u);
884
885         const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
886         {
887                 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,  //      VkStructureType                                                         sType;
888                 nullptr,                                                                                                                //      const void*                                                                     pNext;
889                 0u,                                                                                                                             //      VkPipelineVertexInputStateCreateFlags           flags;
890                 1u,                                                                                                                             //      deUint32                                                                        vertexBindingDescriptionCount;
891                 &vertexBinding,                                                                                                 //      const VkVertexInputBindingDescription*          pVertexBindingDescriptions;
892                 1u,                                                                                                                             //      deUint32                                                                        vertexAttributeDescriptionCount;
893                 &vertexAttribute,                                                                                               //      const VkVertexInputAttributeDescription*        pVertexAttributeDescriptions;
894         };
895
896         // Input assembly.
897         const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
898         {
899                 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,        //      VkStructureType                                                 sType;
900                 nullptr,                                                                                                                        //      const void*                                                             pNext;
901                 0u,                                                                                                                                     //      VkPipelineInputAssemblyStateCreateFlags flags;
902                 m_testConfig.topologyConfig.staticValue,                                                        //      VkPrimitiveTopology                                             topology;
903                 VK_FALSE,                                                                                                                       //      VkBool32                                                                primitiveRestartEnable;
904         };
905
906         // Viewport state.
907         if (m_testConfig.viewportConfig.dynamicValue)
908                 DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
909         else
910                 DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
911
912         if (m_testConfig.scissorConfig.dynamicValue)
913                 DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
914         else
915                 DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
916
917         const vk::VkPipelineViewportStateCreateInfo viewportStateCreateInfo =
918         {
919                 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,                              //      VkStructureType                                         sType;
920                 nullptr,                                                                                                                                //      const void*                                                     pNext;
921                 0u,                                                                                                                                             //      VkPipelineViewportStateCreateFlags      flags;
922                 static_cast<deUint32>(m_testConfig.viewportConfig.staticValue.size()),  //      deUint32                                                        viewportCount;
923                 m_testConfig.viewportConfig.staticValue.data(),                                                 //      const VkViewport*                                       pViewports;
924                 static_cast<deUint32>(m_testConfig.scissorConfig.staticValue.size()),   //      deUint32                                                        scissorCount;
925                 m_testConfig.scissorConfig.staticValue.data(),                                                  //      const VkRect2D*                                         pScissors;
926         };
927
928         // Rasterization state.
929         const vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
930         {
931                 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, //      VkStructureType                                                 sType;
932                 nullptr,                                                                                                                //      const void*                                                             pNext;
933                 0u,                                                                                                                             //      VkPipelineRasterizationStateCreateFlags flags;
934                 VK_FALSE,                                                                                                               //      VkBool32                                                                depthClampEnable;
935                 VK_FALSE,                                                                                                               //      VkBool32                                                                rasterizerDiscardEnable;
936                 vk::VK_POLYGON_MODE_FILL,                                                                               //      VkPolygonMode                                                   polygonMode;
937                 m_testConfig.cullModeConfig.staticValue,                                                //      VkCullModeFlags                                                 cullMode;
938                 m_testConfig.frontFaceConfig.staticValue,                                               //      VkFrontFace                                                             frontFace;
939                 VK_FALSE,                                                                                                               //      VkBool32                                                                depthBiasEnable;
940                 0.0f,                                                                                                                   //      float                                                                   depthBiasConstantFactor;
941                 0.0f,                                                                                                                   //      float                                                                   depthBiasClamp;
942                 0.0f,                                                                                                                   //      float                                                                   depthBiasSlopeFactor;
943                 1.0f,                                                                                                                   //      float                                                                   lineWidth;
944         };
945
946         // Multisample state.
947         const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
948         {
949                 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,   //      VkStructureType                                                 sType;
950                 nullptr,                                                                                                                //      const void*                                                             pNext;
951                 0u,                                                                                                                             //      VkPipelineMultisampleStateCreateFlags   flags;
952                 vk::VK_SAMPLE_COUNT_1_BIT,                                                                              //      VkSampleCountFlagBits                                   rasterizationSamples;
953                 VK_FALSE,                                                                                                               //      VkBool32                                                                sampleShadingEnable;
954                 0.0f,                                                                                                                   //      float                                                                   minSampleShading;
955                 nullptr,                                                                                                                //      const VkSampleMask*                                             pSampleMask;
956                 VK_FALSE,                                                                                                               //      VkBool32                                                                alphaToCoverageEnable;
957                 VK_FALSE,                                                                                                               //      VkBool32                                                                alphaToOneEnable;
958         };
959
960         // Depth/stencil state.
961         vk::VkStencilOpState    staticFrontStencil;
962         vk::VkStencilOpState    staticBackStencil;
963         bool                                    staticFrontStencilSet   = false;
964         bool                                    staticBackStencilSet    = false;
965
966         // Common setup for the front and back operations.
967         staticFrontStencil.compareMask  = 0xFFu;
968         staticFrontStencil.writeMask    = 0xFFu;
969         staticFrontStencil.reference    = m_testConfig.referenceStencil;
970         staticBackStencil                               = staticFrontStencil;
971
972         for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
973         {
974                 if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
975                 {
976                         copy(staticFrontStencil, op);
977                         staticFrontStencilSet = true;
978                 }
979                 if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
980                 {
981                         copy(staticBackStencil, op);
982                         staticBackStencilSet = true;
983                 }
984         }
985
986         // Default values for the static part.
987         if (!staticFrontStencilSet)
988                 copy(staticFrontStencil, kDefaultStencilOpParams);
989         if (!staticBackStencilSet)
990                 copy(staticBackStencil, kDefaultStencilOpParams);
991
992         const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
993         {
994                 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,         //      VkStructureType                                                 sType;
995                 nullptr,                                                                                                                        //      const void*                                                             pNext;
996                 0u,                                                                                                                                     //      VkPipelineDepthStencilStateCreateFlags  flags;
997                 makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue),           //      VkBool32                                                                depthTestEnable;
998                 makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue),          //      VkBool32                                                                depthWriteEnable;
999                 m_testConfig.depthCompareOpConfig.staticValue,                                          //      VkCompareOp                                                             depthCompareOp;
1000                 makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue),     //      VkBool32                                                                depthBoundsTestEnable;
1001                 makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue),         //      VkBool32                                                                stencilTestEnable;
1002                 staticFrontStencil,                                                                                                     //      VkStencilOpState                                                front;
1003                 staticBackStencil,                                                                                                      //      VkStencilOpState                                                back;
1004                 m_testConfig.minDepthBounds,                                                                            //      float                                                                   minDepthBounds;
1005                 m_testConfig.maxDepthBounds,                                                                            //      float                                                                   maxDepthBounds;
1006         };
1007
1008         // Dynamic state. Here we will set all states which have a dynamic value.
1009         std::vector<vk::VkDynamicState> dynamicStates;
1010
1011         if (m_testConfig.cullModeConfig.dynamicValue)                           dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
1012         if (m_testConfig.frontFaceConfig.dynamicValue)                          dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
1013         if (m_testConfig.topologyConfig.dynamicValue)                           dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
1014         if (m_testConfig.viewportConfig.dynamicValue)                           dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
1015         if (m_testConfig.scissorConfig.dynamicValue)                            dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
1016         if (m_testConfig.strideConfig.dynamicValue)                                     dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
1017         if (m_testConfig.depthTestEnableConfig.dynamicValue)            dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
1018         if (m_testConfig.depthWriteEnableConfig.dynamicValue)           dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
1019         if (m_testConfig.depthCompareOpConfig.dynamicValue)                     dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
1020         if (m_testConfig.depthBoundsTestEnableConfig.dynamicValue)      dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
1021         if (m_testConfig.stencilTestEnableConfig.dynamicValue)          dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
1022         if (m_testConfig.stencilOpConfig.dynamicValue)                          dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
1023
1024         const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
1025         {
1026                 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,       //      VkStructureType                                         sType;
1027                 nullptr,                                                                                                        //      const void*                                                     pNext;
1028                 0u,                                                                                                                     //      VkPipelineDynamicStateCreateFlags       flags;
1029                 static_cast<deUint32>(dynamicStates.size()),                            //      deUint32                                                        dynamicStateCount;
1030                 dynamicStates.data(),                                                                           //      const VkDynamicState*                           pDynamicStates;
1031         };
1032
1033         const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1034         {
1035                 VK_FALSE,                                               // VkBool32                 blendEnable
1036                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcColorBlendFactor
1037                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstColorBlendFactor
1038                 vk::VK_BLEND_OP_ADD,                    // VkBlendOp                colorBlendOp
1039                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            srcAlphaBlendFactor
1040                 vk::VK_BLEND_FACTOR_ZERO,               // VkBlendFactor            dstAlphaBlendFactor
1041                 vk::VK_BLEND_OP_ADD,                    // VkBlendOp                alphaBlendOp
1042                 vk::VK_COLOR_COMPONENT_R_BIT    // VkColorComponentFlags    colorWriteMask
1043                 | vk::VK_COLOR_COMPONENT_G_BIT
1044                 | vk::VK_COLOR_COMPONENT_B_BIT
1045                 | vk::VK_COLOR_COMPONENT_A_BIT
1046         };
1047
1048         const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
1049         {
1050                 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,   // VkStructureType                               sType
1051                 nullptr,                                                                                                                // const void*                                   pNext
1052                 0u,                                                                                                                             // VkPipelineColorBlendStateCreateFlags          flags
1053                 VK_FALSE,                                                                                                               // VkBool32                                      logicOpEnable
1054                 vk::VK_LOGIC_OP_CLEAR,                                                                                  // VkLogicOp                                     logicOp
1055                 1u,                                                                                                                             // deUint32                                      attachmentCount
1056                 &colorBlendAttachmentState,                                                                             // const VkPipelineColorBlendAttachmentState*    pAttachments
1057                 { 0.0f, 0.0f, 0.0f, 0.0f }                                                                              // float                                         blendConstants[4]
1058         };
1059
1060         const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo =
1061         {
1062                 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,    //      VkStructureType                                                                 sType;
1063                 nullptr,                                                                                                //      const void*                                                                             pNext;
1064                 0u,                                                                                                             //      VkPipelineCreateFlags                                                   flags;
1065                 static_cast<deUint32>(shaderStages.size()),                             //      deUint32                                                                                stageCount;
1066                 shaderStages.data(),                                                                    //      const VkPipelineShaderStageCreateInfo*                  pStages;
1067                 &vertexInputStateCreateInfo,                                                    //      const VkPipelineVertexInputStateCreateInfo*             pVertexInputState;
1068                 &inputAssemblyStateCreateInfo,                                                  //      const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState;
1069                 nullptr,                                                                                                //      const VkPipelineTessellationStateCreateInfo*    pTessellationState;
1070                 &viewportStateCreateInfo,                                                               //      const VkPipelineViewportStateCreateInfo*                pViewportState;
1071                 &rasterizationStateCreateInfo,                                                  //      const VkPipelineRasterizationStateCreateInfo*   pRasterizationState;
1072                 &multisampleStateCreateInfo,                                                    //      const VkPipelineMultisampleStateCreateInfo*             pMultisampleState;
1073                 &depthStencilStateCreateInfo,                                                   //      const VkPipelineDepthStencilStateCreateInfo*    pDepthStencilState;
1074                 &colorBlendStateCreateInfo,                                                             //      const VkPipelineColorBlendStateCreateInfo*              pColorBlendState;
1075                 &dynamicStateCreateInfo,                                                                //      const VkPipelineDynamicStateCreateInfo*                 pDynamicState;
1076                 pipelineLayout.get(),                                                                   //      VkPipelineLayout                                                                layout;
1077                 renderPass.get(),                                                                               //      VkRenderPass                                                                    renderPass;
1078                 0u,                                                                                                             //      deUint32                                                                                subpass;
1079                 DE_NULL,                                                                                                //      VkPipeline                                                                              basePipelineHandle;
1080                 0,                                                                                                              //      deInt32                                                                                 basePipelineIndex;
1081         };
1082         const auto graphicsPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &graphicsPipelineCreateInfo);
1083
1084         const bool useStaticPipeline = (m_testConfig.sequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES || m_testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1085
1086         vk::Move<vk::VkPipeline> staticPipeline;
1087         if (useStaticPipeline)
1088         {
1089                 auto staticPipelineCreateInfo                   = graphicsPipelineCreateInfo;
1090                 staticPipelineCreateInfo.pDynamicState  = nullptr;
1091                 staticPipeline                                                  = vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
1092         }
1093
1094         // Command buffer.
1095         const auto cmdPool              = vk::makeCommandPool(vkd, device, queueIndex);
1096         const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1097         const auto cmdBuffer    = cmdBufferPtr.get();
1098
1099         // Clear values.
1100         std::vector<vk::VkClearValue> clearValues;
1101         clearValues.push_back(vk::makeClearValueColor(m_testConfig.clearColorValue));
1102         clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
1103
1104         // Track in-advance vertex buffer binding.
1105         bool boundInAdvance = false;
1106
1107         // Record command buffer.
1108         vk::beginCommandBuffer(vkd, cmdBuffer);
1109
1110                 // Maybe set extended dynamic state here.
1111                 if (m_testConfig.sequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
1112                 {
1113                         setDynamicStates(m_testConfig, vkd, cmdBuffer);
1114                         boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertBufferSize, vertBufferOffset);
1115                 }
1116
1117                 // Begin render pass.
1118                 vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffer.get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
1119
1120                         // Bind a static pipeline first if needed.
1121                         if (useStaticPipeline)
1122                                 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
1123
1124                         // Maybe set extended dynamic state here.
1125                         if (m_testConfig.sequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
1126                         {
1127                                 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1128                                 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertBufferSize, vertBufferOffset);
1129                         }
1130
1131                         // Bind dynamic pipeline.
1132                         vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
1133
1134                         const auto& viewportVec = getActiveViewportVec(m_testConfig);
1135                         for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
1136                         {
1137                                 for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
1138                                 {
1139                                         // Push constants.
1140                                         PushConstants pushConstants =
1141                                         {
1142                                                 m_testConfig.meshParams[meshIdx].color,         //      tcu::Vec4       triangleColor;
1143                                                 m_testConfig.meshParams[meshIdx].depth,         //      float           meshDepth;
1144                                                 static_cast<deInt32>(viewportIdx),                      //      deInt32         viewPortIndex;
1145                                                 m_testConfig.meshParams[meshIdx].scaleX,        //      float           scaleX;
1146                                                 m_testConfig.meshParams[meshIdx].scaleY,        //      float           scaleY;
1147                                                 m_testConfig.meshParams[meshIdx].offsetX,       //      float           offsetX;
1148                                                 m_testConfig.meshParams[meshIdx].offsetY,       //      float           offsetY;
1149                                         };
1150                                         vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
1151
1152                                         // Track vertex bounding state for this mesh.
1153                                         bool boundBeforeDraw = false;
1154
1155                                         // Maybe set extended dynamic state here.
1156                                         if (m_testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW || m_testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
1157                                         {
1158                                                 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1159                                                 boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffer.get(), rvertBuffer.get(), vertBufferSize, vertBufferOffset);
1160                                         }
1161
1162                                         // Bind vertex buffer with static stride if needed and draw.
1163                                         if (!(boundInAdvance || boundBeforeDraw))
1164                                                 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, (m_testConfig.meshParams[meshIdx].reversed ? &rvertBuffer.get() : &vertBuffer.get()), &vertBufferOffset);
1165
1166                                         // Draw mesh.
1167                                         vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(vertices.size()), 1u, 0u, 0u);
1168                                 }
1169                         }
1170
1171                 vk::endRenderPass(vkd, cmdBuffer);
1172         vk::endCommandBuffer(vkd, cmdBuffer);
1173
1174         // Submit commands.
1175         vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1176
1177         // Read result image aspects.
1178         const tcu::UVec2        renderSize              (kFramebufferWidth, kFramebufferHeight);
1179         const auto                      colorBuffer             = readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImage.get(), kColorFormat, renderSize);
1180         const auto                      depthBuffer             = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImage.get(), kDepthStencilFormat, renderSize);
1181         const auto                      stencilBuffer   = readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImage.get(), kDepthStencilFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1182         const auto                      colorAccess             = colorBuffer->getAccess();
1183         const auto                      depthAccess             = depthBuffer->getAccess();
1184         const auto                      stencilAccess   = stencilBuffer->getAccess();
1185
1186         const int kWidth        = static_cast<int>(kFramebufferWidth);
1187         const int kHeight       = static_cast<int>(kFramebufferHeight);
1188
1189         const tcu::TextureFormat        errorFormat                     (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1190         tcu::TextureLevel                       colorError                      (errorFormat, kWidth, kHeight);
1191         tcu::TextureLevel                       depthError                      (errorFormat, kWidth, kHeight);
1192         tcu::TextureLevel                       stencilError            (errorFormat, kWidth, kHeight);
1193         const auto                                      colorErrorAccess        = colorError.getAccess();
1194         const auto                                      depthErrorAccess        = depthError.getAccess();
1195         const auto                                      stencilErrorAccess      = stencilError.getAccess();
1196         const tcu::Vec4                         kGood                           (0.0f, 1.0f, 0.0f, 1.0f);
1197         const tcu::Vec4                         kBad                            (1.0f, 0.0f, 0.0f, 1.0f);
1198
1199         // Check expected values.
1200         bool colorMatch         = true;
1201         bool depthMatch         = true;
1202         bool stencilMatch       = true;
1203         bool match;
1204
1205         for (int x = 0; x < kWidth; ++x)
1206         for (int y = 0; y < kHeight; ++y)
1207         {
1208                 const auto colorPixel = colorAccess.getPixel(x, y);
1209                 match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, m_testConfig.expectedColor), kColorThreshold));
1210                 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
1211                 if (!match)
1212                         colorMatch = false;
1213
1214                 const auto depthPixel = depthAccess.getPixDepth(x, y);
1215                 match = (depthPixel == m_testConfig.expectedDepth);
1216                 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
1217                 if (!match)
1218                         depthMatch = false;
1219
1220                 const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
1221                 match = (stencilPixel == m_testConfig.expectedStencil);
1222                 stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
1223                 if (!match)
1224                         stencilMatch = false;
1225         }
1226
1227         if (!(colorMatch && depthMatch && stencilMatch))
1228         {
1229                 auto& log = m_context.getTestContext().getLog();
1230
1231                 if (!colorMatch)
1232                         logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
1233
1234                 if (!depthMatch)
1235                         logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
1236
1237                 if (!stencilMatch)
1238                         logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
1239
1240                 return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
1241         }
1242
1243         return tcu::TestStatus::pass("Pass");
1244 }
1245
1246 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
1247 {
1248         switch (op)
1249         {
1250         case vk::VK_COMPARE_OP_NEVER:                           return false;
1251         case vk::VK_COMPARE_OP_LESS:                            return (referenceValue <        storedValue);
1252         case vk::VK_COMPARE_OP_EQUAL:                           return (referenceValue ==       storedValue);
1253         case vk::VK_COMPARE_OP_LESS_OR_EQUAL:           return (referenceValue <=       storedValue);
1254         case vk::VK_COMPARE_OP_GREATER:                         return (referenceValue >        storedValue);
1255         case vk::VK_COMPARE_OP_GREATER_OR_EQUAL:        return (referenceValue >=       storedValue);
1256         case vk::VK_COMPARE_OP_ALWAYS:                          return true;
1257         default: DE_ASSERT(false); return false;
1258         }
1259
1260         return false;   // Unreachable.
1261 }
1262
1263 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
1264 {
1265         deUint8 result = storedValue;
1266
1267         switch (op)
1268         {
1269         case vk::VK_STENCIL_OP_KEEP:                                    break;
1270         case vk::VK_STENCIL_OP_ZERO:                                    result = 0; break;
1271         case vk::VK_STENCIL_OP_REPLACE:                                 result = referenceValue; break;
1272         case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP:             result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
1273         case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP:             result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
1274         case vk::VK_STENCIL_OP_INVERT:                                  result = static_cast<deUint8>(~result); break;
1275         case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP:              result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
1276         case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP:              result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
1277         default: DE_ASSERT(false); break;
1278         }
1279
1280         return result;
1281 }
1282
1283 } // anonymous namespace
1284
1285 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
1286 {
1287         de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
1288
1289         // Auxiliar constants.
1290         const deUint32  kHalfWidthU     = kFramebufferWidth/2u;
1291         const deInt32   kHalfWidthI     = static_cast<deInt32>(kHalfWidthU);
1292         const float             kHalfWidthF     = static_cast<float>(kHalfWidthU);
1293         const float             kHeightF        = static_cast<float>(kFramebufferHeight);
1294
1295         static const struct
1296         {
1297                 SequenceOrdering        ordering;
1298                 std::string                     name;
1299                 std::string                     desc;
1300         } kOrderingCases[] =
1301         {
1302                 { SequenceOrdering::CMD_BUFFER_START,   "cmd_buffer_start",             "Dynamic state set after command buffer start"                                                                                                                                                  },
1303                 { SequenceOrdering::BEFORE_DRAW,                "before_draw",                  "Dynamic state set just before drawing"                                                                                                                                                                 },
1304                 { SequenceOrdering::BETWEEN_PIPELINES,  "between_pipelines",    "Dynamic after a pipeline with static states has been bound and before a pipeline with dynamic states has been bound"   },
1305                 { SequenceOrdering::AFTER_PIPELINES,    "after_pipelines",              "Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound"                              },
1306         };
1307
1308         for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
1309         {
1310                 const auto& kOrderingCase       = kOrderingCases[orderingIdx];
1311                 const auto& kOrdering           = kOrderingCase.ordering;
1312
1313                 de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
1314
1315                 // Cull modes.
1316                 {
1317                         TestConfig config(kOrdering);
1318                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_FRONT_BIT;
1319                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
1320                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
1321                 }
1322                 {
1323                         TestConfig config(kOrdering);
1324                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_FRONT_AND_BACK;
1325                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
1326                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
1327                 }
1328                 {
1329                         TestConfig config(kOrdering);
1330                         // Make triangles look back.
1331                         config.meshParams[0].reversed           = true;
1332                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
1333                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
1334                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
1335                 }
1336                 {
1337                         TestConfig config(kOrdering);
1338                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_NONE;
1339                         config.cullModeConfig.dynamicValue      = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
1340                         config.expectedColor                            = kDefaultClearColor;
1341                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
1342                 }
1343
1344                 // Front face.
1345                 {
1346                         TestConfig config(kOrdering);
1347                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
1348                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_CLOCKWISE;
1349                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
1350                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
1351                 }
1352                 {
1353                         TestConfig config(kOrdering);
1354                         // Pass triangles in clockwise order.
1355                         config.meshParams[0].reversed           = true;
1356                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
1357                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
1358                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
1359                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
1360                 }
1361                 {
1362                         TestConfig config(kOrdering);
1363                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
1364                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
1365                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
1366                         config.expectedColor                            = kDefaultClearColor;
1367                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
1368                 }
1369                 {
1370                         TestConfig config(kOrdering);
1371                         // Pass triangles in clockwise order.
1372                         config.meshParams[0].reversed           = true;
1373                         config.cullModeConfig.staticValue       = vk::VK_CULL_MODE_BACK_BIT;
1374                         config.frontFaceConfig.staticValue      = vk::VK_FRONT_FACE_CLOCKWISE;
1375                         config.frontFaceConfig.dynamicValue     = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
1376                         config.expectedColor                            = kDefaultClearColor;
1377                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
1378                 }
1379
1380                 // Dynamic topology.
1381                 {
1382                         TestConfig baseConfig(kOrdering);
1383
1384                         for (int i = 0; i < 2; ++i)
1385                         {
1386                                 const bool useGeometryShader = (i > 0);
1387
1388                                 static const struct
1389                                 {
1390                                         vk::VkPrimitiveTopology staticVal;
1391                                         vk::VkPrimitiveTopology dynamicVal;
1392                                 } kTopologyCases[] =
1393                                 {
1394                                         { vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,      vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN  },
1395                                         { vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST,          vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP    },
1396                                 };
1397
1398                                 for (int topoCaseIdx = 0; topoCaseIdx < DE_LENGTH_OF_ARRAY(kTopologyCases); ++topoCaseIdx)
1399                                 {
1400                                         TestConfig config(baseConfig);
1401                                         config.useGeometryShader                        = useGeometryShader;
1402                                         config.topologyConfig.staticValue       = kTopologyCases[topoCaseIdx].staticVal;
1403                                         config.topologyConfig.dynamicValue      = tcu::just<vk::VkPrimitiveTopology>(kTopologyCases[topoCaseIdx].dynamicVal);
1404
1405                                         const std::string       className       = topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
1406                                         const std::string       name            = "topology_" + className + (useGeometryShader ? "_geom" : "");
1407                                         const std::string       desc            = "Dynamically switch primitive topologies from the " + className + " class" + (useGeometryShader ? " and use a geometry shader" : "");
1408                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
1409                                 }
1410                         }
1411                 }
1412
1413                 // Viewport.
1414                 {
1415                         TestConfig config(kOrdering);
1416                         // 2 scissors, bad static single viewport.
1417                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
1418                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
1419                         config.viewportConfig.dynamicValue      = ViewportVec{
1420                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1421                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1422                         };
1423                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
1424                 }
1425                 {
1426                         TestConfig config(kOrdering);
1427                         // Bad static reduced viewport.
1428                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
1429                         config.viewportConfig.staticValue       = ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
1430                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
1431                 }
1432                 {
1433                         TestConfig config(kOrdering);
1434                         // 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
1435                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
1436                         config.viewportConfig.staticValue       = ViewportVec{
1437                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
1438                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),                // Left.
1439                         };
1440                         config.viewportConfig.dynamicValue      = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
1441                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
1442                 }
1443                 {
1444                         TestConfig config(kOrdering);
1445                         // 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
1446                         config.scissorConfig.staticValue        = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
1447                         config.viewportConfig.staticValue       = ViewportVec{
1448                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),                // Left.
1449                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
1450                         };
1451                         config.viewportConfig.dynamicValue      = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
1452                         config.expectedColor                            = kDefaultClearColor;
1453                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
1454                 }
1455
1456                 // Scissor.
1457                 {
1458                         TestConfig config(kOrdering);
1459                         // 2 viewports, bad static single scissor.
1460                         config.viewportConfig.staticValue       = ViewportVec{
1461                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1462                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1463                         };
1464                         config.scissorConfig.staticValue        = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
1465                         config.scissorConfig.dynamicValue       = ScissorVec{
1466                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
1467                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
1468                         };
1469                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
1470                 }
1471                 {
1472                         TestConfig config(kOrdering);
1473                         // 1 viewport, bad static single scissor.
1474                         config.scissorConfig.staticValue        = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
1475                         config.scissorConfig.dynamicValue       = ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
1476                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
1477                 }
1478                 {
1479                         TestConfig config(kOrdering);
1480                         // 2 viewports, 2 reversed scissors that need fixing.
1481                         config.viewportConfig.staticValue       = ViewportVec{
1482                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1483                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1484                         };
1485                         config.scissorConfig.staticValue        = ScissorVec{
1486                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
1487                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
1488                         };
1489                         config.scissorConfig.dynamicValue       = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
1490                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
1491                 }
1492                 {
1493                         TestConfig config(kOrdering);
1494                         // 2 viewports, 2 scissors switched to prevent drawing.
1495                         config.viewportConfig.staticValue       = ViewportVec{
1496                                 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1497                                 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
1498                         };
1499                         config.scissorConfig.staticValue        = ScissorVec{
1500                                 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
1501                                 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
1502                         };
1503                         config.scissorConfig.dynamicValue       = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
1504                         config.expectedColor                            = kDefaultClearColor;
1505                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
1506                 }
1507
1508                 // Stride.
1509                 {
1510                         TestConfig config(kOrdering);
1511                         config.strideConfig.staticValue         = kCoordsSize;
1512                         config.strideConfig.dynamicValue        = kVertexStride;
1513                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stride", "Dynamically set stride", config));
1514                 }
1515
1516                 // Depth test enable.
1517                 {
1518                         TestConfig config(kOrdering);
1519                         config.depthTestEnableConfig.staticValue        = false;
1520                         config.depthTestEnableConfig.dynamicValue       = tcu::just(true);
1521                         // By default, the depth test never passes when enabled.
1522                         config.expectedColor                                            = kDefaultClearColor;
1523                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
1524                 }
1525                 {
1526                         TestConfig config(kOrdering);
1527                         config.depthTestEnableConfig.staticValue        = true;
1528                         config.depthTestEnableConfig.dynamicValue       = tcu::just(false);
1529                         config.expectedColor                                            = kDefaultTriangleColor;
1530                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
1531                 }
1532
1533                 // Depth write enable.
1534                 {
1535                         TestConfig config(kOrdering);
1536
1537                         // Enable depth test and set values so it passes.
1538                         config.depthTestEnableConfig.staticValue        = true;
1539                         config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
1540                         config.clearDepthValue                                          = 0.5f;
1541                         config.meshParams[0].depth                                      = 0.25f;
1542
1543                         // Enable writes and expect the mesh value.
1544                         config.depthWriteEnableConfig.staticValue       = false;
1545                         config.depthWriteEnableConfig.dynamicValue      = tcu::just(true);
1546                         config.expectedDepth                                            = 0.25f;
1547
1548                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
1549                 }
1550                 {
1551                         TestConfig config(kOrdering);
1552
1553                         // Enable depth test and set values so it passes.
1554                         config.depthTestEnableConfig.staticValue        = true;
1555                         config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
1556                         config.clearDepthValue                                          = 0.5f;
1557                         config.meshParams[0].depth                                      = 0.25f;
1558
1559                         // But disable writing dynamically and expect the clear value.
1560                         config.depthWriteEnableConfig.staticValue       = true;
1561                         config.depthWriteEnableConfig.dynamicValue      = tcu::just(false);
1562                         config.expectedDepth                                            = 0.5f;
1563
1564                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
1565                 }
1566
1567                 // Depth compare op.
1568                 {
1569                         TestConfig baseConfig(kOrdering);
1570                         const tcu::Vec4 kAlternativeColor                               (0.0f, 0.0f, 0.5f, 1.0f);
1571                         baseConfig.depthTestEnableConfig.staticValue    = true;
1572                         baseConfig.depthWriteEnableConfig.staticValue   = true;
1573                         baseConfig.depthCompareOpConfig.staticValue             = vk::VK_COMPARE_OP_NEVER;
1574                         baseConfig.clearDepthValue                                              = 0.5f;
1575
1576                         {
1577                                 TestConfig config = baseConfig;
1578                                 config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_ALWAYS;
1579                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_NEVER;
1580                                 config.meshParams[0].depth                                      = 0.25f;
1581                                 config.expectedDepth                                            = 0.5f;
1582                                 config.expectedColor                                            = kDefaultClearColor;
1583                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
1584                         }
1585                         {
1586                                 TestConfig config = baseConfig;
1587                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS;
1588                                 config.meshParams[0].depth                                      = 0.25f;
1589                                 config.expectedDepth                                            = 0.25f;
1590                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
1591                         }
1592                         {
1593                                 TestConfig config = baseConfig;
1594                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER;
1595                                 config.meshParams[0].depth                                      = 0.75f;
1596                                 config.expectedDepth                                            = 0.75f;
1597                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
1598                         }
1599                         {
1600                                 TestConfig config = baseConfig;
1601                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_EQUAL;
1602                                 config.meshParams[0].depth                                      = 0.5f;
1603                                 config.meshParams[0].color                                      = kAlternativeColor;
1604                                 // Draw another mesh in front to verify it does not pass the equality test.
1605                                 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
1606                                 config.expectedDepth                                            = 0.5f;
1607                                 config.expectedColor                                            = kAlternativeColor;
1608                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
1609                         }
1610                         {
1611                                 TestConfig config = baseConfig;
1612                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
1613                                 config.meshParams[0].depth                                      = 0.25f;
1614                                 config.expectedDepth                                            = 0.25f;
1615                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with smaller depth", config));
1616                         }
1617                         {
1618                                 TestConfig config = baseConfig;
1619                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
1620                                 config.meshParams[0].depth                                      = 0.5f;
1621                                 config.expectedDepth                                            = 0.5f;
1622                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_equal", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw with equal depth", config));
1623                         }
1624                         {
1625                                 TestConfig config = baseConfig;
1626                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
1627                                 config.meshParams[0].depth                                      = 0.25f;
1628                                 // Draw another mesh with the same depth in front of it.
1629                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
1630                                 config.expectedDepth                                            = 0.25f;
1631                                 config.expectedColor                                            = kAlternativeColor;
1632                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less_equal_less_then_equal", "Dynamically set the depth compare operator to LESS_OR_EQUAL and draw two meshes with less and equal depth", config));
1633                         }
1634                         {
1635                                 TestConfig config = baseConfig;
1636                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
1637                                 config.meshParams[0].depth                                      = 0.75f;
1638                                 config.expectedDepth                                            = 0.75f;
1639                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_greater", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with greater depth", config));
1640                         }
1641                         {
1642                                 TestConfig config = baseConfig;
1643                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
1644                                 config.meshParams[0].depth                                      = 0.5f;
1645                                 config.expectedDepth                                            = 0.5f;
1646                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_equal", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw with equal depth", config));
1647                         }
1648                         {
1649                                 TestConfig config = baseConfig;
1650                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
1651                                 config.meshParams[0].depth                                      = 0.75f;
1652                                 // Draw another mesh with the same depth in front of it.
1653                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
1654                                 config.expectedDepth                                            = 0.75f;
1655                                 config.expectedColor                                            = kAlternativeColor;
1656                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater_equal_greater_then_equal", "Dynamically set the depth compare operator to GREATER_OR_EQUAL and draw two meshes with greater and equal depth", config));
1657                         }
1658                         {
1659                                 TestConfig config = baseConfig;
1660                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_NOT_EQUAL;
1661
1662                                 // Draw first mesh in front.
1663                                 config.meshParams[0].depth                                      = 0.25f;
1664                                 // Draw another mesh in the back, this should pass too.
1665                                 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
1666                                 // Finally a new mesh with the same depth. This should not pass.
1667                                 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
1668
1669                                 config.expectedColor                                            = kAlternativeColor;
1670                                 config.expectedDepth                                            = 0.5f;
1671                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
1672                         }
1673                         {
1674                                 TestConfig config = baseConfig;
1675                                 config.depthCompareOpConfig.dynamicValue        = vk::VK_COMPARE_OP_ALWAYS;
1676
1677                                 config.meshParams[0].depth                                      = 0.5f;
1678                                 config.expectedDepth                                            = 0.5f;
1679                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
1680
1681                                 config.meshParams[0].depth                                      = 0.25f;
1682                                 config.expectedDepth                                            = 0.25f;
1683                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
1684
1685                                 config.meshParams[0].depth                                      = 0.75f;
1686                                 config.expectedDepth                                            = 0.75f;
1687                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
1688                         }
1689                 }
1690
1691                 // Depth bounds test.
1692                 {
1693                         TestConfig baseConfig(kOrdering);
1694                         baseConfig.minDepthBounds                                                       = 0.25f;
1695                         baseConfig.maxDepthBounds                                                       = 0.75f;
1696                         baseConfig.meshParams[0].depth                                          = 0.0f;
1697
1698                         {
1699                                 TestConfig config = baseConfig;
1700                                 config.depthBoundsTestEnableConfig.staticValue  = false;
1701                                 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(true);
1702                                 config.expectedColor                                                    = kDefaultClearColor;
1703                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
1704                         }
1705                         {
1706                                 TestConfig config = baseConfig;
1707                                 config.depthBoundsTestEnableConfig.staticValue  = true;
1708                                 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(false);
1709                                 config.expectedColor                                                    = kDefaultTriangleColor;
1710                                 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
1711                         }
1712                 }
1713
1714                 // Stencil test enable.
1715                 {
1716                         TestConfig config(kOrdering);
1717                         config.stencilTestEnableConfig.staticValue                              = false;
1718                         config.stencilTestEnableConfig.dynamicValue                             = tcu::just(true);
1719                         config.stencilOpConfig.staticValue.front().compareOp    = vk::VK_COMPARE_OP_NEVER;
1720                         config.expectedColor                                                                    = kDefaultClearColor;
1721                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
1722                 }
1723                 {
1724                         TestConfig config(kOrdering);
1725                         config.stencilTestEnableConfig.staticValue                              = true;
1726                         config.stencilTestEnableConfig.dynamicValue                             = tcu::just(false);
1727                         config.stencilOpConfig.staticValue.front().compareOp    = vk::VK_COMPARE_OP_NEVER;
1728                         config.expectedColor                                                                    = kDefaultTriangleColor;
1729                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
1730                 }
1731
1732                 // Stencil operation. Many combinations are possible.
1733                 {
1734                         static const struct
1735                         {
1736                                 vk::VkStencilFaceFlags  face;
1737                                 std::string                             name;
1738                         } kFaces[] =
1739                         {
1740                                 { vk::VK_STENCIL_FACE_FRONT_BIT,                        "face_front"            },
1741                                 { vk::VK_STENCIL_FACE_BACK_BIT,                         "face_back"                     },
1742                                 { vk::VK_STENCIL_FRONT_AND_BACK,                        "face_both_single"      },
1743                                 { vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM,       "face_both_dual"        },      // MAX_ENUM is a placeholder.
1744                         };
1745
1746                         static const struct
1747                         {
1748                                 vk::VkCompareOp         compareOp;
1749                                 std::string                     name;
1750                         } kCompare[] =
1751                         {
1752                                 { vk::VK_COMPARE_OP_NEVER,                              "xf"            },
1753                                 { vk::VK_COMPARE_OP_LESS,                               "lt"            },
1754                                 { vk::VK_COMPARE_OP_EQUAL,                              "eq"            },
1755                                 { vk::VK_COMPARE_OP_LESS_OR_EQUAL,              "le"            },
1756                                 { vk::VK_COMPARE_OP_GREATER,                    "gt"            },
1757                                 { vk::VK_COMPARE_OP_GREATER_OR_EQUAL,   "ge"            },
1758                                 { vk::VK_COMPARE_OP_ALWAYS,                             "xt"            },
1759                         };
1760
1761                         using u8vec = std::vector<deUint8>;
1762
1763                         static const auto kMinVal       = std::numeric_limits<deUint8>::min();
1764                         static const auto kMaxVal       = std::numeric_limits<deUint8>::max();
1765                         static const auto kMidVal       = static_cast<deUint8>(kMaxVal * 2u / 5u);
1766                         static const auto kMinValI      = static_cast<int>(kMinVal);
1767                         static const auto kMaxValI      = static_cast<int>(kMaxVal);
1768
1769                         static const struct
1770                         {
1771                                 vk::VkStencilOp         stencilOp;
1772                                 std::string                     name;
1773                                 u8vec                           clearValues;    // One test per clear value interesting for this operation.
1774                                 vk::VkStencilOp         incompatibleOp; // Alternative operation giving incompatible results for the given values.
1775                         } kStencilOps[] =
1776                         {
1777                                 { vk::VK_STENCIL_OP_KEEP,                                       "keep",                 u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
1778                                 { vk::VK_STENCIL_OP_ZERO,                                       "zero",                 u8vec{kMidVal},                                 vk::VK_STENCIL_OP_KEEP                                  },
1779                                 { vk::VK_STENCIL_OP_REPLACE,                            "replace",              u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
1780                                 { vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP,        "inc_clamp",    u8vec{kMaxVal - 1, kMaxVal},    vk::VK_STENCIL_OP_ZERO                                  },
1781                                 { vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP,        "dec_clamp",    u8vec{kMinVal + 1, kMinVal},    vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP   },
1782                                 { vk::VK_STENCIL_OP_INVERT,                                     "invert",               u8vec{kMidVal},                                 vk::VK_STENCIL_OP_ZERO                                  },
1783                                 { vk::VK_STENCIL_OP_INCREMENT_AND_WRAP,         "inc_wrap",             u8vec{kMaxVal - 1, kMaxVal},    vk::VK_STENCIL_OP_KEEP                                  },
1784                                 { vk::VK_STENCIL_OP_DECREMENT_AND_WRAP,         "dec_wrap",             u8vec{kMinVal + 1, kMinVal},    vk::VK_STENCIL_OP_KEEP                                  },
1785                         };
1786
1787                         for (int facesIdx       = 0; facesIdx   < DE_LENGTH_OF_ARRAY(kFaces);           ++facesIdx)
1788                         for (int compareIdx     = 0; compareIdx < DE_LENGTH_OF_ARRAY(kCompare);         ++compareIdx)
1789                         for (int opIdx          = 0; opIdx              < DE_LENGTH_OF_ARRAY(kStencilOps);      ++opIdx)
1790                         {
1791                                 const auto& face        = kFaces[facesIdx];
1792                                 const auto& compare     = kCompare[compareIdx];
1793                                 const auto& op          = kStencilOps[opIdx];
1794
1795                                 // Try clearing the stencil value with different values.
1796                                 for (const auto clearVal : op.clearValues)
1797                                 {
1798                                         // Use interesting values as the reference stencil value.
1799                                         for (int delta = -1; delta <= 1; ++delta)
1800                                         {
1801                                                 const int refVal = clearVal + delta;
1802                                                 if (refVal < kMinValI || refVal > kMaxValI)
1803                                                         continue;
1804
1805                                                 const auto refValU8             = static_cast<deUint8>(refVal);
1806                                                 const auto refValU32    = static_cast<deUint32>(refVal);
1807
1808                                                 // Calculate outcome of the stencil test itself.
1809                                                 const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
1810
1811                                                 // If the test passes, use an additional variant for the depthFail operation.
1812                                                 const int subCases = (wouldPass ? 2 : 1);
1813
1814                                                 for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
1815                                                 {
1816                                                         const bool depthFail    = (subCaseIdx > 0);                             // depthFail would be the second variant.
1817                                                         const bool globalPass   = (wouldPass && !depthFail);    // Global result of the stencil+depth test.
1818
1819                                                         // Start tuning test parameters.
1820                                                         TestConfig config(kOrdering);
1821
1822                                                         // No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
1823                                                         if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
1824                                                         {
1825                                                                 // Default parameters are OK.
1826                                                         }
1827                                                         else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
1828                                                         {
1829                                                                 // Reverse the mesh so it applies the back operation.
1830                                                                 config.meshParams[0].reversed = true;
1831                                                         }
1832                                                         else    // Front and back.
1833                                                         {
1834                                                                 // Draw both a front and a back-facing mesh so both are applied.
1835                                                                 // The first mesh will be drawn in the top half and the second mesh in the bottom half.
1836
1837                                                                 // Make the second mesh a reversed copy of the first mesh.
1838                                                                 config.meshParams.push_back(config.meshParams.front());
1839                                                                 config.meshParams.back().reversed = true;
1840
1841                                                                 // Apply scale and offset to the top mesh.
1842                                                                 config.meshParams.front().scaleY = 0.5f;
1843                                                                 config.meshParams.front().offsetY = -0.5f;
1844
1845                                                                 // Apply scale and offset to the bottom mesh.
1846                                                                 config.meshParams.back().scaleY = 0.5f;
1847                                                                 config.meshParams.back().offsetY = 0.5f;
1848                                                         }
1849
1850                                                         // Enable the stencil test.
1851                                                         config.stencilTestEnableConfig.staticValue = true;
1852
1853                                                         // Set dynamic configuration.
1854                                                         StencilOpParams dynamicStencilConfig;
1855                                                         dynamicStencilConfig.faceMask           = face.face;
1856                                                         dynamicStencilConfig.compareOp          = compare.compareOp;
1857                                                         dynamicStencilConfig.failOp                     = vk::VK_STENCIL_OP_MAX_ENUM;
1858                                                         dynamicStencilConfig.passOp                     = vk::VK_STENCIL_OP_MAX_ENUM;
1859                                                         dynamicStencilConfig.depthFailOp        = vk::VK_STENCIL_OP_MAX_ENUM;
1860
1861                                                         // Set operations so only the appropriate operation for this case gives the right result.
1862                                                         vk::VkStencilOp* activeOp               = nullptr;
1863                                                         vk::VkStencilOp* inactiveOps[2] = { nullptr, nullptr };
1864                                                         if (wouldPass)
1865                                                         {
1866                                                                 if (depthFail)
1867                                                                 {
1868                                                                         activeOp                = &dynamicStencilConfig.depthFailOp;
1869                                                                         inactiveOps[0]  = &dynamicStencilConfig.passOp;
1870                                                                         inactiveOps[1]  = &dynamicStencilConfig.failOp;
1871                                                                 }
1872                                                                 else
1873                                                                 {
1874                                                                         activeOp                = &dynamicStencilConfig.passOp;
1875                                                                         inactiveOps[0]  = &dynamicStencilConfig.depthFailOp;
1876                                                                         inactiveOps[1]  = &dynamicStencilConfig.failOp;
1877                                                                 }
1878                                                         }
1879                                                         else
1880                                                         {
1881                                                                 activeOp                = &dynamicStencilConfig.failOp;
1882                                                                 inactiveOps[0]  = &dynamicStencilConfig.passOp;
1883                                                                 inactiveOps[1]  = &dynamicStencilConfig.depthFailOp;
1884                                                         }
1885
1886                                                         *activeOp = op.stencilOp;
1887                                                         *inactiveOps[0] = op.incompatibleOp;
1888                                                         *inactiveOps[1] = op.incompatibleOp;
1889
1890                                                         // Make sure all ops have been configured properly.
1891                                                         DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
1892                                                         DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
1893                                                         DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
1894
1895                                                         // Set an incompatible static operation too.
1896                                                         auto& staticStencilConfig               = config.stencilOpConfig.staticValue.front();
1897                                                         staticStencilConfig.faceMask    = face.face;
1898                                                         staticStencilConfig.compareOp   = (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
1899                                                         staticStencilConfig.passOp              = op.incompatibleOp;
1900                                                         staticStencilConfig.failOp              = op.incompatibleOp;
1901                                                         staticStencilConfig.depthFailOp = op.incompatibleOp;
1902
1903                                                         // Set dynamic configuration.
1904                                                         StencilOpVec stencilOps;
1905                                                         stencilOps.push_back(dynamicStencilConfig);
1906
1907                                                         if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
1908                                                         {
1909                                                                 // This is the dual case. We will set the front and back face values with two separate calls.
1910                                                                 stencilOps.push_back(stencilOps.front());
1911                                                                 stencilOps.front().faceMask     = vk::VK_STENCIL_FACE_FRONT_BIT;
1912                                                                 stencilOps.back().faceMask      = vk::VK_STENCIL_FACE_BACK_BIT;
1913                                                         }
1914
1915                                                         config.stencilOpConfig.dynamicValue     = tcu::just(stencilOps);
1916                                                         config.clearStencilValue                        = clearVal;
1917                                                         config.referenceStencil                         = refValU32;
1918
1919                                                         if (depthFail)
1920                                                         {
1921                                                                 // Enable depth test and make it fail.
1922                                                                 config.depthTestEnableConfig.staticValue        = true;
1923                                                                 config.clearDepthValue                                          = 0.5f;
1924                                                                 config.depthCompareOpConfig.staticValue         = vk::VK_COMPARE_OP_LESS;
1925
1926                                                                 for (auto& meshPar : config.meshParams)
1927                                                                         meshPar.depth = 0.75f;
1928                                                         }
1929
1930                                                         // Set expected outcome.
1931                                                         config.expectedColor    = (globalPass ? kDefaultTriangleColor : kDefaultClearColor);
1932                                                         config.expectedDepth    = config.clearDepthValue; // No depth writing by default.
1933                                                         config.expectedStencil  = stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
1934
1935                                                         const std::string testName = std::string("stencil_state")
1936                                                                 + "_" + face.name
1937                                                                 + "_" + compare.name
1938                                                                 + "_" + op.name
1939                                                                 + "_clear_" + de::toString(static_cast<int>(clearVal))
1940                                                                 + "_ref_" + de::toString(refVal)
1941                                                                 + "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
1942
1943                                                         orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
1944                                                 }
1945                                         }
1946                                 }
1947                         }
1948                 }
1949
1950                 extendedDynamicStateGroup->addChild(orderingGroup.release());
1951         }
1952
1953         return extendedDynamicStateGroup.release();
1954 }
1955
1956 } // pipeline
1957 } // vkt