1 /*------------------------------------------------------------------------
2  * Vulkan Conformance Tests
3  * ------------------------
4  *
5  * Copyright (c) 2016 The Khronos Group Inc.
6  * Copyright (c) 2016 Imagination Technologies Ltd.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  *//*!
21  * \file
22  * \brief Robust Vertex Buffer Access Tests
23  *//*--------------------------------------------------------------------*/
24 
25 #include "vktRobustnessVertexAccessTests.hpp"
26 #include "vktRobustnessUtil.hpp"
27 #include "vktTestCaseUtil.hpp"
28 #include "vkBuilderUtil.hpp"
29 #include "vkImageUtil.hpp"
30 #include "vkMemUtil.hpp"
31 #include "vkPrograms.hpp"
32 #include "vkQueryUtil.hpp"
33 #include "vkDeviceUtil.hpp"
34 #include "vkRef.hpp"
35 #include "vkRefUtil.hpp"
36 #include "vkTypeUtil.hpp"
37 #include "tcuTestLog.hpp"
38 #include "deMath.h"
39 #include "deUniquePtr.hpp"
40 #include <vector>
41 
42 namespace vkt
43 {
44 namespace robustness
45 {
46 
47 using namespace vk;
48 
49 typedef std::vector<VkVertexInputBindingDescription> BindingList;
50 typedef std::vector<VkVertexInputAttributeDescription> AttributeList;
51 
52 class VertexAccessTest : public vkt::TestCase
53 {
54 public:
55     VertexAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
56                      uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices, uint32_t numInstances);
57 
~VertexAccessTest(void)58     virtual ~VertexAccessTest(void)
59     {
60     }
61 
62     void initPrograms(SourceCollections &programCollection) const;
63     void checkSupport(Context &context) const;
64     TestInstance *createInstance(Context &context) const = 0;
65 
66 protected:
67     const VkFormat m_inputFormat;
68     const uint32_t m_numVertexValues;
69     const uint32_t m_numInstanceValues;
70     const uint32_t m_numVertices;
71     const uint32_t m_numInstances;
72 };
73 
74 class DrawAccessTest : public VertexAccessTest
75 {
76 public:
77     DrawAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
78                    uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices, uint32_t numInstances);
79 
~DrawAccessTest(void)80     virtual ~DrawAccessTest(void)
81     {
82     }
83     TestInstance *createInstance(Context &context) const;
84 
85 protected:
86 };
87 
88 class DrawIndexedAccessTest : public VertexAccessTest
89 {
90 public:
91     enum IndexConfig
92     {
93         INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS,
94         INDEX_CONFIG_INDICES_OUT_OF_BOUNDS,
95         INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS,
96 
97         INDEX_CONFIG_COUNT
98     };
99 
100     const static std::vector<uint32_t> s_indexConfigs[INDEX_CONFIG_COUNT];
101 
102     DrawIndexedAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
103                           IndexConfig indexConfig);
104 
~DrawIndexedAccessTest(void)105     virtual ~DrawIndexedAccessTest(void)
106     {
107     }
108     TestInstance *createInstance(Context &context) const;
109 
110 protected:
111     const IndexConfig m_indexConfig;
112 };
113 
114 class VertexAccessInstance : public vkt::TestInstance
115 {
116 public:
117     VertexAccessInstance(Context &context, Move<VkDevice> device,
118 #ifndef CTS_USES_VULKANSC
119                          de::MovePtr<vk::DeviceDriver> deviceDriver,
120 #else
121                          de::MovePtr<CustomInstance> customInstance,
122                          de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
123 #endif // CTS_USES_VULKANSC
124                          VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
125                          uint32_t numVertices, uint32_t numInstances, const std::vector<uint32_t> &indices);
126 
127     virtual ~VertexAccessInstance(void);
128     virtual tcu::TestStatus iterate(void);
129     virtual bool verifyResult(void);
130 
131 private:
132     bool isValueWithinVertexBufferOrZero(void *vertexBuffer, VkDeviceSize vertexBufferSize, const void *value,
133                                          uint32_t valueIndexa);
134 
135 protected:
136     static bool isExpectedValueFromVertexBuffer(const void *vertexBuffer, uint32_t vertexIndex, VkFormat vertexFormat,
137                                                 const void *value);
138     static VkDeviceSize getBufferSizeInBytes(uint32_t numScalars, VkFormat format);
139 
140     virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount) = 0;
141     virtual uint32_t getIndex(uint32_t vertexNum) const                 = 0;
142 
143 #ifndef CTS_USES_VULKANSC
144     Move<VkDevice> m_device;
145     de::MovePtr<vk::DeviceDriver> m_deviceDriver;
146 #else
147     // Construction needs to happen in this exact order to ensure proper resource destruction
148     de::MovePtr<CustomInstance> m_customInstance;
149     Move<VkDevice> m_device;
150     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> m_deviceDriver;
151 #endif // CTS_USES_VULKANSC
152 
153     const VkFormat m_inputFormat;
154     const uint32_t m_numVertexValues;
155     const uint32_t m_numInstanceValues;
156     const uint32_t m_numVertices;
157     const uint32_t m_numInstances;
158     AttributeList m_vertexInputAttributes;
159     BindingList m_vertexInputBindings;
160 
161     Move<VkBuffer> m_vertexRateBuffer;
162     VkDeviceSize m_vertexRateBufferSize;
163     de::MovePtr<Allocation> m_vertexRateBufferAlloc;
164     VkDeviceSize m_vertexRateBufferAllocSize;
165 
166     Move<VkBuffer> m_instanceRateBuffer;
167     VkDeviceSize m_instanceRateBufferSize;
168     de::MovePtr<Allocation> m_instanceRateBufferAlloc;
169     VkDeviceSize m_instanceRateBufferAllocSize;
170 
171     Move<VkBuffer> m_vertexNumBuffer;
172     VkDeviceSize m_vertexNumBufferSize;
173     de::MovePtr<Allocation> m_vertexNumBufferAlloc;
174 
175     Move<VkBuffer> m_indexBuffer;
176     VkDeviceSize m_indexBufferSize;
177     de::MovePtr<Allocation> m_indexBufferAlloc;
178 
179     Move<VkBuffer> m_outBuffer; // SSBO
180     VkDeviceSize m_outBufferSize;
181     de::MovePtr<Allocation> m_outBufferAlloc;
182     VkDeviceSize m_outBufferAllocSize;
183 
184     Move<VkDescriptorPool> m_descriptorPool;
185     Move<VkDescriptorSetLayout> m_descriptorSetLayout;
186     Move<VkDescriptorSet> m_descriptorSet;
187 
188     Move<VkFence> m_fence;
189     VkQueue m_queue;
190 
191     de::MovePtr<GraphicsEnvironment> m_graphicsTestEnvironment;
192 };
193 
194 class DrawAccessInstance : public VertexAccessInstance
195 {
196 public:
197     DrawAccessInstance(Context &context, Move<VkDevice> device,
198 #ifndef CTS_USES_VULKANSC
199                        de::MovePtr<vk::DeviceDriver> deviceDriver,
200 #else
201                        de::MovePtr<CustomInstance> customInstance,
202                        de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
203 #endif // CTS_USES_VULKANSC
204                        VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
205                        uint32_t numInstances);
206 
~DrawAccessInstance(void)207     virtual ~DrawAccessInstance(void)
208     {
209     }
210 
211 protected:
212     virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount);
213     virtual uint32_t getIndex(uint32_t vertexNum) const;
214 };
215 
216 class DrawIndexedAccessInstance : public VertexAccessInstance
217 {
218 public:
219     DrawIndexedAccessInstance(Context &context, Move<VkDevice> device,
220 #ifndef CTS_USES_VULKANSC
221                               de::MovePtr<vk::DeviceDriver> deviceDriver,
222 #else
223                               de::MovePtr<CustomInstance> customInstance,
224                               de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
225 #endif // CTS_USES_VULKANSC
226                               VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
227                               uint32_t numVertices, uint32_t numInstances, const std::vector<uint32_t> &indices);
228 
~DrawIndexedAccessInstance(void)229     virtual ~DrawIndexedAccessInstance(void)
230     {
231     }
232 
233 protected:
234     virtual void initVertexIds(uint32_t *indicesPtr, size_t indexCount);
235     virtual uint32_t getIndex(uint32_t vertexNum) const;
236 
237     const std::vector<uint32_t> m_indices;
238 };
239 
240 // VertexAccessTest
241 
VertexAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)242 VertexAccessTest::VertexAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
243                                    uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
244                                    uint32_t numInstances)
245 
246     : vkt::TestCase(testContext, name)
247     , m_inputFormat(inputFormat)
248     , m_numVertexValues(numVertexValues)
249     , m_numInstanceValues(numInstanceValues)
250     , m_numVertices(numVertices)
251     , m_numInstances(numInstances)
252 {
253 }
254 
checkSupport(Context & context) const255 void VertexAccessTest::checkSupport(Context &context) const
256 {
257     if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") &&
258         !context.getDeviceFeatures().robustBufferAccess)
259         TCU_THROW(NotSupportedError,
260                   "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
261 }
262 
initPrograms(SourceCollections & programCollection) const263 void VertexAccessTest::initPrograms(SourceCollections &programCollection) const
264 {
265     std::ostringstream attributeDeclaration;
266     std::ostringstream attributeUse;
267 
268     std::ostringstream vertexShaderSource;
269     std::ostringstream fragmentShaderSource;
270 
271     std::ostringstream attributeTypeStr;
272     const int numChannels              = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
273     const uint32_t numScalarsPerVertex = numChannels * 3; // Use 3 identical attributes
274     uint32_t numValues                 = 0;
275 
276     const bool isR64 = (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT);
277 
278     if (numChannels == 1)
279     {
280         if (isUintFormat(m_inputFormat))
281             attributeTypeStr << "uint";
282         else if (isIntFormat(m_inputFormat))
283             attributeTypeStr << "int";
284         else
285             attributeTypeStr << "float";
286 
287         attributeTypeStr << (isR64 ? "64_t" : " ");
288     }
289     else
290     {
291         if (isUintFormat(m_inputFormat))
292             attributeTypeStr << "uvec";
293         else if (isIntFormat(m_inputFormat))
294             attributeTypeStr << "ivec";
295         else
296             attributeTypeStr << "vec";
297 
298         attributeTypeStr << numChannels;
299     }
300 
301     for (int attrNdx = 0; attrNdx < 3; attrNdx++)
302     {
303         attributeDeclaration << "layout(location = " << attrNdx << ") in " << attributeTypeStr.str() << " attr"
304                              << attrNdx << ";\n";
305 
306         for (int chanNdx = 0; chanNdx < numChannels; chanNdx++)
307         {
308             attributeUse << "\toutData[(gl_InstanceIndex * " << numScalarsPerVertex * m_numVertices
309                          << ") + (vertexNum * " << numScalarsPerVertex << " + " << numValues++ << ")] = attr"
310                          << attrNdx;
311 
312             if (numChannels == 1)
313                 attributeUse << ";\n";
314             else
315                 attributeUse << "[" << chanNdx << "];\n";
316         }
317     }
318 
319     attributeDeclaration << "layout(location = 3) in int vertexNum;\n";
320 
321     attributeUse << "\n";
322 
323     std::string outType = "";
324     if (isUintFormat(m_inputFormat))
325         outType = "uint";
326     else if (isIntFormat(m_inputFormat))
327         outType = "int";
328     else
329         outType = "float";
330 
331     outType += isR64 ? "64_t" : "";
332 
333     std::string extensions = "";
334     std::string version    = "#version 310 es\n";
335     if (isR64)
336     {
337         extensions = "#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require\n";
338         version    = "#version 440\n";
339     }
340 
341     vertexShaderSource << version << "precision highp float;\n"
342                        << extensions << attributeDeclaration.str()
343                        << "layout(set = 0, binding = 0, std430) buffer outBuffer\n"
344                           "{\n"
345                           "\t"
346                        << outType << " outData[" << (m_numVertices * numValues) * m_numInstances
347                        << "];\n"
348                           "};\n\n"
349                           "void main (void)\n"
350                           "{\n"
351                        << attributeUse.str()
352                        << "\tgl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n"
353                           "}\n";
354 
355     programCollection.glslSources.add("vertex") << glu::VertexSource(vertexShaderSource.str());
356 
357     fragmentShaderSource << "#version 310 es\n"
358                             "precision highp float;\n"
359                             "layout(location = 0) out vec4 fragColor;\n"
360                             "void main (void)\n"
361                             "{\n"
362                             "\tfragColor = vec4(1.0);\n"
363                             "}\n";
364 
365     programCollection.glslSources.add("fragment") << glu::FragmentSource(fragmentShaderSource.str());
366 }
367 
368 // DrawAccessTest
369 
DrawAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)370 DrawAccessTest::DrawAccessTest(tcu::TestContext &testContext, const std::string &name, VkFormat inputFormat,
371                                uint32_t numVertexValues, uint32_t numInstanceValues, uint32_t numVertices,
372                                uint32_t numInstances)
373 
374     : VertexAccessTest(testContext, name, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances)
375 {
376 }
377 
createInstance(Context & context) const378 TestInstance *DrawAccessTest::createInstance(Context &context) const
379 {
380 #ifdef CTS_USES_VULKANSC
381     de::MovePtr<CustomInstance> customInstance(new CustomInstance(createCustomInstanceFromContext(context)));
382 #endif // CTS_USES_VULKANSC
383 
384     Move<VkDevice> device = createRobustBufferAccessDevice(context
385 #ifdef CTS_USES_VULKANSC
386                                                            ,
387                                                            *customInstance
388 #endif // CTS_USES_VULKANSC
389     );
390 #ifndef CTS_USES_VULKANSC
391     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
392         new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
393                          context.getTestContext().getCommandLine()));
394 #else
395     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
396         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
397             new DeviceDriverSC(context.getPlatformInterface(), *customInstance, *device,
398                                context.getTestContext().getCommandLine(), context.getResourceInterface(),
399                                context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
400                                context.getUsedApiVersion()),
401             vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
402 #endif // CTS_USES_VULKANSC
403 
404     return new DrawAccessInstance(context, device,
405 #ifdef CTS_USES_VULKANSC
406                                   customInstance,
407 #endif // CTS_USES_VULKANSC
408                                   deviceDriver, m_inputFormat, m_numVertexValues, m_numInstanceValues, m_numVertices,
409                                   m_numInstances);
410 }
411 
412 // DrawIndexedAccessTest
413 
414 const uint32_t lastIndexOutOfBounds[] = {
415     0, 1, 2, 3, 4, 100, // Indices of 100 and above are out of bounds
416 };
417 const uint32_t indicesOutOfBounds[] = {
418     0, 100, 2, 101, 3, 102, // Indices of 100 and above are out of bounds
419 };
420 const uint32_t triangleOutOfBounds[] = {
421     100, 101, 102, 3, 4, 5, // Indices of 100 and above are out of bounds
422 };
423 
424 const std::vector<uint32_t> DrawIndexedAccessTest::s_indexConfigs[INDEX_CONFIG_COUNT] = {
425     std::vector<uint32_t>(lastIndexOutOfBounds, lastIndexOutOfBounds + DE_LENGTH_OF_ARRAY(lastIndexOutOfBounds)),
426     std::vector<uint32_t>(indicesOutOfBounds, indicesOutOfBounds + DE_LENGTH_OF_ARRAY(indicesOutOfBounds)),
427     std::vector<uint32_t>(triangleOutOfBounds, triangleOutOfBounds + DE_LENGTH_OF_ARRAY(triangleOutOfBounds)),
428 };
429 
DrawIndexedAccessTest(tcu::TestContext & testContext,const std::string & name,VkFormat inputFormat,IndexConfig indexConfig)430 DrawIndexedAccessTest::DrawIndexedAccessTest(tcu::TestContext &testContext, const std::string &name,
431                                              VkFormat inputFormat, IndexConfig indexConfig)
432 
433     : VertexAccessTest(testContext, name, inputFormat,
434                        getNumUsedChannels(mapVkFormat(inputFormat).order) *
435                            (uint32_t)s_indexConfigs[indexConfig].size() * 2, // numVertexValues
436                        getNumUsedChannels(mapVkFormat(inputFormat).order),   // numInstanceValues
437                        (uint32_t)s_indexConfigs[indexConfig].size(),         // numVertices
438                        1)                                                    // numInstances
439     , m_indexConfig(indexConfig)
440 {
441 }
442 
createInstance(Context & context) const443 TestInstance *DrawIndexedAccessTest::createInstance(Context &context) const
444 {
445 #ifdef CTS_USES_VULKANSC
446     de::MovePtr<CustomInstance> customInstance(new CustomInstance(createCustomInstanceFromContext(context)));
447 #endif // CTS_USES_VULKANSC
448 
449     Move<VkDevice> device = createRobustBufferAccessDevice(context
450 #ifdef CTS_USES_VULKANSC
451                                                            ,
452                                                            *customInstance
453 #endif // CTS_USES_VULKANSC
454     );
455 #ifndef CTS_USES_VULKANSC
456     de::MovePtr<vk::DeviceDriver> deviceDriver = de::MovePtr<DeviceDriver>(
457         new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion(),
458                          context.getTestContext().getCommandLine()));
459 #else
460     de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver =
461         de::MovePtr<DeviceDriverSC, DeinitDeviceDeleter>(
462             new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device,
463                                context.getTestContext().getCommandLine(), context.getResourceInterface(),
464                                context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(),
465                                context.getUsedApiVersion()),
466             vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
467 #endif // CTS_USES_VULKANSC
468 
469     return new DrawIndexedAccessInstance(context, device,
470 #ifdef CTS_USES_VULKANSC
471                                          customInstance,
472 #endif // CTS_USES_VULKANSC
473                                          deviceDriver, m_inputFormat, m_numVertexValues, m_numInstanceValues,
474                                          m_numVertices, m_numInstances, s_indexConfigs[m_indexConfig]);
475 }
476 
477 // VertexAccessInstance
478 
VertexAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances,const std::vector<uint32_t> & indices)479 VertexAccessInstance::VertexAccessInstance(Context &context, Move<VkDevice> device,
480 #ifndef CTS_USES_VULKANSC
481                                            de::MovePtr<vk::DeviceDriver> deviceDriver,
482 #else
483                                            de::MovePtr<CustomInstance> customInstance,
484                                            de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
485 #endif // CTS_USES_VULKANSC
486                                            VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
487                                            uint32_t numVertices, uint32_t numInstances,
488                                            const std::vector<uint32_t> &indices)
489 
490     : vkt::TestInstance(context)
491 #ifdef CTS_USES_VULKANSC
492     , m_customInstance(customInstance)
493 #endif // CTS_USES_VULKANSC
494     , m_device(device)
495     , m_deviceDriver(deviceDriver)
496     , m_inputFormat(inputFormat)
497     , m_numVertexValues(numVertexValues)
498     , m_numInstanceValues(numInstanceValues)
499     , m_numVertices(numVertices)
500     , m_numInstances(numInstances)
501 {
502     const DeviceInterface &vk       = *m_deviceDriver;
503     const uint32_t queueFamilyIndex = context.getUniversalQueueFamilyIndex();
504     const auto &vki                 = context.getInstanceInterface();
505     const VkPhysicalDevice physicalDevice =
506         chooseDevice(vki, context.getInstance(), context.getTestContext().getCommandLine());
507     SimpleAllocator memAlloc(vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
508     const uint32_t formatSizeInBytes = tcu::getPixelSize(mapVkFormat(m_inputFormat));
509 
510     // Check storage support
511     if (!context.getDeviceFeatures().vertexPipelineStoresAndAtomics)
512     {
513         TCU_THROW(NotSupportedError, "Stores not supported in vertex stage");
514     }
515 
516     if (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT)
517     {
518         const VkFormatProperties formatProperties =
519             getPhysicalDeviceFormatProperties(vki, physicalDevice, m_inputFormat);
520         context.requireDeviceFunctionality("VK_EXT_shader_image_atomic_int64");
521 
522         if ((formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) !=
523             VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)
524             TCU_THROW(NotSupportedError, "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT not supported");
525     }
526 
527     const VkVertexInputAttributeDescription attributes[] = {
528         // input rate: vertex
529         {
530             0u,            // uint32_t location;
531             0u,            // uint32_t binding;
532             m_inputFormat, // VkFormat format;
533             0u,            // uint32_t offset;
534         },
535         {
536             1u,                // uint32_t location;
537             0u,                // uint32_t binding;
538             m_inputFormat,     // VkFormat format;
539             formatSizeInBytes, // uint32_t offset;
540         },
541 
542         // input rate: instance
543         {
544             2u,            // uint32_t location;
545             1u,            // uint32_t binding;
546             m_inputFormat, // VkFormat format;
547             0u,            // uint32_t offset;
548         },
549 
550         // Attribute for vertex number
551         {
552             3u,                 // uint32_t location;
553             2u,                 // uint32_t binding;
554             VK_FORMAT_R32_SINT, // VkFormat format;
555             0,                  // uint32_t offset;
556         },
557     };
558 
559     const VkVertexInputBindingDescription bindings[] = {
560         {
561             0u,                         // uint32_t binding;
562             formatSizeInBytes * 2,      // uint32_t stride;
563             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
564         },
565         {
566             1u,                           // uint32_t binding;
567             formatSizeInBytes,            // uint32_t stride;
568             VK_VERTEX_INPUT_RATE_INSTANCE // VkVertexInputRate inputRate;
569         },
570         {
571             2u,                         // uint32_t binding;
572             sizeof(int32_t),            // uint32_t stride;
573             VK_VERTEX_INPUT_RATE_VERTEX // VkVertexInputRate inputRate;
574         },
575     };
576 
577     m_vertexInputBindings =
578         std::vector<VkVertexInputBindingDescription>(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings));
579     m_vertexInputAttributes =
580         std::vector<VkVertexInputAttributeDescription>(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes));
581 
582     // Create vertex buffer for vertex input rate
583     {
584         VkMemoryRequirements bufferMemoryReqs;
585 
586         m_vertexRateBufferSize = getBufferSizeInBytes(
587             m_numVertexValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
588 
589         const VkBufferCreateInfo vertexRateBufferParams = {
590             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
591             DE_NULL,                              // const void* pNext;
592             0u,                                   // VkBufferCreateFlags flags;
593             m_vertexRateBufferSize,               // VkDeviceSize size;
594             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
595             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
596             1u,                                   // uint32_t queueFamilyIndexCount;
597             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
598         };
599 
600         m_vertexRateBuffer          = createBuffer(vk, *m_device, &vertexRateBufferParams);
601         bufferMemoryReqs            = getBufferMemoryRequirements(vk, *m_device, *m_vertexRateBuffer);
602         m_vertexRateBufferAllocSize = bufferMemoryReqs.size;
603         m_vertexRateBufferAlloc     = memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
604 
605         VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexRateBuffer, m_vertexRateBufferAlloc->getMemory(),
606                                      m_vertexRateBufferAlloc->getOffset()));
607         populateBufferWithTestValues(m_vertexRateBufferAlloc->getHostPtr(), (uint32_t)m_vertexRateBufferAllocSize,
608                                      m_inputFormat);
609         flushMappedMemoryRange(vk, *m_device, m_vertexRateBufferAlloc->getMemory(),
610                                m_vertexRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
611     }
612 
613     // Create vertex buffer for instance input rate
614     {
615         VkMemoryRequirements bufferMemoryReqs;
616 
617         m_instanceRateBufferSize = getBufferSizeInBytes(
618             m_numInstanceValues, m_inputFormat); // All formats used in this test suite are 32-bit based.
619 
620         const VkBufferCreateInfo instanceRateBufferParams = {
621             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
622             DE_NULL,                              // const void* pNext;
623             0u,                                   // VkBufferCreateFlags flags;
624             m_instanceRateBufferSize,             // VkDeviceSize size;
625             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
626             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
627             1u,                                   // uint32_t queueFamilyIndexCount;
628             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
629         };
630 
631         m_instanceRateBuffer          = createBuffer(vk, *m_device, &instanceRateBufferParams);
632         bufferMemoryReqs              = getBufferMemoryRequirements(vk, *m_device, *m_instanceRateBuffer);
633         m_instanceRateBufferAllocSize = bufferMemoryReqs.size;
634         m_instanceRateBufferAlloc     = memAlloc.allocate(bufferMemoryReqs, MemoryRequirement::HostVisible);
635 
636         VK_CHECK(vk.bindBufferMemory(*m_device, *m_instanceRateBuffer, m_instanceRateBufferAlloc->getMemory(),
637                                      m_instanceRateBufferAlloc->getOffset()));
638         populateBufferWithTestValues(m_instanceRateBufferAlloc->getHostPtr(), (uint32_t)m_instanceRateBufferAllocSize,
639                                      m_inputFormat);
640         flushMappedMemoryRange(vk, *m_device, m_instanceRateBufferAlloc->getMemory(),
641                                m_instanceRateBufferAlloc->getOffset(), VK_WHOLE_SIZE);
642     }
643 
644     // Create vertex buffer that stores the vertex number (from 0 to m_numVertices - 1)
645     {
646         m_vertexNumBufferSize = 128 * sizeof(int32_t); // Allocate enough device memory for all indices (0 to 127).
647 
648         const VkBufferCreateInfo vertexNumBufferParams = {
649             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
650             DE_NULL,                              // const void* pNext;
651             0u,                                   // VkBufferCreateFlags flags;
652             m_vertexNumBufferSize,                // VkDeviceSize size;
653             VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,    // VkBufferUsageFlags usage;
654             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
655             1u,                                   // uint32_t queueFamilyIndexCount;
656             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
657         };
658 
659         m_vertexNumBuffer      = createBuffer(vk, *m_device, &vertexNumBufferParams);
660         m_vertexNumBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_vertexNumBuffer),
661                                                    MemoryRequirement::HostVisible);
662 
663         VK_CHECK(vk.bindBufferMemory(*m_device, *m_vertexNumBuffer, m_vertexNumBufferAlloc->getMemory(),
664                                      m_vertexNumBufferAlloc->getOffset()));
665     }
666 
667     // Create index buffer if required
668     if (!indices.empty())
669     {
670         m_indexBufferSize = sizeof(uint32_t) * indices.size();
671 
672         const VkBufferCreateInfo indexBufferParams = {
673             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
674             DE_NULL,                              // const void* pNext;
675             0u,                                   // VkBufferCreateFlags flags;
676             m_indexBufferSize,                    // VkDeviceSize size;
677             VK_BUFFER_USAGE_INDEX_BUFFER_BIT,     // VkBufferUsageFlags usage;
678             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
679             1u,                                   // uint32_t queueFamilyIndexCount;
680             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
681         };
682 
683         m_indexBuffer      = createBuffer(vk, *m_device, &indexBufferParams);
684         m_indexBufferAlloc = memAlloc.allocate(getBufferMemoryRequirements(vk, *m_device, *m_indexBuffer),
685                                                MemoryRequirement::HostVisible);
686 
687         VK_CHECK(vk.bindBufferMemory(*m_device, *m_indexBuffer, m_indexBufferAlloc->getMemory(),
688                                      m_indexBufferAlloc->getOffset()));
689         deMemcpy(m_indexBufferAlloc->getHostPtr(), indices.data(), (size_t)m_indexBufferSize);
690         flushMappedMemoryRange(vk, *m_device, m_indexBufferAlloc->getMemory(), m_indexBufferAlloc->getOffset(),
691                                VK_WHOLE_SIZE);
692     }
693 
694     // Create result ssbo
695     {
696         const int numChannels = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
697 
698         m_outBufferSize = getBufferSizeInBytes(m_numVertices * m_numInstances * numChannels * 3, VK_FORMAT_R32_UINT);
699 
700         const VkBufferCreateInfo outBufferParams = {
701             VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, // VkStructureType sType;
702             DE_NULL,                              // const void* pNext;
703             0u,                                   // VkBufferCreateFlags flags;
704             m_outBufferSize,                      // VkDeviceSize size;
705             VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,   // VkBufferUsageFlags usage;
706             VK_SHARING_MODE_EXCLUSIVE,            // VkSharingMode sharingMode;
707             1u,                                   // uint32_t queueFamilyIndexCount;
708             &queueFamilyIndex                     // const uint32_t* pQueueFamilyIndices;
709         };
710 
711         m_outBuffer                             = createBuffer(vk, *m_device, &outBufferParams);
712         const VkMemoryRequirements requirements = getBufferMemoryRequirements(vk, *m_device, *m_outBuffer);
713         m_outBufferAlloc                        = memAlloc.allocate(requirements, MemoryRequirement::HostVisible);
714         m_outBufferAllocSize                    = requirements.size;
715 
716         VK_CHECK(
717             vk.bindBufferMemory(*m_device, *m_outBuffer, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset()));
718         deMemset(m_outBufferAlloc->getHostPtr(), 0xFF, (size_t)m_outBufferSize);
719         flushMappedMemoryRange(vk, *m_device, m_outBufferAlloc->getMemory(), m_outBufferAlloc->getOffset(),
720                                VK_WHOLE_SIZE);
721     }
722 
723     // Create descriptor set data
724     {
725         DescriptorPoolBuilder descriptorPoolBuilder;
726         descriptorPoolBuilder.addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1u);
727         m_descriptorPool =
728             descriptorPoolBuilder.build(vk, *m_device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u);
729 
730         DescriptorSetLayoutBuilder setLayoutBuilder;
731         setLayoutBuilder.addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT);
732         m_descriptorSetLayout = setLayoutBuilder.build(vk, *m_device);
733 
734         const VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {
735             VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, // VkStructureType sType;
736             DE_NULL,                                        // const void* pNext;
737             *m_descriptorPool,                              // VkDescriptorPool desciptorPool;
738             1u,                                             // uint32_t setLayoutCount;
739             &m_descriptorSetLayout.get()                    // const VkDescriptorSetLayout* pSetLayouts;
740         };
741 
742         m_descriptorSet = allocateDescriptorSet(vk, *m_device, &descriptorSetAllocateInfo);
743 
744         const VkDescriptorBufferInfo outBufferDescriptorInfo =
745             makeDescriptorBufferInfo(*m_outBuffer, 0ull, VK_WHOLE_SIZE);
746 
747         DescriptorSetUpdateBuilder setUpdateBuilder;
748         setUpdateBuilder.writeSingle(*m_descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0),
749                                      VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, &outBufferDescriptorInfo);
750         setUpdateBuilder.update(vk, *m_device);
751     }
752 
753     // Create fence
754     {
755         const VkFenceCreateInfo fenceParams = {
756             VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, // VkStructureType sType;
757             DE_NULL,                             // const void* pNext;
758             0u                                   // VkFenceCreateFlags flags;
759         };
760 
761         m_fence = createFence(vk, *m_device, &fenceParams);
762     }
763 
764     // Get queue
765     vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &m_queue);
766 
767     // Setup graphics test environment
768     {
769         GraphicsEnvironment::DrawConfig drawConfig;
770 
771         drawConfig.vertexBuffers.push_back(*m_vertexRateBuffer);
772         drawConfig.vertexBuffers.push_back(*m_instanceRateBuffer);
773         drawConfig.vertexBuffers.push_back(*m_vertexNumBuffer);
774 
775         drawConfig.vertexCount   = m_numVertices;
776         drawConfig.instanceCount = m_numInstances;
777         drawConfig.indexBuffer   = *m_indexBuffer;
778         drawConfig.indexCount    = (uint32_t)(m_indexBufferSize / sizeof(uint32_t));
779 
780         m_graphicsTestEnvironment = de::MovePtr<GraphicsEnvironment>(new GraphicsEnvironment(
781             m_context, *m_deviceDriver, *m_device, *m_descriptorSetLayout, *m_descriptorSet,
782             GraphicsEnvironment::VertexBindings(bindings, bindings + DE_LENGTH_OF_ARRAY(bindings)),
783             GraphicsEnvironment::VertexAttributes(attributes, attributes + DE_LENGTH_OF_ARRAY(attributes)),
784             drawConfig));
785     }
786 }
787 
~VertexAccessInstance(void)788 VertexAccessInstance::~VertexAccessInstance(void)
789 {
790 }
791 
iterate(void)792 tcu::TestStatus VertexAccessInstance::iterate(void)
793 {
794     const DeviceInterface &vk           = *m_deviceDriver;
795     const vk::VkCommandBuffer cmdBuffer = m_graphicsTestEnvironment->getCommandBuffer();
796 
797     // Initialize vertex ids
798     {
799         uint32_t *bufferPtr = reinterpret_cast<uint32_t *>(m_vertexNumBufferAlloc->getHostPtr());
800         deMemset(bufferPtr, 0, (size_t)m_vertexNumBufferSize);
801 
802         initVertexIds(bufferPtr, (size_t)(m_vertexNumBufferSize / sizeof(uint32_t)));
803 
804         flushMappedMemoryRange(vk, *m_device, m_vertexNumBufferAlloc->getMemory(), m_vertexNumBufferAlloc->getOffset(),
805                                VK_WHOLE_SIZE);
806     }
807 
808     // Submit command buffer
809     {
810         const VkSubmitInfo submitInfo = {
811             VK_STRUCTURE_TYPE_SUBMIT_INFO, // VkStructureType sType;
812             DE_NULL,                       // const void* pNext;
813             0u,                            // uint32_t waitSemaphoreCount;
814             DE_NULL,                       // const VkSemaphore* pWaitSemaphores;
815             DE_NULL,                       // const VkPIpelineStageFlags* pWaitDstStageMask;
816             1u,                            // uint32_t commandBufferCount;
817             &cmdBuffer,                    // const VkCommandBuffer* pCommandBuffers;
818             0u,                            // uint32_t signalSemaphoreCount;
819             DE_NULL                        // const VkSemaphore* pSignalSemaphores;
820         };
821 
822         VK_CHECK(vk.resetFences(*m_device, 1, &m_fence.get()));
823         VK_CHECK(vk.queueSubmit(m_queue, 1, &submitInfo, *m_fence));
824         VK_CHECK(vk.waitForFences(*m_device, 1, &m_fence.get(), true, ~(0ull) /* infinity */));
825     }
826 
827     // Prepare result buffer for read
828     {
829         const VkMappedMemoryRange outBufferRange = {
830             VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, //  VkStructureType sType;
831             DE_NULL,                               //  const void* pNext;
832             m_outBufferAlloc->getMemory(),         //  VkDeviceMemory mem;
833             0ull,                                  //  VkDeviceSize offset;
834             m_outBufferAllocSize,                  //  VkDeviceSize size;
835         };
836 
837         VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
838     }
839 
840     if (verifyResult())
841         return tcu::TestStatus::pass("All values OK");
842     else
843         return tcu::TestStatus::fail("Invalid value(s) found");
844 }
845 
verifyResult(void)846 bool VertexAccessInstance::verifyResult(void)
847 {
848     std::ostringstream logMsg;
849     const DeviceInterface &vk          = *m_deviceDriver;
850     tcu::TestLog &log                  = m_context.getTestContext().getLog();
851     const uint32_t numChannels         = getNumUsedChannels(mapVkFormat(m_inputFormat).order);
852     const uint32_t numScalarsPerVertex = numChannels * 3; // Use 3 identical attributes
853     void *outDataPtr                   = m_outBufferAlloc->getHostPtr();
854     const uint32_t outValueSize        = static_cast<uint32_t>(
855         (m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT) ? sizeof(uint64_t) :
856                                                                                               sizeof(uint32_t));
857     bool allOk = true;
858 
859     const VkMappedMemoryRange outBufferRange = {
860         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, // VkStructureType sType;
861         DE_NULL,                               // const void* pNext;
862         m_outBufferAlloc->getMemory(),         // VkDeviceMemory mem;
863         m_outBufferAlloc->getOffset(),         // VkDeviceSize offset;
864         m_outBufferAllocSize,                  // VkDeviceSize size;
865     };
866 
867     VK_CHECK(vk.invalidateMappedMemoryRanges(*m_device, 1u, &outBufferRange));
868 
869     for (uint32_t valueNdx = 0; valueNdx < m_outBufferSize / outValueSize; valueNdx++)
870     {
871         uint32_t numInBufferValues;
872         void *inBufferPtr;
873         VkDeviceSize inBufferAllocSize;
874         uint32_t inBufferValueIndex;
875         bool isOutOfBoundsAccess      = false;
876         const uint32_t attributeIndex = (valueNdx / numChannels) % 3;
877         uint32_t *ptr32               = (uint32_t *)outDataPtr;
878         uint64_t *ptr64               = (uint64_t *)outDataPtr;
879         const void *outValuePtr =
880             ((m_inputFormat == VK_FORMAT_R64_UINT || m_inputFormat == VK_FORMAT_R64_SINT) ? (void *)(ptr64 + valueNdx) :
881                                                                                             (void *)(ptr32 + valueNdx));
882 
883         if (attributeIndex == 2)
884         {
885             // Instance rate
886             const uint32_t elementIndex = valueNdx / (numScalarsPerVertex * m_numVertices); // instance id
887 
888             numInBufferValues  = m_numInstanceValues;
889             inBufferPtr        = m_instanceRateBufferAlloc->getHostPtr();
890             inBufferAllocSize  = m_instanceRateBufferAllocSize;
891             inBufferValueIndex = (elementIndex * numChannels) + (valueNdx % numScalarsPerVertex) - (2 * numChannels);
892         }
893         else
894         {
895             // Vertex rate
896             const uint32_t vertexNdx    = valueNdx / numScalarsPerVertex;
897             const uint32_t instanceNdx  = vertexNdx / m_numVertices;
898             const uint32_t elementIndex = valueNdx / numScalarsPerVertex; // vertex id
899 
900             numInBufferValues  = m_numVertexValues;
901             inBufferPtr        = m_vertexRateBufferAlloc->getHostPtr();
902             inBufferAllocSize  = m_vertexRateBufferAllocSize;
903             inBufferValueIndex = (getIndex(elementIndex) * (numChannels * 2)) + (valueNdx % numScalarsPerVertex) -
904                                  instanceNdx * (m_numVertices * numChannels * 2);
905 
906             // Binding 0 contains two attributes, so bounds checking for attribute 0 must also consider attribute 1 to determine if the binding is out of bounds.
907             if ((attributeIndex == 0) && (numInBufferValues >= numChannels))
908                 numInBufferValues -= numChannels;
909         }
910 
911         isOutOfBoundsAccess = (inBufferValueIndex >= numInBufferValues);
912 
913         const int32_t distanceToOutOfBounds =
914             (int32_t)outValueSize * ((int32_t)numInBufferValues - (int32_t)inBufferValueIndex);
915 
916         if (!isOutOfBoundsAccess && (distanceToOutOfBounds < 16))
917             isOutOfBoundsAccess = (((inBufferValueIndex / numChannels) + 1) * numChannels > numInBufferValues);
918 
919         // Log value information
920         {
921             // Vertex separator
922             if (valueNdx && valueNdx % numScalarsPerVertex == 0)
923                 logMsg << "\n";
924 
925             logMsg << "\n" << valueNdx << ": Value ";
926 
927             // Result index and value
928             if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
929                 logValue(logMsg, outValuePtr, VK_FORMAT_R32_SFLOAT, 4);
930             else
931                 logValue(logMsg, outValuePtr, m_inputFormat, 4);
932 
933             // Attribute name
934             logMsg << "\tfrom attr" << attributeIndex;
935             if (numChannels > 1)
936                 logMsg << "[" << valueNdx % numChannels << "]";
937 
938             // Input rate
939             if (attributeIndex == 2)
940                 logMsg << "\tinstance rate";
941             else
942                 logMsg << "\tvertex rate";
943         }
944 
945         if (isOutOfBoundsAccess)
946         {
947             const bool isValidValue =
948                 isValueWithinVertexBufferOrZero(inBufferPtr, inBufferAllocSize, outValuePtr, inBufferValueIndex);
949 
950             logMsg << "\t(out of bounds)";
951 
952             if (!isValidValue)
953             {
954                 // Check if we are satisfying the [0, 0, 0, x] pattern, where x may be either 0 or 1,
955                 // or the maximum representable positive integer value (if the format is integer-based).
956 
957                 const bool canMatchVec4Pattern =
958                     ((valueNdx % numChannels == 3) || m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32);
959                 bool matchesVec4Pattern = false;
960 
961                 if (canMatchVec4Pattern)
962                 {
963                     if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
964                         matchesVec4Pattern = verifyOutOfBoundsVec4(outValuePtr, m_inputFormat);
965                     else
966                         matchesVec4Pattern = verifyOutOfBoundsVec4(((uint32_t *)outValuePtr) - 3, m_inputFormat);
967                 }
968 
969                 if (!canMatchVec4Pattern || !matchesVec4Pattern)
970                 {
971                     logMsg << ", Failed: expected a value within the buffer range or 0";
972 
973                     if (canMatchVec4Pattern)
974                         logMsg << ", or the [0, 0, 0, x] pattern";
975 
976                     allOk = false;
977                 }
978             }
979         }
980         else if (!isExpectedValueFromVertexBuffer(inBufferPtr, inBufferValueIndex, m_inputFormat, outValuePtr))
981         {
982             logMsg << ", Failed: unexpected value";
983             allOk = false;
984         }
985     }
986     log << tcu::TestLog::Message << logMsg.str() << tcu::TestLog::EndMessage;
987 
988     return allOk;
989 }
990 
isValueWithinVertexBufferOrZero(void * vertexBuffer,VkDeviceSize vertexBufferSize,const void * value,uint32_t valueIndex)991 bool VertexAccessInstance::isValueWithinVertexBufferOrZero(void *vertexBuffer, VkDeviceSize vertexBufferSize,
992                                                            const void *value, uint32_t valueIndex)
993 {
994     if (m_inputFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
995     {
996         const float normValue      = *reinterpret_cast<const float *>(value);
997         const uint32_t scalarIndex = valueIndex % 4;
998         const bool isAlpha         = (scalarIndex == 3);
999         uint32_t encodedValue;
1000 
1001         if (isAlpha)
1002             encodedValue = deMin32(uint32_t(deFloatRound(normValue * 0x3u)), 0x3u);
1003         else
1004             encodedValue = deMin32(uint32_t(deFloatRound(normValue * 0x3FFu)), 0x3FFu);
1005 
1006         if (encodedValue == 0)
1007             return true;
1008 
1009         for (uint32_t i = 0; i < vertexBufferSize / 4; i++)
1010         {
1011             const uint32_t packedValue = reinterpret_cast<uint32_t *>(vertexBuffer)[i];
1012             uint32_t unpackedValue;
1013 
1014             if (scalarIndex < 3)
1015                 unpackedValue = (packedValue >> (10 * scalarIndex)) & 0x3FFu;
1016             else
1017                 unpackedValue = (packedValue >> 30) & 0x3u;
1018 
1019             if (unpackedValue == encodedValue)
1020                 return true;
1021         }
1022 
1023         return false;
1024     }
1025     else
1026     {
1027         return isValueWithinBufferOrZero(vertexBuffer, vertexBufferSize, value, sizeof(uint32_t));
1028     }
1029 }
1030 
isExpectedValueFromVertexBuffer(const void * vertexBuffer,uint32_t vertexIndex,VkFormat vertexFormat,const void * value)1031 bool VertexAccessInstance::isExpectedValueFromVertexBuffer(const void *vertexBuffer, uint32_t vertexIndex,
1032                                                            VkFormat vertexFormat, const void *value)
1033 {
1034     if (isUintFormat(vertexFormat))
1035     {
1036         if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1037         {
1038             const uint64_t *bufferPtr = reinterpret_cast<const uint64_t *>(vertexBuffer);
1039             return bufferPtr[vertexIndex] == *reinterpret_cast<const uint64_t *>(value);
1040         }
1041         else
1042         {
1043             const uint32_t *bufferPtr = reinterpret_cast<const uint32_t *>(vertexBuffer);
1044             return bufferPtr[vertexIndex] == *reinterpret_cast<const uint32_t *>(value);
1045         }
1046     }
1047     else if (isIntFormat(vertexFormat))
1048     {
1049         if (vertexFormat == VK_FORMAT_R64_UINT || vertexFormat == VK_FORMAT_R64_SINT)
1050         {
1051             const int64_t *bufferPtr = reinterpret_cast<const int64_t *>(vertexBuffer);
1052             return bufferPtr[vertexIndex] == *reinterpret_cast<const int64_t *>(value);
1053         }
1054         else
1055         {
1056             const int32_t *bufferPtr = reinterpret_cast<const int32_t *>(vertexBuffer);
1057             return bufferPtr[vertexIndex] == *reinterpret_cast<const int32_t *>(value);
1058         }
1059     }
1060     else if (isFloatFormat(vertexFormat))
1061     {
1062         const float *bufferPtr = reinterpret_cast<const float *>(vertexBuffer);
1063 
1064         return areEqual(bufferPtr[vertexIndex], *reinterpret_cast<const float *>(value));
1065     }
1066     else if (vertexFormat == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1067     {
1068         const uint32_t *bufferPtr  = reinterpret_cast<const uint32_t *>(vertexBuffer);
1069         const uint32_t packedValue = bufferPtr[vertexIndex / 4];
1070         const uint32_t scalarIndex = vertexIndex % 4;
1071         float normValue;
1072 
1073         if (scalarIndex < 3)
1074             normValue = float((packedValue >> (10 * scalarIndex)) & 0x3FFu) / 0x3FFu;
1075         else
1076             normValue = float(packedValue >> 30) / 0x3u;
1077 
1078         return areEqual(normValue, *reinterpret_cast<const float *>(value));
1079     }
1080 
1081     DE_ASSERT(false);
1082     return false;
1083 }
1084 
getBufferSizeInBytes(uint32_t numScalars,VkFormat format)1085 VkDeviceSize VertexAccessInstance::getBufferSizeInBytes(uint32_t numScalars, VkFormat format)
1086 {
1087     if (isUintFormat(format) || isIntFormat(format) || isFloatFormat(format))
1088     {
1089         return numScalars * ((format == VK_FORMAT_R64_UINT || format == VK_FORMAT_R64_SINT) ? 8 : 4);
1090     }
1091     else if (format == VK_FORMAT_A2B10G10R10_UNORM_PACK32)
1092     {
1093         DE_ASSERT(numScalars % 4 == 0);
1094         return numScalars;
1095     }
1096 
1097     DE_ASSERT(false);
1098     return 0;
1099 }
1100 
1101 // DrawAccessInstance
1102 
DrawAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances)1103 DrawAccessInstance::DrawAccessInstance(Context &context, Move<VkDevice> device,
1104 #ifndef CTS_USES_VULKANSC
1105                                        de::MovePtr<vk::DeviceDriver> deviceDriver,
1106 #else
1107                                        de::MovePtr<CustomInstance> customInstance,
1108                                        de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> deviceDriver,
1109 #endif // CTS_USES_VULKANSC
1110                                        VkFormat inputFormat, uint32_t numVertexValues, uint32_t numInstanceValues,
1111                                        uint32_t numVertices, uint32_t numInstances)
1112     : VertexAccessInstance(context, device,
1113 #ifdef CTS_USES_VULKANSC
1114                            customInstance,
1115 #endif // CTS_USES_VULKANSC
1116                            deviceDriver, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances,
1117                            std::vector<uint32_t>()) // No index buffer
1118 {
1119 }
1120 
initVertexIds(uint32_t * indicesPtr,size_t indexCount)1121 void DrawAccessInstance::initVertexIds(uint32_t *indicesPtr, size_t indexCount)
1122 {
1123     for (uint32_t i = 0; i < indexCount; i++)
1124         indicesPtr[i] = i;
1125 }
1126 
getIndex(uint32_t vertexNum) const1127 uint32_t DrawAccessInstance::getIndex(uint32_t vertexNum) const
1128 {
1129     return vertexNum;
1130 }
1131 
1132 // DrawIndexedAccessInstance
1133 
DrawIndexedAccessInstance(Context & context,Move<VkDevice> device,de::MovePtr<vk::DeviceDriver> deviceDriver,VkFormat inputFormat,uint32_t numVertexValues,uint32_t numInstanceValues,uint32_t numVertices,uint32_t numInstances,const std::vector<uint32_t> & indices)1134 DrawIndexedAccessInstance::DrawIndexedAccessInstance(Context &context, Move<VkDevice> device,
1135 #ifndef CTS_USES_VULKANSC
1136                                                      de::MovePtr<vk::DeviceDriver> deviceDriver,
1137 #else
1138                                                      de::MovePtr<CustomInstance> customInstance,
1139                                                      de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter>
1140                                                          deviceDriver,
1141 #endif // CTS_USES_VULKANSC
1142                                                      VkFormat inputFormat, uint32_t numVertexValues,
1143                                                      uint32_t numInstanceValues, uint32_t numVertices,
1144                                                      uint32_t numInstances, const std::vector<uint32_t> &indices)
1145     : VertexAccessInstance(context, device,
1146 #ifdef CTS_USES_VULKANSC
1147                            customInstance,
1148 #endif // CTS_USES_VULKANSC
1149                            deviceDriver, inputFormat, numVertexValues, numInstanceValues, numVertices, numInstances,
1150                            indices)
1151     , m_indices(indices)
1152 {
1153 }
1154 
initVertexIds(uint32_t * indicesPtr,size_t indexCount)1155 void DrawIndexedAccessInstance::initVertexIds(uint32_t *indicesPtr, size_t indexCount)
1156 {
1157     DE_UNREF(indexCount);
1158 
1159     for (uint32_t i = 0; i < m_indices.size(); i++)
1160     {
1161         DE_ASSERT(m_indices[i] < indexCount);
1162 
1163         indicesPtr[m_indices[i]] = i;
1164     }
1165 }
1166 
getIndex(uint32_t vertexNum) const1167 uint32_t DrawIndexedAccessInstance::getIndex(uint32_t vertexNum) const
1168 {
1169     DE_ASSERT(vertexNum < (uint32_t)m_indices.size());
1170 
1171     return m_indices[vertexNum];
1172 }
1173 
1174 // Test node creation functions
1175 
createDrawTests(tcu::TestContext & testCtx,VkFormat format)1176 static tcu::TestCaseGroup *createDrawTests(tcu::TestContext &testCtx, VkFormat format)
1177 {
1178     struct TestConfig
1179     {
1180         std::string name;
1181         VkFormat inputFormat;
1182         uint32_t numVertexValues;
1183         uint32_t numInstanceValues;
1184         uint32_t numVertices;
1185         uint32_t numInstances;
1186     };
1187 
1188     const uint32_t numChannels = getNumUsedChannels(mapVkFormat(format).order);
1189 
1190     const TestConfig testConfigs[] = {
1191         // name                                            format    numVertexValues            numInstanceValues    numVertices        numInstances
1192         // Create data for 6 vertices, draw 9 vertices
1193         {"vertex_out_of_bounds", format, numChannels * 2 * 6, numChannels, 9, 1},
1194         // Create data for half a vertex, draw 3 vertices
1195         {"vertex_incomplete", format, numChannels, numChannels, 3, 1},
1196         // Create data for 1 instance, draw 3 instances
1197         {"instance_out_of_bounds", format, numChannels * 2 * 9, numChannels, 3, 3},
1198     };
1199 
1200     de::MovePtr<tcu::TestCaseGroup> drawTests(new tcu::TestCaseGroup(testCtx, "draw"));
1201 
1202     for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1203     {
1204         const TestConfig &config = testConfigs[i];
1205 
1206         drawTests->addChild(new DrawAccessTest(testCtx, config.name, config.inputFormat, config.numVertexValues,
1207                                                config.numInstanceValues, config.numVertices, config.numInstances));
1208     }
1209 
1210     return drawTests.release();
1211 }
1212 
createDrawIndexedTests(tcu::TestContext & testCtx,VkFormat format)1213 static tcu::TestCaseGroup *createDrawIndexedTests(tcu::TestContext &testCtx, VkFormat format)
1214 {
1215     struct TestConfig
1216     {
1217         std::string name;
1218         VkFormat inputFormat;
1219         DrawIndexedAccessTest::IndexConfig indexConfig;
1220     };
1221 
1222     const TestConfig testConfigs[] = {
1223         // name                                format        indexConfig
1224         // Only last index is out of bounds
1225         {"last_index_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_LAST_INDEX_OUT_OF_BOUNDS},
1226         // Random indices out of bounds
1227         {"indices_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_INDICES_OUT_OF_BOUNDS},
1228         // First triangle is out of bounds
1229         {"triangle_out_of_bounds", format, DrawIndexedAccessTest::INDEX_CONFIG_TRIANGLE_OUT_OF_BOUNDS},
1230     };
1231 
1232     de::MovePtr<tcu::TestCaseGroup> drawTests(new tcu::TestCaseGroup(testCtx, "draw_indexed"));
1233 
1234     for (int i = 0; i < DE_LENGTH_OF_ARRAY(testConfigs); i++)
1235     {
1236         const TestConfig &config = testConfigs[i];
1237 
1238         drawTests->addChild(new DrawIndexedAccessTest(testCtx, config.name, config.inputFormat, config.indexConfig));
1239     }
1240 
1241     return drawTests.release();
1242 }
1243 
addVertexFormatTests(tcu::TestContext & testCtx,tcu::TestCaseGroup * parentGroup)1244 static void addVertexFormatTests(tcu::TestContext &testCtx, tcu::TestCaseGroup *parentGroup)
1245 {
1246     const VkFormat vertexFormats[] = {VK_FORMAT_R32_UINT,
1247                                       VK_FORMAT_R32_SINT,
1248                                       VK_FORMAT_R32_SFLOAT,
1249                                       VK_FORMAT_R32G32_UINT,
1250                                       VK_FORMAT_R32G32_SINT,
1251                                       VK_FORMAT_R32G32_SFLOAT,
1252                                       VK_FORMAT_R32G32B32_UINT,
1253                                       VK_FORMAT_R32G32B32_SINT,
1254                                       VK_FORMAT_R32G32B32_SFLOAT,
1255                                       VK_FORMAT_R32G32B32A32_UINT,
1256                                       VK_FORMAT_R32G32B32A32_SINT,
1257                                       VK_FORMAT_R32G32B32A32_SFLOAT,
1258                                       VK_FORMAT_R64_UINT,
1259                                       VK_FORMAT_R64_SINT,
1260 
1261                                       VK_FORMAT_A2B10G10R10_UNORM_PACK32};
1262 
1263     for (int i = 0; i < DE_LENGTH_OF_ARRAY(vertexFormats); i++)
1264     {
1265         const std::string formatName = getFormatName(vertexFormats[i]);
1266         de::MovePtr<tcu::TestCaseGroup> formatGroup(
1267             new tcu::TestCaseGroup(testCtx, de::toLower(formatName.substr(10)).c_str()));
1268 
1269         formatGroup->addChild(createDrawTests(testCtx, vertexFormats[i]));
1270         formatGroup->addChild(createDrawIndexedTests(testCtx, vertexFormats[i]));
1271 
1272         parentGroup->addChild(formatGroup.release());
1273     }
1274 }
1275 
createVertexAccessTests(tcu::TestContext & testCtx)1276 tcu::TestCaseGroup *createVertexAccessTests(tcu::TestContext &testCtx)
1277 {
1278     de::MovePtr<tcu::TestCaseGroup> vertexAccessTests(new tcu::TestCaseGroup(testCtx, "vertex_access"));
1279 
1280     addVertexFormatTests(testCtx, vertexAccessTests.get());
1281 
1282     return vertexAccessTests.release();
1283 }
1284 
1285 } // namespace robustness
1286 } // namespace vkt
1287