1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2020 The Khronos Group Inc.
6 * Copyright (c) 2020 Valve Corporation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 *//*
21 * \file
22 * \brief Extended dynamic state tests
23 *//*--------------------------------------------------------------------*/
24
25 #include "vktPipelineExtendedDynamicStateTests.hpp"
26 #include "vktPipelineImageUtil.hpp"
27 #include "vktTestCase.hpp"
28
29 #include "vkDefs.hpp"
30 #include "vkTypeUtil.hpp"
31 #include "vkQueryUtil.hpp"
32 #include "vkObjUtil.hpp"
33 #include "vkBufferWithMemory.hpp"
34 #include "vkImageWithMemory.hpp"
35 #include "vkBuilderUtil.hpp"
36 #include "vkCmdUtil.hpp"
37 #include "vkImageUtil.hpp"
38
39 #include "tcuVector.hpp"
40 #include "tcuMaybe.hpp"
41 #include "tcuTestLog.hpp"
42 #include "tcuVectorUtil.hpp"
43
44 #include "deUniquePtr.hpp"
45 #include "deStringUtil.hpp"
46
47 #include <vector>
48 #include <sstream>
49 #include <algorithm>
50 #include <utility>
51 #include <iterator>
52 #include <string>
53 #include <limits>
54 #include <memory>
55 #include <functional>
56
57 namespace vkt
58 {
59 namespace pipeline
60 {
61
62 namespace
63 {
64
makeVkBool32(bool value)65 inline vk::VkBool32 makeVkBool32(bool value)
66 {
67 return (value ? VK_TRUE : VK_FALSE);
68 }
69
70 // Test versions
71 constexpr deUint32 TEST_VERSION_extended_dynamic_state = 1;
72 constexpr deUint32 TEST_VERSION_vertex_input_dynamic_state = 2;
73 constexpr deUint32 TEST_VERSION_extended_dynamic_state2 = 3;
74
75 // Framebuffer size.
76 constexpr deUint32 kFramebufferWidth = 64u;
77 constexpr deUint32 kFramebufferHeight = 64u;
78
79 // Image formats.
80 constexpr vk::VkFormat kColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
81 constexpr vk::VkFormat kIntColorFormat = vk::VK_FORMAT_R8G8B8A8_UINT;
82 const tcu::Vec4 kColorThreshold (0.005f); // 1/255 < 0.005 < 2/255.
83
84 struct DepthStencilFormat
85 {
86 vk::VkFormat imageFormat;
87 float depthThreshold;
88 };
89
90 const DepthStencilFormat kDepthStencilFormats[] =
91 {
92 { vk::VK_FORMAT_D32_SFLOAT_S8_UINT, 0.0f },
93 { vk::VK_FORMAT_D24_UNORM_S8_UINT, 1.0e-07f }, // 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
94 };
95
96 // We will use several data types in vertex bindings. Each type will need to define a few things.
97 class GeometryVertex
98 {
99 public:
100 // For GLSL.
101
102 // Vertex input attribute declarations in GLSL form. One sentence per element.
103 virtual std::vector<std::string> getAttributeDeclarations() const = 0;
104
105 // Get statements to calculate a vec2 called "vertexCoords" using the vertex input attributes.
106 virtual std::vector<std::string> getVertexCoordCalc() const = 0;
107
108
109 // For the pipeline.
110
111 // Vertex attributes for VkPipelineVertexInputStateCreateInfo.
112 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions(deUint32 offset) const = 0;
113
114 // Size of each vertex.
115 virtual size_t getVertexDataSize() const = 0;
116
117 // Array of bytes containing vertex data. .size() should match getVertexDataSize().
118 virtual std::vector<deUint8> getVertexData() const = 0;
119
120 // Offset to the coords data.
121 virtual size_t getCoordsOffset() const = 0;
122
123 // Offset to the padding data.
124 virtual size_t getPaddingOffset() const = 0;
125 };
126
127 // Vertices in buffers will have 2 components and a padding to properly test the stride.
128 // This is the vertex type that will be used normally.
129 class VertexWithPadding : public GeometryVertex
130 {
131 protected:
132 tcu::Vec2 coords;
133 tcu::Vec2 padding;
134
135 public:
VertexWithPadding(const tcu::Vec2 & coords_)136 VertexWithPadding (const tcu::Vec2& coords_)
137 : coords (coords_)
138 , padding (0.0f, 0.0f)
139 {}
140
getAttributeDeclarations() const141 virtual std::vector<std::string> getAttributeDeclarations() const override
142 {
143 std::vector<std::string> declarations;
144 declarations.push_back("layout(location=0) in vec2 position;");
145 return declarations;
146 }
147
getVertexCoordCalc() const148 virtual std::vector<std::string> getVertexCoordCalc() const override
149 {
150 std::vector<std::string> statements;
151 statements.push_back("vec2 vertexCoords = position;");
152 return statements;
153 }
154
getAttributeDescriptions(deUint32 offset) const155 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions(deUint32 offset) const override
156 {
157 std::vector<vk::VkVertexInputAttributeDescription> descriptions;
158 descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, offset));
159 return descriptions;
160 }
161
getVertexDataSize() const162 virtual size_t getVertexDataSize() const override
163 {
164 return sizeof(coords) + sizeof(padding);
165 }
166
getVertexData() const167 virtual std::vector<deUint8> getVertexData() const override
168 {
169 const auto dataSize = getVertexDataSize();
170 std::vector<deUint8> vertexData (dataSize);
171
172 deMemcpy(&vertexData[0], &coords, sizeof(coords));
173 deMemcpy(&vertexData[sizeof(coords)], &padding, sizeof(padding));
174 return vertexData;
175 }
176
getCoordsOffset() const177 virtual size_t getCoordsOffset() const override
178 {
179 return 0;
180 }
181
getPaddingOffset() const182 virtual size_t getPaddingOffset() const override
183 {
184 return sizeof coords;
185 }
186 };
187
188 class VertexWithExtraAttributes : public GeometryVertex
189 {
190 protected:
191 tcu::Vec2 coords;
192 tcu::Vec2 padding[10];
193 tcu::Vec2 ones;
194
195 public:
VertexWithExtraAttributes(const tcu::Vec2 & coords_)196 VertexWithExtraAttributes (const tcu::Vec2& coords_)
197 : coords (coords_)
198 , ones (1.0f, 1.0f)
199 {
200 deMemset(padding, 0, sizeof(padding));
201 }
202
getAttributeDeclarations() const203 virtual std::vector<std::string> getAttributeDeclarations() const override
204 {
205 std::vector<std::string> declarations;
206 declarations.push_back("layout(location=0) in vec2 position;");
207 declarations.push_back("layout(location=1) in vec2 ones;");
208 return declarations;
209 }
210
getVertexCoordCalc() const211 virtual std::vector<std::string> getVertexCoordCalc() const override
212 {
213 std::vector<std::string> statements;
214 statements.push_back("vec2 vertexCoords = position;");
215 statements.push_back("vertexCoords = vertexCoords * ones;");
216 return statements;
217 }
218
getAttributeDescriptions(deUint32 offset) const219 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions(deUint32 offset) const override
220 {
221 std::vector<vk::VkVertexInputAttributeDescription> descriptions;
222 descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, offset));
223 descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(sizeof(coords) + sizeof(padding))));
224 return descriptions;
225 }
226
getVertexDataSize() const227 virtual size_t getVertexDataSize() const override
228 {
229 return sizeof(coords) + sizeof(padding) + sizeof(ones);
230 }
231
getVertexData() const232 virtual std::vector<deUint8> getVertexData() const override
233 {
234 const auto dataSize = getVertexDataSize();
235 std::vector<deUint8> vertexData (dataSize);
236
237 deMemcpy(&vertexData[0], &coords, sizeof(coords));
238 deMemcpy(&vertexData[sizeof(coords)], &padding, sizeof(padding));
239 deMemcpy(&vertexData[sizeof(coords) + sizeof(padding)], &ones, sizeof(ones));
240 return vertexData;
241 }
242
getCoordsOffset() const243 virtual size_t getCoordsOffset() const override
244 {
245 return 0;
246 }
247
getPaddingOffset() const248 virtual size_t getPaddingOffset() const override
249 {
250 return sizeof coords;
251 }
252 };
253
254 constexpr auto kCoordsSize = static_cast<vk::VkDeviceSize>(sizeof(tcu::Vec2));
255
256 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
257 struct StencilOpParams
258 {
259 vk::VkStencilFaceFlags faceMask;
260 vk::VkStencilOp failOp;
261 vk::VkStencilOp passOp;
262 vk::VkStencilOp depthFailOp;
263 vk::VkCompareOp compareOp;
264 };
265
266 const StencilOpParams kDefaultStencilOpParams =
267 {
268 vk::VK_STENCIL_FACE_FRONT_AND_BACK,
269 vk::VK_STENCIL_OP_KEEP,
270 vk::VK_STENCIL_OP_KEEP,
271 vk::VK_STENCIL_OP_KEEP,
272 vk::VK_COMPARE_OP_ALWAYS
273 };
274
275 using ViewportVec = std::vector<vk::VkViewport>;
276 using ScissorVec = std::vector<vk::VkRect2D>;
277 using StencilOpVec = std::vector<StencilOpParams>;
278
279 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
280 template<typename T>
281 struct StaticAndDynamicPair
282 {
283 T staticValue;
284 tcu::Maybe<T> dynamicValue;
285
286 // Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair287 StaticAndDynamicPair (const T& value)
288 : staticValue (value)
289 , dynamicValue (tcu::nothing<T>())
290 {
291 }
292
293 // Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair294 StaticAndDynamicPair (const T& sVal, const T& dVal)
295 : staticValue (sVal)
296 , dynamicValue (tcu::just<T>(dVal))
297 {
298 }
299
300 // If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anonc593e7400111::StaticAndDynamicPair301 void swapValues (void)
302 {
303 if (!dynamicValue)
304 return;
305 std::swap(staticValue, dynamicValue.get());
306 }
307 };
308
309 // For anything boolean, see below.
310 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
311
312 // Configuration for every aspect of the extended dynamic state.
313 using CullModeConfig = StaticAndDynamicPair<vk::VkCullModeFlags>;
314 using FrontFaceConfig = StaticAndDynamicPair<vk::VkFrontFace>;
315 using TopologyConfig = StaticAndDynamicPair<vk::VkPrimitiveTopology>;
316 using ViewportConfig = StaticAndDynamicPair<ViewportVec>; // At least one element.
317 using ScissorConfig = StaticAndDynamicPair<ScissorVec>; // At least one element.
318 using StrideConfig = StaticAndDynamicPair<vk::VkDeviceSize>;
319 using DepthTestEnableConfig = BooleanFlagConfig;
320 using DepthWriteEnableConfig = BooleanFlagConfig;
321 using DepthCompareOpConfig = StaticAndDynamicPair<vk::VkCompareOp>;
322 using DepthBoundsTestEnableConfig = BooleanFlagConfig;
323 using StencilTestEnableConfig = BooleanFlagConfig;
324 using StencilOpConfig = StaticAndDynamicPair<StencilOpVec>; // At least one element.
325 using VertexInputConfig = StaticAndDynamicPair<deUint32>;
326 using DepthBiasEnableConfig = BooleanFlagConfig;
327 using RastDiscardEnableConfig = BooleanFlagConfig;
328 using PrimRestartEnableConfig = BooleanFlagConfig;
329 using LogicOpConfig = StaticAndDynamicPair<vk::VkLogicOp>;
330 using PatchControlPointsConfig = StaticAndDynamicPair<deUint8>;
331
332 const tcu::Vec4 kDefaultTriangleColor (0.0f, 0.0f, 1.0f, 1.0f); // Opaque blue.
333 const tcu::Vec4 kDefaultClearColor (0.0f, 0.0f, 0.0f, 1.0f); // Opaque black.
334 const tcu::Vec4 kGreenClearColor (0.0f, 1.0f, 0.0f, 1.0f); // Opaque green.
335 const tcu::Vec4 kCyanColor (0.0f, 1.0f, 1.0f, 1.0f); // Opaque cyan
336
337 struct MeshParams
338 {
339 tcu::Vec4 color;
340 float depth;
341 bool reversed;
342 float scaleX;
343 float scaleY;
344 float offsetX;
345 float offsetY;
346
MeshParamsvkt::pipeline::__anonc593e7400111::MeshParams347 MeshParams (const tcu::Vec4& color_ = kDefaultTriangleColor,
348 float depth_ = 0.0f,
349 bool reversed_ = false,
350 float scaleX_ = 1.0f,
351 float scaleY_ = 1.0f,
352 float offsetX_ = 0.0f,
353 float offsetY_ = 0.0f)
354 : color (color_)
355 , depth (depth_)
356 , reversed (reversed_)
357 , scaleX (scaleX_)
358 , scaleY (scaleY_)
359 , offsetX (offsetX_)
360 , offsetY (offsetY_)
361 {}
362 };
363
364 enum class SequenceOrdering
365 {
366 CMD_BUFFER_START = 0, // Set state at the start of the command buffer.
367 BEFORE_DRAW = 1, // After binding dynamic pipeline and just before drawing.
368 BETWEEN_PIPELINES = 2, // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
369 AFTER_PIPELINES = 3, // After a static state pipeline and a second dynamic state pipeline have been bound.
370 BEFORE_GOOD_STATIC = 4, // Before a static state pipeline with the correct values has been bound.
371 TWO_DRAWS_DYNAMIC = 5, // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
372 TWO_DRAWS_STATIC = 6, // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
373 };
374
375 using ReferenceColorGenerator = std::function<void(tcu::PixelBufferAccess&)>;
376
377 // Most tests expect a single output color in the whole image.
378 class SingleColorGenerator
379 {
380 public:
SingleColorGenerator(const tcu::Vec4 & color)381 SingleColorGenerator (const tcu::Vec4& color)
382 : m_color(color)
383 {}
384
operator ()(tcu::PixelBufferAccess & access)385 void operator()(tcu::PixelBufferAccess& access)
386 {
387 constexpr auto kWidth = static_cast<int>(kFramebufferWidth);
388 constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
389
390 for (int y = 0; y < kHeight; ++y)
391 for (int x = 0; x < kWidth; ++x)
392 {
393 access.setPixel(m_color, x, y);
394 }
395 }
396
397 private:
398 const tcu::Vec4 m_color;
399 };
400
401 // Some tests expect the upper half and the lower half having different color values.
402 class HorizontalSplitGenerator
403 {
404 public:
HorizontalSplitGenerator(const tcu::Vec4 & top,const tcu::Vec4 & bottom)405 HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
406 : m_top(top), m_bottom(bottom)
407 {}
408
operator ()(tcu::PixelBufferAccess & access)409 void operator()(tcu::PixelBufferAccess& access)
410 {
411 constexpr auto kWidth = static_cast<int>(kFramebufferWidth);
412 constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
413 constexpr auto kHalfHeight = kHeight / 2;
414
415 for (int y = 0; y < kHeight; ++y)
416 for (int x = 0; x < kWidth; ++x)
417 {
418 const auto& color = (y < kHalfHeight ? m_top : m_bottom);
419 access.setPixel(color, x, y);
420 }
421 }
422
423 private:
424 const tcu::Vec4 m_top;
425 const tcu::Vec4 m_bottom;
426 };
427
428 using VertexFactory = de::MovePtr<GeometryVertex> (*)(const tcu::Vec2&);
429
getVertexWithPadding(const tcu::Vec2 & coords)430 de::MovePtr<GeometryVertex> getVertexWithPadding(const tcu::Vec2& coords)
431 {
432 return de::MovePtr<GeometryVertex>(new VertexWithPadding(coords));
433 }
434
getVertexWithExtraAttributes(const tcu::Vec2 & coords)435 de::MovePtr<GeometryVertex> getVertexWithExtraAttributes(const tcu::Vec2& coords)
436 {
437 return de::MovePtr<GeometryVertex>(new VertexWithExtraAttributes(coords));
438 }
439
440 struct TestConfig
441 {
442 // Main sequence ordering.
443 SequenceOrdering sequenceOrdering;
444
445 // Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
446 std::vector<MeshParams> meshParams; // Mesh parameters for each full-screen layer of geometry.
447 deUint32 referenceStencil; // Reference stencil value.
448
449 // Clearing parameters for the framebuffer.
450 tcu::Vec4 clearColorValue;
451 float clearDepthValue;
452 deUint32 clearStencilValue;
453
454 // Expected output in the attachments.
455 ReferenceColorGenerator referenceColor;
456 float expectedDepth;
457 deUint32 expectedStencil;
458
459 // Depth bounds parameters for the pipeline.
460 float minDepthBounds;
461 float maxDepthBounds;
462
463 // Force inclusion of passthrough geometry shader or not.
464 bool forceGeometryShader;
465
466 // Version 1 = VK_EXT_extended_dynamic_state
467 // Version 2 = VK_EXT_vertex_input_dynamic_state
468 // Version 3 = VK_EXT_extended_dynamic_state2
469 deUint32 testExtendedDynamicStateVersion;
470
471 // For VK_EXT_extended_dynamic_state2
472 bool testExtendedDynamicState2LogicOp;
473 bool testExtendedDynamicState2PatchControlPoints;
474
475 // Use index buffer for rendering
476 bool useIndexBuffer;
477
478 bool useTessellation;
479
480 // Vertex factory function.
481 VertexFactory vertexFactory;
482
483 // Offset and extra room after the vertex buffer data.
484 vk::VkDeviceSize vertexDataOffset;
485 vk::VkDeviceSize vertexDataExtraBytes;
486
487 // Static and dynamic pipeline configuration.
488 CullModeConfig cullModeConfig;
489 FrontFaceConfig frontFaceConfig;
490 TopologyConfig topologyConfig;
491 ViewportConfig viewportConfig;
492 ScissorConfig scissorConfig;
493 StrideConfig strideConfig;
494 DepthTestEnableConfig depthTestEnableConfig;
495 DepthWriteEnableConfig depthWriteEnableConfig;
496 DepthCompareOpConfig depthCompareOpConfig;
497 DepthBoundsTestEnableConfig depthBoundsTestEnableConfig;
498 StencilTestEnableConfig stencilTestEnableConfig;
499 StencilOpConfig stencilOpConfig;
500 VertexInputConfig vertexInputConfig;
501 DepthBiasEnableConfig depthBiasEnableConfig;
502 RastDiscardEnableConfig rastDiscardEnableConfig;
503 PrimRestartEnableConfig primRestartEnableConfig;
504 LogicOpConfig logicOpConfig;
505 PatchControlPointsConfig patchControlPointsConfig;
506
507 // Sane defaults.
TestConfigvkt::pipeline::__anonc593e7400111::TestConfig508 TestConfig (SequenceOrdering ordering, VertexFactory vertexFactory_ = getVertexWithPadding)
509 : sequenceOrdering (ordering)
510 , meshParams (1u, MeshParams())
511 , referenceStencil (0u)
512 , clearColorValue (kDefaultClearColor)
513 , clearDepthValue (1.0f)
514 , clearStencilValue (0u)
515 , referenceColor (SingleColorGenerator(kDefaultTriangleColor))
516 , expectedDepth (1.0f)
517 , expectedStencil (0u)
518 , minDepthBounds (0.0f)
519 , maxDepthBounds (1.0f)
520 , forceGeometryShader (false)
521 , testExtendedDynamicStateVersion(TEST_VERSION_extended_dynamic_state)
522 , testExtendedDynamicState2LogicOp(false)
523 , testExtendedDynamicState2PatchControlPoints(false)
524 , useIndexBuffer (false)
525 , useTessellation (false)
526 , vertexFactory (vertexFactory_)
527 , vertexDataOffset (0ull)
528 , vertexDataExtraBytes (0ull)
529 , cullModeConfig (static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
530 , frontFaceConfig (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
531 // By default we will use a triangle fan with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
532 , topologyConfig (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN)
533 , viewportConfig (ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
534 , scissorConfig (ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
535 // By default, the vertex stride is the size of a vertex according to the chosen vertex type.
536 , strideConfig (static_cast<vk::VkDeviceSize>(vertexFactory(tcu::Vec2(0.0f, 0.0f))->getVertexDataSize()))
537 , depthTestEnableConfig (false)
538 , depthWriteEnableConfig (false)
539 , depthCompareOpConfig (vk::VK_COMPARE_OP_NEVER)
540 , depthBoundsTestEnableConfig (false)
541 , stencilTestEnableConfig (false)
542 , stencilOpConfig (StencilOpVec(1u, kDefaultStencilOpParams))
543 , vertexInputConfig (static_cast<deUint32>(vertexFactory(tcu::Vec2(0.0f, 0.0f))->getCoordsOffset()))
544 , depthBiasEnableConfig (false)
545 , rastDiscardEnableConfig (false)
546 , primRestartEnableConfig (false)
547 , logicOpConfig (vk::VK_LOGIC_OP_CLEAR)
548 , patchControlPointsConfig (1)
549 , m_swappedValues (false)
550 {
551 }
552
553 // Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anonc593e7400111::TestConfig554 const ViewportVec& getActiveViewportVec () const
555 {
556 return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() : viewportConfig.staticValue);
557 }
558
559 // Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anonc593e7400111::TestConfig560 bool isMultiViewport () const
561 {
562 return (getActiveViewportVec().size() > 1);
563 }
564
565 // Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anonc593e7400111::TestConfig566 bool needsGeometryShader () const
567 {
568 // Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
569 // commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
570 return (isMultiViewport() || forceGeometryShader);
571 }
572
573 // Returns true if we should use the static and dynamic values exchanged.
574 // This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anonc593e7400111::TestConfig575 bool isReversed () const
576 {
577 return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
578 sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
579 }
580
581 // Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anonc593e7400111::TestConfig582 void swapValues ()
583 {
584 cullModeConfig.swapValues();
585 frontFaceConfig.swapValues();
586 topologyConfig.swapValues();
587 viewportConfig.swapValues();
588 scissorConfig.swapValues();
589 strideConfig.swapValues();
590 depthTestEnableConfig.swapValues();
591 depthWriteEnableConfig.swapValues();
592 depthCompareOpConfig.swapValues();
593 depthBoundsTestEnableConfig.swapValues();
594 stencilTestEnableConfig.swapValues();
595 stencilOpConfig.swapValues();
596 vertexInputConfig.swapValues();
597 depthBiasEnableConfig.swapValues();
598 rastDiscardEnableConfig.swapValues();
599 primRestartEnableConfig.swapValues();
600 logicOpConfig.swapValues();
601 patchControlPointsConfig.swapValues();
602
603 m_swappedValues = !m_swappedValues;
604 }
605
606 // Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anonc593e7400111::TestConfig607 deUint32 numIterations () const
608 {
609 deUint32 iterations = 0u;
610
611 switch (sequenceOrdering)
612 {
613 case SequenceOrdering::TWO_DRAWS_DYNAMIC:
614 case SequenceOrdering::TWO_DRAWS_STATIC:
615 iterations = 2u;
616 break;
617 default:
618 iterations = 1u;
619 break;
620 }
621
622 return iterations;
623 }
624
625 private:
626 // Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
627 // has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
628 // expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
629 // pipeline with wrong values and a static one with good values.
630 //
631 // Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
632 // dynamic values and to know if we should do it for a given test case. However, we need to know were the good value is at any
633 // given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
634 bool m_swappedValues;
635 };
636
637 struct PushConstants
638 {
639 tcu::Vec4 triangleColor;
640 float meshDepth;
641 deInt32 viewPortIndex;
642 float scaleX;
643 float scaleY;
644 float offsetX;
645 float offsetY;
646 };
647
copy(vk::VkStencilOpState & dst,const StencilOpParams & src)648 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
649 {
650 dst.failOp = src.failOp;
651 dst.passOp = src.passOp;
652 dst.depthFailOp = src.depthFailOp;
653 dst.compareOp = src.compareOp;
654 }
655
656 enum class TopologyClass
657 {
658 POINT,
659 LINE,
660 TRIANGLE,
661 PATCH,
662 INVALID,
663 };
664
topologyClassName(TopologyClass tclass)665 std::string topologyClassName (TopologyClass tclass)
666 {
667 switch (tclass)
668 {
669 case TopologyClass::POINT: return "point";
670 case TopologyClass::LINE: return "line";
671 case TopologyClass::TRIANGLE: return "triangle";
672 case TopologyClass::PATCH: return "patch";
673 default:
674 break;
675 }
676
677 DE_ASSERT(false);
678 return "";
679 }
680
getTopologyClass(vk::VkPrimitiveTopology topology)681 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
682 {
683 switch (topology)
684 {
685 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
686 return TopologyClass::POINT;
687 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
688 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
689 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
690 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
691 return TopologyClass::LINE;
692 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
693 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
694 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
695 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
696 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
697 return TopologyClass::TRIANGLE;
698 case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
699 return TopologyClass::PATCH;
700 default:
701 break;
702 }
703
704 DE_ASSERT(false);
705 return TopologyClass::INVALID;
706 }
707
708 class ExtendedDynamicStateTest : public vkt::TestCase
709 {
710 public:
711 ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ExtendedDynamicStateTest(void)712 virtual ~ExtendedDynamicStateTest (void) {}
713
714 virtual void checkSupport (Context& context) const;
715 virtual void initPrograms (vk::SourceCollections& programCollection) const;
716 virtual TestInstance* createInstance (Context& context) const;
717
718 private:
719 TestConfig m_testConfig;
720 };
721
722 class ExtendedDynamicStateInstance : public vkt::TestInstance
723 {
724 public:
725 ExtendedDynamicStateInstance (Context& context, const TestConfig& testConfig);
~ExtendedDynamicStateInstance(void)726 virtual ~ExtendedDynamicStateInstance (void) {}
727
728 virtual tcu::TestStatus iterate (void);
729
730 private:
731 TestConfig m_testConfig;
732 };
733
ExtendedDynamicStateTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)734 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
735 : vkt::TestCase (testCtx, name, description)
736 , m_testConfig (testConfig)
737 {
738 const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
739 DE_UNREF(staticTopologyClass); // For release builds.
740
741 // Matching topology classes.
742 DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
743 staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
744
745 // Supported topology classes for these tests.
746 DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE
747 || staticTopologyClass == TopologyClass::PATCH);
748 }
749
checkSupport(Context & context) const750 void ExtendedDynamicStateTest::checkSupport (Context& context) const
751 {
752 const auto& vki = context.getInstanceInterface();
753 const auto physicalDevice = context.getPhysicalDevice();
754
755 if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_extended_dynamic_state)
756 context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state");
757
758 if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_vertex_input_dynamic_state)
759 context.requireDeviceFunctionality("VK_EXT_vertex_input_dynamic_state");
760
761 // Needed for extended state included as part of VK_EXT_extended_dynamic_state2
762 if (m_testConfig.testExtendedDynamicStateVersion == TEST_VERSION_extended_dynamic_state2) {
763 context.requireDeviceFunctionality("VK_EXT_extended_dynamic_state2");
764
765 const vk::VkPhysicalDeviceExtendedDynamicState2FeaturesEXT& extendedDynamicState2Features = context.getExtendedDynamicState2FeaturesEXT();
766
767 if (m_testConfig.testExtendedDynamicState2LogicOp && extendedDynamicState2Features.extendedDynamicState2LogicOp == DE_FALSE)
768 TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing LogicOp dynamically is not supported");
769
770 if (m_testConfig.testExtendedDynamicState2PatchControlPoints && extendedDynamicState2Features.extendedDynamicState2PatchControlPoints == DE_FALSE)
771 TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing patch control points dynamically is not supported");
772 }
773
774 // Check the number of viewports needed and the corresponding limits.
775 const auto& viewportConfig = m_testConfig.viewportConfig;
776 auto numViewports = viewportConfig.staticValue.size();
777
778 if (viewportConfig.dynamicValue)
779 numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
780
781 if (numViewports > 1)
782 {
783 const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
784 if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
785 TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
786 }
787
788 const auto& dbTestEnable = m_testConfig.depthBoundsTestEnableConfig;
789 const bool useDepthBounds = (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
790 if (useDepthBounds || m_testConfig.needsGeometryShader())
791 {
792 const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
793
794 // Check depth bounds test support.
795 if (useDepthBounds && !features.depthBounds)
796 TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
797
798 // Check geometry shader support.
799 if (m_testConfig.needsGeometryShader() && !features.geometryShader)
800 TCU_THROW(NotSupportedError, "Geometry shader not supported");
801
802 // Check tessellation support
803 if (m_testConfig.useTessellation && !features.tessellationShader)
804 TCU_THROW(NotSupportedError, "Tessellation feature not supported");
805 }
806
807 // Check color image format support (depth/stencil will be chosen at runtime).
808 const vk::VkFormatFeatureFlags kColorFeatures = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
809
810 // Pick int color format for logic op
811 vk::VkFormat colorFormat = m_testConfig.logicOpConfig.dynamicValue ? kIntColorFormat : kColorFormat;
812 const auto colorProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, colorFormat);
813
814 if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
815 TCU_THROW(NotSupportedError, "Required color image features not supported");
816 }
817
initPrograms(vk::SourceCollections & programCollection) const818 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
819 {
820 std::ostringstream pushSource;
821 std::ostringstream vertSource;
822 std::ostringstream fragSource;
823 std::ostringstream geomSource;
824 std::ostringstream tescSource;
825 std::ostringstream teseSource;
826
827 pushSource
828 << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
829 << " vec4 triangleColor;\n"
830 << " float depthValue;\n"
831 << " int viewPortIndex;\n"
832 << " float scaleX;\n"
833 << " float scaleY;\n"
834 << " float offsetX;\n"
835 << " float offsetY;\n"
836 << "} pushConstants;\n"
837 ;
838 const auto pushConstants = pushSource.str();
839
840 const auto dummyVertex = m_testConfig.vertexFactory(tcu::Vec2(0.0f, 0.0f));
841 const auto attribDecls = dummyVertex->getAttributeDeclarations();
842 const auto coordCalcs = dummyVertex->getVertexCoordCalc();
843 std::ostringstream attributes;
844 std::ostringstream calculations;
845
846 for (const auto& decl : attribDecls)
847 attributes << decl << "\n";
848
849 for (const auto& statement : coordCalcs)
850 calculations << " " << statement << "\n";
851
852 vertSource
853 << "#version 450\n"
854 << pushConstants
855 << attributes.str()
856 << "out gl_PerVertex\n"
857 << "{\n"
858 << " vec4 gl_Position;\n"
859 << "};\n"
860 << "void main() {\n"
861 << calculations.str()
862 << " gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
863 << "}\n"
864 ;
865
866 fragSource
867 << "#version 450\n"
868 << pushConstants
869 << "layout(location=0) out vec4 color;\n"
870 << "void main() {\n"
871 << " color = pushConstants.triangleColor;\n"
872 << "}\n"
873 ;
874
875 if (m_testConfig.needsGeometryShader())
876 {
877 const auto topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
878 const std::string inputPrimitive = ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
879 const deUint32 vertexCount = ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
880 const std::string outputPrimitive = ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
881
882 geomSource
883 << "#version 450\n"
884 << "layout (" << inputPrimitive << ") in;\n"
885 << "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
886 << (m_testConfig.isMultiViewport() ? pushConstants : "")
887 << "in gl_PerVertex\n"
888 << "{\n"
889 << " vec4 gl_Position;\n"
890 << "} gl_in[" << vertexCount << "];\n"
891 << "out gl_PerVertex\n"
892 << "{\n"
893 << " vec4 gl_Position;\n"
894 << "};\n"
895 << "void main() {\n"
896 << (m_testConfig.isMultiViewport() ? " gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "")
897 ;
898
899 for (deUint32 i = 0; i < vertexCount; ++i)
900 {
901 geomSource
902 << " gl_Position = gl_in[" << i << "].gl_Position;\n"
903 << " EmitVertex();\n"
904 ;
905 }
906
907 geomSource
908 << "}\n"
909 ;
910 }
911
912 if (m_testConfig.useTessellation)
913 {
914 tescSource
915 << "#version 450\n"
916 << "#extension GL_EXT_tessellation_shader : require\n"
917 << "layout(vertices=3) out;\n"
918 << "in gl_PerVertex\n"
919 << "{\n"
920 << " vec4 gl_Position;\n"
921 << "} gl_in[];\n"
922 << "void main() {\n"
923 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
924 << " gl_TessLevelOuter[0] = 3.0;\n"
925 << " gl_TessLevelOuter[1] = 3.0;\n"
926 << " gl_TessLevelOuter[2] = 3.0;\n"
927 << " gl_TessLevelInner[0] = 3.0;\n"
928 << "}\n"
929 ;
930 teseSource
931 << "#version 450\n"
932 << "#extension GL_EXT_tessellation_shader : require\n"
933 << "layout(triangles) in;\n"
934 << "void main() {\n"
935 << " gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
936 << " gl_in[1].gl_Position * gl_TessCoord.y + \n"
937 << " gl_in[2].gl_Position * gl_TessCoord.z);\n"
938 << "}\n";
939 ;
940 }
941
942
943 programCollection.glslSources.add("vert") << glu::VertexSource(vertSource.str());
944 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
945 if (m_testConfig.needsGeometryShader())
946 programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
947 if (m_testConfig.useTessellation)
948 {
949 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
950 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
951 }
952 }
953
createInstance(Context & context) const954 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
955 {
956 return new ExtendedDynamicStateInstance(context, m_testConfig);
957 }
958
ExtendedDynamicStateInstance(Context & context,const TestConfig & testConfig)959 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
960 : vkt::TestInstance (context)
961 , m_testConfig (testConfig)
962 {
963 }
964
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)965 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
966 {
967 log << tcu::TestLog::ImageSet(setName, setDesc)
968 << tcu::TestLog::Image(setName + "Result", "Result image", result)
969 << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
970 << tcu::TestLog::EndImageSet;
971 }
972
973 // Fill a section of the given buffer (from offset to offset+count) with repeating copies of the given data.
fillWithPattern(vk::BufferWithMemory & buffer,size_t offset,size_t count,const void * src,size_t srcSize)974 void fillWithPattern(vk::BufferWithMemory& buffer, size_t offset, size_t count, const void* src, size_t srcSize)
975 {
976 auto& alloc = buffer.getAllocation();
977 auto ptr = reinterpret_cast<char*>(alloc.getHostPtr());
978 size_t done = 0u;
979 size_t pending = count;
980
981 while (pending > 0u)
982 {
983 const size_t stepSize = de::min(srcSize, pending);
984 deMemcpy(ptr + offset + done, src, stepSize);
985 done += stepSize;
986 pending -= stepSize;
987 }
988 }
989
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)990 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
991 {
992 auto& alloc = buffer.getAllocation();
993 auto dst = reinterpret_cast<char*>(alloc.getHostPtr());
994
995 deMemcpy(dst + offset, src, size);
996 vk::flushAlloc(vkd, device, alloc);
997 }
998
concatenateVertexData(const std::vector<GeometryVertex * > & vertices)999 std::vector<deUint8> concatenateVertexData(const std::vector<GeometryVertex*>& vertices)
1000 {
1001 std::vector<deUint8> concatenatedData;
1002
1003 if (vertices.empty())
1004 return concatenatedData;
1005
1006 const auto dataSize = vertices.size() * vertices[0]->getVertexDataSize();
1007 concatenatedData.reserve(dataSize);
1008
1009 auto backInserter = std::back_inserter(concatenatedData);
1010 for (const auto ptr : vertices)
1011 {
1012 const auto singleData = ptr->getVertexData();
1013 std::copy(begin(singleData), end(singleData), backInserter);
1014 }
1015
1016 return concatenatedData;
1017 }
1018
1019 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)1020 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
1021 {
1022 if (testConfig.cullModeConfig.dynamicValue)
1023 vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
1024
1025 if (testConfig.frontFaceConfig.dynamicValue)
1026 vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
1027
1028 if (testConfig.topologyConfig.dynamicValue)
1029 vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
1030
1031 if (testConfig.viewportConfig.dynamicValue)
1032 {
1033 const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
1034 vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
1035 }
1036
1037 if (testConfig.scissorConfig.dynamicValue)
1038 {
1039 const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
1040 vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
1041 }
1042
1043 if (testConfig.depthTestEnableConfig.dynamicValue)
1044 vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
1045
1046 if (testConfig.depthWriteEnableConfig.dynamicValue)
1047 vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
1048
1049 if (testConfig.depthCompareOpConfig.dynamicValue)
1050 vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
1051
1052 if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
1053 vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
1054
1055 if (testConfig.stencilTestEnableConfig.dynamicValue)
1056 vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
1057
1058 if (testConfig.depthBiasEnableConfig.dynamicValue)
1059 vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
1060
1061 if (testConfig.rastDiscardEnableConfig.dynamicValue)
1062 vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
1063
1064 if (testConfig.primRestartEnableConfig.dynamicValue)
1065 vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
1066
1067 if (testConfig.logicOpConfig.dynamicValue)
1068 vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
1069
1070 if (testConfig.patchControlPointsConfig.dynamicValue)
1071 vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
1072
1073 if (testConfig.stencilOpConfig.dynamicValue)
1074 {
1075 for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
1076 vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
1077 }
1078
1079 if (testConfig.vertexInputConfig.dynamicValue)
1080 {
1081 const vk::VkVertexInputBindingDescription2EXT vertexBinding =
1082 {
1083 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT, // VkStructureType sType;
1084 nullptr, // void* pNext;
1085 0u, // deUint32 binding;
1086 static_cast<deUint32>(testConfig.strideConfig.staticValue), // deUint32 stride;
1087 vk::VK_VERTEX_INPUT_RATE_VERTEX, // VkVertexInputRate inputRate;
1088 1u, // deUint32 divisor;
1089 };
1090 const vk::VkVertexInputAttributeDescription2EXT vertexAttribute =
1091 {
1092 vk::VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, // VkStructureType sType;
1093 nullptr, // void* pNext;
1094 0u, // deUint32 location;
1095 0u, // deUint32 binding;
1096 vk::VK_FORMAT_R32G32_SFLOAT, // VkFormat format;
1097 static_cast<deUint32>(testConfig.vertexInputConfig.dynamicValue.get()), // deUint32 offset;
1098 };
1099 vkd.cmdSetVertexInputEXT(cmdBuffer, 1, &vertexBinding, 1, &vertexAttribute);
1100 }
1101 }
1102
1103 // Bind the appropriate vertex buffer with a dynamic stride if the test configuration needs a dynamic stride.
1104 // Return true if the vertex buffer was bound.
maybeBindVertexBufferDynStride(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,size_t meshIdx,vk::VkBuffer vertBuffer,vk::VkBuffer rvertBuffer,vk::VkDeviceSize vertDataSize)1105 bool maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, vk::VkBuffer vertBuffer, vk::VkBuffer rvertBuffer, vk::VkDeviceSize vertDataSize)
1106 {
1107 if (testConfig.strideConfig.dynamicValue)
1108 {
1109 const auto& viewportVec = testConfig.getActiveViewportVec();
1110 DE_UNREF(viewportVec); // For release builds.
1111
1112 // When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
1113 // orderings if we have several viewports or meshes.
1114 DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
1115 || testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
1116 || testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1117
1118 const auto strideValue = (testConfig.strideConfig.dynamicValue ? testConfig.strideConfig.dynamicValue.get() : testConfig.strideConfig.staticValue);
1119 vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, 1u, (testConfig.meshParams[meshIdx].reversed ? &rvertBuffer : &vertBuffer), &testConfig.vertexDataOffset, &vertDataSize, &strideValue);
1120 return true;
1121 }
1122
1123 return false;
1124 }
1125
iterate(void)1126 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
1127 {
1128 using ImageWithMemoryVec = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
1129 using ImageViewVec = std::vector<vk::Move<vk::VkImageView>>;
1130 using FramebufferVec = std::vector<vk::Move<vk::VkFramebuffer>>;
1131
1132 const auto& vki = m_context.getInstanceInterface();
1133 const auto& vkd = m_context.getDeviceInterface();
1134 const auto physicalDevice = m_context.getPhysicalDevice();
1135 const auto device = m_context.getDevice();
1136 auto& allocator = m_context.getDefaultAllocator();
1137 const auto queue = m_context.getUniversalQueue();
1138 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
1139 auto& log = m_context.getTestContext().getLog();
1140
1141 const auto kReversed = m_testConfig.isReversed();
1142 const auto kNumIterations = m_testConfig.numIterations();
1143 const auto kSequenceOrdering = m_testConfig.sequenceOrdering;
1144
1145 const auto kFramebufferExtent = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
1146 const vk::VkImageUsageFlags kColorUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1147 const vk::VkImageUsageFlags kDSUsage = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1148 const vk::VkFormatFeatureFlags kDSFeatures = (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1149
1150 // Pick int color format for logic op
1151 vk::VkFormat colorFormat = m_testConfig.logicOpConfig.dynamicValue ? kIntColorFormat : kColorFormat;
1152
1153 // Choose depth/stencil format.
1154 const DepthStencilFormat* dsFormatInfo = nullptr;
1155
1156 for (int formatIdx = 0; formatIdx < DE_LENGTH_OF_ARRAY(kDepthStencilFormats); ++formatIdx)
1157 {
1158 const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormats[formatIdx].imageFormat);
1159 if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
1160 {
1161 dsFormatInfo = kDepthStencilFormats + formatIdx;
1162 break;
1163 }
1164 }
1165
1166 // Note: Not Supported insted of Fail because the transfer feature is not mandatory.
1167 if (!dsFormatInfo)
1168 TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
1169 log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
1170
1171 // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
1172 // where we will bind the static pipeline last before drawing.
1173 if (kReversed)
1174 m_testConfig.swapValues();
1175
1176 // Create color and depth/stencil images.
1177 ImageWithMemoryVec colorImages;
1178 ImageWithMemoryVec dsImages;
1179
1180 const vk::VkImageCreateInfo colorImageInfo =
1181 {
1182 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1183 nullptr, // const void* pNext;
1184 0u, // VkImageCreateFlags flags;
1185 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1186 colorFormat, // VkFormat format;
1187 kFramebufferExtent, // VkExtent3D extent;
1188 1u, // deUint32 mipLevels;
1189 1u, // deUint32 arrayLayers;
1190 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1191 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1192 kColorUsage, // VkImageUsageFlags usage;
1193 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1194 1u, // deUint32 queueFamilyIndexCount;
1195 &queueIndex, // const deUint32* pQueueFamilyIndices;
1196 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1197 };
1198 for (deUint32 i = 0u; i < kNumIterations; ++i)
1199 colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
1200
1201 const vk::VkImageCreateInfo dsImageInfo =
1202 {
1203 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1204 nullptr, // const void* pNext;
1205 0u, // VkImageCreateFlags flags;
1206 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1207 dsFormatInfo->imageFormat, // VkFormat format;
1208 kFramebufferExtent, // VkExtent3D extent;
1209 1u, // deUint32 mipLevels;
1210 1u, // deUint32 arrayLayers;
1211 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1212 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1213 kDSUsage, // VkImageUsageFlags usage;
1214 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1215 1u, // deUint32 queueFamilyIndexCount;
1216 &queueIndex, // const deUint32* pQueueFamilyIndices;
1217 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1218 };
1219 for (deUint32 i = 0u; i < kNumIterations; ++i)
1220 dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
1221
1222 const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1223 const auto dsSubresourceRange = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
1224
1225 ImageViewVec colorImageViews;
1226 ImageViewVec dsImageViews;
1227
1228 for (const auto& img : colorImages)
1229 colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
1230
1231 for (const auto& img : dsImages)
1232 dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
1233
1234 // Vertex buffer.
1235 const auto topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
1236 std::vector<de::MovePtr<GeometryVertex>> vertexPtrs;
1237 std::vector<deUint32> indices{ 0, 1, 2, 3, 0xFFFFFFFF, 4, 5, 0, 3 };
1238
1239 if (topologyClass == TopologyClass::TRIANGLE)
1240 {
1241 // Full-screen triangle fan with 6 vertices.
1242 //
1243 // 4 3 2
1244 // +-------+-------+
1245 // |X X X|
1246 // | X X X |
1247 // | X X X |
1248 // | X X X |
1249 // | X X X |
1250 // | X X X |
1251 // | XXX |
1252 // +-------+-------+
1253 // 5 0 1
1254 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.0f, 1.0f)));
1255 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f, 1.0f)));
1256 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f, -1.0f)));
1257 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.0f, -1.0f)));
1258 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, -1.0f)));
1259 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, 1.0f)));
1260 }
1261 else if (topologyClass == TopologyClass::PATCH)
1262 {
1263 // 2 triangles making a quad
1264 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, 1.0f)));
1265 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, 1.0f)));
1266 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, -1.0f)));
1267 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(1.0f, -1.0f)));
1268 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, -1.0f)));
1269 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, 1.0f)));
1270 }
1271 else // TopologyClass::LINE
1272 {
1273 // 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.
1274 const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
1275 for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
1276 {
1277 // Offset of 0.5 pixels + one line per row from -1 to 1.
1278 const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
1279 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-1.0f, yCoord)));
1280 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2(-0.5f, yCoord)));
1281 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 0.5f, yCoord)));
1282 vertexPtrs.push_back(m_testConfig.vertexFactory(tcu::Vec2( 1.0f, yCoord)));
1283 }
1284 }
1285
1286 std::vector<GeometryVertex*> vertexRawPtrs;
1287 vertexRawPtrs.reserve(vertexPtrs.size());
1288 std::transform(begin(vertexPtrs), end(vertexPtrs), std::back_inserter(vertexRawPtrs),
1289 [](const de::MovePtr<GeometryVertex>& p) { return p.get(); });
1290
1291 // Reversed vertices, except for the first one (0, 5, 4, 3, 2, 1): clockwise mesh for triangles. Not to be used with lines.
1292 std::vector<GeometryVertex*> reversedVertexRawPtrs;
1293 reversedVertexRawPtrs.push_back(vertexRawPtrs[0]);
1294 if (topologyClass == TopologyClass::TRIANGLE)
1295 {
1296 std::copy_n(vertexRawPtrs.rbegin(), vertexRawPtrs.size() - 1u, std::back_inserter(reversedVertexRawPtrs));
1297 }
1298
1299 if (topologyClass == TopologyClass::LINE)
1300 {
1301 for (const auto& mesh : m_testConfig.meshParams)
1302 {
1303 DE_UNREF(mesh); // For release builds.
1304 DE_ASSERT(!mesh.reversed);
1305 }
1306 }
1307
1308 DE_ASSERT(!vertexRawPtrs.empty());
1309 const auto vertDataSize = static_cast<vk::VkDeviceSize>(vertexRawPtrs.size() * vertexRawPtrs[0]->getVertexDataSize());
1310 const auto vertBufferSize = m_testConfig.vertexDataOffset + vertDataSize + m_testConfig.vertexDataExtraBytes;
1311 const auto vertBufferInfo = vk::makeBufferCreateInfo(vertBufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1312 vk::BufferWithMemory vertBuffer (vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
1313 vk::BufferWithMemory rvertBuffer (vkd, device, allocator, vertBufferInfo, vk::MemoryRequirement::HostVisible);
1314
1315
1316 const auto indexDataSize = static_cast<vk::VkDeviceSize>(indices.size() * sizeof(deUint32));
1317 const auto indexBufferInfo = vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1318 vk::BufferWithMemory indexBuffer(vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible);
1319
1320
1321 // Copy data to vertex/index buffers and flush allocations.
1322 {
1323 const auto offScreenVertexPtr = m_testConfig.vertexFactory(tcu::Vec2(0.0f, 3.0f));
1324 const auto offScreenVertex = offScreenVertexPtr->getVertexData();
1325 const auto offScreenVertexSz = offScreenVertex.size();
1326 const auto dataSize = static_cast<size_t>(vertDataSize);
1327 const auto offset = static_cast<size_t>(m_testConfig.vertexDataOffset);
1328 const auto extraSize = static_cast<size_t>(m_testConfig.vertexDataExtraBytes);
1329
1330 std::vector<vk::BufferWithMemory*> buffersToFill = { &vertBuffer, &rvertBuffer };
1331 for (auto b : buffersToFill)
1332 {
1333 // Fill bytes surrounding vertex data with the offScreenVertex.
1334 fillWithPattern(*b, 0u, offset, offScreenVertex.data(), offScreenVertexSz);
1335 fillWithPattern(*b, offset + dataSize, extraSize, offScreenVertex.data(), offScreenVertexSz);
1336 }
1337
1338 // Create vectors with all vertex data and all reversed vertex data concatenated in order to fill the buffers.
1339 const auto vertices = concatenateVertexData(vertexRawPtrs);
1340 const auto reversedVertices = concatenateVertexData(reversedVertexRawPtrs);
1341
1342 copyAndFlush(vkd, device, vertBuffer, offset, vertices.data(), static_cast<size_t>(vertices.size() * sizeof(vertices[0])));
1343 copyAndFlush(vkd, device, rvertBuffer, offset, reversedVertices.data(), static_cast<size_t>(reversedVertices.size() * sizeof(reversedVertices[0])));
1344 copyAndFlush(vkd, device, indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
1345 }
1346
1347 // Descriptor set layout.
1348 vk::DescriptorSetLayoutBuilder layoutBuilder;
1349 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1350
1351 // Pipeline layout.
1352 vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1353 if (m_testConfig.isMultiViewport())
1354 pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1355
1356 const vk::VkPushConstantRange pushConstantRange =
1357 {
1358 pushConstantStageFlags, // VkShaderStageFlags stageFlags;
1359 0u, // deUint32 offset;
1360 static_cast<deUint32>(sizeof(PushConstants)), // deUint32 size;
1361 };
1362
1363 const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1364 {
1365 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1366 nullptr, // const void* pNext;
1367 0u, // VkPipelineLayoutCreateFlags flags;
1368 1u, // deUint32 setLayoutCount;
1369 &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1370 1u, // deUint32 pushConstantRangeCount;
1371 &pushConstantRange, // const VkPushConstantRange* pPushConstantRanges;
1372 };
1373 const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
1374
1375 // Render pass with single subpass.
1376 const vk::VkAttachmentReference colorAttachmentReference =
1377 {
1378 0u, // deUint32 attachment;
1379 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1380 };
1381
1382 const vk::VkAttachmentReference dsAttachmentReference =
1383 {
1384 1u, // deUint32 attachment;
1385 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1386 };
1387
1388 const vk::VkSubpassDescription subpassDescription =
1389 {
1390 0u, // VkSubpassDescriptionFlags flags;
1391 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1392 0u, // deUint32 inputAttachmentCount;
1393 nullptr, // const VkAttachmentReference* pInputAttachments;
1394 1u, // deUint32 colorAttachmentCount;
1395 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
1396 nullptr, // const VkAttachmentReference* pResolveAttachments;
1397 &dsAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment;
1398 0u, // deUint32 preserveAttachmentCount;
1399 nullptr, // const deUint32* pPreserveAttachments;
1400 };
1401
1402 std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
1403
1404 attachmentDescriptions.push_back(vk::VkAttachmentDescription
1405 {
1406 0u, // VkAttachmentDescriptionFlags flags;
1407 colorFormat, // VkFormat format;
1408 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1409 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1410 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1411 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1412 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1413 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1414 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1415 });
1416
1417 attachmentDescriptions.push_back(vk::VkAttachmentDescription
1418 {
1419 0u, // VkAttachmentDescriptionFlags flags;
1420 dsFormatInfo->imageFormat, // VkFormat format;
1421 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1422 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1423 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1424 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
1425 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
1426 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1427 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1428 });
1429
1430 const vk::VkRenderPassCreateInfo renderPassCreateInfo =
1431 {
1432 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1433 nullptr, // const void* pNext;
1434 0u, // VkRenderPassCreateFlags flags;
1435 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
1436 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments;
1437 1u, // deUint32 subpassCount;
1438 &subpassDescription, // const VkSubpassDescription* pSubpasses;
1439 0u, // deUint32 dependencyCount;
1440 nullptr, // const VkSubpassDependency* pDependencies;
1441 };
1442 const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
1443
1444 // Framebuffers.
1445 FramebufferVec framebuffers;
1446
1447 DE_ASSERT(colorImageViews.size() == dsImageViews.size());
1448 for (size_t imgIdx = 0; imgIdx < colorImageViews.size(); ++imgIdx)
1449 {
1450 std::vector<vk::VkImageView> attachments;
1451 attachments.push_back(colorImageViews[imgIdx].get());
1452 attachments.push_back(dsImageViews[imgIdx].get());
1453
1454 const vk::VkFramebufferCreateInfo framebufferCreateInfo =
1455 {
1456 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1457 nullptr, // const void* pNext;
1458 0u, // VkFramebufferCreateFlags flags;
1459 renderPass.get(), // VkRenderPass renderPass;
1460 static_cast<deUint32>(attachments.size()), // deUint32 attachmentCount;
1461 attachments.data(), // const VkImageView* pAttachments;
1462 kFramebufferWidth, // deUint32 width;
1463 kFramebufferHeight, // deUint32 height;
1464 1u, // deUint32 layers;
1465 };
1466
1467 framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
1468 }
1469
1470 // Shader modules.
1471 const auto vertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("vert"), 0u);
1472 const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
1473 vk::Move<vk::VkShaderModule> geomModule;
1474
1475 if (m_testConfig.needsGeometryShader())
1476 geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
1477
1478 vk::Move<vk::VkShaderModule> tescModule;
1479 vk::Move<vk::VkShaderModule> teseModule;
1480
1481 if (m_testConfig.useTessellation)
1482 {
1483 tescModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
1484 teseModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
1485 }
1486
1487 // Shader stages.
1488 std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
1489
1490 vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
1491 {
1492 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
1493 nullptr, // const void* pNext;
1494 0u, // VkPipelineShaderStageCreateFlags flags;
1495 vk::VK_SHADER_STAGE_VERTEX_BIT, // VkShaderStageFlagBits stage;
1496 vertModule.get(), // VkShaderModule module;
1497 "main", // const char* pName;
1498 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
1499 };
1500
1501 shaderStages.push_back(shaderStageCreateInfo);
1502 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_FRAGMENT_BIT;
1503 shaderStageCreateInfo.module = fragModule.get();
1504 shaderStages.push_back(shaderStageCreateInfo);
1505
1506 if (m_testConfig.needsGeometryShader())
1507 {
1508 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1509 shaderStageCreateInfo.module = geomModule.get();
1510 shaderStages.push_back(shaderStageCreateInfo);
1511 }
1512
1513 if (m_testConfig.useTessellation)
1514 {
1515 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
1516 shaderStageCreateInfo.module = tescModule.get();
1517 shaderStages.push_back(shaderStageCreateInfo);
1518
1519 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
1520 shaderStageCreateInfo.module = teseModule.get();
1521 shaderStages.push_back(shaderStageCreateInfo);
1522 }
1523
1524 // Input state.
1525 DE_ASSERT(!vertexRawPtrs.empty());
1526 const auto vertexBinding = vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(m_testConfig.strideConfig.staticValue), vk::VK_VERTEX_INPUT_RATE_VERTEX);
1527 const auto vertexAttributes = vertexRawPtrs[0]->getAttributeDescriptions(static_cast<deUint32>(m_testConfig.vertexInputConfig.staticValue));
1528
1529 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
1530 {
1531 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1532 nullptr, // const void* pNext;
1533 0u, // VkPipelineVertexInputStateCreateFlags flags;
1534 1u, // deUint32 vertexBindingDescriptionCount;
1535 &vertexBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1536 static_cast<deUint32>(vertexAttributes.size()), // deUint32 vertexAttributeDescriptionCount;
1537 vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1538 };
1539
1540 // Input assembly.
1541 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
1542 {
1543 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
1544 nullptr, // const void* pNext;
1545 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
1546 m_testConfig.topologyConfig.staticValue, // VkPrimitiveTopology topology;
1547 makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue), // VkBool32 primitiveRestartEnable;
1548 };
1549
1550 // Viewport state.
1551 if (m_testConfig.viewportConfig.dynamicValue)
1552 DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
1553 else
1554 DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
1555
1556 if (m_testConfig.scissorConfig.dynamicValue)
1557 DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
1558 else
1559 DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
1560
1561 // The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
1562 const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
1563
1564 // For the static pipeline.
1565 const vk::VkPipelineViewportStateCreateInfo staticViewportStateCreateInfo =
1566 {
1567 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
1568 nullptr, // const void* pNext;
1569 0u, // VkPipelineViewportStateCreateFlags flags;
1570 minStaticCount, // deUint32 viewportCount;
1571 m_testConfig.viewportConfig.staticValue.data(), // const VkViewport* pViewports;
1572 minStaticCount, // deUint32 scissorCount;
1573 m_testConfig.scissorConfig.staticValue.data(), // const VkRect2D* pScissors;
1574 };
1575
1576 // For the dynamic pipeline.
1577 const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
1578 ? m_testConfig.viewportConfig.dynamicValue.get().size()
1579 : m_testConfig.viewportConfig.staticValue.size());
1580
1581 const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
1582 ? m_testConfig.scissorConfig.dynamicValue.get().size()
1583 : m_testConfig.scissorConfig.staticValue.size());
1584
1585 const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
1586
1587 // The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
1588 const vk::VkPipelineViewportStateCreateInfo dynamicViewportStateCreateInfo =
1589 {
1590 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
1591 nullptr, // const void* pNext;
1592 0u, // VkPipelineViewportStateCreateFlags flags;
1593 (m_testConfig.viewportConfig.dynamicValue ? 0u : minDynamicCount), // deUint32 viewportCount;
1594 m_testConfig.viewportConfig.staticValue.data(), // const VkViewport* pViewports;
1595 (m_testConfig.scissorConfig.dynamicValue ? 0u : minDynamicCount), // deUint32 scissorCount;
1596 m_testConfig.scissorConfig.staticValue.data(), // const VkRect2D* pScissors;
1597 };
1598
1599 // Rasterization state.
1600 vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
1601 {
1602 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
1603 nullptr, // const void* pNext;
1604 0u, // VkPipelineRasterizationStateCreateFlags flags;
1605 VK_FALSE, // VkBool32 depthClampEnable;
1606 makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue), // VkBool32 rasterizerDiscardEnable;
1607 vk::VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
1608 m_testConfig.cullModeConfig.staticValue, // VkCullModeFlags cullMode;
1609 m_testConfig.frontFaceConfig.staticValue, // VkFrontFace frontFace;
1610 makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue), // VkBool32 depthBiasEnable;
1611 // Change the depth bias parameters if depth bias is dynamic
1612 m_testConfig.depthBiasEnableConfig.dynamicValue ? 2e7f : 0.0f, // float depthBiasConstantFactor;
1613 m_testConfig.depthBiasEnableConfig.dynamicValue ? 0.25f : 0.0f, // float depthBiasClamp;
1614 0.0f, // float depthBiasSlopeFactor;
1615 1.0f, // float lineWidth;
1616 };
1617
1618 // Multisample state.
1619 const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
1620 {
1621 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
1622 nullptr, // const void* pNext;
1623 0u, // VkPipelineMultisampleStateCreateFlags flags;
1624 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
1625 VK_FALSE, // VkBool32 sampleShadingEnable;
1626 0.0f, // float minSampleShading;
1627 nullptr, // const VkSampleMask* pSampleMask;
1628 VK_FALSE, // VkBool32 alphaToCoverageEnable;
1629 VK_FALSE, // VkBool32 alphaToOneEnable;
1630 };
1631
1632 // Depth/stencil state.
1633 vk::VkStencilOpState staticFrontStencil;
1634 vk::VkStencilOpState staticBackStencil;
1635 bool staticFrontStencilSet = false;
1636 bool staticBackStencilSet = false;
1637
1638 // Common setup for the front and back operations.
1639 staticFrontStencil.compareMask = 0xFFu;
1640 staticFrontStencil.writeMask = 0xFFu;
1641 staticFrontStencil.reference = m_testConfig.referenceStencil;
1642 staticBackStencil = staticFrontStencil;
1643
1644 for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
1645 {
1646 if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
1647 {
1648 copy(staticFrontStencil, op);
1649 staticFrontStencilSet = true;
1650 }
1651 if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
1652 {
1653 copy(staticBackStencil, op);
1654 staticBackStencilSet = true;
1655 }
1656 }
1657
1658 // Default values for the static part.
1659 if (!staticFrontStencilSet)
1660 copy(staticFrontStencil, kDefaultStencilOpParams);
1661 if (!staticBackStencilSet)
1662 copy(staticBackStencil, kDefaultStencilOpParams);
1663
1664 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
1665 {
1666 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
1667 nullptr, // const void* pNext;
1668 0u, // VkPipelineDepthStencilStateCreateFlags flags;
1669 makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue), // VkBool32 depthTestEnable;
1670 makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue), // VkBool32 depthWriteEnable;
1671 m_testConfig.depthCompareOpConfig.staticValue, // VkCompareOp depthCompareOp;
1672 makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue), // VkBool32 depthBoundsTestEnable;
1673 makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue), // VkBool32 stencilTestEnable;
1674 staticFrontStencil, // VkStencilOpState front;
1675 staticBackStencil, // VkStencilOpState back;
1676 m_testConfig.minDepthBounds, // float minDepthBounds;
1677 m_testConfig.maxDepthBounds, // float maxDepthBounds;
1678 };
1679
1680 // Dynamic state. Here we will set all states which have a dynamic value.
1681 std::vector<vk::VkDynamicState> dynamicStates;
1682
1683 if (m_testConfig.cullModeConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
1684 if (m_testConfig.frontFaceConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
1685 if (m_testConfig.topologyConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
1686 if (m_testConfig.viewportConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
1687 if (m_testConfig.scissorConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
1688 if (m_testConfig.strideConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
1689 if (m_testConfig.depthTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
1690 if (m_testConfig.depthWriteEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
1691 if (m_testConfig.depthCompareOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
1692 if (m_testConfig.depthBoundsTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
1693 if (m_testConfig.stencilTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
1694 if (m_testConfig.stencilOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
1695 if (m_testConfig.vertexInputConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
1696 if (m_testConfig.depthBiasEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
1697 if (m_testConfig.rastDiscardEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
1698 if (m_testConfig.primRestartEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
1699 if (m_testConfig.logicOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
1700 if (m_testConfig.patchControlPointsConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
1701
1702 const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
1703 {
1704 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
1705 nullptr, // const void* pNext;
1706 0u, // VkPipelineDynamicStateCreateFlags flags;
1707 static_cast<deUint32>(dynamicStates.size()), // deUint32 dynamicStateCount;
1708 dynamicStates.data(), // const VkDynamicState* pDynamicStates;
1709 };
1710
1711 const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
1712 {
1713 VK_FALSE, // VkBool32 blendEnable
1714 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
1715 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
1716 vk::VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
1717 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
1718 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
1719 vk::VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
1720 vk::VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
1721 | vk::VK_COLOR_COMPONENT_G_BIT
1722 | vk::VK_COLOR_COMPONENT_B_BIT
1723 | vk::VK_COLOR_COMPONENT_A_BIT
1724 };
1725
1726 const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
1727 {
1728 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
1729 nullptr, // const void* pNext
1730 0u, // VkPipelineColorBlendStateCreateFlags flags
1731 m_testConfig.logicOpConfig.dynamicValue ? VK_TRUE : VK_FALSE, // VkBool32 logicOpEnable
1732 m_testConfig.logicOpConfig.staticValue, // VkLogicOp logicOp
1733 1u, // deUint32 attachmentCount
1734 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments
1735 { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4]
1736 };
1737
1738 const vk::VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo =
1739 {
1740 vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType
1741 nullptr, // const void* pNext
1742 0u, // VkPipelineTessellationStateCreateFlags flags
1743 m_testConfig.patchControlPointsConfig.staticValue, // uint32_t patchControlPoints
1744 };
1745
1746 const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
1747 {
1748 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
1749 nullptr, // const void* pNext;
1750 0u, // VkPipelineCreateFlags flags;
1751 static_cast<deUint32>(shaderStages.size()), // deUint32 stageCount;
1752 shaderStages.data(), // const VkPipelineShaderStageCreateInfo* pStages;
1753 &vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
1754 &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
1755 m_testConfig.useTessellation ? &pipelineTessellationStateCreateInfo : nullptr, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
1756 nullptr, // const VkPipelineViewportStateCreateInfo * pViewportState;
1757 &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
1758 &multisampleStateCreateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
1759 &depthStencilStateCreateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
1760 &colorBlendStateCreateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
1761 nullptr, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
1762 pipelineLayout.get(), // VkPipelineLayout layout;
1763 renderPass.get(), // VkRenderPass renderPass;
1764 0u, // deUint32 subpass;
1765 DE_NULL, // VkPipeline basePipelineHandle;
1766 0, // deInt32 basePipelineIndex;
1767 };
1768
1769 vk::Move<vk::VkPipeline> staticPipeline;
1770 const bool bindStaticFirst = (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
1771 kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
1772 kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
1773 const bool useStaticPipeline = (bindStaticFirst || kReversed);
1774
1775 // Create static pipeline when needed.
1776 if (useStaticPipeline)
1777 {
1778 auto staticPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
1779 staticPipelineCreateInfo.pViewportState = &staticViewportStateCreateInfo;
1780 staticPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
1781 }
1782
1783 // Create dynamic pipeline.
1784 vk::Move<vk::VkPipeline> graphicsPipeline;
1785 {
1786 auto dynamicPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
1787 dynamicPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
1788 dynamicPipelineCreateInfo.pViewportState = &dynamicViewportStateCreateInfo;
1789 graphicsPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
1790 }
1791
1792 // Command buffer.
1793 const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
1794 const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1795 const auto cmdBuffer = cmdBufferPtr.get();
1796
1797 // Clear values, clear to green for dynamic logicOp
1798 std::vector<vk::VkClearValue> clearValues;
1799 if (m_testConfig.logicOpConfig.dynamicValue)
1800 m_testConfig.clearColorValue = kGreenClearColor;
1801 clearValues.push_back(vk::makeClearValueColor(m_testConfig.clearColorValue));
1802 clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
1803
1804 // Record command buffer.
1805 vk::beginCommandBuffer(vkd, cmdBuffer);
1806
1807 for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
1808 {
1809 // Track in-advance vertex buffer binding.
1810 bool boundInAdvance = false;
1811
1812 // Maybe set extended dynamic state here.
1813 if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
1814 {
1815 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1816 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1817 }
1818
1819 // Begin render pass.
1820 vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
1821
1822 // Bind a static pipeline first if needed.
1823 if (bindStaticFirst && iteration == 0u)
1824 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
1825
1826 // Maybe set extended dynamic state here.
1827 if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
1828 {
1829 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1830 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1831 }
1832
1833 // Bind dynamic pipeline.
1834 if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
1835 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
1836 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
1837 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
1838 {
1839 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
1840 }
1841
1842 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
1843 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
1844 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
1845 {
1846 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1847 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1848 }
1849
1850 // Bind a static pipeline last if needed.
1851 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
1852 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
1853 {
1854 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
1855 }
1856
1857 const auto& viewportVec = m_testConfig.getActiveViewportVec();
1858 for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
1859 {
1860 for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
1861 {
1862 // Push constants.
1863 PushConstants pushConstants =
1864 {
1865 m_testConfig.meshParams[meshIdx].color, // tcu::Vec4 triangleColor;
1866 m_testConfig.meshParams[meshIdx].depth, // float meshDepth;
1867 static_cast<deInt32>(viewportIdx), // deInt32 viewPortIndex;
1868 m_testConfig.meshParams[meshIdx].scaleX, // float scaleX;
1869 m_testConfig.meshParams[meshIdx].scaleY, // float scaleY;
1870 m_testConfig.meshParams[meshIdx].offsetX, // float offsetX;
1871 m_testConfig.meshParams[meshIdx].offsetY, // float offsetY;
1872 };
1873 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
1874
1875 // Track vertex bounding state for this mesh.
1876 bool boundBeforeDraw = false;
1877
1878 // Maybe set extended dynamic state here.
1879 if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
1880 {
1881 setDynamicStates(m_testConfig, vkd, cmdBuffer);
1882 boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffer.get(), rvertBuffer.get(), vertDataSize);
1883 }
1884
1885 // Bind vertex buffer with static stride if needed and draw.
1886 if (!(boundInAdvance || boundBeforeDraw))
1887 {
1888 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, (m_testConfig.meshParams[meshIdx].reversed ? &rvertBuffer.get() : &vertBuffer.get()), &m_testConfig.vertexDataOffset);
1889 if (m_testConfig.useIndexBuffer)
1890 {
1891 vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0, vk::VK_INDEX_TYPE_UINT32);
1892 }
1893 }
1894 // Draw mesh.
1895 if (m_testConfig.useIndexBuffer) {
1896 deUint32 numIndices = static_cast<deUint32>(indices.size());
1897 // For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
1898 // So, draw without using the invalid (0xFFFFFFFF) index, the second draw with primitive restart enabled will replace the results
1899 // using all indices.
1900 if (iteration == 0u &&
1901 (m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
1902 m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
1903 numIndices = 3u;
1904 vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
1905 }
1906 else
1907 vkd.cmdDraw(cmdBuffer, static_cast<deUint32>(vertexPtrs.size()), 1u, 0u, 0u);
1908 }
1909 }
1910
1911 vk::endRenderPass(vkd, cmdBuffer);
1912 }
1913
1914 vk::endCommandBuffer(vkd, cmdBuffer);
1915
1916 // Submit commands.
1917 vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
1918
1919 // Read result image aspects from the last used framebuffer.
1920 const tcu::UVec2 renderSize (kFramebufferWidth, kFramebufferHeight);
1921 const auto colorBuffer = readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImages.back()->get(), colorFormat, renderSize);
1922 const auto depthBuffer = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
1923 const auto stencilBuffer = readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1924 const auto colorAccess = colorBuffer->getAccess();
1925 const auto depthAccess = depthBuffer->getAccess();
1926 const auto stencilAccess = stencilBuffer->getAccess();
1927
1928 const int kWidth = static_cast<int>(kFramebufferWidth);
1929 const int kHeight = static_cast<int>(kFramebufferHeight);
1930
1931 // Generate reference color buffer.
1932 const auto tcuColorFormat = vk::mapVkFormat(colorFormat);
1933 tcu::TextureLevel referenceColorLevel (tcuColorFormat, kWidth, kHeight);
1934 tcu::PixelBufferAccess referenceColorAccess = referenceColorLevel.getAccess();
1935 m_testConfig.referenceColor(referenceColorAccess);
1936
1937 const tcu::TextureFormat errorFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
1938 tcu::TextureLevel colorError (errorFormat, kWidth, kHeight);
1939 tcu::TextureLevel depthError (errorFormat, kWidth, kHeight);
1940 tcu::TextureLevel stencilError (errorFormat, kWidth, kHeight);
1941 const auto colorErrorAccess = colorError.getAccess();
1942 const auto depthErrorAccess = depthError.getAccess();
1943 const auto stencilErrorAccess = stencilError.getAccess();
1944 const tcu::Vec4 kGood (0.0f, 1.0f, 0.0f, 1.0f);
1945 const tcu::Vec4 kBad (1.0f, 0.0f, 0.0f, 1.0f);
1946
1947 // Check expected values.
1948 const auto minDepth = m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
1949 const auto maxDepth = m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
1950 bool colorMatch = true;
1951 bool depthMatch = true;
1952 bool stencilMatch = true;
1953 bool match;
1954
1955 for (int y = 0; y < kHeight; ++y)
1956 for (int x = 0; x < kWidth; ++x)
1957 {
1958 auto colorPixel = colorAccess.getPixel(x, y);
1959 auto expectedPixel = referenceColorAccess.getPixel(x, y);
1960
1961 // The logic OP must have ORed the colors to cyan
1962 if (m_testConfig.logicOpConfig.dynamicValue)
1963 {
1964 // Multiply by 255.0f as the color is in R8G8B8A8 format
1965 expectedPixel = kCyanColor * 255.0f;
1966 }
1967
1968 match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kColorThreshold));
1969 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
1970 if (!match)
1971 colorMatch = false;
1972
1973 const auto depthPixel = depthAccess.getPixDepth(x, y);
1974 match = de::inRange(depthPixel, minDepth, maxDepth);
1975 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
1976 if (!match)
1977 depthMatch = false;
1978
1979 const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
1980 match = (stencilPixel == m_testConfig.expectedStencil);
1981 stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
1982 if (!match)
1983 stencilMatch = false;
1984 }
1985
1986 if (!(colorMatch && depthMatch && stencilMatch))
1987 {
1988 if (!colorMatch)
1989 logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
1990
1991 if (!depthMatch)
1992 logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
1993
1994 if (!stencilMatch)
1995 logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
1996
1997 return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
1998 }
1999
2000 return tcu::TestStatus::pass("Pass");
2001 }
2002
stencilPasses(vk::VkCompareOp op,deUint8 storedValue,deUint8 referenceValue)2003 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
2004 {
2005 switch (op)
2006 {
2007 case vk::VK_COMPARE_OP_NEVER: return false;
2008 case vk::VK_COMPARE_OP_LESS: return (referenceValue < storedValue);
2009 case vk::VK_COMPARE_OP_EQUAL: return (referenceValue == storedValue);
2010 case vk::VK_COMPARE_OP_LESS_OR_EQUAL: return (referenceValue <= storedValue);
2011 case vk::VK_COMPARE_OP_GREATER: return (referenceValue > storedValue);
2012 case vk::VK_COMPARE_OP_GREATER_OR_EQUAL: return (referenceValue >= storedValue);
2013 case vk::VK_COMPARE_OP_ALWAYS: return true;
2014 default: DE_ASSERT(false); return false;
2015 }
2016
2017 return false; // Unreachable.
2018 }
2019
stencilResult(vk::VkStencilOp op,deUint8 storedValue,deUint8 referenceValue,deUint8 min,deUint8 max)2020 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
2021 {
2022 deUint8 result = storedValue;
2023
2024 switch (op)
2025 {
2026 case vk::VK_STENCIL_OP_KEEP: break;
2027 case vk::VK_STENCIL_OP_ZERO: result = 0; break;
2028 case vk::VK_STENCIL_OP_REPLACE: result = referenceValue; break;
2029 case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP: result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
2030 case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP: result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
2031 case vk::VK_STENCIL_OP_INVERT: result = static_cast<deUint8>(~result); break;
2032 case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP: result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
2033 case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP: result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
2034 default: DE_ASSERT(false); break;
2035 }
2036
2037 return result;
2038 }
2039
2040 } // anonymous namespace
2041
createExtendedDynamicStateTests(tcu::TestContext & testCtx)2042 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
2043 {
2044 de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
2045
2046 // Auxiliar constants.
2047 const deUint32 kHalfWidthU = kFramebufferWidth/2u;
2048 const deInt32 kHalfWidthI = static_cast<deInt32>(kHalfWidthU);
2049 const float kHalfWidthF = static_cast<float>(kHalfWidthU);
2050 const float kHeightF = static_cast<float>(kFramebufferHeight);
2051
2052 static const struct
2053 {
2054 SequenceOrdering ordering;
2055 std::string name;
2056 std::string desc;
2057 } kOrderingCases[] =
2058 {
2059 { SequenceOrdering::CMD_BUFFER_START, "cmd_buffer_start", "Dynamic state set after command buffer start" },
2060 { SequenceOrdering::BEFORE_DRAW, "before_draw", "Dynamic state set just before drawing" },
2061 { 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" },
2062 { SequenceOrdering::AFTER_PIPELINES, "after_pipelines", "Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound" },
2063 { SequenceOrdering::BEFORE_GOOD_STATIC, "before_good_static", "Dynamic state set after a dynamic pipeline has been bound and before a second static-state pipeline with the right values has been bound" },
2064 { SequenceOrdering::TWO_DRAWS_DYNAMIC, "two_draws_dynamic", "Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again" },
2065 { SequenceOrdering::TWO_DRAWS_STATIC, "two_draws_static", "Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again" },
2066 };
2067
2068 for (int orderingIdx = 0; orderingIdx < DE_LENGTH_OF_ARRAY(kOrderingCases); ++orderingIdx)
2069 {
2070 const auto& kOrderingCase = kOrderingCases[orderingIdx];
2071 const auto& kOrdering = kOrderingCase.ordering;
2072
2073 de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
2074
2075 // Cull modes.
2076 {
2077 TestConfig config(kOrdering);
2078 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_FRONT_BIT;
2079 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
2080 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
2081 }
2082 {
2083 TestConfig config(kOrdering);
2084 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_FRONT_AND_BACK;
2085 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
2086 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
2087 }
2088 {
2089 TestConfig config(kOrdering);
2090 // Make triangles look back.
2091 config.meshParams[0].reversed = true;
2092 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2093 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
2094 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
2095 }
2096 {
2097 TestConfig config(kOrdering);
2098 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_NONE;
2099 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
2100 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2101 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
2102 }
2103
2104 // Front face.
2105 {
2106 TestConfig config(kOrdering);
2107 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2108 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_CLOCKWISE;
2109 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2110 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
2111 }
2112 {
2113 TestConfig config(kOrdering);
2114 // Pass triangles in clockwise order.
2115 config.meshParams[0].reversed = true;
2116 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2117 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2118 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2119 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
2120 }
2121 {
2122 TestConfig config(kOrdering);
2123 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2124 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2125 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2126 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2127 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
2128 }
2129 {
2130 TestConfig config(kOrdering);
2131 // Pass triangles in clockwise order.
2132 config.meshParams[0].reversed = true;
2133 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2134 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_CLOCKWISE;
2135 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2136 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2137 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
2138 }
2139
2140 // Rasterizer discard
2141 {
2142 TestConfig config(kOrdering);
2143 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2144 config.rastDiscardEnableConfig.staticValue = false;
2145 config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
2146 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2147 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
2148 }
2149 {
2150 TestConfig config(kOrdering);
2151 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2152 config.rastDiscardEnableConfig.staticValue = true;
2153 config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
2154 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2155 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
2156 }
2157
2158 // Logic op
2159 {
2160 TestConfig config(kOrdering);
2161 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2162 config.testExtendedDynamicState2LogicOp = true;
2163 config.logicOpConfig.staticValue = vk::VK_LOGIC_OP_CLEAR;
2164 config.logicOpConfig.dynamicValue = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
2165 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2166 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
2167 }
2168
2169 // Dynamically enable primitive restart
2170 {
2171 TestConfig config(kOrdering);
2172 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2173 config.useIndexBuffer = true;
2174 config.primRestartEnableConfig.staticValue = false;
2175 config.primRestartEnableConfig.dynamicValue = tcu::just(true);
2176 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2177 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "prim_restart_enable", "Dynamically enable primitiveRestart", config));
2178 }
2179
2180 // Dynamically change the number of primitive control points
2181 {
2182 TestConfig config(kOrdering);
2183 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2184 config.testExtendedDynamicState2PatchControlPoints = true;
2185 config.useTessellation = true;
2186 config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
2187 config.patchControlPointsConfig.staticValue = 1;
2188 config.patchControlPointsConfig.dynamicValue = 3;
2189 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2190 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points", "Dynamically change patch control points", config));
2191 }
2192
2193 // Dynamic topology.
2194 {
2195 TestConfig baseConfig(kOrdering);
2196
2197 for (int i = 0; i < 2; ++i)
2198 {
2199 const bool forceGeometryShader = (i > 0);
2200
2201 static const struct
2202 {
2203 vk::VkPrimitiveTopology staticVal;
2204 vk::VkPrimitiveTopology dynamicVal;
2205 } kTopologyCases[] =
2206 {
2207 { vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN },
2208 { vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
2209 };
2210
2211 for (int topoCaseIdx = 0; topoCaseIdx < DE_LENGTH_OF_ARRAY(kTopologyCases); ++topoCaseIdx)
2212 {
2213 TestConfig config(baseConfig);
2214 config.forceGeometryShader = forceGeometryShader;
2215 config.topologyConfig.staticValue = kTopologyCases[topoCaseIdx].staticVal;
2216 config.topologyConfig.dynamicValue = tcu::just<vk::VkPrimitiveTopology>(kTopologyCases[topoCaseIdx].dynamicVal);
2217
2218 const std::string className = topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
2219 const std::string name = "topology_" + className + (forceGeometryShader ? "_geom" : "");
2220 const std::string desc = "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "");
2221 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
2222 }
2223 }
2224 }
2225
2226 // Viewport.
2227 {
2228 TestConfig config(kOrdering);
2229 // 2 scissors, bad static single viewport.
2230 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2231 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2232 config.viewportConfig.dynamicValue = ViewportVec{
2233 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2234 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2235 };
2236 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
2237 }
2238 {
2239 TestConfig config(kOrdering);
2240 // Bad static reduced viewport.
2241 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2242 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
2243 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
2244 }
2245 {
2246 TestConfig config(kOrdering);
2247 // 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
2248 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2249 config.viewportConfig.staticValue = ViewportVec{
2250 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2251 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Left.
2252 };
2253 config.viewportConfig.dynamicValue = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2254 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
2255 }
2256 {
2257 TestConfig config(kOrdering);
2258 // 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
2259 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2260 config.viewportConfig.staticValue = ViewportVec{
2261 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Left.
2262 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2263 };
2264 config.viewportConfig.dynamicValue = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2265 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2266 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
2267 }
2268
2269 // Scissor.
2270 {
2271 TestConfig config(kOrdering);
2272 // 2 viewports, bad static single scissor.
2273 config.viewportConfig.staticValue = ViewportVec{
2274 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2275 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2276 };
2277 config.scissorConfig.staticValue = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2278 config.scissorConfig.dynamicValue = ScissorVec{
2279 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2280 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2281 };
2282 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
2283 }
2284 {
2285 TestConfig config(kOrdering);
2286 // 1 viewport, bad static single scissor.
2287 config.scissorConfig.staticValue = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2288 config.scissorConfig.dynamicValue = ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
2289 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
2290 }
2291 {
2292 TestConfig config(kOrdering);
2293 // 2 viewports, 2 reversed scissors that need fixing.
2294 config.viewportConfig.staticValue = ViewportVec{
2295 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2296 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2297 };
2298 config.scissorConfig.staticValue = ScissorVec{
2299 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2300 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2301 };
2302 config.scissorConfig.dynamicValue = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2303 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
2304 }
2305 {
2306 TestConfig config(kOrdering);
2307 // 2 viewports, 2 scissors switched to prevent drawing.
2308 config.viewportConfig.staticValue = ViewportVec{
2309 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2310 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2311 };
2312 config.scissorConfig.staticValue = ScissorVec{
2313 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2314 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2315 };
2316 config.scissorConfig.dynamicValue = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2317 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2318 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
2319 }
2320
2321 // Stride.
2322 {
2323 struct
2324 {
2325 VertexFactory factory;
2326 const std::string prefix;
2327 } strideCases[] =
2328 {
2329 { getVertexWithPadding, "stride" },
2330 { getVertexWithExtraAttributes, "large_stride" },
2331 };
2332
2333 for (int strideCaseIndex = 0; strideCaseIndex < DE_LENGTH_OF_ARRAY(strideCases); ++strideCaseIndex)
2334 {
2335 const auto factory = strideCases[strideCaseIndex].factory;
2336 const auto& prefix = strideCases[strideCaseIndex].prefix;
2337 const auto dummyVertex = factory(tcu::Vec2(0.0f, 0.0f));
2338 const auto vertexStride = static_cast<vk::VkDeviceSize>(dummyVertex->getVertexDataSize());
2339
2340 if (factory == getVertexWithExtraAttributes && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
2341 {
2342 // This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
2343 // stride being less than the extent of the binding for the second attribute.
2344 continue;
2345 }
2346
2347 {
2348 TestConfig config(kOrdering, factory);
2349 config.strideConfig.staticValue = kCoordsSize;
2350 config.strideConfig.dynamicValue = vertexStride;
2351 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix, "Dynamically set stride", config));
2352 }
2353 {
2354 TestConfig config(kOrdering, factory);
2355 config.strideConfig.staticValue = kCoordsSize;
2356 config.strideConfig.dynamicValue = vertexStride;
2357 config.vertexDataOffset = static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex));
2358 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset", "Dynamically set stride using a nonzero vertex data offset", config));
2359 }
2360 {
2361 TestConfig config(kOrdering, factory);
2362 config.strideConfig.staticValue = kCoordsSize;
2363 config.strideConfig.dynamicValue = vertexStride;
2364 config.vertexDataOffset = static_cast<vk::VkDeviceSize>(sizeof(GeometryVertex));
2365 config.vertexDataExtraBytes = config.vertexDataOffset;
2366
2367 // Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
2368 // offscreen vertex and draw something in the bottom half.
2369 config.referenceColor = HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2370 config.meshParams[0].scaleY = 0.5f;
2371 config.meshParams[0].offsetY = -0.5f;
2372
2373 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding", "Dynamically set stride using a nonzero vertex data offset and extra bytes", config));
2374 }
2375 }
2376 }
2377
2378 // Depth test enable.
2379 {
2380 TestConfig config(kOrdering);
2381 config.depthTestEnableConfig.staticValue = false;
2382 config.depthTestEnableConfig.dynamicValue = tcu::just(true);
2383 // By default, the depth test never passes when enabled.
2384 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2385 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
2386 }
2387 {
2388 TestConfig config(kOrdering);
2389 config.depthTestEnableConfig.staticValue = true;
2390 config.depthTestEnableConfig.dynamicValue = tcu::just(false);
2391 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2392 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
2393 }
2394
2395 // Depth write enable.
2396 {
2397 TestConfig config(kOrdering);
2398
2399 // Enable depth test and set values so it passes.
2400 config.depthTestEnableConfig.staticValue = true;
2401 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
2402 config.clearDepthValue = 0.5f;
2403 config.meshParams[0].depth = 0.25f;
2404
2405 // Enable writes and expect the mesh value.
2406 config.depthWriteEnableConfig.staticValue = false;
2407 config.depthWriteEnableConfig.dynamicValue = tcu::just(true);
2408 config.expectedDepth = 0.25f;
2409
2410 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
2411 }
2412 {
2413 TestConfig config(kOrdering);
2414
2415 // Enable depth test and set values so it passes.
2416 config.depthTestEnableConfig.staticValue = true;
2417 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
2418 config.clearDepthValue = 0.5f;
2419 config.meshParams[0].depth = 0.25f;
2420
2421 // But disable writing dynamically and expect the clear value.
2422 config.depthWriteEnableConfig.staticValue = true;
2423 config.depthWriteEnableConfig.dynamicValue = tcu::just(false);
2424 config.expectedDepth = 0.5f;
2425
2426 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
2427 }
2428
2429 // Depth bias enable.
2430 {
2431 {
2432 TestConfig config(kOrdering);
2433 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2434
2435 // Enable depth test and write 1.0f
2436 config.depthTestEnableConfig.staticValue = true;
2437 config.depthWriteEnableConfig.staticValue = true;
2438 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2439 // Clear depth buffer to 0.25f
2440 config.clearDepthValue = 0.25f;
2441 // Write depth to 0.5f
2442 config.meshParams[0].depth = 0.5f;
2443
2444 // Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
2445 config.depthBiasEnableConfig.staticValue = false;
2446 config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
2447 config.expectedDepth = 0.75f;
2448
2449 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bias_enable", "Dynamically enable the depth bias", config));
2450 }
2451 {
2452 TestConfig config(kOrdering);
2453 config.testExtendedDynamicStateVersion = TEST_VERSION_extended_dynamic_state2;
2454
2455 // Enable depth test and write 1.0f
2456 config.depthTestEnableConfig.staticValue = true;
2457 config.depthWriteEnableConfig.staticValue = true;
2458 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2459 // Clear depth buffer to 0.25f
2460 config.clearDepthValue = 0.25f;
2461 // Write depth to 0.5f
2462 config.meshParams[0].depth = 0.5f;
2463
2464 // Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
2465 config.depthBiasEnableConfig.staticValue = true;
2466 config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
2467 config.expectedDepth = 0.5f;
2468
2469 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bias_disable", "Dynamically disable the depth bias", config));
2470 }
2471 }
2472
2473 // Depth compare op.
2474 {
2475 TestConfig baseConfig(kOrdering);
2476 const tcu::Vec4 kAlternativeColor (0.0f, 0.0f, 0.5f, 1.0f);
2477 baseConfig.depthTestEnableConfig.staticValue = true;
2478 baseConfig.depthWriteEnableConfig.staticValue = true;
2479 baseConfig.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_NEVER;
2480 baseConfig.clearDepthValue = 0.5f;
2481
2482 {
2483 TestConfig config = baseConfig;
2484 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2485 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NEVER;
2486 config.meshParams[0].depth = 0.25f;
2487 config.expectedDepth = 0.5f;
2488 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2489 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
2490 }
2491 {
2492 TestConfig config = baseConfig;
2493 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS;
2494 config.meshParams[0].depth = 0.25f;
2495 config.expectedDepth = 0.25f;
2496 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
2497 }
2498 {
2499 TestConfig config = baseConfig;
2500 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER;
2501 config.meshParams[0].depth = 0.75f;
2502 config.expectedDepth = 0.75f;
2503 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
2504 }
2505 {
2506 TestConfig config = baseConfig;
2507 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_EQUAL;
2508 config.meshParams[0].depth = 0.5f;
2509 config.meshParams[0].color = kAlternativeColor;
2510 // Draw another mesh in front to verify it does not pass the equality test.
2511 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
2512 config.expectedDepth = 0.5f;
2513 config.referenceColor = SingleColorGenerator(kAlternativeColor);
2514 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
2515 }
2516 {
2517 TestConfig config = baseConfig;
2518 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2519 config.meshParams[0].depth = 0.25f;
2520 config.expectedDepth = 0.25f;
2521 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));
2522 }
2523 {
2524 TestConfig config = baseConfig;
2525 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2526 config.meshParams[0].depth = 0.5f;
2527 config.expectedDepth = 0.5f;
2528 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));
2529 }
2530 {
2531 TestConfig config = baseConfig;
2532 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
2533 config.meshParams[0].depth = 0.25f;
2534 // Draw another mesh with the same depth in front of it.
2535 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
2536 config.expectedDepth = 0.25f;
2537 config.referenceColor = SingleColorGenerator(kAlternativeColor);
2538 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));
2539 }
2540 {
2541 TestConfig config = baseConfig;
2542 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2543 config.meshParams[0].depth = 0.75f;
2544 config.expectedDepth = 0.75f;
2545 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));
2546 }
2547 {
2548 TestConfig config = baseConfig;
2549 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2550 config.meshParams[0].depth = 0.5f;
2551 config.expectedDepth = 0.5f;
2552 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));
2553 }
2554 {
2555 TestConfig config = baseConfig;
2556 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
2557 config.meshParams[0].depth = 0.75f;
2558 // Draw another mesh with the same depth in front of it.
2559 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
2560 config.expectedDepth = 0.75f;
2561 config.referenceColor = SingleColorGenerator(kAlternativeColor);
2562 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));
2563 }
2564 {
2565 TestConfig config = baseConfig;
2566 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NOT_EQUAL;
2567
2568 // Draw first mesh in front.
2569 config.meshParams[0].depth = 0.25f;
2570 // Draw another mesh in the back, this should pass too.
2571 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
2572 // Finally a new mesh with the same depth. This should not pass.
2573 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
2574
2575 config.referenceColor = SingleColorGenerator(kAlternativeColor);
2576 config.expectedDepth = 0.5f;
2577 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
2578 }
2579 {
2580 TestConfig config = baseConfig;
2581 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_ALWAYS;
2582
2583 config.meshParams[0].depth = 0.5f;
2584 config.expectedDepth = 0.5f;
2585 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
2586
2587 config.meshParams[0].depth = 0.25f;
2588 config.expectedDepth = 0.25f;
2589 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
2590
2591 config.meshParams[0].depth = 0.75f;
2592 config.expectedDepth = 0.75f;
2593 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
2594 }
2595 }
2596
2597 // Depth bounds test.
2598 {
2599 TestConfig baseConfig(kOrdering);
2600 baseConfig.minDepthBounds = 0.25f;
2601 baseConfig.maxDepthBounds = 0.75f;
2602 baseConfig.meshParams[0].depth = 0.0f;
2603
2604 {
2605 TestConfig config = baseConfig;
2606 config.depthBoundsTestEnableConfig.staticValue = false;
2607 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(true);
2608 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2609 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
2610 }
2611 {
2612 TestConfig config = baseConfig;
2613 config.depthBoundsTestEnableConfig.staticValue = true;
2614 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(false);
2615 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2616 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
2617 }
2618 }
2619
2620 // Stencil test enable.
2621 {
2622 TestConfig config(kOrdering);
2623 config.stencilTestEnableConfig.staticValue = false;
2624 config.stencilTestEnableConfig.dynamicValue = tcu::just(true);
2625 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
2626 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2627 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
2628 }
2629 {
2630 TestConfig config(kOrdering);
2631 config.stencilTestEnableConfig.staticValue = true;
2632 config.stencilTestEnableConfig.dynamicValue = tcu::just(false);
2633 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
2634 config.referenceColor = SingleColorGenerator(kDefaultTriangleColor);
2635 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
2636 }
2637
2638 // Stencil operation. Many combinations are possible.
2639 {
2640 static const struct
2641 {
2642 vk::VkStencilFaceFlags face;
2643 std::string name;
2644 } kFaces[] =
2645 {
2646 { vk::VK_STENCIL_FACE_FRONT_BIT, "face_front" },
2647 { vk::VK_STENCIL_FACE_BACK_BIT, "face_back" },
2648 { vk::VK_STENCIL_FRONT_AND_BACK, "face_both_single" },
2649 { vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM, "face_both_dual" }, // MAX_ENUM is a placeholder.
2650 };
2651
2652 static const struct
2653 {
2654 vk::VkCompareOp compareOp;
2655 std::string name;
2656 } kCompare[] =
2657 {
2658 { vk::VK_COMPARE_OP_NEVER, "xf" },
2659 { vk::VK_COMPARE_OP_LESS, "lt" },
2660 { vk::VK_COMPARE_OP_EQUAL, "eq" },
2661 { vk::VK_COMPARE_OP_LESS_OR_EQUAL, "le" },
2662 { vk::VK_COMPARE_OP_GREATER, "gt" },
2663 { vk::VK_COMPARE_OP_GREATER_OR_EQUAL, "ge" },
2664 { vk::VK_COMPARE_OP_ALWAYS, "xt" },
2665 };
2666
2667 using u8vec = std::vector<deUint8>;
2668
2669 static const auto kMinVal = std::numeric_limits<deUint8>::min();
2670 static const auto kMaxVal = std::numeric_limits<deUint8>::max();
2671 static const auto kMidVal = static_cast<deUint8>(kMaxVal * 2u / 5u);
2672 static const auto kMinValI = static_cast<int>(kMinVal);
2673 static const auto kMaxValI = static_cast<int>(kMaxVal);
2674
2675 static const struct
2676 {
2677 vk::VkStencilOp stencilOp;
2678 std::string name;
2679 u8vec clearValues; // One test per clear value interesting for this operation.
2680 vk::VkStencilOp incompatibleOp; // Alternative operation giving incompatible results for the given values.
2681 } kStencilOps[] =
2682 {
2683 { vk::VK_STENCIL_OP_KEEP, "keep", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
2684 { vk::VK_STENCIL_OP_ZERO, "zero", u8vec{kMidVal}, vk::VK_STENCIL_OP_KEEP },
2685 { vk::VK_STENCIL_OP_REPLACE, "replace", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
2686 { vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP, "inc_clamp", u8vec{kMaxVal - 1, kMaxVal}, vk::VK_STENCIL_OP_ZERO },
2687 { vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP, "dec_clamp", u8vec{kMinVal + 1, kMinVal}, vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP },
2688 { vk::VK_STENCIL_OP_INVERT, "invert", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
2689 { vk::VK_STENCIL_OP_INCREMENT_AND_WRAP, "inc_wrap", u8vec{kMaxVal - 1, kMaxVal}, vk::VK_STENCIL_OP_KEEP },
2690 { vk::VK_STENCIL_OP_DECREMENT_AND_WRAP, "dec_wrap", u8vec{kMinVal + 1, kMinVal}, vk::VK_STENCIL_OP_KEEP },
2691 };
2692
2693 for (int facesIdx = 0; facesIdx < DE_LENGTH_OF_ARRAY(kFaces); ++facesIdx)
2694 for (int compareIdx = 0; compareIdx < DE_LENGTH_OF_ARRAY(kCompare); ++compareIdx)
2695 for (int opIdx = 0; opIdx < DE_LENGTH_OF_ARRAY(kStencilOps); ++opIdx)
2696 {
2697 const auto& face = kFaces[facesIdx];
2698 const auto& compare = kCompare[compareIdx];
2699 const auto& op = kStencilOps[opIdx];
2700
2701 // Try clearing the stencil value with different values.
2702 for (const auto clearVal : op.clearValues)
2703 {
2704 // Use interesting values as the reference stencil value.
2705 for (int delta = -1; delta <= 1; ++delta)
2706 {
2707 const int refVal = clearVal + delta;
2708 if (refVal < kMinValI || refVal > kMaxValI)
2709 continue;
2710
2711 const auto refValU8 = static_cast<deUint8>(refVal);
2712 const auto refValU32 = static_cast<deUint32>(refVal);
2713
2714 // Calculate outcome of the stencil test itself.
2715 const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
2716
2717 // If the test passes, use an additional variant for the depthFail operation.
2718 const int subCases = (wouldPass ? 2 : 1);
2719
2720 for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
2721 {
2722 const bool depthFail = (subCaseIdx > 0); // depthFail would be the second variant.
2723 const bool globalPass = (wouldPass && !depthFail); // Global result of the stencil+depth test.
2724
2725 // Start tuning test parameters.
2726 TestConfig config(kOrdering);
2727
2728 // No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
2729 if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
2730 {
2731 // Default parameters are OK.
2732 }
2733 else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
2734 {
2735 // Reverse the mesh so it applies the back operation.
2736 config.meshParams[0].reversed = true;
2737 }
2738 else // Front and back.
2739 {
2740 // Draw both a front and a back-facing mesh so both are applied.
2741 // The first mesh will be drawn in the top half and the second mesh in the bottom half.
2742
2743 // Make the second mesh a reversed copy of the first mesh.
2744 config.meshParams.push_back(config.meshParams.front());
2745 config.meshParams.back().reversed = true;
2746
2747 // Apply scale and offset to the top mesh.
2748 config.meshParams.front().scaleY = 0.5f;
2749 config.meshParams.front().offsetY = -0.5f;
2750
2751 // Apply scale and offset to the bottom mesh.
2752 config.meshParams.back().scaleY = 0.5f;
2753 config.meshParams.back().offsetY = 0.5f;
2754 }
2755
2756 // Enable the stencil test.
2757 config.stencilTestEnableConfig.staticValue = true;
2758
2759 // Set dynamic configuration.
2760 StencilOpParams dynamicStencilConfig;
2761 dynamicStencilConfig.faceMask = face.face;
2762 dynamicStencilConfig.compareOp = compare.compareOp;
2763 dynamicStencilConfig.failOp = vk::VK_STENCIL_OP_MAX_ENUM;
2764 dynamicStencilConfig.passOp = vk::VK_STENCIL_OP_MAX_ENUM;
2765 dynamicStencilConfig.depthFailOp = vk::VK_STENCIL_OP_MAX_ENUM;
2766
2767 // Set operations so only the appropriate operation for this case gives the right result.
2768 vk::VkStencilOp* activeOp = nullptr;
2769 vk::VkStencilOp* inactiveOps[2] = { nullptr, nullptr };
2770 if (wouldPass)
2771 {
2772 if (depthFail)
2773 {
2774 activeOp = &dynamicStencilConfig.depthFailOp;
2775 inactiveOps[0] = &dynamicStencilConfig.passOp;
2776 inactiveOps[1] = &dynamicStencilConfig.failOp;
2777 }
2778 else
2779 {
2780 activeOp = &dynamicStencilConfig.passOp;
2781 inactiveOps[0] = &dynamicStencilConfig.depthFailOp;
2782 inactiveOps[1] = &dynamicStencilConfig.failOp;
2783 }
2784 }
2785 else
2786 {
2787 activeOp = &dynamicStencilConfig.failOp;
2788 inactiveOps[0] = &dynamicStencilConfig.passOp;
2789 inactiveOps[1] = &dynamicStencilConfig.depthFailOp;
2790 }
2791
2792 *activeOp = op.stencilOp;
2793 *inactiveOps[0] = op.incompatibleOp;
2794 *inactiveOps[1] = op.incompatibleOp;
2795
2796 // Make sure all ops have been configured properly.
2797 DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
2798 DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
2799 DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
2800
2801 // Set an incompatible static operation too.
2802 auto& staticStencilConfig = config.stencilOpConfig.staticValue.front();
2803 staticStencilConfig.faceMask = face.face;
2804 staticStencilConfig.compareOp = (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
2805 staticStencilConfig.passOp = op.incompatibleOp;
2806 staticStencilConfig.failOp = op.incompatibleOp;
2807 staticStencilConfig.depthFailOp = op.incompatibleOp;
2808
2809 // Set dynamic configuration.
2810 StencilOpVec stencilOps;
2811 stencilOps.push_back(dynamicStencilConfig);
2812
2813 if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
2814 {
2815 // This is the dual case. We will set the front and back face values with two separate calls.
2816 stencilOps.push_back(stencilOps.front());
2817 stencilOps.front().faceMask = vk::VK_STENCIL_FACE_FRONT_BIT;
2818 stencilOps.back().faceMask = vk::VK_STENCIL_FACE_BACK_BIT;
2819 staticStencilConfig.faceMask = vk::VK_STENCIL_FACE_FRONT_AND_BACK;
2820 }
2821
2822 config.stencilOpConfig.dynamicValue = tcu::just(stencilOps);
2823 config.clearStencilValue = clearVal;
2824 config.referenceStencil = refValU32;
2825
2826 if (depthFail)
2827 {
2828 // Enable depth test and make it fail.
2829 config.depthTestEnableConfig.staticValue = true;
2830 config.clearDepthValue = 0.5f;
2831 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
2832
2833 for (auto& meshPar : config.meshParams)
2834 meshPar.depth = 0.75f;
2835 }
2836
2837 // Set expected outcome.
2838 config.referenceColor = SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor);
2839 config.expectedDepth = config.clearDepthValue; // No depth writing by default.
2840 config.expectedStencil = stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
2841
2842 const std::string testName = std::string("stencil_state")
2843 + "_" + face.name
2844 + "_" + compare.name
2845 + "_" + op.name
2846 + "_clear_" + de::toString(static_cast<int>(clearVal))
2847 + "_ref_" + de::toString(refVal)
2848 + "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
2849
2850 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
2851 }
2852 }
2853 }
2854 }
2855 }
2856
2857 // Vertex input.
2858 {
2859 const auto dummyVertex = getVertexWithPadding(tcu::Vec2(0.0f, 0.0f));
2860
2861 TestConfig config(kOrdering);
2862 config.testExtendedDynamicStateVersion = TEST_VERSION_vertex_input_dynamic_state;
2863 config.vertexInputConfig.staticValue = static_cast<deUint32>(dummyVertex->getPaddingOffset());
2864 config.vertexInputConfig.dynamicValue = static_cast<deUint32>(dummyVertex->getCoordsOffset());
2865 config.strideConfig.staticValue = kCoordsSize;
2866 config.strideConfig.dynamicValue = static_cast<vk::VkDeviceSize>(dummyVertex->getVertexDataSize());
2867 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input", "Dynamically set vertex input", config));
2868 }
2869
2870 extendedDynamicStateGroup->addChild(orderingGroup.release());
2871 }
2872
2873 return extendedDynamicStateGroup.release();
2874 }
2875
2876 } // pipeline
2877 } // vkt
2878