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