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