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 #include "tcuStringTemplate.hpp"
44
45 #include "deUniquePtr.hpp"
46 #include "deStringUtil.hpp"
47
48 #include <vector>
49 #include <sstream>
50 #include <algorithm>
51 #include <utility>
52 #include <iterator>
53 #include <string>
54 #include <limits>
55 #include <memory>
56 #include <functional>
57 #include <cstddef>
58 #include <set>
59
60 namespace vkt
61 {
62 namespace pipeline
63 {
64
65 namespace
66 {
67
makeVkBool32(bool value)68 inline vk::VkBool32 makeVkBool32(bool value)
69 {
70 return (value ? VK_TRUE : VK_FALSE);
71 }
72
73 // Framebuffer size.
74 constexpr deUint32 kFramebufferWidth = 64u;
75 constexpr deUint32 kFramebufferHeight = 64u;
76
77 // Image formats.
78 constexpr vk::VkFormat kUnormColorFormat = vk::VK_FORMAT_R8G8B8A8_UNORM;
79 constexpr vk::VkFormat kIntColorFormat = vk::VK_FORMAT_R8G8B8A8_UINT;
80 const tcu::Vec4 kUnormColorThreshold (0.005f); // 1/255 < 0.005 < 2/255.
81
82 struct DepthStencilFormat
83 {
84 vk::VkFormat imageFormat;
85 float depthThreshold;
86 };
87
88 const DepthStencilFormat kDepthStencilFormats[] =
89 {
90 { vk::VK_FORMAT_D32_SFLOAT_S8_UINT, 0.0f },
91 { vk::VK_FORMAT_D24_UNORM_S8_UINT, 1.0e-07f }, // 1/(2**24-1) < 1.0e-07f < 2/(2**24-1)
92 };
93
94 using StrideVec = std::vector<vk::VkDeviceSize>;
95
96 // We will use several data types in vertex bindings. Each type will need to define a few things.
97 class VertexGenerator
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() const = 0;
113
114 // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
115 virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const = 0;
116
117 // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
118 virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions (const StrideVec& strides) const = 0;
119
120 // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
121 virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2 (const StrideVec& strides) const = 0;
122
123 // Create buffer data given an array of coordinates and an initial padding.
124 virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const = 0;
125
126 // Stride of vertex data in each binding.
127 virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const = 0;
128 };
129
130 // Auxiliar function to create these structs more easily.
makeVertexInputAttributeDescription2EXT(deUint32 location,deUint32 binding,vk::VkFormat format,deUint32 offset)131 vk::VkVertexInputAttributeDescription2EXT makeVertexInputAttributeDescription2EXT (deUint32 location, deUint32 binding, vk::VkFormat format, deUint32 offset)
132 {
133 vk::VkVertexInputAttributeDescription2EXT desc = vk::initVulkanStructure();
134 desc.location = location;
135 desc.binding = binding;
136 desc.format = format;
137 desc.offset = offset;
138 return desc;
139 }
140
makeVertexInputBindingDescription2EXT(deUint32 binding,deUint32 stride,vk::VkVertexInputRate inputRate)141 vk::VkVertexInputBindingDescription2EXT makeVertexInputBindingDescription2EXT (deUint32 binding, deUint32 stride, vk::VkVertexInputRate inputRate)
142 {
143 vk::VkVertexInputBindingDescription2EXT desc = vk::initVulkanStructure();
144 desc.binding = binding;
145 desc.stride = stride;
146 desc.inputRate = inputRate;
147 desc.divisor = 1u;
148 return desc;
149 }
150
151 // Fill a section of the given buffer (from offset to offset+count) with repeating copies of the given data.
fillWithPattern(void * ptr_,size_t offset,size_t count,const void * src,size_t srcSize)152 void fillWithPattern(void* ptr_, size_t offset, size_t count, const void* src, size_t srcSize)
153 {
154 auto ptr = reinterpret_cast<char*>(ptr_);
155 size_t done = 0u;
156 size_t pending = count;
157
158 while (pending > 0u)
159 {
160 const size_t stepSize = de::min(srcSize, pending);
161 deMemcpy(ptr + offset + done, src, stepSize);
162 done += stepSize;
163 pending -= stepSize;
164 }
165 }
166
167 // Create a single binding vertex data vector given a type T for vertex data.
168 template<class T>
createSingleBindingVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize)169 std::vector<deUint8> createSingleBindingVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize)
170 {
171 DE_ASSERT(!coords.empty());
172
173 const auto dataOffsetSz = static_cast<size_t>(dataOffset);
174 const auto trailingPaddingSz = static_cast<size_t>(trailingPadding);
175
176 std::vector<deUint8> buffer;
177 buffer.resize(dataOffsetSz + coords.size() * sizeof(T) + trailingPaddingSz);
178
179 fillWithPattern(buffer.data(), 0u, dataOffsetSz, paddingPattern, patternSize);
180
181 auto pos = dataOffsetSz;
182 for (const auto& coord : coords)
183 {
184 new (&buffer[pos]) T(coord);
185 pos += sizeof(T);
186 }
187
188 fillWithPattern(buffer.data(), pos, trailingPaddingSz, paddingPattern, patternSize);
189
190 return buffer;
191 }
192
193 // Vertices in buffers will have 2 components and a padding to properly test the stride.
194 // This is the vertex type that will be used normally.
195 class VertexWithPadding : public VertexGenerator
196 {
197 protected:
198 struct VertexData
199 {
VertexDatavkt::pipeline::__anon8f7ea4da0111::VertexWithPadding::VertexData200 VertexData(const tcu::Vec2& coords_)
201 : coords (coords_)
202 , padding (0.0f, 0.0f)
203 {}
204
205 tcu::Vec2 coords;
206 tcu::Vec2 padding;
207 };
208
209 public:
getAttributeDeclarations() const210 virtual std::vector<std::string> getAttributeDeclarations() const override
211 {
212 std::vector<std::string> declarations;
213 declarations.push_back("layout(location=0) in vec2 position;");
214 return declarations;
215 }
216
getVertexCoordCalc() const217 virtual std::vector<std::string> getVertexCoordCalc() const override
218 {
219 std::vector<std::string> statements;
220 statements.push_back("vec2 vertexCoords = position;");
221 return statements;
222 }
223
getAttributeDescriptions() const224 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
225 {
226 std::vector<vk::VkVertexInputAttributeDescription> descriptions;
227 descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
228 return descriptions;
229 }
230
231 // Vertex attributes for VK_EXT_vertex_input_dynamic_state.
getAttributeDescriptions2() const232 virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
233 {
234 std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
235 descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
236 return descriptions;
237 }
238
239 // Vertex bindings for VkPipelineVertexInputStateCreateInfo.
getBindingDescriptions(const StrideVec & strides) const240 virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
241 {
242 std::vector<vk::VkVertexInputBindingDescription> descriptions;
243 descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
244 return descriptions;
245 }
246
247 // Vertex bindings for VK_EXT_vertex_input_dynamic_state.
getBindingDescriptions2(const StrideVec & strides) const248 virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
249 {
250 std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
251 descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
252 return descriptions;
253 }
254
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const255 virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
256 {
257 return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
258 }
259
getVertexDataStrides() const260 virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
261 {
262 return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
263 }
264 };
265
266 // Vertices with coordinates, padding and an extra constant field.
267 class VertexWithExtraAttributes : public VertexGenerator
268 {
269 protected:
270 struct VertexData
271 {
VertexDatavkt::pipeline::__anon8f7ea4da0111::VertexWithExtraAttributes::VertexData272 VertexData (const tcu::Vec2& coords_)
273 : coords (coords_)
274 , ones (1.0f, 1.0f)
275 {
276 deMemset(padding, 0, sizeof(padding));
277 }
278
279 tcu::Vec2 coords;
280 tcu::Vec2 padding[10];
281 tcu::Vec2 ones;
282 };
283
284 public:
getAttributeDeclarations() const285 virtual std::vector<std::string> getAttributeDeclarations() const override
286 {
287 std::vector<std::string> declarations;
288 declarations.push_back("layout(location=0) in vec2 position;");
289 declarations.push_back("layout(location=1) in vec2 ones;");
290 return declarations;
291 }
292
getVertexCoordCalc() const293 virtual std::vector<std::string> getVertexCoordCalc() const override
294 {
295 std::vector<std::string> statements;
296 statements.push_back("vec2 vertexCoords = position;");
297 statements.push_back("vertexCoords = vertexCoords * ones;");
298 return statements;
299 }
300
getAttributeDescriptions() const301 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
302 {
303 std::vector<vk::VkVertexInputAttributeDescription> descriptions;
304 descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
305 descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
306 return descriptions;
307 }
308
getAttributeDescriptions2() const309 virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
310 {
311 std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
312 descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, 0u));
313 descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 0u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(VertexData, ones))));
314 return descriptions;
315 }
316
getBindingDescriptions(const StrideVec & strides) const317 virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
318 {
319 std::vector<vk::VkVertexInputBindingDescription> descriptions;
320 descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
321 return descriptions;
322 }
323
getBindingDescriptions2(const StrideVec & strides) const324 virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
325 {
326 std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
327 descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
328 return descriptions;
329 }
330
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const331 virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
332 {
333 return std::vector<std::vector<deUint8>>(1u, createSingleBindingVertexData<VertexData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize));
334 }
335
getVertexDataStrides() const336 virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
337 {
338 return std::vector<vk::VkDeviceSize>(1u, static_cast<vk::VkDeviceSize>(sizeof(VertexData)));
339 }
340 };
341
342 // Vertices using multiple bindings and constant fields.
343 // Binding 0: no data actually used.
344 // Binding 1: contains location 0, array of PaddingOnes.
345 // Binding 2: no data actually used.
346 // Binding 3: contains location 1, array of CoordsData.
347 // Binding 4: no data actually used.
348 // Binding 5: contains location 2, array of OneZeroPadding.
349 // See getAttributeDeclarations().
350 class MultipleBindingsVertex : public VertexGenerator
351 {
352 protected:
353 struct CoordsData
354 {
355 tcu::Vec2 padding0;
356 tcu::Vec2 coords;
357 tcu::Vec2 padding1;
358
CoordsDatavkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::CoordsData359 CoordsData (const tcu::Vec2& coords_)
360 : padding0 (0.0f, 3.0f)
361 , coords (coords_)
362 , padding1 (3.0f, 0.0f)
363 {}
364 };
365
366 struct PaddingOnes
367 {
368 tcu::Vec2 padding[4];
369 tcu::Vec2 ones;
370
PaddingOnesvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::PaddingOnes371 PaddingOnes (const tcu::Vec2&)
372 : ones (1.0f, 1.0f)
373 {
374 deMemset(&padding, 0, sizeof(padding));
375 }
376 };
377
378 struct OneZeroPadding
379 {
380 tcu::Vec4 oneZero;
381 tcu::Vec2 padding[3];
382
OneZeroPaddingvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::OneZeroPadding383 OneZeroPadding (const tcu::Vec2&)
384 : oneZero (1.0f, 1.0f, 0.0f, 0.0f)
385 {
386 deMemset(&padding, 0, sizeof(padding));
387 }
388 };
389
390 struct Zeros
391 {
392 tcu::Vec2 zeros;
393
Zerosvkt::pipeline::__anon8f7ea4da0111::MultipleBindingsVertex::Zeros394 Zeros (const tcu::Vec2&)
395 : zeros (0.0f, 0.0f)
396 {}
397 };
398
399 public:
getAttributeDeclarations() const400 virtual std::vector<std::string> getAttributeDeclarations() const override
401 {
402 std::vector<std::string> declarations;
403 declarations.reserve(3u);
404
405 declarations.push_back("layout(location=0) in vec2 ones;");
406 declarations.push_back("layout(location=1) in vec2 position;");
407 declarations.push_back("layout(location=2) in vec4 oneZero;");
408
409 return declarations;
410 }
411
getVertexCoordCalc() const412 virtual std::vector<std::string> getVertexCoordCalc() const override
413 {
414 std::vector<std::string> statements;
415 statements.reserve(2u);
416
417 statements.push_back("vec2 vertexCoords = position;");
418 statements.push_back("vertexCoords = ((vertexCoords * ones) + oneZero.zw) * oneZero.xy;");
419
420 return statements;
421 }
422
getAttributeDescriptions() const423 virtual std::vector<vk::VkVertexInputAttributeDescription> getAttributeDescriptions() const override
424 {
425 // We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
426 std::vector<vk::VkVertexInputAttributeDescription> descriptions;
427 descriptions.reserve(3u);
428
429 descriptions.push_back(vk::makeVertexInputAttributeDescription(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
430 descriptions.push_back(vk::makeVertexInputAttributeDescription(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
431 descriptions.push_back(vk::makeVertexInputAttributeDescription(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
432
433 return descriptions;
434 }
435
getAttributeDescriptions2() const436 virtual std::vector<vk::VkVertexInputAttributeDescription2EXT> getAttributeDescriptions2() const override
437 {
438 // We create the descriptions vector out of order to make it more interesting. See the attribute declarations.
439 std::vector<vk::VkVertexInputAttributeDescription2EXT> descriptions;
440 descriptions.reserve(3u);
441
442 descriptions.push_back(makeVertexInputAttributeDescription2EXT(2u, 5u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<deUint32>(offsetof(OneZeroPadding, oneZero))));
443 descriptions.push_back(makeVertexInputAttributeDescription2EXT(1u, 3u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(CoordsData, coords))));
444 descriptions.push_back(makeVertexInputAttributeDescription2EXT(0u, 1u, vk::VK_FORMAT_R32G32_SFLOAT, static_cast<deUint32>(offsetof(PaddingOnes, ones))));
445
446 return descriptions;
447 }
448
getBindingDescriptions(const StrideVec & strides) const449 virtual std::vector<vk::VkVertexInputBindingDescription> getBindingDescriptions(const StrideVec& strides) const override
450 {
451 // Provide descriptions out of order to make it more interesting.
452 std::vector<vk::VkVertexInputBindingDescription> descriptions;
453 descriptions.reserve(6u);
454
455 descriptions.push_back(vk::makeVertexInputBindingDescription(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
456 descriptions.push_back(vk::makeVertexInputBindingDescription(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
457 descriptions.push_back(vk::makeVertexInputBindingDescription(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
458 descriptions.push_back(vk::makeVertexInputBindingDescription(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
459 descriptions.push_back(vk::makeVertexInputBindingDescription(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
460 descriptions.push_back(vk::makeVertexInputBindingDescription(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
461
462 return descriptions;
463 }
464
getBindingDescriptions2(const StrideVec & strides) const465 virtual std::vector<vk::VkVertexInputBindingDescription2EXT> getBindingDescriptions2(const StrideVec& strides) const override
466 {
467 // Provide descriptions out of order to make it more interesting.
468 std::vector<vk::VkVertexInputBindingDescription2EXT> descriptions;
469 descriptions.reserve(6u);
470
471 descriptions.push_back(makeVertexInputBindingDescription2EXT(2u, static_cast<deUint32>(strides.at(2)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
472 descriptions.push_back(makeVertexInputBindingDescription2EXT(0u, static_cast<deUint32>(strides.at(0)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
473 descriptions.push_back(makeVertexInputBindingDescription2EXT(1u, static_cast<deUint32>(strides.at(1)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
474 descriptions.push_back(makeVertexInputBindingDescription2EXT(5u, static_cast<deUint32>(strides.at(5)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
475 descriptions.push_back(makeVertexInputBindingDescription2EXT(4u, static_cast<deUint32>(strides.at(4)), vk::VK_VERTEX_INPUT_RATE_INSTANCE));
476 descriptions.push_back(makeVertexInputBindingDescription2EXT(3u, static_cast<deUint32>(strides.at(3)), vk::VK_VERTEX_INPUT_RATE_VERTEX));
477
478 return descriptions;
479 }
480
createVertexData(const std::vector<tcu::Vec2> & coords,vk::VkDeviceSize dataOffset,vk::VkDeviceSize trailingPadding,const void * paddingPattern,size_t patternSize) const481 virtual std::vector<std::vector<deUint8>> createVertexData (const std::vector<tcu::Vec2>& coords, vk::VkDeviceSize dataOffset, vk::VkDeviceSize trailingPadding, const void* paddingPattern, size_t patternSize) const override
482 {
483 std::vector<std::vector<deUint8>> result;
484 result.reserve(6u);
485
486 result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Not actually used.
487 result.push_back(createSingleBindingVertexData<PaddingOnes>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Binding 1 contains location=0 as PaddingOnes.
488 result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Not actually used.
489 result.push_back(createSingleBindingVertexData<CoordsData>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Binding 3 contains location=1 as CoordsData.
490 result.push_back(createSingleBindingVertexData<Zeros>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Not actually used.
491 result.push_back(createSingleBindingVertexData<OneZeroPadding>(coords, dataOffset, trailingPadding, paddingPattern, patternSize)); // Binding 5 contains location=2 as OneZeroPadding.
492
493 return result;
494 }
495
getVertexDataStrides() const496 virtual std::vector<vk::VkDeviceSize> getVertexDataStrides() const override
497 {
498 std::vector<vk::VkDeviceSize> strides;
499 strides.reserve(6u);
500
501 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
502 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(PaddingOnes)));
503 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
504 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(CoordsData)));
505 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(Zeros)));
506 strides.push_back(static_cast<vk::VkDeviceSize>(sizeof(OneZeroPadding)));
507
508 return strides;
509 }
510 };
511
512 // Stencil Operation parameters, as used in vkCmdSetStencilOpEXT().
513 struct StencilOpParams
514 {
515 vk::VkStencilFaceFlags faceMask;
516 vk::VkStencilOp failOp;
517 vk::VkStencilOp passOp;
518 vk::VkStencilOp depthFailOp;
519 vk::VkCompareOp compareOp;
520 };
521
522 const StencilOpParams kDefaultStencilOpParams =
523 {
524 vk::VK_STENCIL_FACE_FRONT_AND_BACK,
525 vk::VK_STENCIL_OP_KEEP,
526 vk::VK_STENCIL_OP_KEEP,
527 vk::VK_STENCIL_OP_KEEP,
528 vk::VK_COMPARE_OP_ALWAYS
529 };
530
531 struct DepthBiasParams
532 {
533 float constantFactor;
534 float clamp;
535 };
536
537 const DepthBiasParams kNoDepthBiasParams = { 0.0f, 0.0f };
538
539 using ViewportVec = std::vector<vk::VkViewport>;
540 using ScissorVec = std::vector<vk::VkRect2D>;
541 using StencilOpVec = std::vector<StencilOpParams>;
542
543 // Generic, to be used with any state than can be set statically and, as an option, dynamically.
544 template<typename T>
545 struct StaticAndDynamicPair
546 {
547 T staticValue;
548 tcu::Maybe<T> dynamicValue;
549
550 // Helper constructor to set a static value and no dynamic value.
StaticAndDynamicPairvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair551 StaticAndDynamicPair (const T& value)
552 : staticValue (value)
553 , dynamicValue (tcu::Nothing)
554 {
555 }
556
557 // Helper constructor to set both.
StaticAndDynamicPairvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair558 StaticAndDynamicPair (const T& sVal, const T& dVal)
559 : staticValue (sVal)
560 , dynamicValue (tcu::just<T>(dVal))
561 {
562 }
563
564 // If the dynamic value is present, swap static and dynamic values.
swapValuesvkt::pipeline::__anon8f7ea4da0111::StaticAndDynamicPair565 void swapValues (void)
566 {
567 if (!dynamicValue)
568 return;
569 std::swap(staticValue, dynamicValue.get());
570 }
571 };
572
573 // For anything boolean, see below.
574 using BooleanFlagConfig = StaticAndDynamicPair<bool>;
575
576 // Configuration for every aspect of the extended dynamic state.
577 using CullModeConfig = StaticAndDynamicPair<vk::VkCullModeFlags>;
578 using FrontFaceConfig = StaticAndDynamicPair<vk::VkFrontFace>;
579 using TopologyConfig = StaticAndDynamicPair<vk::VkPrimitiveTopology>;
580 using ViewportConfig = StaticAndDynamicPair<ViewportVec>; // At least one element.
581 using ScissorConfig = StaticAndDynamicPair<ScissorVec>; // At least one element.
582 using StrideConfig = StaticAndDynamicPair<StrideVec>; // At least one element.
583 using DepthTestEnableConfig = BooleanFlagConfig;
584 using DepthWriteEnableConfig = BooleanFlagConfig;
585 using DepthCompareOpConfig = StaticAndDynamicPair<vk::VkCompareOp>;
586 using DepthBoundsTestEnableConfig = BooleanFlagConfig;
587 using StencilTestEnableConfig = BooleanFlagConfig;
588 using StencilOpConfig = StaticAndDynamicPair<StencilOpVec>; // At least one element.
589 using VertexGeneratorConfig = StaticAndDynamicPair<const VertexGenerator*>;
590 using DepthBiasEnableConfig = BooleanFlagConfig;
591 using RastDiscardEnableConfig = BooleanFlagConfig;
592 using PrimRestartEnableConfig = BooleanFlagConfig;
593 using LogicOpConfig = StaticAndDynamicPair<vk::VkLogicOp>;
594 using PatchControlPointsConfig = StaticAndDynamicPair<deUint8>;
595 using DepthBiasConfig = StaticAndDynamicPair<DepthBiasParams>;
596
597 const tcu::Vec4 kDefaultTriangleColor (0.0f, 0.0f, 1.0f, 1.0f); // Opaque blue.
598 const tcu::Vec4 kDefaultClearColor (0.0f, 0.0f, 0.0f, 1.0f); // Opaque black.
599
600 const tcu::Vec4 kLogicOpTriangleColor (0.0f, 0.0f,255.f,255.f); // Opaque blue. Note: tcu::Vec4 and will be cast to the appropriate type in the shader.
601 const tcu::UVec4 kGreenClearColor ( 0u, 255u, 0u, 255u); // Opaque green, UINT.
602 const tcu::UVec4 kLogicOpFinalColor ( 0u, 255u, 255u, 255u); // Opaque cyan, UINT.
603
604 struct MeshParams
605 {
606 tcu::Vec4 color;
607 float depth;
608 bool reversed;
609 float scaleX;
610 float scaleY;
611 float offsetX;
612 float offsetY;
613 float stripScale;
614
MeshParamsvkt::pipeline::__anon8f7ea4da0111::MeshParams615 MeshParams (const tcu::Vec4& color_ = kDefaultTriangleColor,
616 float depth_ = 0.0f,
617 bool reversed_ = false,
618 float scaleX_ = 1.0f,
619 float scaleY_ = 1.0f,
620 float offsetX_ = 0.0f,
621 float offsetY_ = 0.0f,
622 float stripScale_ = 0.0f)
623 : color (color_)
624 , depth (depth_)
625 , reversed (reversed_)
626 , scaleX (scaleX_)
627 , scaleY (scaleY_)
628 , offsetX (offsetX_)
629 , offsetY (offsetY_)
630 , stripScale (stripScale_)
631 {}
632 };
633
634 enum class SequenceOrdering
635 {
636 CMD_BUFFER_START = 0, // Set state at the start of the command buffer.
637 BEFORE_DRAW = 1, // After binding dynamic pipeline and just before drawing.
638 BETWEEN_PIPELINES = 2, // After a static state pipeline has been bound but before the dynamic state pipeline has been bound.
639 AFTER_PIPELINES = 3, // After a static state pipeline and a second dynamic state pipeline have been bound.
640 BEFORE_GOOD_STATIC = 4, // Before a static state pipeline with the correct values has been bound.
641 TWO_DRAWS_DYNAMIC = 5, // Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again.
642 TWO_DRAWS_STATIC = 6, // Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again.
643 };
644
645 using ReferenceColorGenerator = std::function<void(tcu::PixelBufferAccess&)>;
646
647 // Most tests expect a single output color in the whole image.
648 class SingleColorGenerator
649 {
650 public:
SingleColorGenerator(const tcu::Vec4 & color)651 SingleColorGenerator (const tcu::Vec4& color)
652 : m_colorFloat (color)
653 , m_colorUint (0u)
654 , isUint (false)
655 {}
656
SingleColorGenerator(const tcu::UVec4 & color)657 SingleColorGenerator (const tcu::UVec4& color)
658 : m_colorFloat (0.0f)
659 , m_colorUint (color)
660 , isUint (true)
661 {}
662
operator ()(tcu::PixelBufferAccess & access)663 void operator()(tcu::PixelBufferAccess& access)
664 {
665 constexpr auto kWidth = static_cast<int>(kFramebufferWidth);
666 constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
667
668 for (int y = 0; y < kHeight; ++y)
669 for (int x = 0; x < kWidth; ++x)
670 {
671 if (isUint)
672 access.setPixel(m_colorUint, x, y);
673 else
674 access.setPixel(m_colorFloat, x, y);
675 }
676 }
677
678 private:
679 const tcu::Vec4 m_colorFloat;
680 const tcu::UVec4 m_colorUint;
681 const bool isUint;
682 };
683
684 // Some tests expect the upper half and the lower half having different color values.
685 class HorizontalSplitGenerator
686 {
687 public:
HorizontalSplitGenerator(const tcu::Vec4 & top,const tcu::Vec4 & bottom)688 HorizontalSplitGenerator (const tcu::Vec4& top, const tcu::Vec4& bottom)
689 : m_top(top), m_bottom(bottom)
690 {}
691
operator ()(tcu::PixelBufferAccess & access)692 void operator()(tcu::PixelBufferAccess& access)
693 {
694 constexpr auto kWidth = static_cast<int>(kFramebufferWidth);
695 constexpr auto kHeight = static_cast<int>(kFramebufferHeight);
696 constexpr auto kHalfHeight = kHeight / 2;
697
698 for (int y = 0; y < kHeight; ++y)
699 for (int x = 0; x < kWidth; ++x)
700 {
701 const auto& color = (y < kHalfHeight ? m_top : m_bottom);
702 access.setPixel(color, x, y);
703 }
704 }
705
706 private:
707 const tcu::Vec4 m_top;
708 const tcu::Vec4 m_bottom;
709 };
710
getVertexWithPaddingGenerator()711 const VertexGenerator* getVertexWithPaddingGenerator ()
712 {
713 static const VertexWithPadding vertexWithPadding;
714 return &vertexWithPadding;
715 }
716
getVertexWithExtraAttributesGenerator()717 const VertexGenerator* getVertexWithExtraAttributesGenerator ()
718 {
719 static const VertexWithExtraAttributes vertexWithExtraAttributes;
720 return &vertexWithExtraAttributes;
721 }
722
getVertexWithMultipleBindingsGenerator()723 const VertexGenerator* getVertexWithMultipleBindingsGenerator ()
724 {
725 static const MultipleBindingsVertex multipleBindingsVertex;
726 return &multipleBindingsVertex;
727 }
728
729 // Create VertexGeneratorConfig varying constructor depending on having none, only the static or both.
makeVertexGeneratorConfig(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)730 VertexGeneratorConfig makeVertexGeneratorConfig (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
731 {
732 DE_ASSERT(!(dynamicGen && !staticGen));
733 if (dynamicGen)
734 return VertexGeneratorConfig(staticGen, dynamicGen);
735 if (staticGen)
736 return VertexGeneratorConfig(staticGen);
737 return VertexGeneratorConfig(getVertexWithPaddingGenerator()); // Only static part with a default option.c
738 }
739
740 // Similar to makeVertexGeneratorConfig, choosing the final value.
chooseVertexGenerator(const VertexGenerator * staticGen,const VertexGenerator * dynamicGen)741 const VertexGenerator* chooseVertexGenerator (const VertexGenerator* staticGen, const VertexGenerator* dynamicGen)
742 {
743 DE_ASSERT(!(dynamicGen && !staticGen));
744 if (dynamicGen)
745 return dynamicGen;
746 if (staticGen)
747 return staticGen;
748 return getVertexWithPaddingGenerator();
749 }
750
751 enum class TopologyClass
752 {
753 POINT,
754 LINE,
755 TRIANGLE,
756 PATCH,
757 INVALID,
758 };
759
topologyClassName(TopologyClass tclass)760 std::string topologyClassName (TopologyClass tclass)
761 {
762 switch (tclass)
763 {
764 case TopologyClass::POINT: return "point";
765 case TopologyClass::LINE: return "line";
766 case TopologyClass::TRIANGLE: return "triangle";
767 case TopologyClass::PATCH: return "patch";
768 default:
769 break;
770 }
771
772 DE_ASSERT(false);
773 return "";
774 }
775
getTopologyClass(vk::VkPrimitiveTopology topology)776 TopologyClass getTopologyClass (vk::VkPrimitiveTopology topology)
777 {
778 switch (topology)
779 {
780 case vk::VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
781 return TopologyClass::POINT;
782 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST:
783 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
784 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY:
785 case vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY:
786 return TopologyClass::LINE;
787 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
788 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
789 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
790 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY:
791 case vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY:
792 return TopologyClass::TRIANGLE;
793 case vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST:
794 return TopologyClass::PATCH;
795 default:
796 break;
797 }
798
799 DE_ASSERT(false);
800 return TopologyClass::INVALID;
801 }
802
803 struct TestConfig
804 {
805 // Main sequence ordering.
806 SequenceOrdering sequenceOrdering;
807
808 // Drawing parameters: tests will draw one or more flat meshes of triangles covering the whole "screen".
809 std::vector<MeshParams> meshParams; // Mesh parameters for each full-screen layer of geometry.
810 deUint32 referenceStencil; // Reference stencil value.
811
812 // Clearing parameters for the framebuffer.
813 vk::VkClearValue clearColorValue;
814 float clearDepthValue;
815 deUint32 clearStencilValue;
816
817 // Expected output in the attachments.
818 ReferenceColorGenerator referenceColor;
819 float expectedDepth;
820 deUint32 expectedStencil;
821
822 // Depth bounds parameters for the pipeline.
823 float minDepthBounds;
824 float maxDepthBounds;
825
826 // Force inclusion of passthrough geometry shader or not.
827 bool forceGeometryShader;
828
829 // Force single vertex in the VBO.
830 bool singleVertex;
831 deUint32 singleVertexDrawCount;
832
833 // Offset and extra room after the vertex buffer data.
834 vk::VkDeviceSize vertexDataOffset;
835 vk::VkDeviceSize vertexDataExtraBytes;
836
837 // Static and dynamic pipeline configuration.
838 VertexGeneratorConfig vertexGenerator;
839 CullModeConfig cullModeConfig;
840 FrontFaceConfig frontFaceConfig;
841 TopologyConfig topologyConfig;
842 ViewportConfig viewportConfig;
843 ScissorConfig scissorConfig;
844 StrideConfig strideConfig;
845 DepthTestEnableConfig depthTestEnableConfig;
846 DepthWriteEnableConfig depthWriteEnableConfig;
847 DepthCompareOpConfig depthCompareOpConfig;
848 DepthBoundsTestEnableConfig depthBoundsTestEnableConfig;
849 StencilTestEnableConfig stencilTestEnableConfig;
850 StencilOpConfig stencilOpConfig;
851 DepthBiasEnableConfig depthBiasEnableConfig;
852 RastDiscardEnableConfig rastDiscardEnableConfig;
853 PrimRestartEnableConfig primRestartEnableConfig;
854 LogicOpConfig logicOpConfig;
855 PatchControlPointsConfig patchControlPointsConfig;
856 DepthBiasConfig depthBiasConfig;
857
858 // Sane defaults.
TestConfigvkt::pipeline::__anon8f7ea4da0111::TestConfig859 TestConfig (SequenceOrdering ordering, const VertexGenerator* staticVertexGenerator = nullptr, const VertexGenerator* dynamicVertexGenerator = nullptr)
860 : sequenceOrdering (ordering)
861 , meshParams (1u, MeshParams())
862 , referenceStencil (0u)
863 , clearColorValue (vk::makeClearValueColor(kDefaultClearColor))
864 , clearDepthValue (1.0f)
865 , clearStencilValue (0u)
866 , referenceColor (SingleColorGenerator(kDefaultTriangleColor))
867 , expectedDepth (1.0f)
868 , expectedStencil (0u)
869 , minDepthBounds (0.0f)
870 , maxDepthBounds (1.0f)
871 , forceGeometryShader (false)
872 , singleVertex (false)
873 , singleVertexDrawCount (0)
874 , vertexDataOffset (0ull)
875 , vertexDataExtraBytes (0ull)
876 , vertexGenerator (makeVertexGeneratorConfig(staticVertexGenerator, dynamicVertexGenerator))
877 , cullModeConfig (static_cast<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE))
878 , frontFaceConfig (vk::VK_FRONT_FACE_COUNTER_CLOCKWISE)
879 // By default we will use a triangle strip with 6 vertices that could be wrongly interpreted as a triangle list with 2 triangles.
880 , topologyConfig (vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
881 , viewportConfig (ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight)))
882 , scissorConfig (ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight)))
883 // By default, the vertex stride is the size of a vertex according to the chosen vertex type.
884 , strideConfig (chooseVertexGenerator(staticVertexGenerator, dynamicVertexGenerator)->getVertexDataStrides())
885 , depthTestEnableConfig (false)
886 , depthWriteEnableConfig (false)
887 , depthCompareOpConfig (vk::VK_COMPARE_OP_NEVER)
888 , depthBoundsTestEnableConfig (false)
889 , stencilTestEnableConfig (false)
890 , stencilOpConfig (StencilOpVec(1u, kDefaultStencilOpParams))
891 , depthBiasEnableConfig (false)
892 , rastDiscardEnableConfig (false)
893 , primRestartEnableConfig (false)
894 , logicOpConfig (vk::VK_LOGIC_OP_CLEAR)
895 , patchControlPointsConfig (1u)
896 , depthBiasConfig (kNoDepthBiasParams)
897 , m_swappedValues (false)
898 {
899 }
900
901 // Get the proper viewport vector according to the test config.
getActiveViewportVecvkt::pipeline::__anon8f7ea4da0111::TestConfig902 const ViewportVec& getActiveViewportVec () const
903 {
904 return ((viewportConfig.dynamicValue && !m_swappedValues) ? viewportConfig.dynamicValue.get() : viewportConfig.staticValue);
905 }
906
907 // Gets the proper vertex generator according to the test config.
getActiveVertexGeneratorvkt::pipeline::__anon8f7ea4da0111::TestConfig908 const VertexGenerator* getActiveVertexGenerator () const
909 {
910 return ((vertexGenerator.dynamicValue && !m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
911 }
912
913 // Gets the inactive vertex generator according to the test config. If there's only one, return that.
getInactiveVertexGeneratorvkt::pipeline::__anon8f7ea4da0111::TestConfig914 const VertexGenerator* getInactiveVertexGenerator () const
915 {
916 return ((vertexGenerator.dynamicValue && m_swappedValues) ? vertexGenerator.dynamicValue.get() : vertexGenerator.staticValue);
917 }
918
919 // Get the active number of patch control points according to the test config.
getActivePatchControlPointsvkt::pipeline::__anon8f7ea4da0111::TestConfig920 deUint32 getActivePatchControlPoints () const
921 {
922 return ((patchControlPointsConfig.dynamicValue && !m_swappedValues) ? patchControlPointsConfig.dynamicValue.get() : patchControlPointsConfig.staticValue);
923 }
924
925 // Get the active depth bias parameters.
getActiveDepthBiasParamsvkt::pipeline::__anon8f7ea4da0111::TestConfig926 DepthBiasParams getActiveDepthBiasParams () const
927 {
928 return ((depthBiasConfig.dynamicValue && !m_swappedValues) ? depthBiasConfig.dynamicValue.get() : depthBiasConfig.staticValue);
929 }
930
931 // Returns true if there is more than one viewport.
isMultiViewportvkt::pipeline::__anon8f7ea4da0111::TestConfig932 bool isMultiViewport () const
933 {
934 return (getActiveViewportVec().size() > 1);
935 }
936
937 // Returns true if the case needs a geometry shader.
needsGeometryShadervkt::pipeline::__anon8f7ea4da0111::TestConfig938 bool needsGeometryShader () const
939 {
940 // Writing to gl_ViewportIndex from vertex or tesselation shaders needs the shaderOutputViewportIndex feature, which is less
941 // commonly supported than geometry shaders, so we will use a geometry shader if we need to write to it.
942 return (isMultiViewport() || forceGeometryShader);
943 }
944
945 // Returns true if we should use the static and dynamic values exchanged.
946 // This makes the static part of the pipeline have the actual expected values.
isReversedvkt::pipeline::__anon8f7ea4da0111::TestConfig947 bool isReversed () const
948 {
949 return (sequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
950 sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC);
951 }
952
953 // Swaps static and dynamic configuration values.
swapValuesvkt::pipeline::__anon8f7ea4da0111::TestConfig954 void swapValues ()
955 {
956 vertexGenerator.swapValues();
957 cullModeConfig.swapValues();
958 frontFaceConfig.swapValues();
959 topologyConfig.swapValues();
960 viewportConfig.swapValues();
961 scissorConfig.swapValues();
962 strideConfig.swapValues();
963 depthTestEnableConfig.swapValues();
964 depthWriteEnableConfig.swapValues();
965 depthCompareOpConfig.swapValues();
966 depthBoundsTestEnableConfig.swapValues();
967 stencilTestEnableConfig.swapValues();
968 stencilOpConfig.swapValues();
969 depthBiasEnableConfig.swapValues();
970 rastDiscardEnableConfig.swapValues();
971 primRestartEnableConfig.swapValues();
972 logicOpConfig.swapValues();
973 patchControlPointsConfig.swapValues();
974 depthBiasConfig.swapValues();
975
976 m_swappedValues = !m_swappedValues;
977 }
978
979 // Returns the number of iterations when recording commands.
numIterationsvkt::pipeline::__anon8f7ea4da0111::TestConfig980 deUint32 numIterations () const
981 {
982 deUint32 iterations = 0u;
983
984 switch (sequenceOrdering)
985 {
986 case SequenceOrdering::TWO_DRAWS_DYNAMIC:
987 case SequenceOrdering::TWO_DRAWS_STATIC:
988 iterations = 2u;
989 break;
990 default:
991 iterations = 1u;
992 break;
993 }
994
995 return iterations;
996 }
997
998 // Returns true if we're testing the logic op.
testLogicOpvkt::pipeline::__anon8f7ea4da0111::TestConfig999 bool testLogicOp () const
1000 {
1001 return static_cast<bool>(logicOpConfig.dynamicValue);
1002 }
1003
1004 // Returns true if we're testing the patch control points.
testPatchControlPointsvkt::pipeline::__anon8f7ea4da0111::TestConfig1005 bool testPatchControlPoints () const
1006 {
1007 return static_cast<bool>(patchControlPointsConfig.dynamicValue);
1008 }
1009
1010 // Returns true if the topology class is patches for tessellation.
patchesTopologyvkt::pipeline::__anon8f7ea4da0111::TestConfig1011 bool patchesTopology () const
1012 {
1013 return (getTopologyClass(topologyConfig.staticValue) == TopologyClass::PATCH);
1014 }
1015
1016 // Returns true if the test needs tessellation shaders.
needsTessellationvkt::pipeline::__anon8f7ea4da0111::TestConfig1017 bool needsTessellation () const
1018 {
1019 return (testPatchControlPoints() || patchesTopology());
1020 }
1021
1022 // Returns true if the test needs an index buffer.
needsIndexBuffervkt::pipeline::__anon8f7ea4da0111::TestConfig1023 bool needsIndexBuffer () const
1024 {
1025 return static_cast<bool>(primRestartEnableConfig.dynamicValue);
1026 }
1027
1028 // Returns true if the test needs the depth bias clamp feature.
needsDepthBiasClampFeaturevkt::pipeline::__anon8f7ea4da0111::TestConfig1029 bool needsDepthBiasClampFeature () const
1030 {
1031 return (getActiveDepthBiasParams().clamp != 0.0f);
1032 }
1033
1034 // Returns the appropriate color image format for the test.
colorFormatvkt::pipeline::__anon8f7ea4da0111::TestConfig1035 vk::VkFormat colorFormat () const
1036 {
1037 // Pick int color format when testing logic op.
1038 return (testLogicOp() ? kIntColorFormat : kUnormColorFormat);
1039 }
1040
1041 // Returns the list of dynamic states affected by this config.
getDynamicStatesvkt::pipeline::__anon8f7ea4da0111::TestConfig1042 std::vector<vk::VkDynamicState> getDynamicStates () const
1043 {
1044 std::vector<vk::VkDynamicState> dynamicStates;
1045
1046 if (depthBiasConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS);
1047 if (cullModeConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_CULL_MODE_EXT);
1048 if (frontFaceConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_FRONT_FACE_EXT);
1049 if (topologyConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
1050 if (viewportConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT);
1051 if (scissorConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT);
1052 if (strideConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
1053 if (depthTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT);
1054 if (depthWriteEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT);
1055 if (depthCompareOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT);
1056 if (depthBoundsTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT);
1057 if (stencilTestEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT);
1058 if (stencilOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_STENCIL_OP_EXT);
1059 if (vertexGenerator.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
1060 if (patchControlPointsConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
1061 if (rastDiscardEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT);
1062 if (depthBiasEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT);
1063 if (logicOpConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_LOGIC_OP_EXT);
1064 if (primRestartEnableConfig.dynamicValue) dynamicStates.push_back(vk::VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT);
1065
1066 return dynamicStates;
1067 }
1068
1069 // Returns the list of extensions needed by this config.
getRequiredExtensionsvkt::pipeline::__anon8f7ea4da0111::TestConfig1070 std::vector<std::string> getRequiredExtensions () const
1071 {
1072 std::vector<std::string> extensions;
1073
1074 if (cullModeConfig.dynamicValue
1075 || frontFaceConfig.dynamicValue
1076 || topologyConfig.dynamicValue
1077 || viewportConfig.dynamicValue
1078 || scissorConfig.dynamicValue
1079 || strideConfig.dynamicValue
1080 || depthTestEnableConfig.dynamicValue
1081 || depthWriteEnableConfig.dynamicValue
1082 || depthCompareOpConfig.dynamicValue
1083 || depthBoundsTestEnableConfig.dynamicValue
1084 || stencilTestEnableConfig.dynamicValue
1085 || stencilOpConfig.dynamicValue)
1086 {
1087 extensions.push_back("VK_EXT_extended_dynamic_state");
1088 }
1089
1090 if (vertexGenerator.dynamicValue)
1091 {
1092 extensions.push_back("VK_EXT_vertex_input_dynamic_state");
1093 }
1094
1095 if (patchControlPointsConfig.dynamicValue
1096 || rastDiscardEnableConfig.dynamicValue
1097 || depthBiasEnableConfig.dynamicValue
1098 || logicOpConfig.dynamicValue
1099 || primRestartEnableConfig.dynamicValue)
1100 {
1101 extensions.push_back("VK_EXT_extended_dynamic_state2");
1102 }
1103
1104 return extensions;
1105 }
1106
1107 private:
1108 // Extended dynamic state cases as created by createExtendedDynamicStateTests() are based on the assumption that, when a state
1109 // has a static and a dynamic value configured at the same time, the static value is wrong and the dynamic value will give
1110 // expected results. That's appropriate for most test variants, but in some others we want to reverse the situation: a dynamic
1111 // pipeline with wrong values and a static one with good values.
1112 //
1113 // Instead of modifying how tests are created, we use isReversed() and swapValues() above, allowing us to swap static and
1114 // 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
1115 // given point in time in order to correctly answer some questions while running the test. m_swappedValues tracks that state.
1116 bool m_swappedValues;
1117 };
1118
1119 struct PushConstants
1120 {
1121 tcu::Vec4 triangleColor;
1122 float meshDepth;
1123 deInt32 viewPortIndex;
1124 float scaleX;
1125 float scaleY;
1126 float offsetX;
1127 float offsetY;
1128 float stripScale;
1129 };
1130
copy(vk::VkStencilOpState & dst,const StencilOpParams & src)1131 void copy(vk::VkStencilOpState& dst, const StencilOpParams& src)
1132 {
1133 dst.failOp = src.failOp;
1134 dst.passOp = src.passOp;
1135 dst.depthFailOp = src.depthFailOp;
1136 dst.compareOp = src.compareOp;
1137 }
1138
1139 class ExtendedDynamicStateTest : public vkt::TestCase
1140 {
1141 public:
1142 ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig);
~ExtendedDynamicStateTest(void)1143 virtual ~ExtendedDynamicStateTest (void) {}
1144
1145 virtual void checkSupport (Context& context) const;
1146 virtual void initPrograms (vk::SourceCollections& programCollection) const;
1147 virtual TestInstance* createInstance (Context& context) const;
1148
1149 private:
1150 TestConfig m_testConfig;
1151 };
1152
1153 class ExtendedDynamicStateInstance : public vkt::TestInstance
1154 {
1155 public:
1156 ExtendedDynamicStateInstance (Context& context, const TestConfig& testConfig);
~ExtendedDynamicStateInstance(void)1157 virtual ~ExtendedDynamicStateInstance (void) {}
1158
1159 virtual tcu::TestStatus iterate (void);
1160
1161 private:
1162 TestConfig m_testConfig;
1163 };
1164
ExtendedDynamicStateTest(tcu::TestContext & testCtx,const std::string & name,const std::string & description,const TestConfig & testConfig)1165 ExtendedDynamicStateTest::ExtendedDynamicStateTest (tcu::TestContext& testCtx, const std::string& name, const std::string& description, const TestConfig& testConfig)
1166 : vkt::TestCase (testCtx, name, description)
1167 , m_testConfig (testConfig)
1168 {
1169 const auto staticTopologyClass = getTopologyClass(testConfig.topologyConfig.staticValue);
1170 DE_UNREF(staticTopologyClass); // For release builds.
1171
1172 // Matching topology classes.
1173 DE_ASSERT(!testConfig.topologyConfig.dynamicValue ||
1174 staticTopologyClass == getTopologyClass(testConfig.topologyConfig.dynamicValue.get()));
1175
1176 // Supported topology classes for these tests.
1177 DE_ASSERT(staticTopologyClass == TopologyClass::LINE || staticTopologyClass == TopologyClass::TRIANGLE
1178 || staticTopologyClass == TopologyClass::PATCH);
1179
1180 // Make sure these are consistent.
1181 DE_ASSERT(!(m_testConfig.testPatchControlPoints() && !m_testConfig.patchesTopology()));
1182 DE_ASSERT(!(m_testConfig.patchesTopology() && m_testConfig.getActivePatchControlPoints() <= 1u));
1183 }
1184
checkSupport(Context & context) const1185 void ExtendedDynamicStateTest::checkSupport (Context& context) const
1186 {
1187 const auto& vki = context.getInstanceInterface();
1188 const auto physicalDevice = context.getPhysicalDevice();
1189
1190 // Check extension support.
1191 const auto requiredExtensions = m_testConfig.getRequiredExtensions();
1192 for (const auto& extension : requiredExtensions)
1193 context.requireDeviceFunctionality(extension);
1194
1195 // Needed for extended state included as part of VK_EXT_extended_dynamic_state2.
1196 if (de::contains(begin(requiredExtensions), end(requiredExtensions), "VK_EXT_extended_dynamic_state2"))
1197 {
1198 const auto& eds2Features = context.getExtendedDynamicState2FeaturesEXT();
1199
1200 if (m_testConfig.testLogicOp() && !eds2Features.extendedDynamicState2LogicOp)
1201 TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing LogicOp dynamically is not supported");
1202
1203 if (m_testConfig.testPatchControlPoints() && !eds2Features.extendedDynamicState2PatchControlPoints)
1204 TCU_THROW(NotSupportedError, "VK_EXT_extended_dynamic_state2 : changing patch control points dynamically is not supported");
1205 }
1206
1207 // Check the number of viewports needed and the corresponding limits.
1208 const auto& viewportConfig = m_testConfig.viewportConfig;
1209 auto numViewports = viewportConfig.staticValue.size();
1210
1211 if (viewportConfig.dynamicValue)
1212 numViewports = std::max(numViewports, viewportConfig.dynamicValue.get().size());
1213
1214 if (numViewports > 1)
1215 {
1216 const auto properties = vk::getPhysicalDeviceProperties(vki, physicalDevice);
1217 if (numViewports > static_cast<decltype(numViewports)>(properties.limits.maxViewports))
1218 TCU_THROW(NotSupportedError, "Number of viewports not supported (" + de::toString(numViewports) + ")");
1219 }
1220
1221 const auto& dbTestEnable = m_testConfig.depthBoundsTestEnableConfig;
1222 const bool useDepthBounds = (dbTestEnable.staticValue || (dbTestEnable.dynamicValue && dbTestEnable.dynamicValue.get()));
1223
1224 if (useDepthBounds || m_testConfig.needsGeometryShader() || m_testConfig.needsTessellation() || m_testConfig.needsDepthBiasClampFeature())
1225 {
1226 const auto features = vk::getPhysicalDeviceFeatures(vki, physicalDevice);
1227
1228 // Check depth bounds test support.
1229 if (useDepthBounds && !features.depthBounds)
1230 TCU_THROW(NotSupportedError, "Depth bounds feature not supported");
1231
1232 // Check geometry shader support.
1233 if (m_testConfig.needsGeometryShader() && !features.geometryShader)
1234 TCU_THROW(NotSupportedError, "Geometry shader not supported");
1235
1236 // Check tessellation support
1237 if (m_testConfig.needsTessellation() && !features.tessellationShader)
1238 TCU_THROW(NotSupportedError, "Tessellation feature not supported");
1239
1240 // Check depth bias clamp feature.
1241 if (m_testConfig.needsDepthBiasClampFeature() && !features.depthBiasClamp)
1242 TCU_THROW(NotSupportedError, "Depth bias clamp not supported");
1243 }
1244
1245 // Check color image format support (depth/stencil will be chosen at runtime).
1246 const vk::VkFormatFeatureFlags kColorFeatures = (vk::VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1247
1248 // Pick int color format for logic op
1249 vk::VkFormat colorFormat = m_testConfig.colorFormat();
1250 const auto colorProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, colorFormat);
1251
1252 if ((colorProperties.optimalTilingFeatures & kColorFeatures) != kColorFeatures)
1253 TCU_THROW(NotSupportedError, "Required color image features not supported");
1254 }
1255
initPrograms(vk::SourceCollections & programCollection) const1256 void ExtendedDynamicStateTest::initPrograms (vk::SourceCollections& programCollection) const
1257 {
1258 std::ostringstream pushSource;
1259 std::ostringstream vertSourceTemplateStream;
1260 std::ostringstream fragSource;
1261 std::ostringstream geomSource;
1262 std::ostringstream tescSource;
1263 std::ostringstream teseSource;
1264
1265 pushSource
1266 << "layout(push_constant, std430) uniform PushConstantsBlock {\n"
1267 << " vec4 triangleColor;\n"
1268 << " float depthValue;\n"
1269 << " int viewPortIndex;\n"
1270 << " float scaleX;\n"
1271 << " float scaleY;\n"
1272 << " float offsetX;\n"
1273 << " float offsetY;\n"
1274 << " float stripScale;\n"
1275 << "} pushConstants;\n"
1276 ;
1277 const auto pushConstants = pushSource.str();
1278
1279 // The actual generator, attributes and calculations.
1280 const auto activeGen = m_testConfig.getActiveVertexGenerator();
1281 const auto attribDecls = activeGen->getAttributeDeclarations();
1282 const auto coordCalcs = activeGen->getVertexCoordCalc();
1283
1284 // The static generator, attributes and calculations, for the static pipeline, if needed.
1285 const auto inactiveGen = m_testConfig.getInactiveVertexGenerator();
1286 const auto staticAttribDec = inactiveGen->getAttributeDeclarations();
1287 const auto staticCoordCalc = inactiveGen->getVertexCoordCalc();
1288
1289 std::ostringstream activeAttribs;
1290 std::ostringstream activeCalcs;
1291 std::ostringstream inactiveAttribs;
1292 std::ostringstream inactiveCalcs;
1293
1294 for (const auto& decl : attribDecls)
1295 activeAttribs << decl << "\n";
1296
1297 for (const auto& statement : coordCalcs)
1298 activeCalcs << " " << statement << "\n";
1299
1300 for (const auto& decl : staticAttribDec)
1301 inactiveAttribs << decl << "\n";
1302
1303 for (const auto& statement : staticCoordCalc)
1304 inactiveCalcs << " " << statement << "\n";
1305
1306 vertSourceTemplateStream
1307 << "#version 450\n"
1308 << pushConstants
1309 << "${ATTRIBUTES}"
1310 << "out gl_PerVertex\n"
1311 << "{\n"
1312 << " vec4 gl_Position;\n"
1313 << "};\n"
1314 << "void main() {\n"
1315 << "${CALCULATIONS}"
1316 << " gl_Position = vec4(vertexCoords.x * pushConstants.scaleX + pushConstants.offsetX, vertexCoords.y * pushConstants.scaleY + pushConstants.offsetY, pushConstants.depthValue, 1.0);\n"
1317 << " vec2 stripOffset;\n"
1318 << " switch (gl_VertexIndex) {\n"
1319 << " case 0: stripOffset = vec2(0.0, 0.0); break;\n"
1320 << " case 1: stripOffset = vec2(0.0, 1.0); break;\n"
1321 << " case 2: stripOffset = vec2(1.0, 0.0); break;\n"
1322 << " case 3: stripOffset = vec2(1.0, 1.0); break;\n"
1323 << " case 4: stripOffset = vec2(2.0, 0.0); break;\n"
1324 << " case 5: stripOffset = vec2(2.0, 1.0); break;\n"
1325 << " default: stripOffset = vec2(-1000.0); break;\n"
1326 << " }\n"
1327 << " gl_Position.xy += pushConstants.stripScale * stripOffset;\n"
1328 << "}\n"
1329 ;
1330
1331 tcu::StringTemplate vertSourceTemplate (vertSourceTemplateStream.str());
1332
1333 std::map<std::string, std::string> activeMap;
1334 std::map<std::string, std::string> inactiveMap;
1335
1336 activeMap["ATTRIBUTES"] = activeAttribs.str();
1337 activeMap["CALCULATIONS"] = activeCalcs.str();
1338
1339 inactiveMap["ATTRIBUTES"] = inactiveAttribs.str();
1340 inactiveMap["CALCULATIONS"] = inactiveCalcs.str();
1341
1342 const auto activeVertSource = vertSourceTemplate.specialize(activeMap);
1343 const auto inactiveVertSource = vertSourceTemplate.specialize(inactiveMap);
1344
1345 const auto colorFormat = m_testConfig.colorFormat();
1346 const auto vecType = (vk::isUnormFormat(colorFormat) ? "vec4" : "uvec4");
1347
1348 fragSource
1349 << "#version 450\n"
1350 << pushConstants
1351 << "layout(location=0) out " << vecType << " color;\n"
1352 << "void main() {\n"
1353 << " color = " << vecType << "(pushConstants.triangleColor);\n"
1354 << "}\n"
1355 ;
1356
1357 if (m_testConfig.needsGeometryShader())
1358 {
1359 const auto topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
1360 const std::string inputPrimitive = ((topologyClass == TopologyClass::LINE) ? "lines" : "triangles");
1361 const deUint32 vertexCount = ((topologyClass == TopologyClass::LINE) ? 2u : 3u);
1362 const std::string outputPrimitive = ((topologyClass == TopologyClass::LINE) ? "line_strip" : "triangle_strip");
1363
1364 geomSource
1365 << "#version 450\n"
1366 << "layout (" << inputPrimitive << ") in;\n"
1367 << "layout (" << outputPrimitive << ", max_vertices=" << vertexCount << ") out;\n"
1368 << (m_testConfig.isMultiViewport() ? pushConstants : "")
1369 << "in gl_PerVertex\n"
1370 << "{\n"
1371 << " vec4 gl_Position;\n"
1372 << "} gl_in[" << vertexCount << "];\n"
1373 << "out gl_PerVertex\n"
1374 << "{\n"
1375 << " vec4 gl_Position;\n"
1376 << "};\n"
1377 << "void main() {\n"
1378 << (m_testConfig.isMultiViewport() ? " gl_ViewportIndex = pushConstants.viewPortIndex;\n" : "")
1379 ;
1380
1381 for (deUint32 i = 0; i < vertexCount; ++i)
1382 {
1383 geomSource
1384 << " gl_Position = gl_in[" << i << "].gl_Position;\n"
1385 << " EmitVertex();\n"
1386 ;
1387 }
1388
1389 geomSource
1390 << "}\n"
1391 ;
1392 }
1393
1394 if (m_testConfig.needsTessellation())
1395 {
1396 tescSource
1397 << "#version 450\n"
1398 << "#extension GL_EXT_tessellation_shader : require\n"
1399 << "layout(vertices=3) out;\n"
1400 << "in gl_PerVertex\n"
1401 << "{\n"
1402 << " vec4 gl_Position;\n"
1403 << "} gl_in[gl_MaxPatchVertices];\n"
1404 << "out gl_PerVertex\n"
1405 << "{\n"
1406 << " vec4 gl_Position;\n"
1407 << "} gl_out[];\n"
1408 << "void main() {\n"
1409 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
1410 << " gl_TessLevelOuter[0] = 3.0;\n"
1411 << " gl_TessLevelOuter[1] = 3.0;\n"
1412 << " gl_TessLevelOuter[2] = 3.0;\n"
1413 << " gl_TessLevelInner[0] = 3.0;\n"
1414 << "}\n"
1415 ;
1416 teseSource
1417 << "#version 450\n"
1418 << "#extension GL_EXT_tessellation_shader : require\n"
1419 << "layout(triangles) in;\n"
1420 << "in gl_PerVertex\n"
1421 << "{\n"
1422 << " vec4 gl_Position;\n"
1423 << "} gl_in[gl_MaxPatchVertices];\n"
1424 << "out gl_PerVertex\n"
1425 << "{\n"
1426 << " vec4 gl_Position;\n"
1427 << "};\n"
1428 << "void main() {\n"
1429 << " gl_Position = (gl_in[0].gl_Position * gl_TessCoord.x + \n"
1430 << " gl_in[1].gl_Position * gl_TessCoord.y + \n"
1431 << " gl_in[2].gl_Position * gl_TessCoord.z);\n"
1432 << "}\n";
1433 }
1434
1435 // In reversed test configurations, the pipeline with dynamic state needs to have the inactive shader.
1436 const auto kReversed = m_testConfig.isReversed();
1437 programCollection.glslSources.add("dynamicVert") << glu::VertexSource(kReversed ? inactiveVertSource : activeVertSource);
1438 programCollection.glslSources.add("staticVert") << glu::VertexSource(kReversed ? activeVertSource : inactiveVertSource);
1439
1440 programCollection.glslSources.add("frag") << glu::FragmentSource(fragSource.str());
1441 if (m_testConfig.needsGeometryShader())
1442 programCollection.glslSources.add("geom") << glu::GeometrySource(geomSource.str());
1443 if (m_testConfig.needsTessellation())
1444 {
1445 programCollection.glslSources.add("tesc") << glu::TessellationControlSource(tescSource.str());
1446 programCollection.glslSources.add("tese") << glu::TessellationEvaluationSource(teseSource.str());
1447 }
1448 }
1449
createInstance(Context & context) const1450 TestInstance* ExtendedDynamicStateTest::createInstance (Context& context) const
1451 {
1452 return new ExtendedDynamicStateInstance(context, m_testConfig);
1453 }
1454
ExtendedDynamicStateInstance(Context & context,const TestConfig & testConfig)1455 ExtendedDynamicStateInstance::ExtendedDynamicStateInstance(Context& context, const TestConfig& testConfig)
1456 : vkt::TestInstance (context)
1457 , m_testConfig (testConfig)
1458 {
1459 }
1460
1461 struct VertexBufferInfo
1462 {
VertexBufferInfovkt::pipeline::__anon8f7ea4da0111::VertexBufferInfo1463 VertexBufferInfo ()
1464 : buffer ()
1465 , offset (0ull)
1466 , dataSize (0ull)
1467 {}
1468
VertexBufferInfovkt::pipeline::__anon8f7ea4da0111::VertexBufferInfo1469 VertexBufferInfo (VertexBufferInfo&& other)
1470 : buffer (other.buffer.release())
1471 , offset (other.offset)
1472 , dataSize (other.dataSize)
1473 {}
1474
1475 de::MovePtr<vk::BufferWithMemory> buffer;
1476 vk::VkDeviceSize offset;
1477 vk::VkDeviceSize dataSize;
1478 };
1479
logErrors(tcu::TestLog & log,const std::string & setName,const std::string & setDesc,const tcu::ConstPixelBufferAccess & result,const tcu::ConstPixelBufferAccess & errorMask)1480 void logErrors(tcu::TestLog& log, const std::string& setName, const std::string& setDesc, const tcu::ConstPixelBufferAccess& result, const tcu::ConstPixelBufferAccess& errorMask)
1481 {
1482 log << tcu::TestLog::ImageSet(setName, setDesc)
1483 << tcu::TestLog::Image(setName + "Result", "Result image", result)
1484 << tcu::TestLog::Image(setName + "ErrorMask", "Error mask with errors marked in red", errorMask)
1485 << tcu::TestLog::EndImageSet;
1486 }
1487
copyAndFlush(const vk::DeviceInterface & vkd,vk::VkDevice device,vk::BufferWithMemory & buffer,size_t offset,const void * src,size_t size)1488 void copyAndFlush(const vk::DeviceInterface& vkd, vk::VkDevice device, vk::BufferWithMemory& buffer, size_t offset, const void* src, size_t size)
1489 {
1490 auto& alloc = buffer.getAllocation();
1491 auto dst = reinterpret_cast<char*>(alloc.getHostPtr());
1492
1493 deMemcpy(dst + offset, src, size);
1494 vk::flushAlloc(vkd, device, alloc);
1495 }
1496
1497 // Sets values for dynamic states if needed according to the test configuration.
setDynamicStates(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer)1498 void setDynamicStates(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer)
1499 {
1500 if (testConfig.cullModeConfig.dynamicValue)
1501 vkd.cmdSetCullModeEXT(cmdBuffer, testConfig.cullModeConfig.dynamicValue.get());
1502
1503 if (testConfig.frontFaceConfig.dynamicValue)
1504 vkd.cmdSetFrontFaceEXT(cmdBuffer, testConfig.frontFaceConfig.dynamicValue.get());
1505
1506 if (testConfig.topologyConfig.dynamicValue)
1507 vkd.cmdSetPrimitiveTopologyEXT(cmdBuffer, testConfig.topologyConfig.dynamicValue.get());
1508
1509 if (testConfig.viewportConfig.dynamicValue)
1510 {
1511 const auto& viewports = testConfig.viewportConfig.dynamicValue.get();
1512 vkd.cmdSetViewportWithCountEXT(cmdBuffer, static_cast<deUint32>(viewports.size()), viewports.data());
1513 }
1514
1515 if (testConfig.scissorConfig.dynamicValue)
1516 {
1517 const auto& scissors = testConfig.scissorConfig.dynamicValue.get();
1518 vkd.cmdSetScissorWithCountEXT(cmdBuffer, static_cast<deUint32>(scissors.size()), scissors.data());
1519 }
1520
1521 if (testConfig.depthTestEnableConfig.dynamicValue)
1522 vkd.cmdSetDepthTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthTestEnableConfig.dynamicValue.get()));
1523
1524 if (testConfig.depthWriteEnableConfig.dynamicValue)
1525 vkd.cmdSetDepthWriteEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthWriteEnableConfig.dynamicValue.get()));
1526
1527 if (testConfig.depthCompareOpConfig.dynamicValue)
1528 vkd.cmdSetDepthCompareOpEXT(cmdBuffer, testConfig.depthCompareOpConfig.dynamicValue.get());
1529
1530 if (testConfig.depthBoundsTestEnableConfig.dynamicValue)
1531 vkd.cmdSetDepthBoundsTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBoundsTestEnableConfig.dynamicValue.get()));
1532
1533 if (testConfig.stencilTestEnableConfig.dynamicValue)
1534 vkd.cmdSetStencilTestEnableEXT(cmdBuffer, makeVkBool32(testConfig.stencilTestEnableConfig.dynamicValue.get()));
1535
1536 if (testConfig.depthBiasEnableConfig.dynamicValue)
1537 vkd.cmdSetDepthBiasEnableEXT(cmdBuffer, makeVkBool32(testConfig.depthBiasEnableConfig.dynamicValue.get()));
1538
1539 if (testConfig.depthBiasConfig.dynamicValue)
1540 {
1541 const auto& bias = testConfig.depthBiasConfig.dynamicValue.get();
1542 vkd.cmdSetDepthBias(cmdBuffer, bias.constantFactor, bias.clamp, 0.0f);
1543 }
1544
1545 if (testConfig.rastDiscardEnableConfig.dynamicValue)
1546 vkd.cmdSetRasterizerDiscardEnableEXT(cmdBuffer, makeVkBool32(testConfig.rastDiscardEnableConfig.dynamicValue.get()));
1547
1548 if (testConfig.primRestartEnableConfig.dynamicValue)
1549 vkd.cmdSetPrimitiveRestartEnableEXT(cmdBuffer, makeVkBool32(testConfig.primRestartEnableConfig.dynamicValue.get()));
1550
1551 if (testConfig.logicOpConfig.dynamicValue)
1552 vkd.cmdSetLogicOpEXT(cmdBuffer, testConfig.logicOpConfig.dynamicValue.get());
1553
1554 if (testConfig.patchControlPointsConfig.dynamicValue)
1555 vkd.cmdSetPatchControlPointsEXT(cmdBuffer, testConfig.patchControlPointsConfig.dynamicValue.get());
1556
1557 if (testConfig.stencilOpConfig.dynamicValue)
1558 {
1559 for (const auto& params : testConfig.stencilOpConfig.dynamicValue.get())
1560 vkd.cmdSetStencilOpEXT(cmdBuffer, params.faceMask, params.failOp, params.passOp, params.depthFailOp, params.compareOp);
1561 }
1562
1563 if (testConfig.vertexGenerator.dynamicValue)
1564 {
1565 const auto generator = testConfig.vertexGenerator.dynamicValue.get();
1566 const auto bindings = generator->getBindingDescriptions2(testConfig.strideConfig.staticValue);
1567 const auto attributes = generator->getAttributeDescriptions2();
1568
1569 vkd.cmdSetVertexInputEXT(cmdBuffer,
1570 static_cast<deUint32>(bindings.size()), de::dataOrNull(bindings),
1571 static_cast<deUint32>(attributes.size()), de::dataOrNull(attributes));
1572 }
1573 }
1574
1575 // Bind the appropriate vertex buffers using dynamic strides if the test configuration needs a dynamic stride.
1576 // Return true if the vertex buffer was bound.
maybeBindVertexBufferDynStride(const TestConfig & testConfig,const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,size_t meshIdx,const std::vector<VertexBufferInfo> & vertBuffers,const std::vector<VertexBufferInfo> & rvertBuffers)1577 bool maybeBindVertexBufferDynStride(const TestConfig& testConfig, const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, size_t meshIdx, const std::vector<VertexBufferInfo>& vertBuffers, const std::vector<VertexBufferInfo>& rvertBuffers)
1578 {
1579 if (!testConfig.strideConfig.dynamicValue)
1580 return false;
1581
1582 const auto& viewportVec = testConfig.getActiveViewportVec();
1583 DE_UNREF(viewportVec); // For release builds.
1584
1585 // When dynamically setting the vertex buffer stride, we cannot bind the vertex buffer in advance for some sequence
1586 // orderings if we have several viewports or meshes.
1587 DE_ASSERT((viewportVec.size() == 1u && testConfig.meshParams.size() == 1u)
1588 || testConfig.sequenceOrdering == SequenceOrdering::BEFORE_DRAW
1589 || testConfig.sequenceOrdering == SequenceOrdering::AFTER_PIPELINES);
1590
1591 // Split buffers, offsets, sizes and strides into their own vectors for the call.
1592 std::vector<vk::VkBuffer> buffers;
1593 std::vector<vk::VkDeviceSize> offsets;
1594 std::vector<vk::VkDeviceSize> sizes;
1595 const auto strides = testConfig.strideConfig.dynamicValue.get();
1596
1597 const auto& chosenBuffers = (testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers);
1598
1599 buffers.reserve (chosenBuffers.size());
1600 offsets.reserve (chosenBuffers.size());
1601 sizes.reserve (chosenBuffers.size());
1602 DE_ASSERT(chosenBuffers.size() == strides.size());
1603
1604 for (const auto& vertBuffer : chosenBuffers)
1605 {
1606 buffers.push_back (vertBuffer.buffer->get());
1607 offsets.push_back (vertBuffer.offset);
1608 sizes.push_back (vertBuffer.dataSize);
1609 }
1610
1611 vkd.cmdBindVertexBuffers2EXT(cmdBuffer, 0u, static_cast<deUint32>(chosenBuffers.size()), buffers.data(), offsets.data(), sizes.data(), strides.data());
1612
1613 return true;
1614 }
1615
1616 // Bind the given vertex buffers with the non-dynamic call. Similar to maybeBindVertexBufferDynStride but simpler.
bindVertexBuffers(const vk::DeviceInterface & vkd,vk::VkCommandBuffer cmdBuffer,const std::vector<VertexBufferInfo> & vertexBuffers)1617 void bindVertexBuffers (const vk::DeviceInterface& vkd, vk::VkCommandBuffer cmdBuffer, const std::vector<VertexBufferInfo>& vertexBuffers)
1618 {
1619 std::vector<vk::VkBuffer> buffers;
1620 std::vector<vk::VkDeviceSize> offsets;
1621
1622 buffers.reserve (vertexBuffers.size());
1623 offsets.reserve (vertexBuffers.size());
1624
1625 for (const auto& vertBuffer : vertexBuffers)
1626 {
1627 buffers.push_back (vertBuffer.buffer->get());
1628 offsets.push_back (vertBuffer.offset);
1629 }
1630
1631 vkd.cmdBindVertexBuffers(cmdBuffer, 0u, static_cast<deUint32>(vertexBuffers.size()), buffers.data(), offsets.data());
1632 }
1633
1634
1635 // Create a vector of VertexBufferInfo elements using the given vertex generator and set of vertices.
prepareVertexBuffers(std::vector<VertexBufferInfo> & buffers,const vk::DeviceInterface & vkd,vk::VkDevice device,vk::Allocator & allocator,const VertexGenerator * generator,const std::vector<tcu::Vec2> & vertices,deUint32 dataOffset,deUint32 trailingSize)1636 void prepareVertexBuffers ( std::vector<VertexBufferInfo>& buffers,
1637 const vk::DeviceInterface& vkd,
1638 vk::VkDevice device,
1639 vk::Allocator& allocator,
1640 const VertexGenerator* generator,
1641 const std::vector<tcu::Vec2>& vertices,
1642 deUint32 dataOffset,
1643 deUint32 trailingSize)
1644 {
1645 const deUint32 paddingBytes = 0xDEADBEEFu;
1646 const auto vertexData = generator->createVertexData(vertices, dataOffset, trailingSize, &paddingBytes, sizeof(paddingBytes));
1647
1648 for (const auto& bufferBytes : vertexData)
1649 {
1650 const auto bufferSize = static_cast<vk::VkDeviceSize>(de::dataSize(bufferBytes));
1651 const auto extraSize = static_cast<vk::VkDeviceSize>(dataOffset + trailingSize);
1652 DE_ASSERT(bufferSize > extraSize);
1653 const auto dataSize = bufferSize - extraSize;
1654
1655 // Create a full-size buffer but remember the data size and offset for it.
1656 const auto createInfo = vk::makeBufferCreateInfo(bufferSize, vk::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
1657
1658 VertexBufferInfo bufferInfo;
1659 bufferInfo.buffer = de::MovePtr<vk::BufferWithMemory>(new vk::BufferWithMemory(vkd, device, allocator, createInfo, vk::MemoryRequirement::HostVisible));
1660 bufferInfo.offset = static_cast<vk::VkDeviceSize>(dataOffset);
1661 bufferInfo.dataSize = dataSize;
1662 buffers.emplace_back(std::move(bufferInfo));
1663
1664 // Copy the whole contents to the full buffer.
1665 copyAndFlush(vkd, device, *buffers.back().buffer, 0, bufferBytes.data(), de::dataSize(bufferBytes));
1666 }
1667 }
1668
iterate(void)1669 tcu::TestStatus ExtendedDynamicStateInstance::iterate (void)
1670 {
1671 using ImageWithMemoryVec = std::vector<std::unique_ptr<vk::ImageWithMemory>>;
1672 using ImageViewVec = std::vector<vk::Move<vk::VkImageView>>;
1673 using FramebufferVec = std::vector<vk::Move<vk::VkFramebuffer>>;
1674
1675 const auto& vki = m_context.getInstanceInterface();
1676 const auto& vkd = m_context.getDeviceInterface();
1677 const auto physicalDevice = m_context.getPhysicalDevice();
1678 const auto device = m_context.getDevice();
1679 auto& allocator = m_context.getDefaultAllocator();
1680 const auto queue = m_context.getUniversalQueue();
1681 const auto queueIndex = m_context.getUniversalQueueFamilyIndex();
1682 auto& log = m_context.getTestContext().getLog();
1683
1684 const auto kReversed = m_testConfig.isReversed();
1685 const auto kNumIterations = m_testConfig.numIterations();
1686 const auto kSequenceOrdering = m_testConfig.sequenceOrdering;
1687
1688 const auto kFramebufferExtent = vk::makeExtent3D(kFramebufferWidth, kFramebufferHeight, 1u);
1689 const vk::VkImageUsageFlags kColorUsage = (vk::VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1690 const vk::VkImageUsageFlags kDSUsage = (vk::VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
1691 const vk::VkFormatFeatureFlags kDSFeatures = (vk::VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | vk::VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1692 const auto colorFormat = m_testConfig.colorFormat();
1693
1694 // Choose depth/stencil format.
1695 const DepthStencilFormat* dsFormatInfo = nullptr;
1696
1697 for (const auto& kDepthStencilFormat : kDepthStencilFormats)
1698 {
1699 const auto dsProperties = vk::getPhysicalDeviceFormatProperties(vki, physicalDevice, kDepthStencilFormat.imageFormat);
1700 if ((dsProperties.optimalTilingFeatures & kDSFeatures) == kDSFeatures)
1701 {
1702 dsFormatInfo = &kDepthStencilFormat;
1703 break;
1704 }
1705 }
1706
1707 // Note: Not Supported insted of Fail because the transfer feature is not mandatory.
1708 if (!dsFormatInfo)
1709 TCU_THROW(NotSupportedError, "Required depth/stencil image features not supported");
1710 log << tcu::TestLog::Message << "Chosen depth/stencil format: " << dsFormatInfo->imageFormat << tcu::TestLog::EndMessage;
1711
1712 // Swap static and dynamic values in the test configuration so the static pipeline ends up with the expected values for cases
1713 // where we will bind the static pipeline last before drawing.
1714 if (kReversed)
1715 m_testConfig.swapValues();
1716
1717 // Create color and depth/stencil images.
1718 ImageWithMemoryVec colorImages;
1719 ImageWithMemoryVec dsImages;
1720
1721 const vk::VkImageCreateInfo colorImageInfo =
1722 {
1723 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1724 nullptr, // const void* pNext;
1725 0u, // VkImageCreateFlags flags;
1726 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1727 colorFormat, // VkFormat format;
1728 kFramebufferExtent, // VkExtent3D extent;
1729 1u, // deUint32 mipLevels;
1730 1u, // deUint32 arrayLayers;
1731 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1732 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1733 kColorUsage, // VkImageUsageFlags usage;
1734 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1735 1u, // deUint32 queueFamilyIndexCount;
1736 &queueIndex, // const deUint32* pQueueFamilyIndices;
1737 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1738 };
1739 for (deUint32 i = 0u; i < kNumIterations; ++i)
1740 colorImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, colorImageInfo, vk::MemoryRequirement::Any));
1741
1742 const vk::VkImageCreateInfo dsImageInfo =
1743 {
1744 vk::VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1745 nullptr, // const void* pNext;
1746 0u, // VkImageCreateFlags flags;
1747 vk::VK_IMAGE_TYPE_2D, // VkImageType imageType;
1748 dsFormatInfo->imageFormat, // VkFormat format;
1749 kFramebufferExtent, // VkExtent3D extent;
1750 1u, // deUint32 mipLevels;
1751 1u, // deUint32 arrayLayers;
1752 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1753 vk::VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1754 kDSUsage, // VkImageUsageFlags usage;
1755 vk::VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1756 1u, // deUint32 queueFamilyIndexCount;
1757 &queueIndex, // const deUint32* pQueueFamilyIndices;
1758 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1759 };
1760 for (deUint32 i = 0u; i < kNumIterations; ++i)
1761 dsImages.emplace_back(new vk::ImageWithMemory(vkd, device, allocator, dsImageInfo, vk::MemoryRequirement::Any));
1762
1763 const auto colorSubresourceRange = vk::makeImageSubresourceRange(vk::VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
1764 const auto dsSubresourceRange = vk::makeImageSubresourceRange((vk::VK_IMAGE_ASPECT_DEPTH_BIT | vk::VK_IMAGE_ASPECT_STENCIL_BIT), 0u, 1u, 0u, 1u);
1765
1766 ImageViewVec colorImageViews;
1767 ImageViewVec dsImageViews;
1768
1769 for (const auto& img : colorImages)
1770 colorImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSubresourceRange));
1771
1772 for (const auto& img : dsImages)
1773 dsImageViews.emplace_back(vk::makeImageView(vkd, device, img->get(), vk::VK_IMAGE_VIEW_TYPE_2D, dsFormatInfo->imageFormat, dsSubresourceRange));
1774
1775 // Vertex buffer.
1776 const auto topologyClass = getTopologyClass(m_testConfig.topologyConfig.staticValue);
1777 std::vector<tcu::Vec2> vertices;
1778 std::vector<deUint32> indices{ 0, 1, 2, 3, 0xFFFFFFFF, 2, 3, 4, 5 };
1779
1780 if (topologyClass == TopologyClass::TRIANGLE)
1781 {
1782 // Full-screen triangle strip with 6 vertices.
1783 //
1784 // 0 2 4
1785 // +-------+-------+
1786 // | XX X|
1787 // | X X X |
1788 // | X X X |
1789 // | X X X |
1790 // | X X X |
1791 // | X X X |
1792 // |X XX |
1793 // +-------+-------+
1794 // 1 3 5
1795 vertices.reserve(6u);
1796 vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
1797 vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
1798 vertices.push_back(tcu::Vec2( 0.0f, -1.0f));
1799 vertices.push_back(tcu::Vec2( 0.0f, 1.0f));
1800 vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1801 vertices.push_back(tcu::Vec2( 1.0f, 1.0f));
1802 }
1803 else if (topologyClass == TopologyClass::PATCH)
1804 {
1805 DE_ASSERT(m_testConfig.getActivePatchControlPoints() > 1u);
1806
1807 // 2 triangles making a quad
1808 vertices.reserve(6u);
1809 vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
1810 vertices.push_back(tcu::Vec2( 1.0f, 1.0f));
1811 vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1812 vertices.push_back(tcu::Vec2( 1.0f, -1.0f));
1813 vertices.push_back(tcu::Vec2(-1.0f, -1.0f));
1814 vertices.push_back(tcu::Vec2(-1.0f, 1.0f));
1815 }
1816 else // TopologyClass::LINE
1817 {
1818 // 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.
1819 vertices.reserve(kFramebufferHeight * 4u);
1820 const float lineHeight = 2.0f / static_cast<float>(kFramebufferHeight);
1821 for (deUint32 rowIdx = 0; rowIdx < kFramebufferHeight; ++rowIdx)
1822 {
1823 // Offset of 0.5 pixels + one line per row from -1 to 1.
1824 const float yCoord = (lineHeight / 2.0f) + lineHeight * static_cast<float>(rowIdx) - 1.0f;
1825 vertices.push_back(tcu::Vec2(-1.0f, yCoord));
1826 vertices.push_back(tcu::Vec2(-0.5f, yCoord));
1827 vertices.push_back(tcu::Vec2( 0.5f, yCoord));
1828 vertices.push_back(tcu::Vec2( 1.0f, yCoord));
1829 }
1830 }
1831
1832 if (m_testConfig.singleVertex)
1833 vertices.resize(1);
1834
1835 // Reversed vertices order in triangle strip (1, 0, 3, 2, 5, 4)
1836 std::vector<tcu::Vec2> rvertices;
1837 if (topologyClass == TopologyClass::TRIANGLE)
1838 {
1839 DE_ASSERT(!vertices.empty());
1840 if (m_testConfig.singleVertex)
1841 rvertices.push_back(vertices[0]);
1842 else
1843 {
1844 rvertices.reserve(6u);
1845 rvertices.push_back(vertices[1]);
1846 rvertices.push_back(vertices[0]);
1847 rvertices.push_back(vertices[3]);
1848 rvertices.push_back(vertices[2]);
1849 rvertices.push_back(vertices[5]);
1850 rvertices.push_back(vertices[4]);
1851 }
1852 }
1853
1854 if (topologyClass != TopologyClass::TRIANGLE)
1855 {
1856 for (const auto& mesh : m_testConfig.meshParams)
1857 {
1858 DE_UNREF(mesh); // For release builds.
1859 DE_ASSERT(!mesh.reversed);
1860 }
1861 }
1862
1863 // Buffers with vertex data for the different bindings.
1864 std::vector<VertexBufferInfo> vertBuffers;
1865 std::vector<VertexBufferInfo> rvertBuffers;
1866
1867 {
1868 const auto dataOffset = static_cast<deUint32>(m_testConfig.vertexDataOffset);
1869 const auto trailingSize = static_cast<deUint32>(m_testConfig.vertexDataExtraBytes);
1870 const auto generator = m_testConfig.getActiveVertexGenerator();
1871 prepareVertexBuffers(vertBuffers, vkd, device, allocator, generator, vertices, dataOffset, trailingSize);
1872 if (topologyClass == TopologyClass::TRIANGLE)
1873 prepareVertexBuffers(rvertBuffers, vkd, device, allocator, generator, rvertices, dataOffset, trailingSize);
1874 }
1875
1876 // Index buffer.
1877 const auto indexDataSize = static_cast<vk::VkDeviceSize>(de::dataSize(indices));
1878 const auto indexBufferInfo = vk::makeBufferCreateInfo(indexDataSize, vk::VK_BUFFER_USAGE_INDEX_BUFFER_BIT);
1879 vk::BufferWithMemory indexBuffer (vkd, device, allocator, indexBufferInfo, vk::MemoryRequirement::HostVisible);
1880 copyAndFlush(vkd, device, indexBuffer, 0, indices.data(), static_cast<size_t>(indexDataSize));
1881
1882 // Descriptor set layout.
1883 vk::DescriptorSetLayoutBuilder layoutBuilder;
1884 const auto descriptorSetLayout = layoutBuilder.build(vkd, device);
1885
1886 // Pipeline layout.
1887 vk::VkShaderStageFlags pushConstantStageFlags = (vk::VK_SHADER_STAGE_VERTEX_BIT | vk::VK_SHADER_STAGE_FRAGMENT_BIT);
1888 if (m_testConfig.isMultiViewport())
1889 pushConstantStageFlags |= vk::VK_SHADER_STAGE_GEOMETRY_BIT;
1890
1891 const vk::VkPushConstantRange pushConstantRange =
1892 {
1893 pushConstantStageFlags, // VkShaderStageFlags stageFlags;
1894 0u, // deUint32 offset;
1895 static_cast<deUint32>(sizeof(PushConstants)), // deUint32 size;
1896 };
1897
1898 const vk::VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
1899 {
1900 vk::VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1901 nullptr, // const void* pNext;
1902 0u, // VkPipelineLayoutCreateFlags flags;
1903 1u, // deUint32 setLayoutCount;
1904 &descriptorSetLayout.get(), // const VkDescriptorSetLayout* pSetLayouts;
1905 1u, // deUint32 pushConstantRangeCount;
1906 &pushConstantRange, // const VkPushConstantRange* pPushConstantRanges;
1907 };
1908 const auto pipelineLayout = vk::createPipelineLayout(vkd, device, &pipelineLayoutCreateInfo);
1909
1910 // Render pass with single subpass.
1911 const vk::VkAttachmentReference colorAttachmentReference =
1912 {
1913 0u, // deUint32 attachment;
1914 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1915 };
1916
1917 const vk::VkAttachmentReference dsAttachmentReference =
1918 {
1919 1u, // deUint32 attachment;
1920 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout layout;
1921 };
1922
1923 const vk::VkSubpassDescription subpassDescription =
1924 {
1925 0u, // VkSubpassDescriptionFlags flags;
1926 vk::VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint;
1927 0u, // deUint32 inputAttachmentCount;
1928 nullptr, // const VkAttachmentReference* pInputAttachments;
1929 1u, // deUint32 colorAttachmentCount;
1930 &colorAttachmentReference, // const VkAttachmentReference* pColorAttachments;
1931 nullptr, // const VkAttachmentReference* pResolveAttachments;
1932 &dsAttachmentReference, // const VkAttachmentReference* pDepthStencilAttachment;
1933 0u, // deUint32 preserveAttachmentCount;
1934 nullptr, // const deUint32* pPreserveAttachments;
1935 };
1936
1937 std::vector<vk::VkAttachmentDescription> attachmentDescriptions;
1938
1939 attachmentDescriptions.push_back(vk::VkAttachmentDescription
1940 {
1941 0u, // VkAttachmentDescriptionFlags flags;
1942 colorFormat, // VkFormat format;
1943 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1944 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1945 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1946 vk::VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp;
1947 vk::VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp;
1948 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1949 vk::VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1950 });
1951
1952 attachmentDescriptions.push_back(vk::VkAttachmentDescription
1953 {
1954 0u, // VkAttachmentDescriptionFlags flags;
1955 dsFormatInfo->imageFormat, // VkFormat format;
1956 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1957 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp loadOp;
1958 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp;
1959 vk::VK_ATTACHMENT_LOAD_OP_CLEAR, // VkAttachmentLoadOp stencilLoadOp;
1960 vk::VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp stencilStoreOp;
1961 vk::VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1962 vk::VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // VkImageLayout finalLayout;
1963 });
1964
1965 const vk::VkRenderPassCreateInfo renderPassCreateInfo =
1966 {
1967 vk::VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType;
1968 nullptr, // const void* pNext;
1969 0u, // VkRenderPassCreateFlags flags;
1970 static_cast<deUint32>(attachmentDescriptions.size()), // deUint32 attachmentCount;
1971 attachmentDescriptions.data(), // const VkAttachmentDescription* pAttachments;
1972 1u, // deUint32 subpassCount;
1973 &subpassDescription, // const VkSubpassDescription* pSubpasses;
1974 0u, // deUint32 dependencyCount;
1975 nullptr, // const VkSubpassDependency* pDependencies;
1976 };
1977 const auto renderPass = vk::createRenderPass(vkd, device, &renderPassCreateInfo);
1978
1979 // Framebuffers.
1980 FramebufferVec framebuffers;
1981
1982 DE_ASSERT(colorImageViews.size() == dsImageViews.size());
1983 for (size_t imgIdx = 0; imgIdx < colorImageViews.size(); ++imgIdx)
1984 {
1985 std::vector<vk::VkImageView> attachments;
1986 attachments.push_back(colorImageViews[imgIdx].get());
1987 attachments.push_back(dsImageViews[imgIdx].get());
1988
1989 const vk::VkFramebufferCreateInfo framebufferCreateInfo =
1990 {
1991 vk::VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1992 nullptr, // const void* pNext;
1993 0u, // VkFramebufferCreateFlags flags;
1994 renderPass.get(), // VkRenderPass renderPass;
1995 static_cast<deUint32>(attachments.size()), // deUint32 attachmentCount;
1996 attachments.data(), // const VkImageView* pAttachments;
1997 kFramebufferWidth, // deUint32 width;
1998 kFramebufferHeight, // deUint32 height;
1999 1u, // deUint32 layers;
2000 };
2001
2002 framebuffers.emplace_back(vk::createFramebuffer(vkd, device, &framebufferCreateInfo));
2003 }
2004
2005 // Shader modules.
2006 const auto dynamicVertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("dynamicVert"), 0u);
2007 const auto staticVertModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("staticVert"), 0u);
2008 const auto fragModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("frag"), 0u);
2009 vk::Move<vk::VkShaderModule> geomModule;
2010 vk::Move<vk::VkShaderModule> tescModule;
2011 vk::Move<vk::VkShaderModule> teseModule;
2012
2013 if (m_testConfig.needsGeometryShader())
2014 geomModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("geom"), 0u);
2015
2016 if (m_testConfig.needsTessellation())
2017 {
2018 tescModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tesc"), 0u);
2019 teseModule = vk::createShaderModule(vkd, device, m_context.getBinaryCollection().get("tese"), 0u);
2020 }
2021
2022 // Shader stages.
2023 std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStages;
2024 std::vector<vk::VkPipelineShaderStageCreateInfo> shaderStaticStages;
2025
2026 vk::VkPipelineShaderStageCreateInfo shaderStageCreateInfo =
2027 {
2028 vk::VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, // VkStructureType sType;
2029 nullptr, // const void* pNext;
2030 0u, // VkPipelineShaderStageCreateFlags flags;
2031 vk::VK_SHADER_STAGE_FRAGMENT_BIT, // VkShaderStageFlagBits stage;
2032 fragModule.get(), // VkShaderModule module;
2033 "main", // const char* pName;
2034 nullptr, // const VkSpecializationInfo* pSpecializationInfo;
2035 };
2036
2037 shaderStages.push_back(shaderStageCreateInfo);
2038
2039 if (m_testConfig.needsGeometryShader())
2040 {
2041 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_GEOMETRY_BIT;
2042 shaderStageCreateInfo.module = geomModule.get();
2043 shaderStages.push_back(shaderStageCreateInfo);
2044 }
2045
2046 if (m_testConfig.needsTessellation())
2047 {
2048 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
2049 shaderStageCreateInfo.module = tescModule.get();
2050 shaderStages.push_back(shaderStageCreateInfo);
2051
2052 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2053 shaderStageCreateInfo.module = teseModule.get();
2054 shaderStages.push_back(shaderStageCreateInfo);
2055 }
2056
2057 // Both vectors are the same up to here. Then, they differ in the vertex stage.
2058 shaderStaticStages = shaderStages;
2059 shaderStageCreateInfo.stage = vk::VK_SHADER_STAGE_VERTEX_BIT;
2060
2061 shaderStageCreateInfo.module = dynamicVertModule.get();
2062 shaderStages.push_back(shaderStageCreateInfo);
2063
2064 shaderStageCreateInfo.module = staticVertModule.get();
2065 shaderStaticStages.push_back(shaderStageCreateInfo);
2066
2067 // Input state.
2068 const auto vertexBindings = m_testConfig.vertexGenerator.staticValue->getBindingDescriptions(m_testConfig.strideConfig.staticValue);
2069 const auto vertexAttributes = m_testConfig.vertexGenerator.staticValue->getAttributeDescriptions();
2070
2071 const vk::VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo =
2072 {
2073 vk::VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
2074 nullptr, // const void* pNext;
2075 0u, // VkPipelineVertexInputStateCreateFlags flags;
2076 static_cast<deUint32>(vertexBindings.size()), // deUint32 vertexBindingDescriptionCount;
2077 vertexBindings.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2078 static_cast<deUint32>(vertexAttributes.size()), // deUint32 vertexAttributeDescriptionCount;
2079 vertexAttributes.data(), // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
2080 };
2081
2082 // Input assembly.
2083 const vk::VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo =
2084 {
2085 vk::VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType;
2086 nullptr, // const void* pNext;
2087 0u, // VkPipelineInputAssemblyStateCreateFlags flags;
2088 m_testConfig.topologyConfig.staticValue, // VkPrimitiveTopology topology;
2089 makeVkBool32(m_testConfig.primRestartEnableConfig.staticValue), // VkBool32 primitiveRestartEnable;
2090 };
2091
2092 // Viewport state.
2093 if (m_testConfig.viewportConfig.dynamicValue)
2094 DE_ASSERT(m_testConfig.viewportConfig.dynamicValue.get().size() > 0u);
2095 else
2096 DE_ASSERT(m_testConfig.viewportConfig.staticValue.size() > 0u);
2097
2098 if (m_testConfig.scissorConfig.dynamicValue)
2099 DE_ASSERT(m_testConfig.scissorConfig.dynamicValue.get().size() > 0u);
2100 else
2101 DE_ASSERT(m_testConfig.scissorConfig.staticValue.size() > 0u);
2102
2103 // The viewport and scissor counts must match in the static part, which will be used by the static pipeline.
2104 const auto minStaticCount = static_cast<deUint32>(std::min(m_testConfig.viewportConfig.staticValue.size(), m_testConfig.scissorConfig.staticValue.size()));
2105
2106 // For the static pipeline.
2107 const vk::VkPipelineViewportStateCreateInfo staticViewportStateCreateInfo =
2108 {
2109 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
2110 nullptr, // const void* pNext;
2111 0u, // VkPipelineViewportStateCreateFlags flags;
2112 minStaticCount, // deUint32 viewportCount;
2113 m_testConfig.viewportConfig.staticValue.data(), // const VkViewport* pViewports;
2114 minStaticCount, // deUint32 scissorCount;
2115 m_testConfig.scissorConfig.staticValue.data(), // const VkRect2D* pScissors;
2116 };
2117
2118 // For the dynamic pipeline.
2119 const auto finalDynamicViewportCount = (m_testConfig.viewportConfig.dynamicValue
2120 ? m_testConfig.viewportConfig.dynamicValue.get().size()
2121 : m_testConfig.viewportConfig.staticValue.size());
2122
2123 const auto finalDynamicScissorCount = (m_testConfig.scissorConfig.dynamicValue
2124 ? m_testConfig.scissorConfig.dynamicValue.get().size()
2125 : m_testConfig.scissorConfig.staticValue.size());
2126
2127 const auto minDynamicCount = static_cast<deUint32>(std::min(finalDynamicScissorCount, finalDynamicViewportCount));
2128
2129 // The viewport and scissor counts must be zero when a dynamic value will be provided, as per the spec.
2130 const vk::VkPipelineViewportStateCreateInfo dynamicViewportStateCreateInfo =
2131 {
2132 vk::VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, // VkStructureType sType;
2133 nullptr, // const void* pNext;
2134 0u, // VkPipelineViewportStateCreateFlags flags;
2135 (m_testConfig.viewportConfig.dynamicValue ? 0u : minDynamicCount), // deUint32 viewportCount;
2136 m_testConfig.viewportConfig.staticValue.data(), // const VkViewport* pViewports;
2137 (m_testConfig.scissorConfig.dynamicValue ? 0u : minDynamicCount), // deUint32 scissorCount;
2138 m_testConfig.scissorConfig.staticValue.data(), // const VkRect2D* pScissors;
2139 };
2140
2141 // Rasterization state.
2142 vk::VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo =
2143 {
2144 vk::VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType;
2145 nullptr, // const void* pNext;
2146 0u, // VkPipelineRasterizationStateCreateFlags flags;
2147 VK_FALSE, // VkBool32 depthClampEnable;
2148 makeVkBool32(m_testConfig.rastDiscardEnableConfig.staticValue), // VkBool32 rasterizerDiscardEnable;
2149 vk::VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode;
2150 m_testConfig.cullModeConfig.staticValue, // VkCullModeFlags cullMode;
2151 m_testConfig.frontFaceConfig.staticValue, // VkFrontFace frontFace;
2152 makeVkBool32(m_testConfig.depthBiasEnableConfig.staticValue), // VkBool32 depthBiasEnable;
2153 m_testConfig.depthBiasConfig.staticValue.constantFactor, // float depthBiasConstantFactor;
2154 m_testConfig.depthBiasConfig.staticValue.clamp, // float depthBiasClamp;
2155 0.0f, // float depthBiasSlopeFactor;
2156 1.0f, // float lineWidth;
2157 };
2158
2159 // Multisample state.
2160 const vk::VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo =
2161 {
2162 vk::VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType;
2163 nullptr, // const void* pNext;
2164 0u, // VkPipelineMultisampleStateCreateFlags flags;
2165 vk::VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits rasterizationSamples;
2166 VK_FALSE, // VkBool32 sampleShadingEnable;
2167 0.0f, // float minSampleShading;
2168 nullptr, // const VkSampleMask* pSampleMask;
2169 VK_FALSE, // VkBool32 alphaToCoverageEnable;
2170 VK_FALSE, // VkBool32 alphaToOneEnable;
2171 };
2172
2173 // Depth/stencil state.
2174 vk::VkStencilOpState staticFrontStencil;
2175 vk::VkStencilOpState staticBackStencil;
2176 bool staticFrontStencilSet = false;
2177 bool staticBackStencilSet = false;
2178
2179 // Common setup for the front and back operations.
2180 staticFrontStencil.compareMask = 0xFFu;
2181 staticFrontStencil.writeMask = 0xFFu;
2182 staticFrontStencil.reference = m_testConfig.referenceStencil;
2183 staticBackStencil = staticFrontStencil;
2184
2185 for (const auto& op : m_testConfig.stencilOpConfig.staticValue)
2186 {
2187 if ((op.faceMask & vk::VK_STENCIL_FACE_FRONT_BIT) != 0u)
2188 {
2189 copy(staticFrontStencil, op);
2190 staticFrontStencilSet = true;
2191 }
2192 if ((op.faceMask & vk::VK_STENCIL_FACE_BACK_BIT) != 0u)
2193 {
2194 copy(staticBackStencil, op);
2195 staticBackStencilSet = true;
2196 }
2197 }
2198
2199 // Default values for the static part.
2200 if (!staticFrontStencilSet)
2201 copy(staticFrontStencil, kDefaultStencilOpParams);
2202 if (!staticBackStencilSet)
2203 copy(staticBackStencil, kDefaultStencilOpParams);
2204
2205 const vk::VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo =
2206 {
2207 vk::VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType;
2208 nullptr, // const void* pNext;
2209 0u, // VkPipelineDepthStencilStateCreateFlags flags;
2210 makeVkBool32(m_testConfig.depthTestEnableConfig.staticValue), // VkBool32 depthTestEnable;
2211 makeVkBool32(m_testConfig.depthWriteEnableConfig.staticValue), // VkBool32 depthWriteEnable;
2212 m_testConfig.depthCompareOpConfig.staticValue, // VkCompareOp depthCompareOp;
2213 makeVkBool32(m_testConfig.depthBoundsTestEnableConfig.staticValue), // VkBool32 depthBoundsTestEnable;
2214 makeVkBool32(m_testConfig.stencilTestEnableConfig.staticValue), // VkBool32 stencilTestEnable;
2215 staticFrontStencil, // VkStencilOpState front;
2216 staticBackStencil, // VkStencilOpState back;
2217 m_testConfig.minDepthBounds, // float minDepthBounds;
2218 m_testConfig.maxDepthBounds, // float maxDepthBounds;
2219 };
2220
2221 // Dynamic state. Here we will set all states which have a dynamic value.
2222 const auto dynamicStates = m_testConfig.getDynamicStates();
2223
2224 const vk::VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo =
2225 {
2226 vk::VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, // VkStructureType sType;
2227 nullptr, // const void* pNext;
2228 0u, // VkPipelineDynamicStateCreateFlags flags;
2229 static_cast<deUint32>(dynamicStates.size()), // deUint32 dynamicStateCount;
2230 de::dataOrNull(dynamicStates), // const VkDynamicState* pDynamicStates;
2231 };
2232
2233 const vk::VkPipelineColorBlendAttachmentState colorBlendAttachmentState =
2234 {
2235 VK_FALSE, // VkBool32 blendEnable
2236 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcColorBlendFactor
2237 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor
2238 vk::VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp
2239 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor srcAlphaBlendFactor
2240 vk::VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor
2241 vk::VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp
2242 vk::VK_COLOR_COMPONENT_R_BIT // VkColorComponentFlags colorWriteMask
2243 | vk::VK_COLOR_COMPONENT_G_BIT
2244 | vk::VK_COLOR_COMPONENT_B_BIT
2245 | vk::VK_COLOR_COMPONENT_A_BIT
2246 };
2247
2248 const vk::VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo =
2249 {
2250 vk::VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
2251 nullptr, // const void* pNext
2252 0u, // VkPipelineColorBlendStateCreateFlags flags
2253 makeVkBool32(m_testConfig.testLogicOp()), // VkBool32 logicOpEnable
2254 m_testConfig.logicOpConfig.staticValue, // VkLogicOp logicOp
2255 1u, // deUint32 attachmentCount
2256 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments
2257 { 0.0f, 0.0f, 0.0f, 0.0f } // float blendConstants[4]
2258 };
2259
2260 const vk::VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo =
2261 {
2262 vk::VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO, // VkStructureType sType
2263 nullptr, // const void* pNext
2264 0u, // VkPipelineTessellationStateCreateFlags flags
2265 m_testConfig.patchControlPointsConfig.staticValue, // uint32_t patchControlPoints
2266 };
2267
2268 const auto pTessellationState = (m_testConfig.needsTessellation() ? &pipelineTessellationStateCreateInfo : nullptr);
2269
2270 const vk::VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfoTemplate =
2271 {
2272 vk::VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, // VkStructureType sType;
2273 nullptr, // const void* pNext;
2274 0u, // VkPipelineCreateFlags flags;
2275 static_cast<deUint32>(shaderStages.size()), // deUint32 stageCount;
2276 shaderStages.data(), // const VkPipelineShaderStageCreateInfo* pStages;
2277 &vertexInputStateCreateInfo, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState;
2278 &inputAssemblyStateCreateInfo, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState;
2279 pTessellationState, // const VkPipelineTessellationStateCreateInfo* pTessellationState;
2280 nullptr, // const VkPipelineViewportStateCreateInfo * pViewportState;
2281 &rasterizationStateCreateInfo, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState;
2282 &multisampleStateCreateInfo, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState;
2283 &depthStencilStateCreateInfo, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState;
2284 &colorBlendStateCreateInfo, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState;
2285 nullptr, // const VkPipelineDynamicStateCreateInfo* pDynamicState;
2286 pipelineLayout.get(), // VkPipelineLayout layout;
2287 renderPass.get(), // VkRenderPass renderPass;
2288 0u, // deUint32 subpass;
2289 DE_NULL, // VkPipeline basePipelineHandle;
2290 0, // deInt32 basePipelineIndex;
2291 };
2292
2293 vk::Move<vk::VkPipeline> staticPipeline;
2294 const bool bindStaticFirst = (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES ||
2295 kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES ||
2296 kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC);
2297 const bool useStaticPipeline = (bindStaticFirst || kReversed);
2298
2299 // Create static pipeline when needed.
2300 if (useStaticPipeline)
2301 {
2302 auto staticPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
2303 staticPipelineCreateInfo.pViewportState = &staticViewportStateCreateInfo;
2304 staticPipelineCreateInfo.pStages = shaderStaticStages.data();
2305 staticPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &staticPipelineCreateInfo);
2306 }
2307
2308 // Create dynamic pipeline.
2309 vk::Move<vk::VkPipeline> graphicsPipeline;
2310 {
2311 auto dynamicPipelineCreateInfo = graphicsPipelineCreateInfoTemplate;
2312 dynamicPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo;
2313 dynamicPipelineCreateInfo.pViewportState = &dynamicViewportStateCreateInfo;
2314 graphicsPipeline = vk::createGraphicsPipeline(vkd, device, DE_NULL, &dynamicPipelineCreateInfo);
2315 }
2316
2317 // Command buffer.
2318 const auto cmdPool = vk::makeCommandPool(vkd, device, queueIndex);
2319 const auto cmdBufferPtr = vk::allocateCommandBuffer(vkd , device, cmdPool.get(), vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
2320 const auto cmdBuffer = cmdBufferPtr.get();
2321
2322 // Clear values, clear to green for dynamic logicOp
2323 std::vector<vk::VkClearValue> clearValues;
2324 clearValues.push_back(m_testConfig.clearColorValue);
2325 clearValues.push_back(vk::makeClearValueDepthStencil(m_testConfig.clearDepthValue, m_testConfig.clearStencilValue));
2326
2327 // Record command buffer.
2328 vk::beginCommandBuffer(vkd, cmdBuffer);
2329
2330 for (deUint32 iteration = 0u; iteration < kNumIterations; ++iteration)
2331 {
2332 // Track in-advance vertex buffer binding.
2333 bool boundInAdvance = false;
2334
2335 // Maybe set extended dynamic state here.
2336 if (kSequenceOrdering == SequenceOrdering::CMD_BUFFER_START)
2337 {
2338 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2339 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2340 }
2341
2342 // Begin render pass.
2343 vk::beginRenderPass(vkd, cmdBuffer, renderPass.get(), framebuffers[iteration].get(), vk::makeRect2D(kFramebufferWidth, kFramebufferHeight), static_cast<deUint32>(clearValues.size()), clearValues.data());
2344
2345 // Bind a static pipeline first if needed.
2346 if (bindStaticFirst && iteration == 0u)
2347 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2348
2349 // Maybe set extended dynamic state here.
2350 if (kSequenceOrdering == SequenceOrdering::BETWEEN_PIPELINES)
2351 {
2352 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2353 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2354 }
2355
2356 // Bind dynamic pipeline.
2357 if ((kSequenceOrdering != SequenceOrdering::TWO_DRAWS_DYNAMIC &&
2358 kSequenceOrdering != SequenceOrdering::TWO_DRAWS_STATIC) ||
2359 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2360 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2361 {
2362 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline.get());
2363 }
2364
2365 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2366 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC && iteration > 0u) ||
2367 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration == 0u))
2368 {
2369 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2370 boundInAdvance = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, 0u, vertBuffers, rvertBuffers);
2371 }
2372
2373 // Bind a static pipeline last if needed.
2374 if (kSequenceOrdering == SequenceOrdering::BEFORE_GOOD_STATIC ||
2375 (kSequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC && iteration > 0u))
2376 {
2377 vkd.cmdBindPipeline(cmdBuffer, vk::VK_PIPELINE_BIND_POINT_GRAPHICS, staticPipeline.get());
2378 }
2379
2380 const auto& viewportVec = m_testConfig.getActiveViewportVec();
2381 for (size_t viewportIdx = 0u; viewportIdx < viewportVec.size(); ++viewportIdx)
2382 {
2383 for (size_t meshIdx = 0u; meshIdx < m_testConfig.meshParams.size(); ++meshIdx)
2384 {
2385 // Push constants.
2386 PushConstants pushConstants =
2387 {
2388 m_testConfig.meshParams[meshIdx].color, // tcu::Vec4 triangleColor;
2389 m_testConfig.meshParams[meshIdx].depth, // float meshDepth;
2390 static_cast<deInt32>(viewportIdx), // deInt32 viewPortIndex;
2391 m_testConfig.meshParams[meshIdx].scaleX, // float scaleX;
2392 m_testConfig.meshParams[meshIdx].scaleY, // float scaleY;
2393 m_testConfig.meshParams[meshIdx].offsetX, // float offsetX;
2394 m_testConfig.meshParams[meshIdx].offsetY, // float offsetY;
2395 m_testConfig.meshParams[meshIdx].stripScale, // float stripScale;
2396 };
2397 vkd.cmdPushConstants(cmdBuffer, pipelineLayout.get(), pushConstantStageFlags, 0u, static_cast<deUint32>(sizeof(pushConstants)), &pushConstants);
2398
2399 // Track vertex bounding state for this mesh.
2400 bool boundBeforeDraw = false;
2401
2402 // Maybe set extended dynamic state here.
2403 if (kSequenceOrdering == SequenceOrdering::BEFORE_DRAW || kSequenceOrdering == SequenceOrdering::AFTER_PIPELINES)
2404 {
2405 setDynamicStates(m_testConfig, vkd, cmdBuffer);
2406 boundBeforeDraw = maybeBindVertexBufferDynStride(m_testConfig, vkd, cmdBuffer, meshIdx, vertBuffers, rvertBuffers);
2407 }
2408
2409 // Bind vertex buffer with static stride if needed and draw.
2410 if (!(boundInAdvance || boundBeforeDraw))
2411 {
2412 bindVertexBuffers(vkd, cmdBuffer, (m_testConfig.meshParams[meshIdx].reversed ? rvertBuffers : vertBuffers));
2413 if (m_testConfig.needsIndexBuffer())
2414 {
2415 vkd.cmdBindIndexBuffer(cmdBuffer, indexBuffer.get(), 0, vk::VK_INDEX_TYPE_UINT32);
2416 }
2417 }
2418
2419 // Draw mesh.
2420 if (m_testConfig.needsIndexBuffer())
2421 {
2422 deUint32 numIndices = static_cast<deUint32>(indices.size());
2423 // For SequenceOrdering::TWO_DRAWS_DYNAMIC and TWO_DRAWS_STATIC cases, the first draw does not have primitive restart enabled
2424 // So, draw without using the invalid (0xFFFFFFFF) index, the second draw with primitive restart enabled will replace the results
2425 // using all indices.
2426 if (iteration == 0u &&
2427 (m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_DYNAMIC ||
2428 m_testConfig.sequenceOrdering == SequenceOrdering::TWO_DRAWS_STATIC))
2429 numIndices = 3u;
2430 vkd.cmdDrawIndexed(cmdBuffer, numIndices, 1u, 0u, 0u, 0u);
2431 }
2432 else
2433 {
2434 deUint32 vertex_count = static_cast<deUint32>(vertices.size());
2435 if (m_testConfig.singleVertex)
2436 vertex_count = m_testConfig.singleVertexDrawCount;
2437 vkd.cmdDraw(cmdBuffer, vertex_count, 1u, 0u, 0u);
2438 }
2439 }
2440 }
2441
2442 vk::endRenderPass(vkd, cmdBuffer);
2443 }
2444
2445 vk::endCommandBuffer(vkd, cmdBuffer);
2446
2447 // Submit commands.
2448 vk::submitCommandsAndWait(vkd, device, queue, cmdBuffer);
2449
2450 // Read result image aspects from the last used framebuffer.
2451 const tcu::UVec2 renderSize (kFramebufferWidth, kFramebufferHeight);
2452 const auto colorBuffer = readColorAttachment(vkd, device, queue, queueIndex, allocator, colorImages.back()->get(), colorFormat, renderSize);
2453 const auto depthBuffer = readDepthAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize);
2454 const auto stencilBuffer = readStencilAttachment(vkd, device, queue, queueIndex, allocator, dsImages.back()->get(), dsFormatInfo->imageFormat, renderSize, vk::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
2455 const auto colorAccess = colorBuffer->getAccess();
2456 const auto depthAccess = depthBuffer->getAccess();
2457 const auto stencilAccess = stencilBuffer->getAccess();
2458
2459 const int kWidth = static_cast<int>(kFramebufferWidth);
2460 const int kHeight = static_cast<int>(kFramebufferHeight);
2461
2462 // Generate reference color buffer.
2463 const auto tcuColorFormat = vk::mapVkFormat(colorFormat);
2464 tcu::TextureLevel referenceColorLevel (tcuColorFormat, kWidth, kHeight);
2465 tcu::PixelBufferAccess referenceColorAccess = referenceColorLevel.getAccess();
2466 m_testConfig.referenceColor(referenceColorAccess);
2467
2468 const tcu::TextureFormat errorFormat (tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8);
2469 tcu::TextureLevel colorError (errorFormat, kWidth, kHeight);
2470 tcu::TextureLevel depthError (errorFormat, kWidth, kHeight);
2471 tcu::TextureLevel stencilError (errorFormat, kWidth, kHeight);
2472 const auto colorErrorAccess = colorError.getAccess();
2473 const auto depthErrorAccess = depthError.getAccess();
2474 const auto stencilErrorAccess = stencilError.getAccess();
2475 const tcu::Vec4 kGood (0.0f, 1.0f, 0.0f, 1.0f);
2476 const tcu::Vec4 kBad (1.0f, 0.0f, 0.0f, 1.0f);
2477
2478 // Check expected values.
2479 const auto minDepth = m_testConfig.expectedDepth - dsFormatInfo->depthThreshold;
2480 const auto maxDepth = m_testConfig.expectedDepth + dsFormatInfo->depthThreshold;
2481 bool colorMatch = true;
2482 bool depthMatch = true;
2483 bool stencilMatch = true;
2484 bool match;
2485
2486 for (int y = 0; y < kHeight; ++y)
2487 for (int x = 0; x < kWidth; ++x)
2488 {
2489 if (vk::isUnormFormat(colorFormat))
2490 {
2491 auto colorPixel = colorAccess.getPixel(x, y);
2492 auto expectedPixel = referenceColorAccess.getPixel(x, y);
2493 match = tcu::boolAll(tcu::lessThan(tcu::absDiff(colorPixel, expectedPixel), kUnormColorThreshold));
2494 }
2495 else
2496 {
2497 DE_ASSERT(vk::isUintFormat(colorFormat));
2498 auto colorPixel = colorAccess.getPixelUint(x, y);
2499 auto expectedPixel = referenceColorAccess.getPixelUint(x, y);
2500 match = (colorPixel == expectedPixel);
2501 }
2502
2503 colorErrorAccess.setPixel((match ? kGood : kBad), x, y);
2504 if (!match)
2505 colorMatch = false;
2506
2507 const auto depthPixel = depthAccess.getPixDepth(x, y);
2508 match = de::inRange(depthPixel, minDepth, maxDepth);
2509 depthErrorAccess.setPixel((match ? kGood : kBad), x, y);
2510 if (!match)
2511 depthMatch = false;
2512
2513 const auto stencilPixel = static_cast<deUint32>(stencilAccess.getPixStencil(x, y));
2514 match = (stencilPixel == m_testConfig.expectedStencil);
2515 stencilErrorAccess.setPixel((match ? kGood : kBad), x, y);
2516 if (!match)
2517 stencilMatch = false;
2518 }
2519
2520 if (!(colorMatch && depthMatch && stencilMatch))
2521 {
2522 if (!colorMatch)
2523 logErrors(log, "Color", "Result color image and error mask", colorAccess, colorErrorAccess);
2524
2525 if (!depthMatch)
2526 logErrors(log, "Depth", "Result depth image and error mask", depthAccess, depthErrorAccess);
2527
2528 if (!stencilMatch)
2529 logErrors(log, "Stencil", "Result stencil image and error mask", stencilAccess, stencilErrorAccess);
2530
2531 return tcu::TestStatus::fail("Incorrect value found in attachments; please check logged images");
2532 }
2533
2534 return tcu::TestStatus::pass("Pass");
2535 }
2536
stencilPasses(vk::VkCompareOp op,deUint8 storedValue,deUint8 referenceValue)2537 bool stencilPasses(vk::VkCompareOp op, deUint8 storedValue, deUint8 referenceValue)
2538 {
2539 switch (op)
2540 {
2541 case vk::VK_COMPARE_OP_NEVER: return false;
2542 case vk::VK_COMPARE_OP_LESS: return (referenceValue < storedValue);
2543 case vk::VK_COMPARE_OP_EQUAL: return (referenceValue == storedValue);
2544 case vk::VK_COMPARE_OP_LESS_OR_EQUAL: return (referenceValue <= storedValue);
2545 case vk::VK_COMPARE_OP_GREATER: return (referenceValue > storedValue);
2546 case vk::VK_COMPARE_OP_GREATER_OR_EQUAL: return (referenceValue >= storedValue);
2547 case vk::VK_COMPARE_OP_ALWAYS: return true;
2548 default: DE_ASSERT(false); return false;
2549 }
2550
2551 return false; // Unreachable.
2552 }
2553
stencilResult(vk::VkStencilOp op,deUint8 storedValue,deUint8 referenceValue,deUint8 min,deUint8 max)2554 deUint8 stencilResult(vk::VkStencilOp op, deUint8 storedValue, deUint8 referenceValue, deUint8 min, deUint8 max)
2555 {
2556 deUint8 result = storedValue;
2557
2558 switch (op)
2559 {
2560 case vk::VK_STENCIL_OP_KEEP: break;
2561 case vk::VK_STENCIL_OP_ZERO: result = 0; break;
2562 case vk::VK_STENCIL_OP_REPLACE: result = referenceValue; break;
2563 case vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP: result = ((result == max) ? result : static_cast<deUint8>(result + 1)); break;
2564 case vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP: result = ((result == min) ? result : static_cast<deUint8>(result - 1)); break;
2565 case vk::VK_STENCIL_OP_INVERT: result = static_cast<deUint8>(~result); break;
2566 case vk::VK_STENCIL_OP_INCREMENT_AND_WRAP: result = ((result == max) ? min : static_cast<deUint8>(result + 1)); break;
2567 case vk::VK_STENCIL_OP_DECREMENT_AND_WRAP: result = ((result == min) ? max : static_cast<deUint8>(result - 1)); break;
2568 default: DE_ASSERT(false); break;
2569 }
2570
2571 return result;
2572 }
2573
2574 } // anonymous namespace
2575
createExtendedDynamicStateTests(tcu::TestContext & testCtx)2576 tcu::TestCaseGroup* createExtendedDynamicStateTests (tcu::TestContext& testCtx)
2577 {
2578 de::MovePtr<tcu::TestCaseGroup> extendedDynamicStateGroup(new tcu::TestCaseGroup(testCtx, "extended_dynamic_state", "Tests for VK_EXT_extended_dynamic_state"));
2579
2580 // Auxiliar constants.
2581 const deUint32 kHalfWidthU = kFramebufferWidth/2u;
2582 const deInt32 kHalfWidthI = static_cast<deInt32>(kHalfWidthU);
2583 const float kHalfWidthF = static_cast<float>(kHalfWidthU);
2584 const float kHeightF = static_cast<float>(kFramebufferHeight);
2585
2586 static const struct
2587 {
2588 SequenceOrdering ordering;
2589 std::string name;
2590 std::string desc;
2591 } kOrderingCases[] =
2592 {
2593 { SequenceOrdering::CMD_BUFFER_START, "cmd_buffer_start", "Dynamic state set after command buffer start" },
2594 { SequenceOrdering::BEFORE_DRAW, "before_draw", "Dynamic state set just before drawing" },
2595 { 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" },
2596 { SequenceOrdering::AFTER_PIPELINES, "after_pipelines", "Dynamic state set after both a static-state pipeline and a second dynamic-state pipeline have been bound" },
2597 { 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" },
2598 { SequenceOrdering::TWO_DRAWS_DYNAMIC, "two_draws_dynamic", "Bind bad static pipeline and draw, followed by binding correct dynamic pipeline and drawing again" },
2599 { SequenceOrdering::TWO_DRAWS_STATIC, "two_draws_static", "Bind bad dynamic pipeline and draw, followed by binding correct static pipeline and drawing again" },
2600 };
2601
2602 for (const auto& kOrderingCase : kOrderingCases)
2603 {
2604 const auto& kOrdering = kOrderingCase.ordering;
2605
2606 de::MovePtr<tcu::TestCaseGroup> orderingGroup(new tcu::TestCaseGroup(testCtx, kOrderingCase.name.c_str(), kOrderingCase.desc.c_str()));
2607
2608 // Cull modes.
2609 {
2610 TestConfig config(kOrdering);
2611 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_FRONT_BIT;
2612 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_NONE);
2613 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_none", "Dynamically set cull mode to none", config));
2614 }
2615 {
2616 TestConfig config(kOrdering);
2617 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_FRONT_AND_BACK;
2618 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_BACK_BIT);
2619 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_back", "Dynamically set cull mode to back", config));
2620 }
2621 {
2622 TestConfig config(kOrdering);
2623 // Make triangles look back.
2624 config.meshParams[0].reversed = true;
2625 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2626 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_BIT);
2627 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front", "Dynamically set cull mode to front", config));
2628 }
2629 {
2630 TestConfig config(kOrdering);
2631 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_NONE;
2632 config.cullModeConfig.dynamicValue = tcu::just<vk::VkCullModeFlags>(vk::VK_CULL_MODE_FRONT_AND_BACK);
2633 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2634 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "cull_front_and_back", "Dynamically set cull mode to front and back", config));
2635 }
2636
2637 // Front face.
2638 {
2639 TestConfig config(kOrdering);
2640 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2641 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_CLOCKWISE;
2642 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2643 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw", "Dynamically set front face to clockwise", config));
2644 }
2645 {
2646 TestConfig config(kOrdering);
2647 // Pass triangles in clockwise order.
2648 config.meshParams[0].reversed = true;
2649 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2650 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2651 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2652 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw", "Dynamically set front face to counter-clockwise", config));
2653 }
2654 {
2655 TestConfig config(kOrdering);
2656 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2657 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_COUNTER_CLOCKWISE;
2658 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_CLOCKWISE);
2659 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2660 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_cw_reversed", "Dynamically set front face to clockwise with a counter-clockwise mesh", config));
2661 }
2662 {
2663 TestConfig config(kOrdering);
2664 // Pass triangles in clockwise order.
2665 config.meshParams[0].reversed = true;
2666 config.cullModeConfig.staticValue = vk::VK_CULL_MODE_BACK_BIT;
2667 config.frontFaceConfig.staticValue = vk::VK_FRONT_FACE_CLOCKWISE;
2668 config.frontFaceConfig.dynamicValue = tcu::just<vk::VkFrontFace>(vk::VK_FRONT_FACE_COUNTER_CLOCKWISE);
2669 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2670 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "front_face_ccw_reversed", "Dynamically set front face to counter-clockwise with a clockwise mesh", config));
2671 }
2672
2673 // Rasterizer discard
2674 {
2675 TestConfig config(kOrdering);
2676 config.rastDiscardEnableConfig.staticValue = false;
2677 config.rastDiscardEnableConfig.dynamicValue = tcu::just(true);
2678 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2679 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "disable_raster", "Dynamically disable rasterizer", config));
2680 }
2681 {
2682 TestConfig config(kOrdering);
2683 config.rastDiscardEnableConfig.staticValue = true;
2684 config.rastDiscardEnableConfig.dynamicValue = tcu::just(false);
2685 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "enable_raster", "Dynamically enable rasterizer", config));
2686 }
2687
2688 // Logic op
2689 {
2690 TestConfig config(kOrdering);
2691 config.logicOpConfig.staticValue = vk::VK_LOGIC_OP_CLEAR;
2692 config.logicOpConfig.dynamicValue = tcu::just<vk::VkLogicOp>(vk::VK_LOGIC_OP_OR);
2693 // Clear to green, paint in blue, expect cyan due to logic op.
2694 config.meshParams[0].color = kLogicOpTriangleColor;
2695 config.clearColorValue = vk::makeClearValueColorU32(kGreenClearColor.x(), kGreenClearColor.y(), kGreenClearColor.z(), kGreenClearColor.w());
2696 config.referenceColor = SingleColorGenerator(kLogicOpFinalColor);
2697 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "logic_op_or", "Dynamically change logic op to VK_LOGIC_OP_OR", config));
2698 }
2699
2700 // Dynamically enable primitive restart
2701 {
2702 TestConfig config(kOrdering);
2703 config.primRestartEnableConfig.staticValue = false;
2704 config.primRestartEnableConfig.dynamicValue = tcu::just(true);
2705 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "prim_restart_enable", "Dynamically enable primitiveRestart", config));
2706 }
2707
2708 // Dynamically change the number of primitive control points
2709 {
2710 TestConfig config(kOrdering);
2711 config.topologyConfig.staticValue = vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
2712 config.patchControlPointsConfig.staticValue = 1;
2713 config.patchControlPointsConfig.dynamicValue = 3;
2714 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "patch_control_points", "Dynamically change patch control points", config));
2715 }
2716
2717 // Dynamic topology.
2718 {
2719 TestConfig baseConfig(kOrdering);
2720
2721 for (int i = 0; i < 2; ++i)
2722 {
2723 const bool forceGeometryShader = (i > 0);
2724
2725 static const struct
2726 {
2727 vk::VkPrimitiveTopology staticVal;
2728 vk::VkPrimitiveTopology dynamicVal;
2729 } kTopologyCases[] =
2730 {
2731 { vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP },
2732 { vk::VK_PRIMITIVE_TOPOLOGY_LINE_LIST, vk::VK_PRIMITIVE_TOPOLOGY_LINE_STRIP },
2733 { vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, vk::VK_PRIMITIVE_TOPOLOGY_PATCH_LIST },
2734 };
2735
2736 for (const auto& kTopologyCase : kTopologyCases)
2737 {
2738 TestConfig config(baseConfig);
2739 config.forceGeometryShader = forceGeometryShader;
2740 config.topologyConfig.staticValue = kTopologyCase.staticVal;
2741 config.topologyConfig.dynamicValue = tcu::just<vk::VkPrimitiveTopology>(kTopologyCase.dynamicVal);
2742 config.patchControlPointsConfig.staticValue = (config.needsTessellation() ? 3u : 1u);
2743
2744 const std::string className = topologyClassName(getTopologyClass(config.topologyConfig.staticValue));
2745 const std::string name = "topology_" + className + (forceGeometryShader ? "_geom" : "");
2746 const std::string desc = "Dynamically switch primitive topologies from the " + className + " class" + (forceGeometryShader ? " and use a geometry shader" : "");
2747 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, name, desc, config));
2748 }
2749 }
2750 }
2751
2752 // Viewport.
2753 {
2754 TestConfig config(kOrdering);
2755 // 2 scissors, bad static single viewport.
2756 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2757 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2758 config.viewportConfig.dynamicValue = ViewportVec{
2759 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2760 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2761 };
2762 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports", "Dynamically set 2 viewports", config));
2763 }
2764 {
2765 TestConfig config(kOrdering);
2766 // Bad static reduced viewport.
2767 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kHalfWidthU, kFramebufferHeight));
2768 config.viewportConfig.staticValue = ViewportVec(1u, vk::makeViewport(kFramebufferWidth, kFramebufferHeight));
2769 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_viewport", "Dynamically set viewport to cover full framebuffer", config));
2770 }
2771 {
2772 TestConfig config(kOrdering);
2773 // 2 scissors (left half, right half), 2 reversed static viewports that need fixing (right, left).
2774 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2775 config.viewportConfig.staticValue = ViewportVec{
2776 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2777 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Left.
2778 };
2779 config.viewportConfig.dynamicValue = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2780 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch", "Dynamically switch the order with 2 viewports", config));
2781 }
2782 {
2783 TestConfig config(kOrdering);
2784 // 2 scissors, reversed dynamic viewports that should result in no drawing taking place.
2785 config.scissorConfig.staticValue = ScissorVec{vk::makeRect2D(0, 0, kHalfWidthU, kFramebufferHeight), vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight)};
2786 config.viewportConfig.staticValue = ViewportVec{
2787 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Left.
2788 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f), // Right.
2789 };
2790 config.viewportConfig.dynamicValue = ViewportVec{config.viewportConfig.staticValue.back(), config.viewportConfig.staticValue.front()};
2791 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2792 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_viewports_switch_clean", "Dynamically switch the order with 2 viewports resulting in clean image", config));
2793 }
2794
2795 // Scissor.
2796 {
2797 TestConfig config(kOrdering);
2798 // 2 viewports, bad static single scissor.
2799 config.viewportConfig.staticValue = ViewportVec{
2800 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2801 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2802 };
2803 config.scissorConfig.staticValue = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2804 config.scissorConfig.dynamicValue = ScissorVec{
2805 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2806 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2807 };
2808 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors", "Dynamically set 2 scissors", config));
2809 }
2810 {
2811 TestConfig config(kOrdering);
2812 // 1 viewport, bad static single scissor.
2813 config.scissorConfig.staticValue = ScissorVec(1u, vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight));
2814 config.scissorConfig.dynamicValue = ScissorVec(1u, vk::makeRect2D(kFramebufferWidth, kFramebufferHeight));
2815 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "1_full_scissor", "Dynamically set scissor to cover full framebuffer", config));
2816 }
2817 {
2818 TestConfig config(kOrdering);
2819 // 2 viewports, 2 reversed scissors that need fixing.
2820 config.viewportConfig.staticValue = ViewportVec{
2821 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2822 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2823 };
2824 config.scissorConfig.staticValue = ScissorVec{
2825 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2826 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2827 };
2828 config.scissorConfig.dynamicValue = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2829 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch", "Dynamically switch the order with 2 scissors", config));
2830 }
2831 {
2832 TestConfig config(kOrdering);
2833 // 2 viewports, 2 scissors switched to prevent drawing.
2834 config.viewportConfig.staticValue = ViewportVec{
2835 vk::makeViewport(0.0f, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2836 vk::makeViewport(kHalfWidthF, 0.0f, kHalfWidthF, kHeightF, 0.0f, 1.0f),
2837 };
2838 config.scissorConfig.staticValue = ScissorVec{
2839 vk::makeRect2D(kHalfWidthU, kFramebufferHeight),
2840 vk::makeRect2D(kHalfWidthI, 0, kHalfWidthU, kFramebufferHeight),
2841 };
2842 config.scissorConfig.dynamicValue = ScissorVec{config.scissorConfig.staticValue.back(), config.scissorConfig.staticValue.front()};
2843 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2844 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "2_scissors_switch_clean", "Dynamically switch the order with 2 scissors to avoid drawing", config));
2845 }
2846
2847 // Stride.
2848 {
2849 struct
2850 {
2851 const VertexGenerator* factory;
2852 const std::string prefix;
2853 } strideCases[] =
2854 {
2855 { getVertexWithPaddingGenerator(), "stride" },
2856 { getVertexWithExtraAttributesGenerator(), "large_stride" },
2857 };
2858
2859 for (const auto& strideCase : strideCases)
2860 {
2861 const auto factory = strideCase.factory;
2862 const auto& prefix = strideCase.prefix;
2863 const auto vertexStrides = factory->getVertexDataStrides();
2864 StrideVec halfStrides;
2865
2866 halfStrides.reserve(vertexStrides.size());
2867 for (const auto& stride : vertexStrides)
2868 halfStrides.push_back(stride / 2u);
2869
2870 if (factory == getVertexWithExtraAttributesGenerator() && kOrdering == SequenceOrdering::TWO_DRAWS_STATIC)
2871 {
2872 // This case is invalid because it breaks VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the dynamic
2873 // stride being less than the extent of the binding for the second attribute.
2874 continue;
2875 }
2876
2877 {
2878 TestConfig config(kOrdering, factory);
2879 config.strideConfig.staticValue = halfStrides;
2880 config.strideConfig.dynamicValue = vertexStrides;
2881 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix, "Dynamically set stride", config));
2882 }
2883 {
2884 TestConfig config(kOrdering, factory);
2885 config.strideConfig.staticValue = halfStrides;
2886 config.strideConfig.dynamicValue = vertexStrides;
2887 config.vertexDataOffset = vertexStrides[0];
2888 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset", "Dynamically set stride using a nonzero vertex data offset", config));
2889 }
2890 {
2891 TestConfig config(kOrdering, factory);
2892 config.strideConfig.staticValue = halfStrides;
2893 config.strideConfig.dynamicValue = vertexStrides;
2894 config.vertexDataOffset = vertexStrides[0];
2895 config.vertexDataExtraBytes = config.vertexDataOffset;
2896
2897 // Make the mesh cover the top half only. If the implementation reads data outside the vertex values it may draw something to the bottom half.
2898 config.referenceColor = HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2899 config.meshParams[0].scaleY = 0.5f;
2900 config.meshParams[0].offsetY = -0.5f;
2901
2902 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, prefix + "_with_offset_and_padding", "Dynamically set stride using a nonzero vertex data offset and extra bytes", config));
2903 }
2904 }
2905
2906 // Dynamic stride of 0
2907 {
2908 TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator());
2909 config.strideConfig.staticValue = config.getActiveVertexGenerator()->getVertexDataStrides();
2910 config.strideConfig.dynamicValue = { 0 };
2911 config.vertexDataOffset = 4;
2912 config.singleVertex = true;
2913 config.singleVertexDrawCount = 6;
2914
2915 // Make the mesh cover the top half only. If the implementation reads data outside the vertex data it should read the
2916 // offscreen vertex and draw something in the bottom half.
2917 config.referenceColor = HorizontalSplitGenerator(kDefaultTriangleColor, kDefaultClearColor);
2918 config.meshParams[0].scaleY = 0.5f;
2919 config.meshParams[0].offsetY = -0.5f;
2920
2921 // Use strip scale to synthesize a strip from a vertex attribute which remains constant over the draw call.
2922 config.meshParams[0].stripScale = 1.0f;
2923
2924 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "zero_stride_with_offset", "Dynamically set zero stride using a nonzero vertex data offset", config));
2925 }
2926 }
2927
2928 // Depth test enable.
2929 {
2930 TestConfig config(kOrdering);
2931 config.depthTestEnableConfig.staticValue = false;
2932 config.depthTestEnableConfig.dynamicValue = tcu::just(true);
2933 // By default, the depth test never passes when enabled.
2934 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
2935 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_enable", "Dynamically enable depth test", config));
2936 }
2937 {
2938 TestConfig config(kOrdering);
2939 config.depthTestEnableConfig.staticValue = true;
2940 config.depthTestEnableConfig.dynamicValue = tcu::just(false);
2941 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_test_disable", "Dynamically disable depth test", config));
2942 }
2943
2944 // Depth write enable.
2945 {
2946 TestConfig config(kOrdering);
2947
2948 // Enable depth test and set values so it passes.
2949 config.depthTestEnableConfig.staticValue = true;
2950 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
2951 config.clearDepthValue = 0.5f;
2952 config.meshParams[0].depth = 0.25f;
2953
2954 // Enable writes and expect the mesh value.
2955 config.depthWriteEnableConfig.staticValue = false;
2956 config.depthWriteEnableConfig.dynamicValue = tcu::just(true);
2957 config.expectedDepth = 0.25f;
2958
2959 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_enable", "Dynamically enable writes to the depth buffer", config));
2960 }
2961 {
2962 TestConfig config(kOrdering);
2963
2964 // Enable depth test and set values so it passes.
2965 config.depthTestEnableConfig.staticValue = true;
2966 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
2967 config.clearDepthValue = 0.5f;
2968 config.meshParams[0].depth = 0.25f;
2969
2970 // But disable writing dynamically and expect the clear value.
2971 config.depthWriteEnableConfig.staticValue = true;
2972 config.depthWriteEnableConfig.dynamicValue = tcu::just(false);
2973 config.expectedDepth = 0.5f;
2974
2975 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_write_disable", "Dynamically disable writes to the depth buffer", config));
2976 }
2977
2978 // Depth bias enable with static or dynamic depth bias parameters.
2979 {
2980 const DepthBiasParams kAlternativeDepthBiasParams = { 2e7f, 0.25f };
2981
2982 for (int dynamicBiasIter = 0; dynamicBiasIter < 2; ++dynamicBiasIter)
2983 {
2984 const bool useDynamicBias = (dynamicBiasIter > 0);
2985
2986 {
2987 TestConfig config(kOrdering);
2988
2989 // Enable depth test and write 1.0f
2990 config.depthTestEnableConfig.staticValue = true;
2991 config.depthWriteEnableConfig.staticValue = true;
2992 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
2993 // Clear depth buffer to 0.25f
2994 config.clearDepthValue = 0.25f;
2995 // Write depth to 0.5f
2996 config.meshParams[0].depth = 0.5f;
2997
2998 // Enable dynamic depth bias and expect the depth value to be clamped to 0.75f based on depthBiasConstantFactor and depthBiasClamp
2999 if (useDynamicBias)
3000 {
3001 config.depthBiasConfig.staticValue = kNoDepthBiasParams;
3002 config.depthBiasConfig.dynamicValue = kAlternativeDepthBiasParams;
3003 }
3004 else
3005 {
3006 config.depthBiasConfig.staticValue = kAlternativeDepthBiasParams;
3007 }
3008
3009 config.depthBiasEnableConfig.staticValue = false;
3010 config.depthBiasEnableConfig.dynamicValue = tcu::just(true);
3011 config.expectedDepth = 0.75f;
3012
3013 std::string caseName = "depth_bias_enable";
3014 std::string caseDesc = "Dynamically enable the depth bias";
3015
3016 if (useDynamicBias)
3017 {
3018 caseName += "_dynamic_bias_params";
3019 caseDesc += " and set the bias params dynamically";
3020 }
3021
3022 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3023 }
3024 {
3025 TestConfig config(kOrdering);
3026
3027 // Enable depth test and write 1.0f
3028 config.depthTestEnableConfig.staticValue = true;
3029 config.depthWriteEnableConfig.staticValue = true;
3030 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
3031 // Clear depth buffer to 0.25f
3032 config.clearDepthValue = 0.25f;
3033 // Write depth to 0.5f
3034 config.meshParams[0].depth = 0.5f;
3035
3036 // Disable dynamic depth bias and expect the depth value to remain at 0.5f based on written value
3037 if (useDynamicBias)
3038 {
3039 config.depthBiasConfig.staticValue = kNoDepthBiasParams;
3040 config.depthBiasConfig.dynamicValue = kAlternativeDepthBiasParams;
3041 }
3042 else
3043 {
3044 config.depthBiasConfig.staticValue = kAlternativeDepthBiasParams;
3045 }
3046
3047 config.depthBiasEnableConfig.staticValue = true;
3048 config.depthBiasEnableConfig.dynamicValue = tcu::just(false);
3049 config.expectedDepth = 0.5f;
3050
3051 std::string caseName = "depth_bias_disable";
3052 std::string caseDesc = "Dynamically disable the depth bias";
3053
3054 if (useDynamicBias)
3055 {
3056 caseName += "_dynamic_bias_params";
3057 caseDesc += " and set the bias params dynamically";
3058 }
3059
3060 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, caseName, caseDesc, config));
3061 }
3062 }
3063 }
3064
3065 // Depth compare op.
3066 {
3067 TestConfig baseConfig(kOrdering);
3068 const tcu::Vec4 kAlternativeColor (0.0f, 0.0f, 0.5f, 1.0f);
3069 baseConfig.depthTestEnableConfig.staticValue = true;
3070 baseConfig.depthWriteEnableConfig.staticValue = true;
3071 baseConfig.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_NEVER;
3072 baseConfig.clearDepthValue = 0.5f;
3073
3074 {
3075 TestConfig config = baseConfig;
3076 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_ALWAYS;
3077 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NEVER;
3078 config.meshParams[0].depth = 0.25f;
3079 config.expectedDepth = 0.5f;
3080 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
3081 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_never", "Dynamically set the depth compare operator to NEVER", config));
3082 }
3083 {
3084 TestConfig config = baseConfig;
3085 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS;
3086 config.meshParams[0].depth = 0.25f;
3087 config.expectedDepth = 0.25f;
3088 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_less", "Dynamically set the depth compare operator to LESS", config));
3089 }
3090 {
3091 TestConfig config = baseConfig;
3092 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER;
3093 config.meshParams[0].depth = 0.75f;
3094 config.expectedDepth = 0.75f;
3095 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_greater", "Dynamically set the depth compare operator to GREATER", config));
3096 }
3097 {
3098 TestConfig config = baseConfig;
3099 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_EQUAL;
3100 config.meshParams[0].depth = 0.5f;
3101 config.meshParams[0].color = kAlternativeColor;
3102 // Draw another mesh in front to verify it does not pass the equality test.
3103 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.25f));
3104 config.expectedDepth = 0.5f;
3105 config.referenceColor = SingleColorGenerator(kAlternativeColor);
3106 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_equal", "Dynamically set the depth compare operator to EQUAL", config));
3107 }
3108 {
3109 TestConfig config = baseConfig;
3110 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3111 config.meshParams[0].depth = 0.25f;
3112 config.expectedDepth = 0.25f;
3113 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));
3114 }
3115 {
3116 TestConfig config = baseConfig;
3117 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3118 config.meshParams[0].depth = 0.5f;
3119 config.expectedDepth = 0.5f;
3120 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));
3121 }
3122 {
3123 TestConfig config = baseConfig;
3124 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_LESS_OR_EQUAL;
3125 config.meshParams[0].depth = 0.25f;
3126 // Draw another mesh with the same depth in front of it.
3127 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.25f));
3128 config.expectedDepth = 0.25f;
3129 config.referenceColor = SingleColorGenerator(kAlternativeColor);
3130 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));
3131 }
3132 {
3133 TestConfig config = baseConfig;
3134 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3135 config.meshParams[0].depth = 0.75f;
3136 config.expectedDepth = 0.75f;
3137 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));
3138 }
3139 {
3140 TestConfig config = baseConfig;
3141 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3142 config.meshParams[0].depth = 0.5f;
3143 config.expectedDepth = 0.5f;
3144 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));
3145 }
3146 {
3147 TestConfig config = baseConfig;
3148 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_GREATER_OR_EQUAL;
3149 config.meshParams[0].depth = 0.75f;
3150 // Draw another mesh with the same depth in front of it.
3151 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.75f));
3152 config.expectedDepth = 0.75f;
3153 config.referenceColor = SingleColorGenerator(kAlternativeColor);
3154 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));
3155 }
3156 {
3157 TestConfig config = baseConfig;
3158 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_NOT_EQUAL;
3159
3160 // Draw first mesh in front.
3161 config.meshParams[0].depth = 0.25f;
3162 // Draw another mesh in the back, this should pass too.
3163 config.meshParams.push_back(MeshParams(kAlternativeColor, 0.5f));
3164 // Finally a new mesh with the same depth. This should not pass.
3165 config.meshParams.push_back(MeshParams(kDefaultTriangleColor, 0.5f));
3166
3167 config.referenceColor = SingleColorGenerator(kAlternativeColor);
3168 config.expectedDepth = 0.5f;
3169 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_not_equal", "Dynamically set the depth compare operator to NOT_EQUAL", config));
3170 }
3171 {
3172 TestConfig config = baseConfig;
3173 config.depthCompareOpConfig.dynamicValue = vk::VK_COMPARE_OP_ALWAYS;
3174
3175 config.meshParams[0].depth = 0.5f;
3176 config.expectedDepth = 0.5f;
3177 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_equal", "Dynamically set the depth compare operator to ALWAYS and draw with equal depth", config));
3178
3179 config.meshParams[0].depth = 0.25f;
3180 config.expectedDepth = 0.25f;
3181 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_less", "Dynamically set the depth compare operator to ALWAYS and draw with less depth", config));
3182
3183 config.meshParams[0].depth = 0.75f;
3184 config.expectedDepth = 0.75f;
3185 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_compare_always_greater", "Dynamically set the depth compare operator to ALWAYS and draw with greater depth", config));
3186 }
3187 }
3188
3189 // Depth bounds test.
3190 {
3191 TestConfig baseConfig(kOrdering);
3192 baseConfig.minDepthBounds = 0.25f;
3193 baseConfig.maxDepthBounds = 0.75f;
3194 baseConfig.meshParams[0].depth = 0.0f;
3195
3196 {
3197 TestConfig config = baseConfig;
3198 config.depthBoundsTestEnableConfig.staticValue = false;
3199 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(true);
3200 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
3201 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_enable", "Dynamically enable the depth bounds test", config));
3202 }
3203 {
3204 TestConfig config = baseConfig;
3205 config.depthBoundsTestEnableConfig.staticValue = true;
3206 config.depthBoundsTestEnableConfig.dynamicValue = tcu::just(false);
3207 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "depth_bounds_test_disable", "Dynamically disable the depth bounds test", config));
3208 }
3209 }
3210
3211 // Stencil test enable.
3212 {
3213 TestConfig config(kOrdering);
3214 config.stencilTestEnableConfig.staticValue = false;
3215 config.stencilTestEnableConfig.dynamicValue = tcu::just(true);
3216 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
3217 config.referenceColor = SingleColorGenerator(kDefaultClearColor);
3218 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_enable", "Dynamically enable the stencil test", config));
3219 }
3220 {
3221 TestConfig config(kOrdering);
3222 config.stencilTestEnableConfig.staticValue = true;
3223 config.stencilTestEnableConfig.dynamicValue = tcu::just(false);
3224 config.stencilOpConfig.staticValue.front().compareOp = vk::VK_COMPARE_OP_NEVER;
3225 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "stencil_test_disable", "Dynamically disable the stencil test", config));
3226 }
3227
3228 // Stencil operation. Many combinations are possible.
3229 {
3230 static const struct
3231 {
3232 vk::VkStencilFaceFlags face;
3233 std::string name;
3234 } kFaces[] =
3235 {
3236 { vk::VK_STENCIL_FACE_FRONT_BIT, "face_front" },
3237 { vk::VK_STENCIL_FACE_BACK_BIT, "face_back" },
3238 { vk::VK_STENCIL_FRONT_AND_BACK, "face_both_single" },
3239 { vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM, "face_both_dual" }, // MAX_ENUM is a placeholder.
3240 };
3241
3242 static const struct
3243 {
3244 vk::VkCompareOp compareOp;
3245 std::string name;
3246 } kCompare[] =
3247 {
3248 { vk::VK_COMPARE_OP_NEVER, "xf" },
3249 { vk::VK_COMPARE_OP_LESS, "lt" },
3250 { vk::VK_COMPARE_OP_EQUAL, "eq" },
3251 { vk::VK_COMPARE_OP_LESS_OR_EQUAL, "le" },
3252 { vk::VK_COMPARE_OP_GREATER, "gt" },
3253 { vk::VK_COMPARE_OP_GREATER_OR_EQUAL, "ge" },
3254 { vk::VK_COMPARE_OP_ALWAYS, "xt" },
3255 };
3256
3257 using u8vec = std::vector<deUint8>;
3258
3259 static const auto kMinVal = std::numeric_limits<deUint8>::min();
3260 static const auto kMaxVal = std::numeric_limits<deUint8>::max();
3261 static const auto kMidVal = static_cast<deUint8>(kMaxVal * 2u / 5u);
3262 static const auto kMinValI = static_cast<int>(kMinVal);
3263 static const auto kMaxValI = static_cast<int>(kMaxVal);
3264
3265 static const struct
3266 {
3267 vk::VkStencilOp stencilOp;
3268 std::string name;
3269 u8vec clearValues; // One test per clear value interesting for this operation.
3270 vk::VkStencilOp incompatibleOp; // Alternative operation giving incompatible results for the given values.
3271 } kStencilOps[] =
3272 {
3273 { vk::VK_STENCIL_OP_KEEP, "keep", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
3274 { vk::VK_STENCIL_OP_ZERO, "zero", u8vec{kMidVal}, vk::VK_STENCIL_OP_KEEP },
3275 { vk::VK_STENCIL_OP_REPLACE, "replace", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
3276 { vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP, "inc_clamp", u8vec{kMaxVal - 1, kMaxVal}, vk::VK_STENCIL_OP_ZERO },
3277 { vk::VK_STENCIL_OP_DECREMENT_AND_CLAMP, "dec_clamp", u8vec{kMinVal + 1, kMinVal}, vk::VK_STENCIL_OP_INCREMENT_AND_CLAMP },
3278 { vk::VK_STENCIL_OP_INVERT, "invert", u8vec{kMidVal}, vk::VK_STENCIL_OP_ZERO },
3279 { vk::VK_STENCIL_OP_INCREMENT_AND_WRAP, "inc_wrap", u8vec{kMaxVal - 1, kMaxVal}, vk::VK_STENCIL_OP_KEEP },
3280 { vk::VK_STENCIL_OP_DECREMENT_AND_WRAP, "dec_wrap", u8vec{kMinVal + 1, kMinVal}, vk::VK_STENCIL_OP_KEEP },
3281 };
3282
3283 for (const auto& face : kFaces)
3284 for (const auto& compare : kCompare)
3285 for (const auto& op : kStencilOps)
3286 {
3287 // Try clearing the stencil value with different values.
3288 for (const auto clearVal : op.clearValues)
3289 {
3290 // Use interesting values as the reference stencil value.
3291 for (int delta = -1; delta <= 1; ++delta)
3292 {
3293 const int refVal = clearVal + delta;
3294 if (refVal < kMinValI || refVal > kMaxValI)
3295 continue;
3296
3297 const auto refValU8 = static_cast<deUint8>(refVal);
3298 const auto refValU32 = static_cast<deUint32>(refVal);
3299
3300 // Calculate outcome of the stencil test itself.
3301 const bool wouldPass = stencilPasses(compare.compareOp, clearVal, refValU8);
3302
3303 // If the test passes, use an additional variant for the depthFail operation.
3304 const int subCases = (wouldPass ? 2 : 1);
3305
3306 for (int subCaseIdx = 0; subCaseIdx < subCases; ++subCaseIdx)
3307 {
3308 const bool depthFail = (subCaseIdx > 0); // depthFail would be the second variant.
3309 const bool globalPass = (wouldPass && !depthFail); // Global result of the stencil+depth test.
3310
3311 // Start tuning test parameters.
3312 TestConfig config(kOrdering);
3313
3314 // No face culling is applied by default, so both the front and back operations could apply depending on the mesh.
3315 if (face.face == vk::VK_STENCIL_FACE_FRONT_BIT)
3316 {
3317 // Default parameters are OK.
3318 }
3319 else if (face.face == vk::VK_STENCIL_FACE_BACK_BIT)
3320 {
3321 // Reverse the mesh so it applies the back operation.
3322 config.meshParams[0].reversed = true;
3323 }
3324 else // Front and back.
3325 {
3326 // Draw both a front and a back-facing mesh so both are applied.
3327 // The first mesh will be drawn in the top half and the second mesh in the bottom half.
3328
3329 // Make the second mesh a reversed copy of the first mesh.
3330 config.meshParams.push_back(config.meshParams.front());
3331 config.meshParams.back().reversed = true;
3332
3333 // Apply scale and offset to the top mesh.
3334 config.meshParams.front().scaleY = 0.5f;
3335 config.meshParams.front().offsetY = -0.5f;
3336
3337 // Apply scale and offset to the bottom mesh.
3338 config.meshParams.back().scaleY = 0.5f;
3339 config.meshParams.back().offsetY = 0.5f;
3340 }
3341
3342 // Enable the stencil test.
3343 config.stencilTestEnableConfig.staticValue = true;
3344
3345 // Set dynamic configuration.
3346 StencilOpParams dynamicStencilConfig;
3347 dynamicStencilConfig.faceMask = face.face;
3348 dynamicStencilConfig.compareOp = compare.compareOp;
3349 dynamicStencilConfig.failOp = vk::VK_STENCIL_OP_MAX_ENUM;
3350 dynamicStencilConfig.passOp = vk::VK_STENCIL_OP_MAX_ENUM;
3351 dynamicStencilConfig.depthFailOp = vk::VK_STENCIL_OP_MAX_ENUM;
3352
3353 // Set operations so only the appropriate operation for this case gives the right result.
3354 vk::VkStencilOp* activeOp = nullptr;
3355 vk::VkStencilOp* inactiveOps[2] = { nullptr, nullptr };
3356 if (wouldPass)
3357 {
3358 if (depthFail)
3359 {
3360 activeOp = &dynamicStencilConfig.depthFailOp;
3361 inactiveOps[0] = &dynamicStencilConfig.passOp;
3362 inactiveOps[1] = &dynamicStencilConfig.failOp;
3363 }
3364 else
3365 {
3366 activeOp = &dynamicStencilConfig.passOp;
3367 inactiveOps[0] = &dynamicStencilConfig.depthFailOp;
3368 inactiveOps[1] = &dynamicStencilConfig.failOp;
3369 }
3370 }
3371 else
3372 {
3373 activeOp = &dynamicStencilConfig.failOp;
3374 inactiveOps[0] = &dynamicStencilConfig.passOp;
3375 inactiveOps[1] = &dynamicStencilConfig.depthFailOp;
3376 }
3377
3378 *activeOp = op.stencilOp;
3379 *inactiveOps[0] = op.incompatibleOp;
3380 *inactiveOps[1] = op.incompatibleOp;
3381
3382 // Make sure all ops have been configured properly.
3383 DE_ASSERT(dynamicStencilConfig.failOp != vk::VK_STENCIL_OP_MAX_ENUM);
3384 DE_ASSERT(dynamicStencilConfig.passOp != vk::VK_STENCIL_OP_MAX_ENUM);
3385 DE_ASSERT(dynamicStencilConfig.depthFailOp != vk::VK_STENCIL_OP_MAX_ENUM);
3386
3387 // Set an incompatible static operation too.
3388 auto& staticStencilConfig = config.stencilOpConfig.staticValue.front();
3389 staticStencilConfig.faceMask = face.face;
3390 staticStencilConfig.compareOp = (globalPass ? vk::VK_COMPARE_OP_NEVER : vk::VK_COMPARE_OP_ALWAYS);
3391 staticStencilConfig.passOp = op.incompatibleOp;
3392 staticStencilConfig.failOp = op.incompatibleOp;
3393 staticStencilConfig.depthFailOp = op.incompatibleOp;
3394
3395 // Set dynamic configuration.
3396 StencilOpVec stencilOps;
3397 stencilOps.push_back(dynamicStencilConfig);
3398
3399 if (stencilOps.front().faceMask == vk::VK_STENCIL_FACE_FLAG_BITS_MAX_ENUM)
3400 {
3401 // This is the dual case. We will set the front and back face values with two separate calls.
3402 stencilOps.push_back(stencilOps.front());
3403 stencilOps.front().faceMask = vk::VK_STENCIL_FACE_FRONT_BIT;
3404 stencilOps.back().faceMask = vk::VK_STENCIL_FACE_BACK_BIT;
3405 staticStencilConfig.faceMask = vk::VK_STENCIL_FACE_FRONT_AND_BACK;
3406 }
3407
3408 config.stencilOpConfig.dynamicValue = tcu::just(stencilOps);
3409 config.clearStencilValue = clearVal;
3410 config.referenceStencil = refValU32;
3411
3412 if (depthFail)
3413 {
3414 // Enable depth test and make it fail.
3415 config.depthTestEnableConfig.staticValue = true;
3416 config.clearDepthValue = 0.5f;
3417 config.depthCompareOpConfig.staticValue = vk::VK_COMPARE_OP_LESS;
3418
3419 for (auto& meshPar : config.meshParams)
3420 meshPar.depth = 0.75f;
3421 }
3422
3423 // Set expected outcome.
3424 config.referenceColor = SingleColorGenerator(globalPass ? kDefaultTriangleColor : kDefaultClearColor);
3425 config.expectedDepth = config.clearDepthValue; // No depth writing by default.
3426 config.expectedStencil = stencilResult(op.stencilOp, clearVal, refValU8, kMinVal, kMaxVal);
3427
3428 const std::string testName = std::string("stencil_state")
3429 + "_" + face.name
3430 + "_" + compare.name
3431 + "_" + op.name
3432 + "_clear_" + de::toString(static_cast<int>(clearVal))
3433 + "_ref_" + de::toString(refVal)
3434 + "_" + (wouldPass ? (depthFail ? "depthfail" : "pass") : "fail");
3435
3436 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, testName, "Dynamically configure stencil test, variant " + testName, config));
3437 }
3438 }
3439 }
3440 }
3441 }
3442
3443 // Vertex input.
3444 {
3445 // TWO_DRAWS_STATIC would be invalid because it violates VUID-vkCmdBindVertexBuffers2EXT-pStrides-03363 due to the
3446 // dynamic stride being less than the extent of the binding for the second attribute.
3447 if (kOrdering != SequenceOrdering::TWO_DRAWS_STATIC)
3448 {
3449 const auto staticGen = getVertexWithPaddingGenerator();
3450 const auto dynamicGen = getVertexWithExtraAttributesGenerator();
3451 const auto goodStrides = dynamicGen->getVertexDataStrides();
3452 StrideVec badStrides;
3453
3454 badStrides.reserve(goodStrides.size());
3455 for (const auto& stride : goodStrides)
3456 badStrides.push_back(stride / 2u);
3457
3458 TestConfig config(kOrdering, staticGen, dynamicGen);
3459 config.strideConfig.staticValue = badStrides;
3460 config.strideConfig.dynamicValue = goodStrides;
3461 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input", "Dynamically set vertex input", config));
3462 }
3463
3464 {
3465 // Variant without mixing in the stride config.
3466 TestConfig config(kOrdering, getVertexWithPaddingGenerator(), getVertexWithExtraAttributesGenerator());
3467 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_no_dyn_stride", "Dynamically set vertex input without using dynamic strides", config));
3468 }
3469
3470 {
3471 // Variant using multiple bindings.
3472 TestConfig config(kOrdering, getVertexWithExtraAttributesGenerator(), getVertexWithMultipleBindingsGenerator());
3473 orderingGroup->addChild(new ExtendedDynamicStateTest(testCtx, "vertex_input_multiple_bindings", "Dynamically set vertex input with multiple bindings", config));
3474 }
3475 }
3476
3477 extendedDynamicStateGroup->addChild(orderingGroup.release());
3478 }
3479
3480 return extendedDynamicStateGroup.release();
3481 }
3482
3483 } // pipeline
3484 } // vkt
3485