1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2015 The Khronos Group Inc.
6 * Copyright (c) 2015 Imagination Technologies Ltd.
7 * Copyright (c) 2023 LunarG, Inc.
8 * Copyright (c) 2023 Nintendo
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 *
22 *//*!
23 * \file
24 * \brief Vertex Input Tests
25 *//*--------------------------------------------------------------------*/
26
27 #include "vktPipelineVertexInputTests.hpp"
28 #include "vktTestGroupUtil.hpp"
29 #include "vktPipelineClearUtil.hpp"
30 #include "vktPipelineImageUtil.hpp"
31 #include "vktPipelineVertexUtil.hpp"
32 #include "vktPipelineReferenceRenderer.hpp"
33 #include "vktTestCase.hpp"
34 #include "vktTestCaseUtil.hpp"
35 #include "vkImageUtil.hpp"
36 #include "vkMemUtil.hpp"
37 #include "vkPrograms.hpp"
38 #include "vkQueryUtil.hpp"
39 #include "vkRef.hpp"
40 #include "vkRefUtil.hpp"
41 #include "vkTypeUtil.hpp"
42 #include "vkCmdUtil.hpp"
43 #include "vkObjUtil.hpp"
44 #include "tcuFloat.hpp"
45 #include "tcuImageCompare.hpp"
46 #include "tcuFloat.hpp"
47 #include "deMemory.h"
48 #include "deRandom.hpp"
49 #include "deStringUtil.hpp"
50 #include "deUniquePtr.hpp"
51
52 #include <sstream>
53 #include <vector>
54 #include <map>
55 #include <memory>
56
57 namespace vkt
58 {
59 namespace pipeline
60 {
61
62 namespace
63 {
64
65 using namespace vk;
66
67 constexpr int kMaxComponents = 4;
68
isSupportedVertexFormat(Context & context,VkFormat format)69 bool isSupportedVertexFormat(Context &context, VkFormat format)
70 {
71 if (isVertexFormatDouble(format) && !context.getDeviceFeatures().shaderFloat64)
72 return false;
73
74 VkFormatProperties formatProps;
75 deMemset(&formatProps, 0, sizeof(VkFormatProperties));
76 context.getInstanceInterface().getPhysicalDeviceFormatProperties(context.getPhysicalDevice(), format, &formatProps);
77
78 return (formatProps.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) != 0u;
79 }
80
getRepresentableDifferenceUnorm(VkFormat format)81 float getRepresentableDifferenceUnorm(VkFormat format)
82 {
83 DE_ASSERT(isVertexFormatUnorm(format) || isVertexFormatSRGB(format));
84
85 return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8)) - 1);
86 }
87
getRepresentableDifferenceUnormPacked(VkFormat format,uint32_t componentNdx)88 float getRepresentableDifferenceUnormPacked(VkFormat format, uint32_t componentNdx)
89 {
90 DE_ASSERT((isVertexFormatUnorm(format) || isVertexFormatSRGB(format)) && isVertexFormatPacked(format));
91
92 return 1.0f / float((1 << (getPackedVertexFormatComponentWidth(format, componentNdx))) - 1);
93 }
94
getRepresentableDifferenceSnorm(VkFormat format)95 float getRepresentableDifferenceSnorm(VkFormat format)
96 {
97 DE_ASSERT(isVertexFormatSnorm(format));
98
99 return 1.0f / float((1 << (getVertexFormatComponentSize(format) * 8 - 1)) - 1);
100 }
101
getRepresentableDifferenceSnormPacked(VkFormat format,uint32_t componentNdx)102 float getRepresentableDifferenceSnormPacked(VkFormat format, uint32_t componentNdx)
103 {
104 DE_ASSERT(isVertexFormatSnorm(format) && isVertexFormatPacked(format));
105
106 return 1.0f / float((1 << (getPackedVertexFormatComponentWidth(format, componentNdx) - 1)) - 1);
107 }
108
getNextMultipleOffset(uint32_t divisor,uint32_t value)109 uint32_t getNextMultipleOffset(uint32_t divisor, uint32_t value)
110 {
111 if (value % divisor == 0)
112 return 0;
113 else
114 return divisor - (value % divisor);
115 }
116
117 class VertexInputTest : public vkt::TestCase
118 {
119 public:
120 enum GlslType
121 {
122 GLSL_TYPE_INT,
123 GLSL_TYPE_IVEC2,
124 GLSL_TYPE_IVEC3,
125 GLSL_TYPE_IVEC4,
126
127 GLSL_TYPE_UINT,
128 GLSL_TYPE_UVEC2,
129 GLSL_TYPE_UVEC3,
130 GLSL_TYPE_UVEC4,
131
132 GLSL_TYPE_FLOAT,
133 GLSL_TYPE_VEC2,
134 GLSL_TYPE_VEC3,
135 GLSL_TYPE_VEC4,
136
137 GLSL_TYPE_F16,
138 GLSL_TYPE_F16VEC2,
139 GLSL_TYPE_F16VEC3,
140 GLSL_TYPE_F16VEC4,
141
142 GLSL_TYPE_MAT2,
143 GLSL_TYPE_MAT3,
144 GLSL_TYPE_MAT4,
145
146 GLSL_TYPE_DOUBLE,
147 GLSL_TYPE_DVEC2,
148 GLSL_TYPE_DVEC3,
149 GLSL_TYPE_DVEC4,
150 GLSL_TYPE_DMAT2,
151 GLSL_TYPE_DMAT3,
152 GLSL_TYPE_DMAT4,
153
154 GLSL_TYPE_COUNT
155 };
156
157 enum GlslBasicType
158 {
159 GLSL_BASIC_TYPE_INT,
160 GLSL_BASIC_TYPE_UINT,
161 GLSL_BASIC_TYPE_FLOAT,
162 GLSL_BASIC_TYPE_DOUBLE,
163 GLSL_BASIC_TYPE_FLOAT16,
164 };
165
166 enum BindingMapping
167 {
168 BINDING_MAPPING_ONE_TO_ONE, //!< Vertex input bindings will not contain data for more than one attribute.
169 BINDING_MAPPING_ONE_TO_MANY //!< Vertex input bindings can contain data for more than one attribute.
170 };
171
172 enum AttributeLayout
173 {
174 ATTRIBUTE_LAYOUT_INTERLEAVED, //!< Attribute data is bundled together as if in a structure: [pos 0][color 0][pos 1][color 1]...
175 ATTRIBUTE_LAYOUT_SEQUENTIAL //!< Data for each attribute is laid out separately: [pos 0][pos 1]...[color 0][color 1]...
176 // Sequential only makes a difference if ONE_TO_MANY mapping is used (more than one attribute in a binding).
177 };
178
179 enum LayoutSkip
180 {
181 LAYOUT_SKIP_ENABLED, //!< Skip one location slot after each attribute
182 LAYOUT_SKIP_DISABLED //!< Consume locations sequentially
183 };
184
185 enum LayoutOrder
186 {
187 LAYOUT_ORDER_IN_ORDER, //!< Assign locations in order
188 LAYOUT_ORDER_OUT_OF_ORDER //!< Assign locations out of order
189 };
190
191 struct AttributeInfo
192 {
193 GlslType glslType;
194 VkFormat vkType;
195 VkVertexInputRate inputRate;
196 };
197
198 struct GlslTypeDescription
199 {
200 const char *name;
201 int vertexInputComponentCount;
202 int vertexInputCount;
203 GlslBasicType basicType;
204 };
205
206 static const GlslTypeDescription s_glslTypeDescriptions[GLSL_TYPE_COUNT];
207
208 VertexInputTest(tcu::TestContext &testContext, const std::string &name,
209 const PipelineConstructionType pipelineConstructionType,
210 const std::vector<AttributeInfo> &attributeInfos, BindingMapping bindingMapping,
211 AttributeLayout attributeLayout, LayoutSkip layoutSkip = LAYOUT_SKIP_DISABLED,
212 LayoutOrder layoutOrder = LAYOUT_ORDER_IN_ORDER, const bool testMissingComponents = false);
213
~VertexInputTest(void)214 virtual ~VertexInputTest(void)
215 {
216 }
217 virtual void initPrograms(SourceCollections &programCollection) const;
218 virtual void checkSupport(Context &context) const;
219 virtual TestInstance *createInstance(Context &context) const;
220 static bool isCompatibleType(VkFormat format, GlslType glslType);
221
222 private:
223 AttributeInfo getAttributeInfo(size_t attributeNdx) const;
224 size_t getNumAttributes(void) const;
225 std::string getGlslExtensions(void) const;
226 std::string getGlslInputDeclarations(void) const;
227 std::string getGlslVertexCheck(void) const;
228 std::string getGlslAttributeConditions(const AttributeInfo &attributeInfo, const std::string attributeIndex) const;
229 static tcu::Vec4 getFormatThreshold(VkFormat format);
230
231 const PipelineConstructionType m_pipelineConstructionType;
232 const std::vector<AttributeInfo> m_attributeInfos;
233 const BindingMapping m_bindingMapping;
234 const AttributeLayout m_attributeLayout;
235 const LayoutSkip m_layoutSkip;
236 mutable std::vector<uint32_t> m_locations;
237 const bool m_queryMaxAttributes;
238 bool m_usesDoubleType;
239 bool m_usesFloat16Type;
240 mutable size_t m_maxAttributes;
241 const bool m_testMissingComponents;
242 };
243
244 class VertexInputInstance : public vkt::TestInstance
245 {
246 public:
247 struct VertexInputAttributeDescription
248 {
249 VertexInputTest::GlslType glslType;
250 int vertexInputIndex;
251 VkVertexInputAttributeDescription vkDescription;
252 };
253
254 typedef std::vector<VertexInputAttributeDescription> AttributeDescriptionList;
255
256 VertexInputInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
257 const AttributeDescriptionList &attributeDescriptions,
258 const std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
259 const std::vector<VkDeviceSize> &bindingOffsets);
260
261 virtual ~VertexInputInstance(void);
262 virtual tcu::TestStatus iterate(void);
263
264 static void writeVertexInputData(uint8_t *destPtr, const VkVertexInputBindingDescription &bindingDescription,
265 const VkDeviceSize bindingOffset, const AttributeDescriptionList &attributes);
266 static void writeVertexInputValue(uint8_t *destPtr, const VertexInputAttributeDescription &attributes, int indexId);
267
268 private:
269 tcu::TestStatus verifyImage(void);
270
271 private:
272 std::vector<VkBuffer> m_vertexBuffers;
273 std::vector<Allocation *> m_vertexBufferAllocs;
274
275 const tcu::UVec2 m_renderSize;
276 const VkFormat m_colorFormat;
277
278 Move<VkImage> m_colorImage;
279 de::MovePtr<Allocation> m_colorImageAlloc;
280 Move<VkImage> m_depthImage;
281 Move<VkImageView> m_colorAttachmentView;
282 RenderPassWrapper m_renderPass;
283
284 ShaderWrapper m_vertexShaderModule;
285 ShaderWrapper m_fragmentShaderModule;
286
287 PipelineLayoutWrapper m_pipelineLayout;
288 GraphicsPipelineWrapper m_graphicsPipeline;
289
290 Move<VkCommandPool> m_cmdPool;
291 Move<VkCommandBuffer> m_cmdBuffer;
292 };
293
294 const VertexInputTest::GlslTypeDescription VertexInputTest::s_glslTypeDescriptions[GLSL_TYPE_COUNT] = {
295 {"int", 1, 1, GLSL_BASIC_TYPE_INT}, {"ivec2", 2, 1, GLSL_BASIC_TYPE_INT},
296 {"ivec3", 3, 1, GLSL_BASIC_TYPE_INT}, {"ivec4", 4, 1, GLSL_BASIC_TYPE_INT},
297
298 {"uint", 1, 1, GLSL_BASIC_TYPE_UINT}, {"uvec2", 2, 1, GLSL_BASIC_TYPE_UINT},
299 {"uvec3", 3, 1, GLSL_BASIC_TYPE_UINT}, {"uvec4", 4, 1, GLSL_BASIC_TYPE_UINT},
300
301 {"float", 1, 1, GLSL_BASIC_TYPE_FLOAT}, {"vec2", 2, 1, GLSL_BASIC_TYPE_FLOAT},
302 {"vec3", 3, 1, GLSL_BASIC_TYPE_FLOAT}, {"vec4", 4, 1, GLSL_BASIC_TYPE_FLOAT},
303
304 {"float16_t", 1, 1, GLSL_BASIC_TYPE_FLOAT16}, {"f16vec2", 2, 1, GLSL_BASIC_TYPE_FLOAT16},
305 {"f16vec3", 3, 1, GLSL_BASIC_TYPE_FLOAT16}, {"f16vec4", 4, 1, GLSL_BASIC_TYPE_FLOAT16},
306
307 {"mat2", 2, 2, GLSL_BASIC_TYPE_FLOAT}, {"mat3", 3, 3, GLSL_BASIC_TYPE_FLOAT},
308 {"mat4", 4, 4, GLSL_BASIC_TYPE_FLOAT},
309
310 {"double", 1, 1, GLSL_BASIC_TYPE_DOUBLE}, {"dvec2", 2, 1, GLSL_BASIC_TYPE_DOUBLE},
311 {"dvec3", 3, 1, GLSL_BASIC_TYPE_DOUBLE}, {"dvec4", 4, 1, GLSL_BASIC_TYPE_DOUBLE},
312 {"dmat2", 2, 2, GLSL_BASIC_TYPE_DOUBLE}, {"dmat3", 3, 3, GLSL_BASIC_TYPE_DOUBLE},
313 {"dmat4", 4, 4, GLSL_BASIC_TYPE_DOUBLE}};
314
expandGlslNameToFullComponents(const char * name)315 const char *expandGlslNameToFullComponents(const char *name)
316 {
317 static const std::map<std::string, std::string> nameMap
318 {
319 std::make_pair("int", "ivec4"), std::make_pair("ivec2", "ivec4"), std::make_pair("ivec3", "ivec4"),
320 std::make_pair("ivec4", "ivec4"), std::make_pair("uint", "uvec4"), std::make_pair("uvec2", "uvec4"),
321 std::make_pair("uvec3", "uvec4"), std::make_pair("uvec4", "uvec4"), std::make_pair("float", "vec4"),
322 std::make_pair("vec2", "vec4"), std::make_pair("vec3", "vec4"), std::make_pair("vec4", "vec4"),
323 std::make_pair("float16_t", "f16vec4"), std::make_pair("f16vec2", "f16vec4"),
324 std::make_pair("f16vec3", "f16vec4"), std::make_pair("f16vec4", "f16vec4"),
325 std::make_pair("mat2", "mat2x4"), std::make_pair("mat3", "mat3x4"), std::make_pair("mat4", "mat4"),
326 #if 0
327 // 64-bit types don't have default values, so they cannot be used in missing component tests.
328 // In addition, they may be expanded from one location to using more than one, which creates vertex input mismatches.
329 std::make_pair("double", "dvec4"),
330 std::make_pair("dvec2", "dvec4"),
331 std::make_pair("dvec3", "dvec4"),
332 std::make_pair("dvec4", "dvec4"),
333 std::make_pair("dmat2", "dmat2x4"),
334 std::make_pair("dmat3", "dmat3x4"),
335 std::make_pair("dmat4", "dmat4"),
336 #endif
337 };
338
339 const auto pos = nameMap.find(name);
340 if (pos == nameMap.end())
341 return nullptr;
342 return pos->second.c_str();
343 }
344
getAttributeBinding(const VertexInputTest::BindingMapping bindingMapping,const VkVertexInputRate firstInputRate,const VkVertexInputRate inputRate,const uint32_t attributeNdx)345 uint32_t getAttributeBinding(const VertexInputTest::BindingMapping bindingMapping,
346 const VkVertexInputRate firstInputRate, const VkVertexInputRate inputRate,
347 const uint32_t attributeNdx)
348 {
349 if (bindingMapping == VertexInputTest::BINDING_MAPPING_ONE_TO_ONE)
350 {
351 // Each attribute uses a unique binding
352 return attributeNdx;
353 }
354 else // bindingMapping == BINDING_MAPPING_ONE_TO_MANY
355 {
356 // Alternate between two bindings
357 return uint32_t(firstInputRate + inputRate) % 2u;
358 }
359 }
360
361 //! Number of locations used up by an attribute.
getConsumedLocations(const VertexInputTest::AttributeInfo & attributeInfo)362 uint32_t getConsumedLocations(const VertexInputTest::AttributeInfo &attributeInfo)
363 {
364 // double formats with more than 2 components will take 2 locations
365 const VertexInputTest::GlslType type = attributeInfo.glslType;
366 if ((type == VertexInputTest::GLSL_TYPE_DMAT2 || type == VertexInputTest::GLSL_TYPE_DMAT3 ||
367 type == VertexInputTest::GLSL_TYPE_DMAT4) &&
368 (attributeInfo.vkType == VK_FORMAT_R64G64B64_SFLOAT || attributeInfo.vkType == VK_FORMAT_R64G64B64A64_SFLOAT))
369 {
370 return 2u;
371 }
372 else
373 return 1u;
374 }
375
VertexInputTest(tcu::TestContext & testContext,const std::string & name,const PipelineConstructionType pipelineConstructionType,const std::vector<AttributeInfo> & attributeInfos,BindingMapping bindingMapping,AttributeLayout attributeLayout,LayoutSkip layoutSkip,LayoutOrder layoutOrder,const bool testMissingComponents)376 VertexInputTest::VertexInputTest(tcu::TestContext &testContext, const std::string &name,
377 const PipelineConstructionType pipelineConstructionType,
378 const std::vector<AttributeInfo> &attributeInfos, BindingMapping bindingMapping,
379 AttributeLayout attributeLayout, LayoutSkip layoutSkip, LayoutOrder layoutOrder,
380 const bool testMissingComponents)
381 : vkt::TestCase(testContext, name)
382 , m_pipelineConstructionType(pipelineConstructionType)
383 , m_attributeInfos(attributeInfos)
384 , m_bindingMapping(bindingMapping)
385 , m_attributeLayout(attributeLayout)
386 , m_layoutSkip(layoutSkip)
387 , m_queryMaxAttributes(attributeInfos.size() == 0)
388 , m_usesDoubleType(false)
389 , m_usesFloat16Type(false)
390 , m_maxAttributes(16)
391 , m_testMissingComponents(testMissingComponents)
392 {
393 DE_ASSERT(m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED || m_bindingMapping == BINDING_MAPPING_ONE_TO_MANY);
394
395 for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
396 {
397 const auto &basicType = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].basicType;
398
399 if (basicType == GLSL_BASIC_TYPE_DOUBLE)
400 m_usesDoubleType = true;
401 else if (basicType == GLSL_BASIC_TYPE_FLOAT16)
402 m_usesFloat16Type = true;
403 }
404
405 // Determine number of location slots required for each attribute
406 uint32_t attributeLocation = 0;
407 std::vector<uint32_t> locationSlotsNeeded;
408 const size_t numAttributes = getNumAttributes();
409
410 for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
411 {
412 const AttributeInfo &attributeInfo = getAttributeInfo(attributeNdx);
413 const GlslTypeDescription &glslTypeDescription = s_glslTypeDescriptions[attributeInfo.glslType];
414 const uint32_t prevAttributeLocation = attributeLocation;
415
416 attributeLocation += glslTypeDescription.vertexInputCount * getConsumedLocations(attributeInfo);
417
418 if (m_layoutSkip == LAYOUT_SKIP_ENABLED)
419 attributeLocation++;
420
421 locationSlotsNeeded.push_back(attributeLocation - prevAttributeLocation);
422 }
423
424 if (layoutOrder == LAYOUT_ORDER_IN_ORDER)
425 {
426 uint32_t loc = 0;
427
428 // Assign locations in order
429 for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
430 {
431 m_locations.push_back(loc);
432 loc += locationSlotsNeeded[attributeNdx];
433 }
434 }
435 else
436 {
437 // Assign locations out of order
438 std::vector<uint32_t> indices;
439 std::vector<uint32_t> slots;
440 uint32_t slot = 0;
441
442 // Mix the location slots: first all even and then all odd attributes.
443 for (uint32_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
444 if (attributeNdx % 2 == 0)
445 indices.push_back(attributeNdx);
446 for (uint32_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
447 if (attributeNdx % 2 != 0)
448 indices.push_back(attributeNdx);
449
450 for (size_t i = 0; i < indices.size(); i++)
451 {
452 slots.push_back(slot);
453 slot += locationSlotsNeeded[indices[i]];
454 }
455
456 for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
457 {
458 uint32_t slotIdx = 0;
459 for (uint32_t i = 0; i < (uint32_t)indices.size(); i++)
460 if (attributeNdx == indices[i])
461 slotIdx = i;
462 m_locations.push_back(slots[slotIdx]);
463 }
464 }
465 }
466
getAttributeInfo(size_t attributeNdx) const467 VertexInputTest::AttributeInfo VertexInputTest::getAttributeInfo(size_t attributeNdx) const
468 {
469 if (m_queryMaxAttributes)
470 {
471 AttributeInfo attributeInfo = {GLSL_TYPE_VEC4, VK_FORMAT_R8G8B8A8_SNORM,
472 (attributeNdx % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX :
473 VK_VERTEX_INPUT_RATE_INSTANCE};
474
475 return attributeInfo;
476 }
477 else
478 {
479 return m_attributeInfos.at(attributeNdx);
480 }
481 }
482
getNumAttributes(void) const483 size_t VertexInputTest::getNumAttributes(void) const
484 {
485 if (m_queryMaxAttributes)
486 return m_maxAttributes;
487 else
488 return m_attributeInfos.size();
489 }
490
checkSupport(Context & context) const491 void VertexInputTest::checkSupport(Context &context) const
492 {
493 const uint32_t maxAttributes = context.getDeviceProperties().limits.maxVertexInputAttributes;
494
495 if (m_attributeInfos.size() > maxAttributes)
496 TCU_THROW(NotSupportedError, "Unsupported number of vertex input attributes, maxVertexInputAttributes: " +
497 de::toString(maxAttributes));
498
499 if (m_usesFloat16Type)
500 {
501 const auto &sf16i8Features = context.getShaderFloat16Int8Features();
502 if (!sf16i8Features.shaderFloat16)
503 TCU_THROW(NotSupportedError, "shaderFloat16 not supported");
504
505 const auto &storage16Features = context.get16BitStorageFeatures();
506 if (!storage16Features.storageInputOutput16)
507 TCU_THROW(NotSupportedError, "storageInputOutput16 not supported");
508 }
509
510 checkPipelineConstructionRequirements(context.getInstanceInterface(), context.getPhysicalDevice(),
511 m_pipelineConstructionType);
512 }
513
createInstance(Context & context) const514 TestInstance *VertexInputTest::createInstance(Context &context) const
515 {
516 typedef VertexInputInstance::VertexInputAttributeDescription VertexInputAttributeDescription;
517
518 // Check upfront for maximum number of vertex input attributes
519 {
520 const InstanceInterface &vki = context.getInstanceInterface();
521 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
522 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
523
524 const uint32_t maxAttributes = limits.maxVertexInputAttributes;
525
526 // Use VkPhysicalDeviceLimits::maxVertexInputAttributes
527 if (m_queryMaxAttributes)
528 {
529 m_maxAttributes = maxAttributes;
530 m_locations.clear();
531 for (uint32_t i = 0; i < maxAttributes; i++)
532 m_locations.push_back(i);
533 }
534 }
535
536 // Create enough binding descriptions with random offsets
537 std::vector<VkVertexInputBindingDescription> bindingDescriptions;
538 std::vector<VkDeviceSize> bindingOffsets;
539 const size_t numAttributes = getNumAttributes();
540 const size_t numBindings =
541 (m_bindingMapping == BINDING_MAPPING_ONE_TO_ONE) ? numAttributes : ((numAttributes > 1) ? 2 : 1);
542 const VkVertexInputRate firstInputrate = getAttributeInfo(0).inputRate;
543
544 for (size_t bindingNdx = 0; bindingNdx < numBindings; ++bindingNdx)
545 {
546 // Bindings alternate between STEP_RATE_VERTEX and STEP_RATE_INSTANCE
547 const VkVertexInputRate inputRate =
548 ((firstInputrate + bindingNdx) % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
549
550 // Stride will be updated when creating the attribute descriptions
551 const VkVertexInputBindingDescription bindingDescription = {
552 static_cast<uint32_t>(bindingNdx), // uint32_t binding;
553 0u, // uint32_t stride;
554 inputRate // VkVertexInputRate inputRate;
555 };
556
557 bindingDescriptions.push_back(bindingDescription);
558 bindingOffsets.push_back(4 * bindingNdx);
559 }
560
561 std::vector<VertexInputAttributeDescription> attributeDescriptions;
562 std::vector<uint32_t> attributeOffsets(bindingDescriptions.size(), 0);
563 std::vector<uint32_t> attributeMaxSizes(bindingDescriptions.size(),
564 0); // max component or vector size, depending on which layout we are using
565 std::vector<uint32_t> attributeMaxCompSizes(bindingDescriptions.size(), 0u); // max component size for each binding.
566 std::vector<uint32_t> bindingSeqStrides(bindingDescriptions.size(),
567 0u); // strides for bindings in sequential layout mode
568
569 // To place the attributes sequentially we need to know the largest attribute and use its size in stride and offset calculations.
570 if (m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL)
571 {
572 for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
573 {
574 const AttributeInfo &attributeInfo = getAttributeInfo(attributeNdx);
575 const uint32_t attributeBinding = getAttributeBinding(
576 m_bindingMapping, firstInputrate, attributeInfo.inputRate, static_cast<uint32_t>(attributeNdx));
577 const uint32_t inputSize = getVertexFormatSize(attributeInfo.vkType);
578 const auto componentSize = getVertexFormatComponentSize(attributeInfo.vkType);
579 const auto maxSize = de::max(attributeMaxSizes[attributeBinding], inputSize);
580 const auto maxComponentSize = de::max(attributeMaxCompSizes[attributeBinding], componentSize);
581
582 attributeMaxSizes[attributeBinding] = maxSize;
583 attributeMaxCompSizes[attributeBinding] = maxComponentSize;
584 }
585
586 // Round up the maximum size so the components are always aligned.
587 for (size_t bindingIdx = 0u; bindingIdx < bindingSeqStrides.size(); ++bindingIdx)
588 bindingSeqStrides[bindingIdx] =
589 de::roundUp(attributeMaxSizes[bindingIdx], attributeMaxCompSizes[bindingIdx]);
590 }
591
592 // Create attribute descriptions, assign them to bindings and update stride.
593 for (size_t attributeNdx = 0; attributeNdx < numAttributes; ++attributeNdx)
594 {
595 const AttributeInfo &attributeInfo = getAttributeInfo(attributeNdx);
596 const GlslTypeDescription &glslTypeDescription = s_glslTypeDescriptions[attributeInfo.glslType];
597 const uint32_t inputSize = getVertexFormatSize(attributeInfo.vkType);
598 const uint32_t attributeBinding = getAttributeBinding(m_bindingMapping, firstInputrate, attributeInfo.inputRate,
599 static_cast<uint32_t>(attributeNdx));
600 const uint32_t vertexCount = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
601
602 VertexInputAttributeDescription attributeDescription = {
603 attributeInfo.glslType, // GlslType glslType;
604 0, // int vertexInputIndex;
605 {
606 0u, // uint32_t location;
607 attributeBinding, // uint32_t binding;
608 attributeInfo.vkType, // VkFormat format;
609 0u, // uint32_t offset;
610 },
611 };
612
613 // Matrix types add each column as a separate attribute.
614 for (int descNdx = 0; descNdx < glslTypeDescription.vertexInputCount; ++descNdx)
615 {
616 attributeDescription.vertexInputIndex = descNdx;
617 attributeDescription.vkDescription.location =
618 m_locations[attributeNdx] + getConsumedLocations(attributeInfo) * descNdx;
619
620 if (m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED)
621 {
622 const uint32_t offsetToComponentAlignment = getNextMultipleOffset(
623 inputSize, (uint32_t)bindingOffsets[attributeBinding] + attributeOffsets[attributeBinding]);
624
625 attributeOffsets[attributeBinding] += offsetToComponentAlignment;
626
627 attributeDescription.vkDescription.offset = attributeOffsets[attributeBinding];
628 attributeDescriptions.push_back(attributeDescription);
629
630 bindingDescriptions[attributeBinding].stride += offsetToComponentAlignment + inputSize;
631 attributeOffsets[attributeBinding] += inputSize;
632 attributeMaxSizes[attributeBinding] = de::max(attributeMaxSizes[attributeBinding], inputSize);
633 }
634 else // m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL
635 {
636 attributeDescription.vkDescription.offset = attributeOffsets[attributeBinding];
637 attributeDescriptions.push_back(attributeDescription);
638
639 attributeOffsets[attributeBinding] += vertexCount * bindingSeqStrides[attributeBinding];
640 }
641 }
642
643 if (m_attributeLayout == ATTRIBUTE_LAYOUT_SEQUENTIAL)
644 bindingDescriptions[attributeBinding].stride = bindingSeqStrides[attributeBinding];
645 }
646
647 if (m_attributeLayout == ATTRIBUTE_LAYOUT_INTERLEAVED)
648 {
649 // Make sure the stride results in aligned access
650 for (size_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); ++bindingNdx)
651 {
652 auto &stride = bindingDescriptions[bindingNdx].stride; // note: by reference to modify it below.
653
654 if (attributeMaxSizes[bindingNdx] > 0)
655 stride += getNextMultipleOffset(attributeMaxSizes[bindingNdx], stride);
656 }
657 }
658
659 // Check upfront for maximum number of vertex input bindings
660 {
661 const InstanceInterface &vki = context.getInstanceInterface();
662 const VkPhysicalDevice physDevice = context.getPhysicalDevice();
663 const VkPhysicalDeviceLimits limits = getPhysicalDeviceProperties(vki, physDevice).limits;
664
665 const uint32_t maxBindings = limits.maxVertexInputBindings;
666
667 if (bindingDescriptions.size() > maxBindings)
668 {
669 const std::string notSupportedStr =
670 "Unsupported number of vertex input bindings, maxVertexInputBindings: " + de::toString(maxBindings);
671 TCU_THROW(NotSupportedError, notSupportedStr.c_str());
672 }
673 }
674
675 // Portability requires stride to be multiply of minVertexInputBindingStrideAlignment
676 #ifndef CTS_USES_VULKANSC
677 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset"))
678 {
679 uint32_t minStrideAlignment = context.getPortabilitySubsetProperties().minVertexInputBindingStrideAlignment;
680 for (size_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); ++bindingNdx)
681 {
682 if ((bindingDescriptions[bindingNdx].stride % minStrideAlignment) != 0)
683 TCU_THROW(NotSupportedError,
684 "VK_KHR_portability_subset: stride is not multiply of minVertexInputBindingStrideAlignment");
685 }
686 }
687 #endif // CTS_USES_VULKANSC
688
689 return new VertexInputInstance(context, m_pipelineConstructionType, attributeDescriptions, bindingDescriptions,
690 bindingOffsets);
691 }
692
initPrograms(SourceCollections & programCollection) const693 void VertexInputTest::initPrograms(SourceCollections &programCollection) const
694 {
695 std::ostringstream vertexSrc;
696
697 vertexSrc << "#version 460\n"
698 << getGlslExtensions() << "layout(constant_id = 0) const int numAttributes = " << m_maxAttributes << ";\n"
699 << getGlslInputDeclarations() << "layout(location = 0) out highp vec4 vtxColor;\n"
700 << "out gl_PerVertex {\n"
701 << " vec4 gl_Position;\n"
702 << "};\n";
703
704 vertexSrc << "void main (void)\n"
705 << "{\n"
706 << getGlslVertexCheck() << "}\n";
707
708 programCollection.glslSources.add("attribute_test_vert") << glu::VertexSource(vertexSrc.str());
709
710 programCollection.glslSources.add("attribute_test_frag")
711 << glu::FragmentSource("#version 460\n"
712 "layout(location = 0) in highp vec4 vtxColor;\n"
713 "layout(location = 0) out highp vec4 fragColor;\n"
714 "void main (void)\n"
715 "{\n"
716 " fragColor = vtxColor;\n"
717 "}\n");
718 }
719
getGlslExtensions(void) const720 std::string VertexInputTest::getGlslExtensions(void) const
721 {
722 std::string extensions;
723
724 if (m_usesFloat16Type)
725 extensions += "#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require\n";
726
727 return extensions;
728 }
729
getGlslInputDeclarations(void) const730 std::string VertexInputTest::getGlslInputDeclarations(void) const
731 {
732 std::ostringstream glslInputs;
733
734 if (m_queryMaxAttributes)
735 {
736 // Don't use the first input binding to leave room for VertexIndex and InstanceIndex, which count towards the
737 // total number of inputs attributes. Leave the first binding so that the largest location number are still used.
738 const GlslTypeDescription &glslTypeDesc = s_glslTypeDescriptions[GLSL_TYPE_VEC4];
739 glslInputs << "layout(location = 1) in " << glslTypeDesc.name << " attr[numAttributes-1];\n";
740 }
741 else
742 {
743 for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
744 {
745 const char *declType = nullptr;
746 if (m_testMissingComponents)
747 {
748 const auto &glslType = m_attributeInfos[attributeNdx].glslType;
749 const auto &typeInfo = s_glslTypeDescriptions[glslType];
750
751 DE_ASSERT(typeInfo.vertexInputComponentCount < kMaxComponents);
752 DE_ASSERT(typeInfo.basicType != GLSL_BASIC_TYPE_DOUBLE);
753
754 // Find the equivalent type with 4 components.
755 declType = expandGlslNameToFullComponents(typeInfo.name);
756 }
757 else
758 declType = s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].name;
759
760 glslInputs << "layout(location = " << m_locations[attributeNdx] << ") in " << declType << " attr"
761 << attributeNdx << ";\n";
762 }
763 }
764
765 return glslInputs.str();
766 }
767
getGlslVertexCheck(void) const768 std::string VertexInputTest::getGlslVertexCheck(void) const
769 {
770 std::ostringstream glslCode;
771 std::string inputCountStr;
772
773 glslCode << " int okCount = 0;\n";
774
775 if (m_queryMaxAttributes)
776 {
777 DE_ASSERT(!m_testMissingComponents);
778
779 // numAttributes will be replaced later by a specialisation constant, so this loop and
780 // the multiplication by numAttributes, below, must happen in the shader itself.
781 const AttributeInfo attributeInfo = getAttributeInfo(0);
782
783 glslCode << " for (int checkNdx = 1; checkNdx < numAttributes; checkNdx++)\n"
784 << " {\n"
785 << " uint index = (checkNdx % 2 == 0) ? gl_VertexIndex : gl_InstanceIndex;\n";
786
787 // Because our location is offset by 1 relative to the API definitions, checkNdx-1 here.
788 glslCode << getGlslAttributeConditions(attributeInfo, "checkNdx-1") << " }\n";
789
790 const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
791 int totalInputComponentCount =
792 vertexInputCount *
793 VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
794
795 // Don't count components from location 0 which was skipped.
796 inputCountStr = std::to_string(totalInputComponentCount) + " * (numAttributes-1)";
797 }
798 else
799 {
800 // Generate 1 check per attribute and work out the number of components at compile time.
801 int totalInputComponentCount = 0;
802 for (size_t attributeNdx = 0; attributeNdx < m_attributeInfos.size(); attributeNdx++)
803 {
804 glslCode << getGlslAttributeConditions(m_attributeInfos[attributeNdx], de::toString(attributeNdx));
805
806 const int vertexInputCount =
807 VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType].vertexInputCount;
808 const int vertexCompCount = VertexInputTest::s_glslTypeDescriptions[m_attributeInfos[attributeNdx].glslType]
809 .vertexInputComponentCount;
810 totalInputComponentCount +=
811 vertexInputCount * ((!m_testMissingComponents) ? vertexCompCount : kMaxComponents - vertexCompCount);
812 }
813
814 inputCountStr = std::to_string(totalInputComponentCount);
815 }
816
817 glslCode << " if (okCount == " << inputCountStr
818 << ")\n"
819 " {\n"
820 " if (gl_InstanceIndex == 0)\n"
821 " vtxColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
822 " else\n"
823 " vtxColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
824 " }\n"
825 " else\n"
826 " {\n"
827 " vtxColor = vec4(okCount / float("
828 << inputCountStr << "), 0.0f, 0.0f, 1.0);\n"
829 << " }\n\n"
830 " if (gl_InstanceIndex == 0)\n"
831 " {\n"
832 " if (gl_VertexIndex == 0) gl_Position = vec4(-1.0, -1.0, 0.0, 1.0);\n"
833 " else if (gl_VertexIndex == 1) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
834 " else if (gl_VertexIndex == 2) gl_Position = vec4(-1.0, 1.0, 0.0, 1.0);\n"
835 " else if (gl_VertexIndex == 3) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
836 " else gl_Position = vec4(0.0);\n"
837 " }\n"
838 " else\n"
839 " {\n"
840 " if (gl_VertexIndex == 0) gl_Position = vec4(0.0, -1.0, 0.0, 1.0);\n"
841 " else if (gl_VertexIndex == 1) gl_Position = vec4(1.0, -1.0, 0.0, 1.0);\n"
842 " else if (gl_VertexIndex == 2) gl_Position = vec4(0.0, 1.0, 0.0, 1.0);\n"
843 " else if (gl_VertexIndex == 3) gl_Position = vec4(1.0, 1.0, 0.0, 1.0);\n"
844 " else gl_Position = vec4(0.0);\n"
845 " }\n";
846
847 return glslCode.str();
848 }
849
getGlslAttributeConditions(const AttributeInfo & attributeInfo,const std::string attributeIndex) const850 std::string VertexInputTest::getGlslAttributeConditions(const AttributeInfo &attributeInfo,
851 const std::string attributeIndex) const
852 {
853 std::ostringstream glslCode;
854 std::ostringstream attributeVar;
855 const int componentCount =
856 VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputComponentCount;
857 const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].vertexInputCount;
858 const uint32_t totalComponentCount = componentCount * vertexInputCount;
859 const tcu::Vec4 threshold = getFormatThreshold(attributeInfo.vkType);
860 const std::string indexStr = m_queryMaxAttributes ? "[" + attributeIndex + "]" : attributeIndex;
861 const std::string indentStr = m_queryMaxAttributes ? "\t\t" : "\t";
862 uint32_t componentIndex = 0;
863 uint32_t orderNdx;
864 std::string indexId;
865
866 const uint32_t BGROrder[] = {2, 1, 0, 3};
867 const uint32_t ABGROrder[] = {3, 2, 1, 0};
868 const uint32_t ARGBOrder[] = {1, 2, 3, 0};
869
870 if (m_queryMaxAttributes)
871 indexId = "index";
872 else
873 indexId = (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? "gl_VertexIndex" : "gl_InstanceIndex";
874
875 attributeVar << "attr" << indexStr;
876
877 glslCode << std::fixed;
878
879 for (int columnNdx = 0; columnNdx < vertexInputCount; columnNdx++)
880 {
881 for (int rowNdx = 0; rowNdx < kMaxComponents; rowNdx++)
882 {
883 if (isVertexFormatComponentOrderABGR(attributeInfo.vkType))
884 orderNdx = ABGROrder[rowNdx];
885 else if (isVertexFormatComponentOrderARGB(attributeInfo.vkType))
886 orderNdx = ARGBOrder[rowNdx];
887 else
888 orderNdx = BGROrder[rowNdx];
889
890 std::string accessStr;
891 {
892 // Build string representing the access to the attribute component
893 std::ostringstream accessStream;
894 accessStream << attributeVar.str();
895
896 if (vertexInputCount == 1)
897 {
898 if (componentCount > 1 || m_testMissingComponents)
899 accessStream << "[" << rowNdx << "]";
900 }
901 else
902 {
903 accessStream << "[" << columnNdx << "][" << rowNdx << "]";
904 }
905
906 accessStr = accessStream.str();
907 }
908
909 if (rowNdx < componentCount && !m_testMissingComponents)
910 {
911 if (isVertexFormatSint(attributeInfo.vkType))
912 {
913 if (isVertexFormatPacked(attributeInfo.vkType))
914 {
915 const int32_t maxIntValue =
916 (1 << (getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx) - 1)) - 1;
917 const int32_t minIntValue = -maxIntValue;
918
919 glslCode << indentStr << "if (" << accessStr << " == clamp(-(" << totalComponentCount << " * "
920 << indexId << " + " << componentIndex << "), " << minIntValue << ", " << maxIntValue
921 << "))\n";
922 }
923 else
924 glslCode << indentStr << "if (" << accessStr << " == -(" << totalComponentCount << " * "
925 << indexId << " + " << componentIndex << "))\n";
926 }
927 else if (isVertexFormatUint(attributeInfo.vkType))
928 {
929 if (isVertexFormatPacked(attributeInfo.vkType))
930 {
931 const uint32_t maxUintValue =
932 (1 << getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx)) - 1;
933
934 glslCode << indentStr << "if (" << accessStr << " == clamp(uint(" << totalComponentCount
935 << " * " << indexId << " + " << componentIndex << "), 0, " << maxUintValue << "))\n";
936 }
937 else
938 glslCode << indentStr << "if (" << accessStr << " == uint(" << totalComponentCount << " * "
939 << indexId << " + " << componentIndex << "))\n";
940 }
941 else if (isVertexFormatSfloat(attributeInfo.vkType))
942 {
943 const auto &basicType = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
944
945 if (basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
946 {
947 glslCode << indentStr << "if (abs(" << accessStr << " + double(0.01 * (" << totalComponentCount
948 << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double("
949 << threshold[rowNdx] << "))\n";
950 }
951 else if (basicType == VertexInputTest::GLSL_BASIC_TYPE_FLOAT16)
952 {
953 glslCode << indentStr << "if (abs(" << accessStr << " + float16_t(0.01HF * ("
954 << totalComponentCount << ".0HF * float16_t(" << indexId << ") + " << componentIndex
955 << ".0HF))) < float16_t(" << threshold[rowNdx] << "HF))\n";
956 }
957 else
958 {
959 glslCode << indentStr << "if (abs(" << accessStr << " + (0.01 * (" << totalComponentCount
960 << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < "
961 << threshold[rowNdx] << ")\n";
962 }
963 }
964 else if (isVertexFormatSscaled(attributeInfo.vkType))
965 {
966 if (isVertexFormatPacked(attributeInfo.vkType))
967 {
968 const float maxScaledValue =
969 float((1 << (getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx) - 1)) - 1);
970 const float minScaledValue = -maxScaledValue - 1.0f;
971
972 glslCode << indentStr << "if (abs(" << accessStr << " + clamp(" << totalComponentCount
973 << ".0 * float(" << indexId << ") + " << componentIndex << ".0, " << minScaledValue
974 << ", " << maxScaledValue << ")) < " << threshold[orderNdx] << ")\n";
975 }
976 else
977 glslCode << indentStr << "if (abs(" << accessStr << " + (" << totalComponentCount
978 << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < "
979 << threshold[rowNdx] << ")\n";
980 }
981 else if (isVertexFormatUscaled(attributeInfo.vkType))
982 {
983 if (isVertexFormatPacked(attributeInfo.vkType))
984 {
985 const float maxScaledValue =
986 float((1 << getPackedVertexFormatComponentWidth(attributeInfo.vkType, orderNdx)) - 1);
987
988 glslCode << indentStr << "if (abs(" << accessStr << " - clamp(" << totalComponentCount
989 << ".0 * float(" << indexId << ") + " << componentIndex << ".0, 0, " << maxScaledValue
990 << ")) < " << threshold[orderNdx] << ")\n";
991 }
992 else
993 glslCode << indentStr << "if (abs(" << accessStr << " - (" << totalComponentCount
994 << ".0 * float(" << indexId << ") + " << componentIndex << ".0)) < "
995 << threshold[rowNdx] << ")\n";
996 }
997 else if (isVertexFormatSnorm(attributeInfo.vkType))
998 {
999 const float representableDiff =
1000 isVertexFormatPacked(attributeInfo.vkType) ?
1001 getRepresentableDifferenceSnormPacked(attributeInfo.vkType, orderNdx) :
1002 getRepresentableDifferenceSnorm(attributeInfo.vkType);
1003
1004 if (isVertexFormatPacked(attributeInfo.vkType))
1005 glslCode << indentStr << "if (abs(" << accessStr << " - clamp((-1.0 + " << representableDiff
1006 << " * (" << totalComponentCount << ".0 * float(" << indexId << ") + "
1007 << componentIndex << ".0)), -1.0, 1.0)) < " << threshold[orderNdx] << ")\n";
1008 else
1009 glslCode << indentStr << "if (abs(" << accessStr << " - (-1.0 + " << representableDiff << " * ("
1010 << totalComponentCount << ".0 * float(" << indexId << ") + " << componentIndex
1011 << ".0))) < " << threshold[rowNdx] << ")\n";
1012 }
1013 else if (isVertexFormatUnorm(attributeInfo.vkType) || isVertexFormatSRGB(attributeInfo.vkType))
1014 {
1015 const float representableDiff =
1016 isVertexFormatPacked(attributeInfo.vkType) ?
1017 getRepresentableDifferenceUnormPacked(attributeInfo.vkType, orderNdx) :
1018 getRepresentableDifferenceUnorm(attributeInfo.vkType);
1019
1020 if (isVertexFormatPacked(attributeInfo.vkType))
1021 glslCode << indentStr << "if (abs(" << accessStr << " - "
1022 << "clamp((" << representableDiff << " * (" << totalComponentCount << ".0 * float("
1023 << indexId << ") + " << componentIndex << ".0)), 0.0, 1.0)) < " << threshold[orderNdx]
1024 << ")\n";
1025 else
1026 glslCode << indentStr << "if (abs(" << accessStr << " - "
1027 << "(" << representableDiff << " * (" << totalComponentCount << ".0 * float("
1028 << indexId << ") + " << componentIndex << ".0))) < " << threshold[rowNdx] << ")\n";
1029 }
1030 else if (isVertexFormatUfloat(attributeInfo.vkType))
1031 {
1032 const auto &basicType = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
1033
1034 if (basicType == VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
1035 {
1036 glslCode << indentStr << "if (abs(" << accessStr << " - double(0.01 * (" << totalComponentCount
1037 << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < double("
1038 << threshold[rowNdx] << "))\n";
1039 }
1040 else if (basicType == VertexInputTest::GLSL_BASIC_TYPE_FLOAT16)
1041 {
1042 glslCode << indentStr << "if (abs(" << accessStr << " - float16_t(0.01HF * ("
1043 << totalComponentCount << ".0HF * float16_t(" << indexId << ") + " << componentIndex
1044 << ".0HF))) < float16_t(" << threshold[rowNdx] << "HF))\n";
1045 }
1046 else
1047 {
1048 glslCode << indentStr << "if (abs(" << accessStr << " - (0.01 * (" << totalComponentCount
1049 << ".0 * float(" << indexId << ") + " << componentIndex << ".0))) < ("
1050 << threshold[rowNdx] << "))\n";
1051 }
1052 }
1053 else
1054 {
1055 DE_ASSERT(false);
1056 }
1057
1058 glslCode << indentStr << "\tokCount++;\n\n";
1059
1060 componentIndex++;
1061 }
1062 else if (rowNdx >= componentCount && m_testMissingComponents)
1063 {
1064 const auto expectedValue = ((rowNdx == (kMaxComponents - 1)) ?
1065 1u :
1066 0u); // Color components are expanded with zeros and alpha with one.
1067 const auto &basicType = VertexInputTest::s_glslTypeDescriptions[attributeInfo.glslType].basicType;
1068 std::string glslType;
1069
1070 switch (basicType)
1071 {
1072 case GLSL_BASIC_TYPE_INT:
1073 glslType = "int";
1074 break;
1075 case GLSL_BASIC_TYPE_UINT:
1076 glslType = "uint";
1077 break;
1078 case GLSL_BASIC_TYPE_FLOAT:
1079 glslType = "float";
1080 break;
1081 case GLSL_BASIC_TYPE_DOUBLE:
1082 glslType = "double";
1083 break;
1084 case GLSL_BASIC_TYPE_FLOAT16:
1085 glslType = "float16_t";
1086 break;
1087 default:
1088 DE_ASSERT(false);
1089 break;
1090 }
1091
1092 glslCode << indentStr << "if (" << accessStr << " == " << glslType << "(" << expectedValue << "))\n";
1093 glslCode << indentStr << "\tokCount++;\n\n";
1094 }
1095 }
1096 }
1097 return glslCode.str();
1098 }
1099
getFormatThreshold(VkFormat format)1100 tcu::Vec4 VertexInputTest::getFormatThreshold(VkFormat format)
1101 {
1102 using tcu::Vec4;
1103
1104 switch (format)
1105 {
1106 case VK_FORMAT_R32_SFLOAT:
1107 case VK_FORMAT_R32G32_SFLOAT:
1108 case VK_FORMAT_R32G32B32_SFLOAT:
1109 case VK_FORMAT_R32G32B32A32_SFLOAT:
1110 case VK_FORMAT_R64_SFLOAT:
1111 case VK_FORMAT_R64G64_SFLOAT:
1112 case VK_FORMAT_R64G64B64_SFLOAT:
1113 case VK_FORMAT_R64G64B64A64_SFLOAT:
1114 return Vec4(0.00001f);
1115
1116 default:
1117 break;
1118 }
1119
1120 if (isVertexFormatSnorm(format))
1121 {
1122 return (isVertexFormatPacked(format) ? Vec4(1.5f * getRepresentableDifferenceSnormPacked(format, 0),
1123 1.5f * getRepresentableDifferenceSnormPacked(format, 1),
1124 1.5f * getRepresentableDifferenceSnormPacked(format, 2),
1125 1.5f * getRepresentableDifferenceSnormPacked(format, 3)) :
1126 Vec4(1.5f * getRepresentableDifferenceSnorm(format)));
1127 }
1128 else if (isVertexFormatUnorm(format))
1129 {
1130 return (isVertexFormatPacked(format) ? Vec4(1.5f * getRepresentableDifferenceUnormPacked(format, 0),
1131 1.5f * getRepresentableDifferenceUnormPacked(format, 1),
1132 1.5f * getRepresentableDifferenceUnormPacked(format, 2),
1133 1.5f * getRepresentableDifferenceUnormPacked(format, 3)) :
1134 Vec4(1.5f * getRepresentableDifferenceUnorm(format)));
1135 }
1136 else if (isVertexFormatUfloat(format))
1137 {
1138 return Vec4(0.008f);
1139 }
1140
1141 return Vec4(0.001f);
1142 }
1143
VertexInputInstance(Context & context,const PipelineConstructionType pipelineConstructionType,const AttributeDescriptionList & attributeDescriptions,const std::vector<VkVertexInputBindingDescription> & bindingDescriptions,const std::vector<VkDeviceSize> & bindingOffsets)1144 VertexInputInstance::VertexInputInstance(Context &context, const PipelineConstructionType pipelineConstructionType,
1145 const AttributeDescriptionList &attributeDescriptions,
1146 const std::vector<VkVertexInputBindingDescription> &bindingDescriptions,
1147 const std::vector<VkDeviceSize> &bindingOffsets)
1148 : vkt::TestInstance(context)
1149 , m_renderSize(16, 16)
1150 , m_colorFormat(VK_FORMAT_R8G8B8A8_UNORM)
1151 , m_graphicsPipeline(context.getInstanceInterface(), context.getDeviceInterface(), context.getPhysicalDevice(),
1152 context.getDevice(), context.getDeviceExtensions(), pipelineConstructionType)
1153 {
1154 DE_ASSERT(bindingDescriptions.size() == bindingOffsets.size());
1155
1156 const DeviceInterface &vk = context.getDeviceInterface();
1157 const VkDevice vkDevice = context.getDevice();
1158 const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
1159 SimpleAllocator memAlloc(
1160 vk, vkDevice, getPhysicalDeviceMemoryProperties(context.getInstanceInterface(), context.getPhysicalDevice()));
1161 const VkComponentMapping componentMappingRGBA = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G,
1162 VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A};
1163
1164 // Check upfront for unsupported features
1165 for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
1166 {
1167 const VkVertexInputAttributeDescription &attributeDescription =
1168 attributeDescriptions[attributeNdx].vkDescription;
1169 if (!isSupportedVertexFormat(context, attributeDescription.format))
1170 {
1171 throw tcu::NotSupportedError(std::string("Unsupported format for vertex input: ") +
1172 getFormatName(attributeDescription.format));
1173 }
1174 }
1175
1176 // Create color image
1177 {
1178 const VkImageCreateInfo colorImageParams = {
1179 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
1180 DE_NULL, // const void* pNext;
1181 0u, // VkImageCreateFlags flags;
1182 VK_IMAGE_TYPE_2D, // VkImageType imageType;
1183 m_colorFormat, // VkFormat format;
1184 {m_renderSize.x(), m_renderSize.y(), 1u}, // VkExtent3D extent;
1185 1u, // uint32_t mipLevels;
1186 1u, // uint32_t arrayLayers;
1187 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
1188 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
1189 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
1190 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1191 1u, // uint32_t queueFamilyIndexCount;
1192 &queueFamilyIndex, // const uint32_t* pQueueFamilyIndices;
1193 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
1194 };
1195
1196 m_colorImage = createImage(vk, vkDevice, &colorImageParams);
1197
1198 // Allocate and bind color image memory
1199 m_colorImageAlloc =
1200 memAlloc.allocate(getImageMemoryRequirements(vk, vkDevice, *m_colorImage), MemoryRequirement::Any);
1201 VK_CHECK(vk.bindImageMemory(vkDevice, *m_colorImage, m_colorImageAlloc->getMemory(),
1202 m_colorImageAlloc->getOffset()));
1203 }
1204
1205 // Create color attachment view
1206 {
1207 const VkImageViewCreateInfo colorAttachmentViewParams = {
1208 VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // VkStructureType sType;
1209 DE_NULL, // const void* pNext;
1210 0u, // VkImageViewCreateFlags flags;
1211 *m_colorImage, // VkImage image;
1212 VK_IMAGE_VIEW_TYPE_2D, // VkImageViewType viewType;
1213 m_colorFormat, // VkFormat format;
1214 componentMappingRGBA, // VkComponentMapping components;
1215 {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1216 };
1217
1218 m_colorAttachmentView = createImageView(vk, vkDevice, &colorAttachmentViewParams);
1219 }
1220
1221 // Create render pass
1222 m_renderPass = RenderPassWrapper(pipelineConstructionType, vk, vkDevice, m_colorFormat);
1223
1224 // Create framebuffer
1225 {
1226 const VkFramebufferCreateInfo framebufferParams = {
1227 VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, // VkStructureType sType;
1228 DE_NULL, // const void* pNext;
1229 0u, // VkFramebufferCreateFlags flags;
1230 *m_renderPass, // VkRenderPass renderPass;
1231 1u, // uint32_t attachmentCount;
1232 &m_colorAttachmentView.get(), // const VkImageView* pAttachments;
1233 (uint32_t)m_renderSize.x(), // uint32_t width;
1234 (uint32_t)m_renderSize.y(), // uint32_t height;
1235 1u // uint32_t layers;
1236 };
1237
1238 m_renderPass.createFramebuffer(vk, vkDevice, &framebufferParams, *m_colorImage);
1239 }
1240
1241 // Create pipeline layout
1242 {
1243 const VkPipelineLayoutCreateInfo pipelineLayoutParams = {
1244 VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, // VkStructureType sType;
1245 DE_NULL, // const void* pNext;
1246 0u, // VkPipelineLayoutCreateFlags flags;
1247 0u, // uint32_t setLayoutCount;
1248 DE_NULL, // const VkDescriptorSetLayout* pSetLayouts;
1249 0u, // uint32_t pushConstantRangeCount;
1250 DE_NULL // const VkPushConstantRange* pPushConstantRanges;
1251 };
1252
1253 m_pipelineLayout = PipelineLayoutWrapper(pipelineConstructionType, vk, vkDevice, &pipelineLayoutParams);
1254 }
1255
1256 m_vertexShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_vert"), 0);
1257 m_fragmentShaderModule = ShaderWrapper(vk, vkDevice, m_context.getBinaryCollection().get("attribute_test_frag"), 0);
1258
1259 // Create specialization constant
1260 uint32_t specializationData = static_cast<uint32_t>(attributeDescriptions.size());
1261
1262 const VkSpecializationMapEntry specializationMapEntry = {
1263 0, // uint32_t constantID
1264 0, // uint32_t offset
1265 sizeof(specializationData), // uint32_t size
1266 };
1267 const VkSpecializationInfo specializationInfo = {
1268 1, // uint32_t mapEntryCount
1269 &specializationMapEntry, // const void* pMapEntries
1270 sizeof(specializationData), // size_t dataSize
1271 &specializationData // const void* pData
1272 };
1273
1274 // Create pipeline
1275 {
1276 // Create vertex attribute array and check if their VK formats are supported
1277 std::vector<VkVertexInputAttributeDescription> vkAttributeDescriptions;
1278 for (size_t attributeNdx = 0; attributeNdx < attributeDescriptions.size(); attributeNdx++)
1279 {
1280 const VkVertexInputAttributeDescription &attributeDescription =
1281 attributeDescriptions[attributeNdx].vkDescription;
1282 vkAttributeDescriptions.push_back(attributeDescription);
1283 }
1284
1285 const VkPipelineVertexInputStateCreateInfo vertexInputStateParams = {
1286 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
1287 DE_NULL, // const void* pNext;
1288 0u, // VkPipelineVertexInputStateCreateFlags flags;
1289 (uint32_t)bindingDescriptions.size(), // uint32_t vertexBindingDescriptionCount;
1290 bindingDescriptions.data(), // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
1291 (uint32_t)vkAttributeDescriptions.size(), // uint32_t vertexAttributeDescriptionCount;
1292 vkAttributeDescriptions.data() // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
1293 };
1294
1295 const std::vector<VkViewport> viewport{makeViewport(m_renderSize)};
1296 const std::vector<VkRect2D> scissor{makeRect2D(m_renderSize)};
1297
1298 const VkPipelineColorBlendAttachmentState colorBlendAttachmentState = {
1299 false, // VkBool32 blendEnable;
1300 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcColorBlendFactor;
1301 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstColorBlendFactor;
1302 VK_BLEND_OP_ADD, // VkBlendOp colorBlendOp;
1303 VK_BLEND_FACTOR_ONE, // VkBlendFactor srcAlphaBlendFactor;
1304 VK_BLEND_FACTOR_ZERO, // VkBlendFactor dstAlphaBlendFactor;
1305 VK_BLEND_OP_ADD, // VkBlendOp alphaBlendOp;
1306 VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | // VkColorComponentFlags colorWriteMask;
1307 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
1308
1309 const VkPipelineColorBlendStateCreateInfo colorBlendStateParams = {
1310 VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType;
1311 DE_NULL, // const void* pNext;
1312 0u, // VkPipelineColorBlendStateCreateFlags flags;
1313 false, // VkBool32 logicOpEnable;
1314 VK_LOGIC_OP_COPY, // VkLogicOp logicOp;
1315 1u, // uint32_t attachmentCount;
1316 &colorBlendAttachmentState, // const VkPipelineColorBlendAttachmentState* pAttachments;
1317 {0.0f, 0.0f, 0.0f, 0.0f}, // float blendConstants[4];
1318 };
1319
1320 m_graphicsPipeline.setDefaultRasterizationState()
1321 .setDefaultDepthStencilState()
1322 .setDefaultMultisampleState()
1323 .setDefaultTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP)
1324 .setupVertexInputState(&vertexInputStateParams)
1325 .setupPreRasterizationShaderState(viewport, scissor, m_pipelineLayout, *m_renderPass, 0u,
1326 m_vertexShaderModule, DE_NULL, ShaderWrapper(), ShaderWrapper(),
1327 ShaderWrapper(), &specializationInfo)
1328 .setupFragmentShaderState(m_pipelineLayout, *m_renderPass, 0u, m_fragmentShaderModule)
1329 .setupFragmentOutputState(*m_renderPass, 0u, &colorBlendStateParams)
1330 .setMonolithicPipelineLayout(m_pipelineLayout)
1331 .buildPipeline();
1332 }
1333
1334 // Create vertex buffer
1335 {
1336 // calculate buffer size
1337 // 32 is maximal attribute size (4*sizeof(double)),
1338 // 8 maximal vertex count used in writeVertexInputData
1339 VkDeviceSize bufferSize = 32 * 8 * attributeDescriptions.size();
1340
1341 const VkBufferCreateInfo vertexBufferParams = {
1342 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
1343 DE_NULL, // const void* pNext;
1344 0u, // VkBufferCreateFlags flags;
1345 bufferSize, // VkDeviceSize size;
1346 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, // VkBufferUsageFlags usage;
1347 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
1348 1u, // uint32_t queueFamilyIndexCount;
1349 &queueFamilyIndex // const uint32_t* pQueueFamilyIndices;
1350 };
1351
1352 // Upload data for each vertex input binding
1353 for (uint32_t bindingNdx = 0; bindingNdx < bindingDescriptions.size(); bindingNdx++)
1354 {
1355 Move<VkBuffer> vertexBuffer = createBuffer(vk, vkDevice, &vertexBufferParams);
1356 de::MovePtr<Allocation> vertexBufferAlloc = memAlloc.allocate(
1357 getBufferMemoryRequirements(vk, vkDevice, *vertexBuffer), MemoryRequirement::HostVisible);
1358
1359 VK_CHECK(vk.bindBufferMemory(vkDevice, *vertexBuffer, vertexBufferAlloc->getMemory(),
1360 vertexBufferAlloc->getOffset()));
1361
1362 writeVertexInputData((uint8_t *)vertexBufferAlloc->getHostPtr(), bindingDescriptions[bindingNdx],
1363 bindingOffsets[bindingNdx], attributeDescriptions);
1364 flushAlloc(vk, vkDevice, *vertexBufferAlloc);
1365
1366 m_vertexBuffers.push_back(vertexBuffer.disown());
1367 m_vertexBufferAllocs.push_back(vertexBufferAlloc.release());
1368 }
1369 }
1370
1371 // Create command pool
1372 m_cmdPool = createCommandPool(vk, vkDevice, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, queueFamilyIndex);
1373
1374 // Create command buffer
1375 {
1376 const VkClearValue attachmentClearValue = defaultClearValue(m_colorFormat);
1377
1378 const VkImageMemoryBarrier attachmentLayoutBarrier = {
1379 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType;
1380 DE_NULL, // const void* pNext;
1381 0u, // VkAccessFlags srcAccessMask;
1382 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // VkAccessFlags dstAccessMask;
1383 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout;
1384 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout newLayout;
1385 VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex;
1386 VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex;
1387 *m_colorImage, // VkImage image;
1388 {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}, // VkImageSubresourceRange subresourceRange;
1389 };
1390
1391 m_cmdBuffer = allocateCommandBuffer(vk, vkDevice, *m_cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1392
1393 beginCommandBuffer(vk, *m_cmdBuffer, 0u);
1394
1395 vk.cmdPipelineBarrier(*m_cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
1396 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, (VkDependencyFlags)0, 0u, DE_NULL, 0u,
1397 DE_NULL, 1u, &attachmentLayoutBarrier);
1398
1399 m_renderPass.begin(vk, *m_cmdBuffer, makeRect2D(0, 0, m_renderSize.x(), m_renderSize.y()),
1400 attachmentClearValue);
1401
1402 m_graphicsPipeline.bind(*m_cmdBuffer);
1403
1404 std::vector<VkBuffer> vertexBuffers;
1405 for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
1406 vertexBuffers.push_back(m_vertexBuffers[bufferNdx]);
1407
1408 if (vertexBuffers.size() <= 1)
1409 {
1410 // One vertex buffer
1411 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, (uint32_t)vertexBuffers.size(), vertexBuffers.data(),
1412 bindingOffsets.data());
1413 }
1414 else
1415 {
1416 // Smoke-test vkCmdBindVertexBuffers(..., startBinding, ... )
1417
1418 const uint32_t firstHalfLength = (uint32_t)vertexBuffers.size() / 2;
1419 const uint32_t secondHalfLength = firstHalfLength + (uint32_t)(vertexBuffers.size() % 2);
1420
1421 // Bind first half of vertex buffers
1422 vk.cmdBindVertexBuffers(*m_cmdBuffer, 0, firstHalfLength, vertexBuffers.data(), bindingOffsets.data());
1423
1424 // Bind second half of vertex buffers
1425 vk.cmdBindVertexBuffers(*m_cmdBuffer, firstHalfLength, secondHalfLength,
1426 vertexBuffers.data() + firstHalfLength, bindingOffsets.data() + firstHalfLength);
1427 }
1428
1429 vk.cmdDraw(*m_cmdBuffer, 4, 2, 0, 0);
1430
1431 m_renderPass.end(vk, *m_cmdBuffer);
1432 endCommandBuffer(vk, *m_cmdBuffer);
1433 }
1434 }
1435
~VertexInputInstance(void)1436 VertexInputInstance::~VertexInputInstance(void)
1437 {
1438 const DeviceInterface &vk = m_context.getDeviceInterface();
1439 const VkDevice vkDevice = m_context.getDevice();
1440
1441 for (size_t bufferNdx = 0; bufferNdx < m_vertexBuffers.size(); bufferNdx++)
1442 vk.destroyBuffer(vkDevice, m_vertexBuffers[bufferNdx], DE_NULL);
1443
1444 for (size_t allocNdx = 0; allocNdx < m_vertexBufferAllocs.size(); allocNdx++)
1445 delete m_vertexBufferAllocs[allocNdx];
1446 }
1447
writeVertexInputData(uint8_t * destPtr,const VkVertexInputBindingDescription & bindingDescription,const VkDeviceSize bindingOffset,const AttributeDescriptionList & attributes)1448 void VertexInputInstance::writeVertexInputData(uint8_t *destPtr,
1449 const VkVertexInputBindingDescription &bindingDescription,
1450 const VkDeviceSize bindingOffset,
1451 const AttributeDescriptionList &attributes)
1452 {
1453 const uint32_t vertexCount = (bindingDescription.inputRate == VK_VERTEX_INPUT_RATE_VERTEX) ? (4 * 2) : 2;
1454
1455 uint8_t *destOffsetPtr = ((uint8_t *)destPtr) + bindingOffset;
1456 for (uint32_t vertexNdx = 0; vertexNdx < vertexCount; vertexNdx++)
1457 {
1458 for (size_t attributeNdx = 0; attributeNdx < attributes.size(); attributeNdx++)
1459 {
1460 const VertexInputAttributeDescription &attribDesc = attributes[attributeNdx];
1461
1462 // Only write vertex input data to bindings referenced by attribute descriptions
1463 if (attribDesc.vkDescription.binding == bindingDescription.binding)
1464 {
1465 writeVertexInputValue(destOffsetPtr + attribDesc.vkDescription.offset, attribDesc, vertexNdx);
1466 }
1467 }
1468 destOffsetPtr += bindingDescription.stride;
1469 }
1470 }
1471
writeVertexInputValueSint(uint8_t * destPtr,VkFormat format,int componentNdx,int32_t value)1472 void writeVertexInputValueSint(uint8_t *destPtr, VkFormat format, int componentNdx, int32_t value)
1473 {
1474 const uint32_t componentSize = getVertexFormatComponentSize(format);
1475 uint8_t *destFormatPtr = ((uint8_t *)destPtr) + componentSize * componentNdx;
1476
1477 switch (componentSize)
1478 {
1479 case 1:
1480 *((int8_t *)destFormatPtr) = (int8_t)value;
1481 break;
1482
1483 case 2:
1484 *((int16_t *)destFormatPtr) = (int16_t)value;
1485 break;
1486
1487 case 4:
1488 *((int32_t *)destFormatPtr) = (int32_t)value;
1489 break;
1490
1491 default:
1492 DE_ASSERT(false);
1493 }
1494 }
1495
writeVertexInputValueIntPacked(uint8_t * destPtr,uint32_t & packedFormat,uint32_t & componentOffset,VkFormat format,uint32_t componentNdx,uint32_t value)1496 void writeVertexInputValueIntPacked(uint8_t *destPtr, uint32_t &packedFormat, uint32_t &componentOffset,
1497 VkFormat format, uint32_t componentNdx, uint32_t value)
1498 {
1499 const uint32_t componentWidth = getPackedVertexFormatComponentWidth(format, componentNdx);
1500 const uint32_t componentCount = getVertexFormatComponentCount(format);
1501 const uint32_t usedBits = ~(uint32_t)0 >> ((getVertexFormatSize(format) * 8) - componentWidth);
1502
1503 componentOffset -= componentWidth;
1504 packedFormat |= (((uint32_t)value & usedBits) << componentOffset);
1505
1506 if (componentNdx == componentCount - 1)
1507 *((uint32_t *)destPtr) = (uint32_t)packedFormat;
1508 }
1509
writeVertexInputValueUint(uint8_t * destPtr,VkFormat format,int componentNdx,uint32_t value)1510 void writeVertexInputValueUint(uint8_t *destPtr, VkFormat format, int componentNdx, uint32_t value)
1511 {
1512 const uint32_t componentSize = getVertexFormatComponentSize(format);
1513 uint8_t *destFormatPtr = ((uint8_t *)destPtr) + componentSize * componentNdx;
1514
1515 switch (componentSize)
1516 {
1517 case 1:
1518 *((uint8_t *)destFormatPtr) = (uint8_t)value;
1519 break;
1520
1521 case 2:
1522 *((uint16_t *)destFormatPtr) = (uint16_t)value;
1523 break;
1524
1525 case 4:
1526 *((uint32_t *)destFormatPtr) = (uint32_t)value;
1527 break;
1528
1529 default:
1530 DE_ASSERT(false);
1531 }
1532 }
1533
writeVertexInputValueSfloat(uint8_t * destPtr,VkFormat format,int componentNdx,float value)1534 void writeVertexInputValueSfloat(uint8_t *destPtr, VkFormat format, int componentNdx, float value)
1535 {
1536 const uint32_t componentSize = getVertexFormatComponentSize(format);
1537 uint8_t *destFormatPtr = ((uint8_t *)destPtr) + componentSize * componentNdx;
1538
1539 switch (componentSize)
1540 {
1541 case 2:
1542 {
1543 tcu::Float16 f16(value);
1544 deMemcpy(destFormatPtr, &f16, sizeof(f16));
1545 break;
1546 }
1547
1548 case 4:
1549 deMemcpy(destFormatPtr, &value, sizeof(value));
1550 break;
1551
1552 default:
1553 DE_ASSERT(false);
1554 }
1555 }
1556
writeVertexInputValueUfloat(uint8_t * destPtr,uint32_t & packedFormat,uint32_t & componentOffset,VkFormat format,uint32_t componentNdx,float value)1557 void writeVertexInputValueUfloat(uint8_t *destPtr, uint32_t &packedFormat, uint32_t &componentOffset, VkFormat format,
1558 uint32_t componentNdx, float value)
1559 {
1560 tcu::Float16 f16(value);
1561
1562 const uint32_t componentWidth = getPackedVertexFormatComponentWidth(format, componentNdx);
1563 const uint32_t componentCount = getVertexFormatComponentCount(format);
1564 const uint32_t usedBits = ~(uint32_t)0 >> ((getVertexFormatSize(format) * 8) - componentWidth);
1565 // The ufloat 10 or 11 has no sign bit, but the same exponent bits than float16.
1566 // The sign bit will be removed by the mask. Therefore we pick one more mantissa bit.
1567 uint32_t valueUFloat = f16.bits() >> (16 - componentWidth - 1);
1568
1569 // TODO: VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 not supported.
1570 DE_ASSERT(format == VK_FORMAT_B10G11R11_UFLOAT_PACK32);
1571
1572 componentOffset -= componentWidth;
1573 packedFormat |= (valueUFloat & usedBits) << componentOffset;
1574
1575 if (componentNdx == componentCount - 1)
1576 *((uint32_t *)destPtr) = (uint32_t)packedFormat;
1577 }
1578
writeVertexInputValue(uint8_t * destPtr,const VertexInputAttributeDescription & attribute,int indexId)1579 void VertexInputInstance::writeVertexInputValue(uint8_t *destPtr, const VertexInputAttributeDescription &attribute,
1580 int indexId)
1581 {
1582 const int vertexInputCount = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputCount;
1583 const int componentCount = VertexInputTest::s_glslTypeDescriptions[attribute.glslType].vertexInputComponentCount;
1584 const uint32_t totalComponentCount = componentCount * vertexInputCount;
1585 const uint32_t vertexInputIndex = indexId * totalComponentCount + attribute.vertexInputIndex * componentCount;
1586 const bool hasBGROrder = isVertexFormatComponentOrderBGR(attribute.vkDescription.format);
1587 const bool hasABGROrder = isVertexFormatComponentOrderABGR(attribute.vkDescription.format);
1588 const bool hasARGBOrder = isVertexFormatComponentOrderARGB(attribute.vkDescription.format);
1589 uint32_t componentOffset = getVertexFormatSize(attribute.vkDescription.format) * 8;
1590 uint32_t packedFormat32 = 0;
1591 uint32_t swizzledNdx;
1592
1593 const uint32_t BGRSwizzle[] = {2, 1, 0, 3};
1594 const uint32_t ABGRSwizzle[] = {3, 2, 1, 0};
1595 const uint32_t ARGBSwizzle[] = {3, 0, 1, 2};
1596
1597 for (int componentNdx = 0; componentNdx < componentCount; componentNdx++)
1598 {
1599 if (hasABGROrder)
1600 swizzledNdx = ABGRSwizzle[componentNdx];
1601 else if (hasARGBOrder)
1602 swizzledNdx = ARGBSwizzle[componentNdx];
1603 else if (hasBGROrder)
1604 swizzledNdx = BGRSwizzle[componentNdx];
1605 else
1606 swizzledNdx = componentNdx;
1607
1608 const int32_t maxIntValue =
1609 isVertexFormatPacked(attribute.vkDescription.format) ?
1610 (1 << (getPackedVertexFormatComponentWidth(attribute.vkDescription.format, componentNdx) - 1)) - 1 :
1611 (1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8 - 1)) - 1;
1612 const uint32_t maxUintValue =
1613 isVertexFormatPacked(attribute.vkDescription.format) ?
1614 ((1 << getPackedVertexFormatComponentWidth(attribute.vkDescription.format, componentNdx)) - 1) :
1615 (1 << (getVertexFormatComponentSize(attribute.vkDescription.format) * 8)) - 1;
1616 const int32_t minIntValue = -maxIntValue;
1617 const uint32_t minUintValue = 0;
1618
1619 switch (attribute.glslType)
1620 {
1621 case VertexInputTest::GLSL_TYPE_INT:
1622 case VertexInputTest::GLSL_TYPE_IVEC2:
1623 case VertexInputTest::GLSL_TYPE_IVEC3:
1624 case VertexInputTest::GLSL_TYPE_IVEC4:
1625 {
1626 if (isVertexFormatPacked(attribute.vkDescription.format))
1627 writeVertexInputValueIntPacked(
1628 destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1629 deClamp32(-(int32_t)(vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1630 else
1631 writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1632 -(int32_t)(vertexInputIndex + swizzledNdx));
1633
1634 break;
1635 }
1636 case VertexInputTest::GLSL_TYPE_UINT:
1637 case VertexInputTest::GLSL_TYPE_UVEC2:
1638 case VertexInputTest::GLSL_TYPE_UVEC3:
1639 case VertexInputTest::GLSL_TYPE_UVEC4:
1640 {
1641 if (isVertexFormatPacked(attribute.vkDescription.format))
1642 writeVertexInputValueIntPacked(destPtr, packedFormat32, componentOffset, attribute.vkDescription.format,
1643 componentNdx,
1644 deClamp32(vertexInputIndex + swizzledNdx, minUintValue, maxUintValue));
1645 else
1646 writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx,
1647 vertexInputIndex + swizzledNdx);
1648
1649 break;
1650 }
1651 case VertexInputTest::GLSL_TYPE_FLOAT:
1652 case VertexInputTest::GLSL_TYPE_VEC2:
1653 case VertexInputTest::GLSL_TYPE_VEC3:
1654 case VertexInputTest::GLSL_TYPE_VEC4:
1655 case VertexInputTest::GLSL_TYPE_MAT2:
1656 case VertexInputTest::GLSL_TYPE_MAT3:
1657 case VertexInputTest::GLSL_TYPE_MAT4:
1658 case VertexInputTest::GLSL_TYPE_F16:
1659 case VertexInputTest::GLSL_TYPE_F16VEC2:
1660 case VertexInputTest::GLSL_TYPE_F16VEC3:
1661 case VertexInputTest::GLSL_TYPE_F16VEC4:
1662 {
1663 if (isVertexFormatSfloat(attribute.vkDescription.format))
1664 {
1665 writeVertexInputValueSfloat(destPtr, attribute.vkDescription.format, componentNdx,
1666 -(0.01f * (float)(vertexInputIndex + swizzledNdx)));
1667 }
1668 else if (isVertexFormatUfloat(attribute.vkDescription.format))
1669 {
1670 writeVertexInputValueUfloat(destPtr, packedFormat32, componentOffset, attribute.vkDescription.format,
1671 componentNdx, 0.01f * (float)(vertexInputIndex + swizzledNdx));
1672 }
1673 else if (isVertexFormatSscaled(attribute.vkDescription.format))
1674 {
1675 if (isVertexFormatPacked(attribute.vkDescription.format))
1676 writeVertexInputValueIntPacked(
1677 destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1678 deClamp32(-(int32_t)(vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1679 else
1680 writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1681 -(int32_t)(vertexInputIndex + swizzledNdx));
1682 }
1683 else if (isVertexFormatUscaled(attribute.vkDescription.format) ||
1684 isVertexFormatUnorm(attribute.vkDescription.format) ||
1685 isVertexFormatSRGB(attribute.vkDescription.format))
1686 {
1687 if (isVertexFormatPacked(attribute.vkDescription.format))
1688 writeVertexInputValueIntPacked(
1689 destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1690 deClamp32(vertexInputIndex + swizzledNdx, minUintValue, maxUintValue));
1691 else
1692 writeVertexInputValueUint(destPtr, attribute.vkDescription.format, componentNdx,
1693 vertexInputIndex + swizzledNdx);
1694 }
1695 else if (isVertexFormatSnorm(attribute.vkDescription.format))
1696 {
1697 if (isVertexFormatPacked(attribute.vkDescription.format))
1698 writeVertexInputValueIntPacked(
1699 destPtr, packedFormat32, componentOffset, attribute.vkDescription.format, componentNdx,
1700 deClamp32(minIntValue + (vertexInputIndex + swizzledNdx), minIntValue, maxIntValue));
1701 else
1702 writeVertexInputValueSint(destPtr, attribute.vkDescription.format, componentNdx,
1703 minIntValue + (vertexInputIndex + swizzledNdx));
1704 }
1705 else
1706 DE_ASSERT(false);
1707 break;
1708 }
1709 case VertexInputTest::GLSL_TYPE_DOUBLE:
1710 case VertexInputTest::GLSL_TYPE_DVEC2:
1711 case VertexInputTest::GLSL_TYPE_DVEC3:
1712 case VertexInputTest::GLSL_TYPE_DVEC4:
1713 case VertexInputTest::GLSL_TYPE_DMAT2:
1714 case VertexInputTest::GLSL_TYPE_DMAT3:
1715 case VertexInputTest::GLSL_TYPE_DMAT4:
1716 *(reinterpret_cast<double *>(destPtr) + componentNdx) = -0.01 * (vertexInputIndex + swizzledNdx);
1717
1718 break;
1719
1720 default:
1721 DE_ASSERT(false);
1722 }
1723 }
1724 }
1725
iterate(void)1726 tcu::TestStatus VertexInputInstance::iterate(void)
1727 {
1728 const DeviceInterface &vk = m_context.getDeviceInterface();
1729 const VkDevice vkDevice = m_context.getDevice();
1730 const VkQueue queue = m_context.getUniversalQueue();
1731
1732 submitCommandsAndWait(vk, vkDevice, queue, m_cmdBuffer.get());
1733
1734 return verifyImage();
1735 }
1736
isCompatibleType(VkFormat format,GlslType glslType)1737 bool VertexInputTest::isCompatibleType(VkFormat format, GlslType glslType)
1738 {
1739 const GlslTypeDescription glslTypeDesc = s_glslTypeDescriptions[glslType];
1740
1741 if ((uint32_t)s_glslTypeDescriptions[glslType].vertexInputComponentCount == getVertexFormatComponentCount(format))
1742 {
1743 switch (glslTypeDesc.basicType)
1744 {
1745 case GLSL_BASIC_TYPE_INT:
1746 return isVertexFormatSint(format);
1747
1748 case GLSL_BASIC_TYPE_UINT:
1749 return isVertexFormatUint(format);
1750
1751 case GLSL_BASIC_TYPE_FLOAT:
1752 return (isVertexFormatPacked(format) ? (getVertexFormatSize(format) <= 4) :
1753 getVertexFormatComponentSize(format) <= 4) &&
1754 (isVertexFormatSfloat(format) || isVertexFormatSnorm(format) || isVertexFormatUnorm(format) ||
1755 isVertexFormatSscaled(format) || isVertexFormatUscaled(format) || isVertexFormatSRGB(format) ||
1756 isVertexFormatUfloat(format));
1757
1758 case GLSL_BASIC_TYPE_DOUBLE:
1759 return isVertexFormatSfloat(format) && getVertexFormatComponentSize(format) == 8;
1760
1761 case GLSL_BASIC_TYPE_FLOAT16:
1762 return ((isVertexFormatSfloat(format) /* || isVertexFormatSnorm(format) || isVertexFormatUnorm(format)*/) &&
1763 getVertexFormatComponentSize(format) == 2);
1764
1765 default:
1766 DE_ASSERT(false);
1767 return false;
1768 }
1769 }
1770 else
1771 return false;
1772 }
1773
verifyImage(void)1774 tcu::TestStatus VertexInputInstance::verifyImage(void)
1775 {
1776 bool compareOk = false;
1777 const tcu::TextureFormat tcuColorFormat = mapVkFormat(m_colorFormat);
1778 tcu::TextureLevel reference(tcuColorFormat, m_renderSize.x(), m_renderSize.y());
1779 const tcu::PixelBufferAccess refRedSubregion(tcu::getSubregion(
1780 reference.getAccess(), deRoundFloatToInt32((float)m_renderSize.x() * 0.0f),
1781 deRoundFloatToInt32((float)m_renderSize.y() * 0.0f), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1782 deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
1783 const tcu::PixelBufferAccess refBlueSubregion(tcu::getSubregion(
1784 reference.getAccess(), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1785 deRoundFloatToInt32((float)m_renderSize.y() * 0.0f), deRoundFloatToInt32((float)m_renderSize.x() * 0.5f),
1786 deRoundFloatToInt32((float)m_renderSize.y() * 1.0f)));
1787
1788 // Create reference image
1789 tcu::clear(reference.getAccess(), defaultClearColor(tcuColorFormat));
1790 tcu::clear(refRedSubregion, tcu::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
1791 tcu::clear(refBlueSubregion, tcu::Vec4(0.0f, 0.0f, 1.0f, 1.0f));
1792
1793 // Compare result with reference image
1794 {
1795 const DeviceInterface &vk = m_context.getDeviceInterface();
1796 const VkDevice vkDevice = m_context.getDevice();
1797 const VkQueue queue = m_context.getUniversalQueue();
1798 const uint32_t queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
1799 SimpleAllocator allocator(
1800 vk, vkDevice,
1801 getPhysicalDeviceMemoryProperties(m_context.getInstanceInterface(), m_context.getPhysicalDevice()));
1802 de::MovePtr<tcu::TextureLevel> result = readColorAttachment(vk, vkDevice, queue, queueFamilyIndex, allocator,
1803 *m_colorImage, m_colorFormat, m_renderSize);
1804
1805 compareOk = tcu::intThresholdPositionDeviationCompare(
1806 m_context.getTestContext().getLog(), "IntImageCompare", "Image comparison", reference.getAccess(),
1807 result->getAccess(), tcu::UVec4(2, 2, 2, 2), tcu::IVec3(1, 1, 0), true, tcu::COMPARE_LOG_RESULT);
1808 }
1809
1810 if (compareOk)
1811 return tcu::TestStatus::pass("Result image matches reference");
1812 else
1813 return tcu::TestStatus::fail("Image mismatch");
1814 }
1815
getAttributeInfoCaseName(const VertexInputTest::AttributeInfo & attributeInfo)1816 std::string getAttributeInfoCaseName(const VertexInputTest::AttributeInfo &attributeInfo)
1817 {
1818 std::ostringstream caseName;
1819 const std::string formatName = getFormatName(attributeInfo.vkType);
1820
1821 caseName << "as_" << de::toLower(formatName.substr(10)) << "_rate_";
1822
1823 if (attributeInfo.inputRate == VK_VERTEX_INPUT_RATE_VERTEX)
1824 caseName << "vertex";
1825 else
1826 caseName << "instance";
1827
1828 return caseName.str();
1829 }
1830
1831 struct CompatibleFormats
1832 {
1833 VertexInputTest::GlslType glslType;
1834 std::vector<VkFormat> compatibleVkFormats;
1835 };
1836
createSingleAttributeCases(tcu::TestCaseGroup * singleAttributeTests,PipelineConstructionType pipelineConstructionType,VertexInputTest::GlslType glslType)1837 void createSingleAttributeCases(tcu::TestCaseGroup *singleAttributeTests,
1838 PipelineConstructionType pipelineConstructionType, VertexInputTest::GlslType glslType)
1839 {
1840 const VkFormat vertexFormats[] = {
1841 // Required, unpacked
1842 VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT, VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_UNORM,
1843 VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8A8_UNORM,
1844 VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT, VK_FORMAT_B8G8R8A8_UNORM,
1845 VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM, VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT, VK_FORMAT_R16_SFLOAT,
1846 VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT,
1847 VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16_UNORM, VK_FORMAT_R16G16B16_SNORM, VK_FORMAT_R16G16B16_UINT,
1848 VK_FORMAT_R16G16B16_SINT, VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16B16A16_UNORM,
1849 VK_FORMAT_R16G16B16A16_SNORM, VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT,
1850 VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT,
1851 VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32B32_UINT,
1852 VK_FORMAT_R32G32B32_SINT, VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT,
1853 VK_FORMAT_R32G32B32A32_SFLOAT,
1854
1855 // Scaled formats
1856 VK_FORMAT_R8G8_USCALED, VK_FORMAT_R8G8_SSCALED, VK_FORMAT_R16_USCALED, VK_FORMAT_R16_SSCALED,
1857 VK_FORMAT_R8G8B8_USCALED, VK_FORMAT_R8G8B8_SSCALED, VK_FORMAT_B8G8R8_USCALED, VK_FORMAT_B8G8R8_SSCALED,
1858 VK_FORMAT_R8G8B8A8_USCALED, VK_FORMAT_R8G8B8A8_SSCALED, VK_FORMAT_B8G8R8A8_USCALED, VK_FORMAT_B8G8R8A8_SSCALED,
1859 VK_FORMAT_R16G16_USCALED, VK_FORMAT_R16G16_SSCALED, VK_FORMAT_R16G16B16_USCALED, VK_FORMAT_R16G16B16_SSCALED,
1860 VK_FORMAT_R16G16B16A16_USCALED, VK_FORMAT_R16G16B16A16_SSCALED,
1861
1862 // SRGB formats
1863 VK_FORMAT_R8_SRGB, VK_FORMAT_R8G8_SRGB, VK_FORMAT_R8G8B8_SRGB, VK_FORMAT_B8G8R8_SRGB, VK_FORMAT_R8G8B8A8_SRGB,
1864 VK_FORMAT_B8G8R8A8_SRGB,
1865
1866 // Double formats
1867 VK_FORMAT_R64_SFLOAT, VK_FORMAT_R64G64_SFLOAT, VK_FORMAT_R64G64B64_SFLOAT, VK_FORMAT_R64G64B64A64_SFLOAT,
1868
1869 // Packed formats
1870 VK_FORMAT_A2R10G10B10_USCALED_PACK32, VK_FORMAT_A2R10G10B10_SSCALED_PACK32, VK_FORMAT_A2R10G10B10_UINT_PACK32,
1871 VK_FORMAT_A2R10G10B10_SINT_PACK32, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32,
1872 VK_FORMAT_A2R10G10B10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_SNORM_PACK32, VK_FORMAT_A2B10G10R10_UNORM_PACK32,
1873 VK_FORMAT_A2B10G10R10_SNORM_PACK32, VK_FORMAT_B10G11R11_UFLOAT_PACK32};
1874
1875 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
1876 {
1877 if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], glslType))
1878 {
1879 {
1880 // Create test case for RATE_VERTEX
1881 VertexInputTest::AttributeInfo attributeInfo;
1882 attributeInfo.vkType = vertexFormats[formatNdx];
1883 attributeInfo.glslType = glslType;
1884 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1885
1886 singleAttributeTests->addChild(new VertexInputTest(
1887 singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo),
1888 pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1889 VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
1890
1891 // Create test case for RATE_INSTANCE
1892 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
1893
1894 singleAttributeTests->addChild(new VertexInputTest(
1895 singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo),
1896 pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1897 VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
1898 }
1899
1900 // Test accessing missing components to verify "Converstion to RGBA" is correctly applied.
1901 const auto &typeInfo = VertexInputTest::s_glslTypeDescriptions[glslType];
1902 if (typeInfo.vertexInputComponentCount < kMaxComponents &&
1903 typeInfo.basicType != VertexInputTest::GLSL_BASIC_TYPE_DOUBLE)
1904 {
1905 // Create test case for RATE_VERTEX
1906 VertexInputTest::AttributeInfo attributeInfo;
1907 attributeInfo.vkType = vertexFormats[formatNdx];
1908 attributeInfo.glslType = glslType;
1909 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1910 const auto nameSuffix = "_missing_components";
1911
1912 singleAttributeTests->addChild(new VertexInputTest(
1913 singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo) + nameSuffix,
1914 pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1915 VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED,
1916 VertexInputTest::LAYOUT_SKIP_DISABLED, VertexInputTest::LAYOUT_ORDER_IN_ORDER, true));
1917
1918 // Create test case for RATE_INSTANCE
1919 attributeInfo.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE;
1920
1921 singleAttributeTests->addChild(new VertexInputTest(
1922 singleAttributeTests->getTestContext(), getAttributeInfoCaseName(attributeInfo) + nameSuffix,
1923 pipelineConstructionType, std::vector<VertexInputTest::AttributeInfo>(1, attributeInfo),
1924 VertexInputTest::BINDING_MAPPING_ONE_TO_ONE, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED,
1925 VertexInputTest::LAYOUT_SKIP_DISABLED, VertexInputTest::LAYOUT_ORDER_IN_ORDER, true));
1926 }
1927 }
1928 }
1929 }
1930
createSingleAttributeTests(tcu::TestCaseGroup * singleAttributeTests,PipelineConstructionType pipelineConstructionType)1931 void createSingleAttributeTests(tcu::TestCaseGroup *singleAttributeTests,
1932 PipelineConstructionType pipelineConstructionType)
1933 {
1934 for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
1935 {
1936 VertexInputTest::GlslType glslType = (VertexInputTest::GlslType)glslTypeNdx;
1937 addTestGroup(singleAttributeTests, VertexInputTest::s_glslTypeDescriptions[glslType].name,
1938 createSingleAttributeCases, pipelineConstructionType, glslType);
1939 }
1940 }
1941
1942 // Create all unique GlslType combinations recursively
createMultipleAttributeCases(PipelineConstructionType pipelineConstructionType,uint32_t depth,uint32_t firstNdx,CompatibleFormats * compatibleFormats,de::Random & randomFunc,tcu::TestCaseGroup & testGroup,VertexInputTest::BindingMapping bindingMapping,VertexInputTest::AttributeLayout attributeLayout,VertexInputTest::LayoutSkip layoutSkip,VertexInputTest::LayoutOrder layoutOrder,const std::vector<VertexInputTest::AttributeInfo> & attributeInfos=std::vector<VertexInputTest::AttributeInfo> (0))1943 void createMultipleAttributeCases(
1944 PipelineConstructionType pipelineConstructionType, uint32_t depth, uint32_t firstNdx,
1945 CompatibleFormats *compatibleFormats, de::Random &randomFunc, tcu::TestCaseGroup &testGroup,
1946 VertexInputTest::BindingMapping bindingMapping, VertexInputTest::AttributeLayout attributeLayout,
1947 VertexInputTest::LayoutSkip layoutSkip, VertexInputTest::LayoutOrder layoutOrder,
1948 const std::vector<VertexInputTest::AttributeInfo> &attributeInfos = std::vector<VertexInputTest::AttributeInfo>(0))
1949 {
1950 tcu::TestContext &testCtx = testGroup.getTestContext();
1951
1952 // Exclude double values, which are not included in vertexFormats
1953 for (uint32_t currentNdx = firstNdx; currentNdx < VertexInputTest::GLSL_TYPE_DOUBLE - depth; currentNdx++)
1954 {
1955 std::vector<VertexInputTest::AttributeInfo> newAttributeInfos = attributeInfos;
1956
1957 {
1958 VertexInputTest::AttributeInfo attributeInfo;
1959 attributeInfo.glslType = (VertexInputTest::GlslType)currentNdx;
1960 attributeInfo.inputRate = (depth % 2 == 0) ? VK_VERTEX_INPUT_RATE_VERTEX : VK_VERTEX_INPUT_RATE_INSTANCE;
1961 attributeInfo.vkType = VK_FORMAT_UNDEFINED;
1962
1963 newAttributeInfos.push_back(attributeInfo);
1964 }
1965
1966 // Add test case
1967 if (depth == 0)
1968 {
1969 // Select a random compatible format for each attribute
1970 for (size_t i = 0; i < newAttributeInfos.size(); i++)
1971 {
1972 const std::vector<VkFormat> &formats =
1973 compatibleFormats[newAttributeInfos[i].glslType].compatibleVkFormats;
1974 newAttributeInfos[i].vkType = formats[randomFunc.getUint32() % formats.size()];
1975 }
1976
1977 const std::string caseName = VertexInputTest::s_glslTypeDescriptions[currentNdx].name;
1978
1979 testGroup.addChild(new VertexInputTest(testCtx, caseName, pipelineConstructionType, newAttributeInfos,
1980 bindingMapping, attributeLayout, layoutSkip, layoutOrder));
1981 }
1982 // Add test group
1983 else
1984 {
1985 const std::string name = VertexInputTest::s_glslTypeDescriptions[currentNdx].name;
1986 de::MovePtr<tcu::TestCaseGroup> newTestGroup(new tcu::TestCaseGroup(testCtx, name.c_str()));
1987
1988 createMultipleAttributeCases(pipelineConstructionType, depth - 1u, currentNdx + 1u, compatibleFormats,
1989 randomFunc, *newTestGroup, bindingMapping, attributeLayout, layoutSkip,
1990 layoutOrder, newAttributeInfos);
1991 testGroup.addChild(newTestGroup.release());
1992 }
1993 }
1994 }
1995
createMultipleAttributeTests(tcu::TestCaseGroup * multipleAttributeTests,PipelineConstructionType pipelineConstructionType)1996 void createMultipleAttributeTests(tcu::TestCaseGroup *multipleAttributeTests,
1997 PipelineConstructionType pipelineConstructionType)
1998 {
1999 // Required vertex formats, unpacked
2000 const VkFormat vertexFormats[] = {
2001 VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT,
2002 VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_SNORM,
2003 VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8A8_UNORM,
2004 VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT,
2005 VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM,
2006 VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT, VK_FORMAT_R16_SFLOAT,
2007 VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_UINT,
2008 VK_FORMAT_R16G16_SINT, VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16_UNORM,
2009 VK_FORMAT_R16G16B16_SNORM, VK_FORMAT_R16G16B16_UINT, VK_FORMAT_R16G16B16_SINT,
2010 VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_R16G16B16A16_SNORM,
2011 VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R16G16B16A16_SFLOAT,
2012 VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT,
2013 VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SFLOAT,
2014 VK_FORMAT_R32G32B32_UINT, VK_FORMAT_R32G32B32_SINT, VK_FORMAT_R32G32B32_SFLOAT,
2015 VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_SFLOAT};
2016
2017 const VertexInputTest::LayoutSkip layoutSkips[] = {VertexInputTest::LAYOUT_SKIP_DISABLED,
2018 VertexInputTest::LAYOUT_SKIP_ENABLED};
2019
2020 const VertexInputTest::LayoutOrder layoutOrders[] = {VertexInputTest::LAYOUT_ORDER_IN_ORDER,
2021 VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER};
2022
2023 // Find compatible VK formats for each GLSL vertex type
2024 CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
2025 {
2026 for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
2027 {
2028 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
2029 {
2030 if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
2031 compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
2032 }
2033 }
2034 }
2035
2036 de::Random randomFunc(102030);
2037 tcu::TestContext &testCtx = multipleAttributeTests->getTestContext();
2038
2039 for (uint32_t layoutSkipNdx = 0; layoutSkipNdx < DE_LENGTH_OF_ARRAY(layoutSkips); layoutSkipNdx++)
2040 for (uint32_t layoutOrderNdx = 0; layoutOrderNdx < DE_LENGTH_OF_ARRAY(layoutOrders); layoutOrderNdx++)
2041 {
2042 const VertexInputTest::LayoutSkip layoutSkip = layoutSkips[layoutSkipNdx];
2043 const VertexInputTest::LayoutOrder layoutOrder = layoutOrders[layoutOrderNdx];
2044 de::MovePtr<tcu::TestCaseGroup> oneToOneAttributeTests(new tcu::TestCaseGroup(testCtx, "attributes"));
2045 de::MovePtr<tcu::TestCaseGroup> oneToManyAttributeTests(new tcu::TestCaseGroup(testCtx, "attributes"));
2046 de::MovePtr<tcu::TestCaseGroup> oneToManySequentialAttributeTests(
2047 new tcu::TestCaseGroup(testCtx, "attributes_sequential"));
2048
2049 if (layoutSkip == VertexInputTest::LAYOUT_SKIP_ENABLED &&
2050 layoutOrder == VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER)
2051 continue;
2052
2053 createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2054 *oneToOneAttributeTests, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE,
2055 VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED, layoutSkip, layoutOrder);
2056 createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2057 *oneToManyAttributeTests, VertexInputTest::BINDING_MAPPING_ONE_TO_MANY,
2058 VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED, layoutSkip, layoutOrder);
2059 createMultipleAttributeCases(pipelineConstructionType, 2u, 0u, compatibleFormats, randomFunc,
2060 *oneToManySequentialAttributeTests,
2061 VertexInputTest::BINDING_MAPPING_ONE_TO_MANY,
2062 VertexInputTest::ATTRIBUTE_LAYOUT_SEQUENTIAL, layoutSkip, layoutOrder);
2063
2064 if (layoutSkip == VertexInputTest::LAYOUT_SKIP_ENABLED)
2065 {
2066 // Skip one layout after each attribute
2067 de::MovePtr<tcu::TestCaseGroup> layoutSkipTests(new tcu::TestCaseGroup(testCtx, "layout_skip"));
2068
2069 // Each attribute uses a unique binding
2070 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2071 new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2072 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2073 layoutSkipTests->addChild(bindingOneToOneTests.release());
2074
2075 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2076 new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2077 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2078 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2079 layoutSkipTests->addChild(bindingOneToManyTests.release());
2080 multipleAttributeTests->addChild(layoutSkipTests.release());
2081 }
2082 else if (layoutOrder == VertexInputTest::LAYOUT_ORDER_OUT_OF_ORDER)
2083 {
2084 de::MovePtr<tcu::TestCaseGroup> layoutOutOfOrderTests(new tcu::TestCaseGroup(testCtx, "out_of_order"));
2085
2086 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2087 new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2088 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2089 layoutOutOfOrderTests->addChild(bindingOneToOneTests.release());
2090
2091 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2092 new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2093 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2094 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2095 layoutOutOfOrderTests->addChild(bindingOneToManyTests.release());
2096 multipleAttributeTests->addChild(layoutOutOfOrderTests.release());
2097 }
2098 else
2099 {
2100 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(
2101 new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2102 bindingOneToOneTests->addChild(oneToOneAttributeTests.release());
2103 multipleAttributeTests->addChild(bindingOneToOneTests.release());
2104
2105 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(
2106 new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2107 bindingOneToManyTests->addChild(oneToManyAttributeTests.release());
2108 bindingOneToManyTests->addChild(oneToManySequentialAttributeTests.release());
2109 multipleAttributeTests->addChild(bindingOneToManyTests.release());
2110 }
2111 }
2112 }
2113
createMaxAttributeTests(tcu::TestCaseGroup * maxAttributeTests,PipelineConstructionType pipelineConstructionType)2114 void createMaxAttributeTests(tcu::TestCaseGroup *maxAttributeTests, PipelineConstructionType pipelineConstructionType)
2115 {
2116 // Required vertex formats, unpacked
2117 const VkFormat vertexFormats[] = {
2118 VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT,
2119 VK_FORMAT_R8_SINT, VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_SNORM,
2120 VK_FORMAT_R8G8_UINT, VK_FORMAT_R8G8_SINT, VK_FORMAT_R8G8B8A8_UNORM,
2121 VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, VK_FORMAT_R8G8B8A8_SINT,
2122 VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R16_UNORM, VK_FORMAT_R16_SNORM,
2123 VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT, VK_FORMAT_R16_SFLOAT,
2124 VK_FORMAT_R16G16_UNORM, VK_FORMAT_R16G16_SNORM, VK_FORMAT_R16G16_UINT,
2125 VK_FORMAT_R16G16_SINT, VK_FORMAT_R16G16_SFLOAT, VK_FORMAT_R16G16B16_UNORM,
2126 VK_FORMAT_R16G16B16_SNORM, VK_FORMAT_R16G16B16_UINT, VK_FORMAT_R16G16B16_SINT,
2127 VK_FORMAT_R16G16B16_SFLOAT, VK_FORMAT_R16G16B16A16_UNORM, VK_FORMAT_R16G16B16A16_SNORM,
2128 VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT, VK_FORMAT_R16G16B16A16_SFLOAT,
2129 VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT, VK_FORMAT_R32_SFLOAT,
2130 VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT, VK_FORMAT_R32G32_SFLOAT,
2131 VK_FORMAT_R32G32B32_UINT, VK_FORMAT_R32G32B32_SINT, VK_FORMAT_R32G32B32_SFLOAT,
2132 VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT, VK_FORMAT_R32G32B32A32_SFLOAT};
2133
2134 // VkPhysicalDeviceLimits::maxVertexInputAttributes is used when attributeCount is 0
2135 const uint32_t attributeCount[] = {16, 32, 64, 128, 0};
2136 tcu::TestContext &testCtx(maxAttributeTests->getTestContext());
2137 de::Random randomFunc(132030);
2138
2139 // Find compatible VK formats for each GLSL vertex type
2140 CompatibleFormats compatibleFormats[VertexInputTest::GLSL_TYPE_COUNT];
2141 {
2142 for (int glslTypeNdx = 0; glslTypeNdx < VertexInputTest::GLSL_TYPE_COUNT; glslTypeNdx++)
2143 {
2144 for (int formatNdx = 0; formatNdx < DE_LENGTH_OF_ARRAY(vertexFormats); formatNdx++)
2145 {
2146 if (VertexInputTest::isCompatibleType(vertexFormats[formatNdx], (VertexInputTest::GlslType)glslTypeNdx))
2147 compatibleFormats[glslTypeNdx].compatibleVkFormats.push_back(vertexFormats[formatNdx]);
2148 }
2149 }
2150 }
2151
2152 for (uint32_t attributeCountNdx = 0; attributeCountNdx < DE_LENGTH_OF_ARRAY(attributeCount); attributeCountNdx++)
2153 {
2154 const std::string groupName =
2155 (attributeCount[attributeCountNdx] == 0 ? "query_max" : de::toString(attributeCount[attributeCountNdx])) +
2156 "_attributes";
2157 const std::string groupDesc = de::toString(attributeCount[attributeCountNdx]) + " vertex input attributes";
2158
2159 de::MovePtr<tcu::TestCaseGroup> numAttributeTests(new tcu::TestCaseGroup(testCtx, groupName.c_str()));
2160 de::MovePtr<tcu::TestCaseGroup> bindingOneToOneTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_one"));
2161 de::MovePtr<tcu::TestCaseGroup> bindingOneToManyTests(new tcu::TestCaseGroup(testCtx, "binding_one_to_many"));
2162
2163 std::vector<VertexInputTest::AttributeInfo> attributeInfos(attributeCount[attributeCountNdx]);
2164
2165 for (uint32_t attributeNdx = 0; attributeNdx < attributeCount[attributeCountNdx]; attributeNdx++)
2166 {
2167 // Use random glslTypes, each consuming one attribute location
2168 const VertexInputTest::GlslType glslType =
2169 (VertexInputTest::GlslType)(randomFunc.getUint32() % VertexInputTest::GLSL_TYPE_MAT2);
2170 const std::vector<VkFormat> &formats = compatibleFormats[glslType].compatibleVkFormats;
2171 const VkFormat format = formats[randomFunc.getUint32() % formats.size()];
2172
2173 attributeInfos[attributeNdx].glslType = glslType;
2174 attributeInfos[attributeNdx].inputRate = ((attributeCountNdx + attributeNdx) % 2 == 0) ?
2175 VK_VERTEX_INPUT_RATE_VERTEX :
2176 VK_VERTEX_INPUT_RATE_INSTANCE;
2177 attributeInfos[attributeNdx].vkType = format;
2178 }
2179
2180 // Interleaved attribute layout
2181 bindingOneToOneTests->addChild(new VertexInputTest(testCtx, "interleaved", pipelineConstructionType,
2182 attributeInfos, VertexInputTest::BINDING_MAPPING_ONE_TO_ONE,
2183 VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
2184 // Interleaved attribute layout
2185 bindingOneToManyTests->addChild(new VertexInputTest(
2186 testCtx, "interleaved", pipelineConstructionType, attributeInfos,
2187 VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_INTERLEAVED));
2188 // Sequential attribute layout
2189 bindingOneToManyTests->addChild(new VertexInputTest(
2190 testCtx, "sequential", pipelineConstructionType, attributeInfos,
2191 VertexInputTest::BINDING_MAPPING_ONE_TO_MANY, VertexInputTest::ATTRIBUTE_LAYOUT_SEQUENTIAL));
2192
2193 numAttributeTests->addChild(bindingOneToOneTests.release());
2194 numAttributeTests->addChild(bindingOneToManyTests.release());
2195 maxAttributeTests->addChild(numAttributeTests.release());
2196 }
2197 }
2198
2199 // The goal of the stride change tests are checking a sequence like the following one:
2200 //
2201 // CmdBindVertexBuffers()
2202 // CmdBindPipeline(VS+FS)
2203 // CmdDraw()
2204 // CmdBindPipeline(VS+GS+FS)
2205 // CmdDraw()
2206 //
2207 // Where the second pipeline bind needs different vertex buffer info (like binding stride) that doesn't require a new
2208 // CmdBindVertexBuffers.
2209 //
2210 // We will draw a full screen quad with two triangles, and use one triangle per draw call. The vertex buffer will be set up such
2211 // that the vertices for the first triangle will be contiguous in memory, but the ones for the second triangle will use two extra
2212 // vertices for padding, so it looks like:
2213 //
2214 // FIRST0, FIRST1, FIRST2, SECOND0, PADDING, PADDING, SECOND1, PADDING, PADDING, SECOND2, PADDING, PADDING
2215 //
2216 // The stride in the first pipeline will be sizeof(vec4) and, for the second one, sizeof(vec4)*3.
2217 // Draw calls parameters will be:
2218 // 1. vkCmdDraw(cmdBuffer, 3u, 1u, 0u, 0u);
2219 // 2. vkCmdDraw(cmdBuffer, 3u, 1u, 1u, 0u); // firstVertex == 1u so that FIRST0, FIRST1, FIRST2 are skipped with the new stride.
2220 //
2221 struct StrideChangeParams
2222 {
2223 PipelineConstructionType pipelineConstructionType;
2224 bool useTessellation; // In the second bind.
2225 bool useGeometry; // In the second bind.
2226 };
2227
2228 class StrideChangeTest : public vkt::TestInstance
2229 {
2230 public:
StrideChangeTest(Context & context,const StrideChangeParams & params)2231 StrideChangeTest(Context &context, const StrideChangeParams ¶ms) : vkt::TestInstance(context), m_params(params)
2232 {
2233 }
~StrideChangeTest(void)2234 virtual ~StrideChangeTest(void)
2235 {
2236 }
2237
2238 tcu::TestStatus iterate(void) override;
2239
2240 protected:
2241 const StrideChangeParams m_params;
2242 };
2243
2244 class StrideChangeCase : public vkt::TestCase
2245 {
2246 public:
StrideChangeCase(tcu::TestContext & testCtx,const std::string & name,const StrideChangeParams & params)2247 StrideChangeCase(tcu::TestContext &testCtx, const std::string &name, const StrideChangeParams ¶ms)
2248 : vkt::TestCase(testCtx, name)
2249 , m_params(params)
2250 {
2251 }
~StrideChangeCase(void)2252 virtual ~StrideChangeCase(void)
2253 {
2254 }
2255
2256 void initPrograms(vk::SourceCollections &programCollection) const override;
2257 TestInstance *createInstance(Context &context) const override;
2258 void checkSupport(Context &context) const override;
2259
2260 protected:
2261 const StrideChangeParams m_params;
2262 };
2263
initPrograms(SourceCollections & dst) const2264 void StrideChangeCase::initPrograms(SourceCollections &dst) const
2265 {
2266 std::ostringstream vert;
2267 vert << "#version 460\n"
2268 << "layout (location=0) in vec4 inPos;\n"
2269 << "out gl_PerVertex\n"
2270 << "{\n"
2271 << " vec4 gl_Position;\n"
2272 << "};\n"
2273 << "void main (void) {\n"
2274 << " gl_Position = inPos;\n"
2275 << "}\n";
2276 dst.glslSources.add("vert") << glu::VertexSource(vert.str());
2277
2278 if (m_params.useTessellation)
2279 {
2280 std::ostringstream tesc;
2281 tesc << "#version 460\n"
2282 << "layout (vertices=3) out;\n"
2283 << "in gl_PerVertex\n"
2284 << "{\n"
2285 << " vec4 gl_Position;\n"
2286 << "} gl_in[gl_MaxPatchVertices];\n"
2287 << "out gl_PerVertex\n"
2288 << "{\n"
2289 << " vec4 gl_Position;\n"
2290 << "} gl_out[];\n"
2291 << "void main (void)\n"
2292 << "{\n"
2293 << " gl_TessLevelInner[0] = 1.0;\n"
2294 << " gl_TessLevelInner[1] = 1.0;\n"
2295 << " gl_TessLevelOuter[0] = 1.0;\n"
2296 << " gl_TessLevelOuter[1] = 1.0;\n"
2297 << " gl_TessLevelOuter[2] = 1.0;\n"
2298 << " gl_TessLevelOuter[3] = 1.0;\n"
2299 << " gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
2300 << "}\n";
2301 dst.glslSources.add("tesc") << glu::TessellationControlSource(tesc.str());
2302
2303 std::ostringstream tese;
2304 tese << "#version 460\n"
2305 << "layout (triangles, fractional_odd_spacing, cw) in;\n"
2306 << "in gl_PerVertex\n"
2307 << "{\n"
2308 << " vec4 gl_Position;\n"
2309 << "} gl_in[gl_MaxPatchVertices];\n"
2310 << "out gl_PerVertex\n"
2311 << "{\n"
2312 << " vec4 gl_Position;\n"
2313 << "};\n"
2314 << "void main (void)\n"
2315 << "{\n"
2316 << " gl_Position = (gl_TessCoord.x * gl_in[0].gl_Position) +\n"
2317 << " (gl_TessCoord.y * gl_in[1].gl_Position) +\n"
2318 << " (gl_TessCoord.z * gl_in[2].gl_Position);\n"
2319 << "}\n";
2320 dst.glslSources.add("tese") << glu::TessellationEvaluationSource(tese.str());
2321 }
2322
2323 if (m_params.useGeometry)
2324 {
2325 std::ostringstream geom;
2326 geom << "#version 460\n"
2327 << "layout (triangles) in;\n"
2328 << "layout (triangle_strip, max_vertices=3) out;\n"
2329 << "in gl_PerVertex\n"
2330 << "{\n"
2331 << " vec4 gl_Position;\n"
2332 << "} gl_in[3];\n"
2333 << "out gl_PerVertex\n"
2334 << "{\n"
2335 << " vec4 gl_Position;\n"
2336 << "};\n"
2337 << "void main ()\n"
2338 << "{\n"
2339 << " gl_Position = gl_in[0].gl_Position; EmitVertex();\n"
2340 << " gl_Position = gl_in[1].gl_Position; EmitVertex();\n"
2341 << " gl_Position = gl_in[2].gl_Position; EmitVertex();\n"
2342 << "}\n";
2343 dst.glslSources.add("geom") << glu::GeometrySource(geom.str());
2344 }
2345
2346 std::ostringstream frag;
2347 frag << "#version 460\n"
2348 << "layout (location=0) out vec4 outColor;\n"
2349 << "void main (void) {\n"
2350 << " outColor = vec4(0.0, 0.0, 1.0, 1.0);\n"
2351 << "}\n";
2352 dst.glslSources.add("frag") << glu::FragmentSource(frag.str());
2353 }
2354
createInstance(Context & context) const2355 TestInstance *StrideChangeCase::createInstance(Context &context) const
2356 {
2357 return new StrideChangeTest(context, m_params);
2358 }
2359
checkSupport(Context & context) const2360 void StrideChangeCase::checkSupport(Context &context) const
2361 {
2362 const auto &vki = context.getInstanceInterface();
2363 const auto physicalDevice = context.getPhysicalDevice();
2364
2365 checkPipelineConstructionRequirements(vki, physicalDevice, m_params.pipelineConstructionType);
2366
2367 if (m_params.useTessellation)
2368 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_TESSELLATION_SHADER);
2369
2370 if (m_params.useGeometry)
2371 context.requireDeviceCoreFeature(DEVICE_CORE_FEATURE_GEOMETRY_SHADER);
2372 }
2373
iterate(void)2374 tcu::TestStatus StrideChangeTest::iterate(void)
2375 {
2376 const auto &ctx = m_context.getContextCommonData();
2377 const tcu::IVec3 fbExtent(4, 4, 1);
2378 const auto vkExtent = makeExtent3D(fbExtent);
2379 const auto fbFormat = VK_FORMAT_R8G8B8A8_UNORM;
2380 const auto tcuFormat = mapVkFormat(fbFormat);
2381 const auto fbUsage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT);
2382 const tcu::Vec4 clearColor(0.0f, 0.0f, 0.0f, 1.0f);
2383 const tcu::Vec4 geomColor(0.0f, 0.0f, 1.0f, 1.0f); // Must match frag shader.
2384 const tcu::Vec4 threshold(0.0f, 0.0f, 0.0f, 0.0f); // When using 0 and 1 only, we expect exact results.
2385 const auto kTriVtx = 3u; // 3 vertices per triangle.
2386
2387 // Color buffer with verification buffer.
2388 ImageWithBuffer colorBuffer(ctx.vkd, ctx.device, ctx.allocator, vkExtent, fbFormat, fbUsage, VK_IMAGE_TYPE_2D);
2389
2390 // Vertices. See the test description above about padding and real vertices.
2391 const std::vector<tcu::Vec4> vertices{
2392 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // First triangle, vertex 0.
2393 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // First triangle, vertex 1.
2394 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), // First triangle, vertex 2.
2395
2396 tcu::Vec4(1.0f, -1.0f, 0.0f, 1.0f), // Second triangle, vertex 0. |
2397 tcu::Vec4(-1.0f, -1.0f, 0.0f,
2398 1.0f), // Padding. | Padding such that it's the first triangle again.
2399 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // Padding. |
2400
2401 tcu::Vec4(-1.0f, 1.0f, 0.0f, 1.0f), // Second triangle, vertex 1. |
2402 tcu::Vec4(1.0f, -1.0f, 0.0f,
2403 1.0f), // Padding. | Padding such that it's the first triangle again.
2404 tcu::Vec4(-1.0f, -1.0f, 0.0f, 1.0f), // Padding. |
2405
2406 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Second triangle, vertex 2. |
2407 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Padding. | Padding such that it's a zero-area triangle.
2408 tcu::Vec4(1.0f, 1.0f, 0.0f, 1.0f), // Padding. |
2409 };
2410
2411 // Vertex buffer
2412 const auto vbSize = static_cast<VkDeviceSize>(de::dataSize(vertices));
2413 const auto vbInfo = makeBufferCreateInfo(vbSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
2414 BufferWithMemory vertexBuffer(ctx.vkd, ctx.device, ctx.allocator, vbInfo, MemoryRequirement::HostVisible);
2415 const auto vbAlloc = vertexBuffer.getAllocation();
2416 void *vbData = vbAlloc.getHostPtr();
2417 const auto vbOffset = static_cast<VkDeviceSize>(0);
2418
2419 deMemcpy(vbData, de::dataOrNull(vertices), de::dataSize(vertices));
2420 flushAlloc(ctx.vkd, ctx.device, vbAlloc); // strictly speaking, not needed.
2421
2422 const auto pipelineLayout = PipelineLayoutWrapper(m_params.pipelineConstructionType, ctx.vkd, ctx.device);
2423 auto renderPass = RenderPassWrapper(m_params.pipelineConstructionType, ctx.vkd, ctx.device, fbFormat);
2424 renderPass.createFramebuffer(ctx.vkd, ctx.device, colorBuffer.getImage(), colorBuffer.getImageView(),
2425 vkExtent.width, vkExtent.height);
2426
2427 // Modules.
2428 const auto &binaries = m_context.getBinaryCollection();
2429 const auto nullModule = ShaderWrapper();
2430 const auto vertModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("vert"));
2431 const auto tescModule =
2432 (m_params.useTessellation ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("tesc")) : nullModule);
2433 const auto teseModule =
2434 (m_params.useTessellation ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("tese")) : nullModule);
2435 const auto geomModule =
2436 (m_params.useGeometry ? ShaderWrapper(ctx.vkd, ctx.device, binaries.get("geom")) : nullModule);
2437 const auto fragModule = ShaderWrapper(ctx.vkd, ctx.device, binaries.get("frag"));
2438
2439 const std::vector<VkViewport> viewports(1u, makeViewport(vkExtent));
2440 const std::vector<VkRect2D> scissors(1u, makeRect2D(vkExtent));
2441
2442 const std::vector<uint32_t> vertexStrides{
2443 static_cast<uint32_t>(sizeof(tcu::Vec4)), // Short stride for the first draw.
2444 static_cast<uint32_t>(sizeof(tcu::Vec4) * kTriVtx), // Long stride for the second draw.
2445 };
2446
2447 const std::vector<uint32_t> firstVertices{0u, 1u}; // First vertices for the vkCmdDraw() calls, see comment above.
2448
2449 const std::vector<bool> useTessellation{false, m_params.useTessellation};
2450 const std::vector<bool> useGeometry{false, m_params.useGeometry};
2451
2452 using PipelinePtr = std::unique_ptr<GraphicsPipelineWrapper>;
2453 std::vector<PipelinePtr> pipelines;
2454
2455 const auto inputAttribute = makeVertexInputAttributeDescription(0u, 0u, vk::VK_FORMAT_R32G32B32A32_SFLOAT, 0u);
2456
2457 DE_ASSERT(vertexStrides.size() == useTessellation.size());
2458 DE_ASSERT(vertexStrides.size() == useGeometry.size());
2459
2460 for (size_t i = 0u; i < vertexStrides.size(); ++i)
2461 {
2462 const auto vtxStride = vertexStrides.at(i);
2463 const auto useTess = useTessellation.at(i);
2464 const auto useGeom = useGeometry.at(i);
2465 const auto topology = (useTess ? VK_PRIMITIVE_TOPOLOGY_PATCH_LIST : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
2466 const auto inputBinding = makeVertexInputBindingDescription(0u, vtxStride, VK_VERTEX_INPUT_RATE_VERTEX);
2467
2468 const VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
2469 VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType;
2470 nullptr, // const void* pNext;
2471 0u, // VkPipelineVertexInputStateCreateFlags flags;
2472 1u, // uint32_t vertexBindingDescriptionCount;
2473 &inputBinding, // const VkVertexInputBindingDescription* pVertexBindingDescriptions;
2474 1u, // uint32_t vertexAttributeDescriptionCount;
2475 &inputAttribute, // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions;
2476 };
2477
2478 pipelines.emplace_back(new GraphicsPipelineWrapper(ctx.vki, ctx.vkd, ctx.physicalDevice, ctx.device,
2479 m_context.getDeviceExtensions(),
2480 m_params.pipelineConstructionType));
2481 auto &pipeline = *pipelines.back();
2482 pipeline.setDefaultTopology(topology)
2483 .setDefaultRasterizationState()
2484 .setDefaultDepthStencilState()
2485 .setDefaultMultisampleState()
2486 .setDefaultColorBlendState()
2487 .setupVertexInputState(&vertexInputStateCreateInfo)
2488 .setupPreRasterizationShaderState(viewports, scissors, pipelineLayout, *renderPass, 0u, vertModule, nullptr,
2489 (useTess ? tescModule : nullModule), (useTess ? teseModule : nullModule),
2490 (useGeom ? geomModule : nullModule))
2491 .setupFragmentShaderState(pipelineLayout, *renderPass, 0u, fragModule)
2492 .setupFragmentOutputState(*renderPass)
2493 .setMonolithicPipelineLayout(pipelineLayout)
2494 .buildPipeline();
2495 ;
2496 }
2497
2498 CommandPoolWithBuffer cmd(ctx.vkd, ctx.device, ctx.qfIndex);
2499 const auto cmdBuffer = *cmd.cmdBuffer;
2500
2501 beginCommandBuffer(ctx.vkd, cmdBuffer);
2502 renderPass.begin(ctx.vkd, cmdBuffer, scissors.at(0u), clearColor);
2503 ctx.vkd.cmdBindVertexBuffers(cmdBuffer, 0u, 1u, &vertexBuffer.get(), &vbOffset);
2504 DE_ASSERT(pipelines.size() == firstVertices.size());
2505 for (size_t i = 0; i < pipelines.size(); ++i)
2506 {
2507 pipelines.at(i)->bind(cmdBuffer);
2508 ctx.vkd.cmdDraw(cmdBuffer, kTriVtx, 1u, firstVertices.at(i), 0u);
2509 }
2510 renderPass.end(ctx.vkd, cmdBuffer);
2511 copyImageToBuffer(ctx.vkd, cmdBuffer, colorBuffer.getImage(), colorBuffer.getBuffer(), fbExtent.swizzle(0, 1),
2512 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, 1u,
2513 VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_ASPECT_COLOR_BIT,
2514 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
2515 endCommandBuffer(ctx.vkd, cmdBuffer);
2516 submitCommandsAndWait(ctx.vkd, ctx.device, ctx.queue, cmdBuffer);
2517
2518 // Verify color output.
2519 invalidateAlloc(ctx.vkd, ctx.device, colorBuffer.getBufferAllocation());
2520 tcu::PixelBufferAccess resultAccess(tcuFormat, fbExtent, colorBuffer.getBufferAllocation().getHostPtr());
2521
2522 tcu::TextureLevel referenceLevel(tcuFormat, fbExtent.x(), fbExtent.y());
2523 auto referenceAccess = referenceLevel.getAccess();
2524 tcu::clear(referenceAccess, geomColor);
2525
2526 auto &log = m_context.getTestContext().getLog();
2527 if (!tcu::floatThresholdCompare(log, "Result", "", referenceAccess, resultAccess, threshold,
2528 tcu::COMPARE_LOG_ON_ERROR))
2529 return tcu::TestStatus::fail("Unexpected color in result buffer; check log for details");
2530
2531 return tcu::TestStatus::pass("Pass");
2532 }
2533
createMiscVertexInputTests(tcu::TestCaseGroup * miscTests,PipelineConstructionType pipelineConstructionType)2534 void createMiscVertexInputTests(tcu::TestCaseGroup *miscTests, PipelineConstructionType pipelineConstructionType)
2535 {
2536 auto &testCtx = miscTests->getTestContext();
2537
2538 for (const auto useTess : {false, true})
2539 for (const auto useGeom : {false, true})
2540 {
2541 const StrideChangeParams params{
2542 pipelineConstructionType,
2543 useTess,
2544 useGeom,
2545 };
2546 const auto testName =
2547 std::string("stride_change_vert") + (useTess ? "_tess" : "") + (useGeom ? "_geom" : "") + "_frag";
2548 miscTests->addChild(new StrideChangeCase(testCtx, testName, params));
2549 }
2550 }
2551
2552 } // namespace
2553
createVertexInputTests(tcu::TestCaseGroup * vertexInputTests,PipelineConstructionType pipelineConstructionType)2554 void createVertexInputTests(tcu::TestCaseGroup *vertexInputTests, PipelineConstructionType pipelineConstructionType)
2555 {
2556 // Uses one attribute
2557 addTestGroup(vertexInputTests, "single_attribute", createSingleAttributeTests, pipelineConstructionType);
2558 // Uses more than one attribute
2559 addTestGroup(vertexInputTests, "multiple_attributes", createMultipleAttributeTests, pipelineConstructionType);
2560 // Implementations can use as many vertex input attributes as they advertise
2561 addTestGroup(vertexInputTests, "max_attributes", createMaxAttributeTests, pipelineConstructionType);
2562
2563 // Miscellaneous tests.
2564 addTestGroup(vertexInputTests, "misc", createMiscVertexInputTests, pipelineConstructionType);
2565 }
2566
2567 } // namespace pipeline
2568 } // namespace vkt
2569