1 /*------------------------------------------------------------------------
2 * Vulkan Conformance Tests
3 * ------------------------
4 *
5 * Copyright (c) 2022 The Khronos Group Inc.
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 *//*!
20 * \file
21 * \brief Robust Index Buffer Access Tests
22 *//*--------------------------------------------------------------------*/
23
24 #include "vktRobustnessIndexAccessTests.hpp"
25 #include "vkBufferWithMemory.hpp"
26 #include "vkImageWithMemory.hpp"
27 #include "vktRobustnessUtil.hpp"
28 #include "vktTestCaseUtil.hpp"
29 #include "vkBuilderUtil.hpp"
30 #include "vkImageUtil.hpp"
31 #include "vkMemUtil.hpp"
32 #include "vkPrograms.hpp"
33 #include "vkQueryUtil.hpp"
34 #include "vkDeviceUtil.hpp"
35 #include "vkBarrierUtil.hpp"
36 #include "vkRef.hpp"
37 #include "vkRefUtil.hpp"
38 #include "vkTypeUtil.hpp"
39 #include "vkObjUtil.hpp"
40 #include "vkCmdUtil.hpp"
41 #include "tcuTestLog.hpp"
42 #include "deMath.h"
43 #include "tcuVectorUtil.hpp"
44 #include "deUniquePtr.hpp"
45 #include <algorithm>
46 #include <numeric>
47 #include <tuple>
48 #include <vector>
49
50 namespace vkt
51 {
52 namespace robustness
53 {
54
55 using namespace vk;
56
57 #ifndef CTS_USES_VULKANSC
58 typedef de::MovePtr<vk::DeviceDriver> DeviceDriverPtr;
59 #else
60 typedef de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> DeviceDriverPtr;
61 #endif // CTS_USES_VULKANSC
62
63 enum TestMode
64 {
65 TM_DRAW_INDEXED = 0,
66 TM_DRAW_INDEXED_INDIRECT,
67 TM_DRAW_INDEXED_INDIRECT_COUNT,
68 TM_DRAW_MULTI_INDEXED,
69 };
70
71 enum OOTypes
72 {
73 OO_NONE,
74 OO_INDEX,
75 OO_SIZE,
76 OO_WHOLE_SIZE
77 };
78
79 struct TestParams
80 {
81 TestMode mode;
82 OOTypes ooType;
83 deUint32 leadingCount;
84 };
85
86 class DrawIndexedInstance : public vkt::TestInstance
87 {
88 public:
89 DrawIndexedInstance (Context& context,
90 Move<VkDevice> device,
91 DeviceDriverPtr deviceDriver,
92 TestMode mode,
93 deUint32 robustnessVersion);
94
95 virtual ~DrawIndexedInstance (void) = default;
96
97 virtual tcu::TestStatus iterate (void);
98
99 protected:
100
101 Move<VkDevice> m_device;
102 DeviceDriverPtr m_deviceDriver;
103 TestMode m_mode;
104 deUint32 m_robustnessVersion;
105 };
106
DrawIndexedInstance(Context & context,Move<VkDevice> device,DeviceDriverPtr deviceDriver,TestMode mode,deUint32 robustnessVersion)107 DrawIndexedInstance::DrawIndexedInstance(Context& context,
108 Move<VkDevice> device,
109 DeviceDriverPtr deviceDriver,
110 TestMode mode,
111 deUint32 robustnessVersion)
112 : vkt::TestInstance (context)
113 , m_device (device)
114 , m_deviceDriver (deviceDriver)
115 , m_mode (mode)
116 , m_robustnessVersion (robustnessVersion)
117 {
118 }
119
iterate(void)120 tcu::TestStatus DrawIndexedInstance::iterate(void)
121 {
122 const DeviceInterface& vk = *m_deviceDriver;
123 const deUint32 queueFamilyIndex = m_context.getUniversalQueueFamilyIndex();
124 const auto& vki = m_context.getInstanceInterface();
125 const VkPhysicalDevice physicalDevice = chooseDevice(vki, m_context.getInstance(), m_context.getTestContext().getCommandLine());
126 SimpleAllocator memAlloc (vk, *m_device, getPhysicalDeviceMemoryProperties(vki, physicalDevice));
127
128 // this is testsed - first index in index buffer is outside of bounds
129 const deUint32 oobFirstIndex = std::numeric_limits<deUint32>::max() - 100;
130
131 const VkFormat colorFormat { VK_FORMAT_R8G8B8A8_UNORM };
132 const tcu::UVec2 renderSize { 16 };
133 const std::vector<VkViewport> viewports { makeViewport(renderSize) };
134 const std::vector<VkRect2D> scissors { makeRect2D(renderSize) };
135
136 // create vertex buffer
137 const std::vector<float> vertices
138 {
139 0.0f, -0.8f, 0.0f, 1.0f,
140 0.0f, 0.8f, 0.0f, 1.0f,
141 0.8f, -0.8f, 0.0f, 1.0f,
142 0.8f, 0.8f, 0.0f, 1.0f,
143 -0.8f, -0.8f, 0.0f, 1.0f,
144 -0.8f, 0.8f, 0.0f, 1.0f,
145 };
146 const VkBufferCreateInfo vertexBufferInfo = makeBufferCreateInfo(vertices.size() * sizeof(float), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
147 BufferWithMemory vertexBuffer(vk, *m_device, memAlloc, vertexBufferInfo, MemoryRequirement::HostVisible);
148 deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertices.data(), vertices.size() * sizeof(float));
149 flushAlloc(vk, *m_device, vertexBuffer.getAllocation());
150
151 // create index buffer for 6 points
152 // 4--0--2
153 // | | |
154 // 5--1--3
155 const std::vector<deUint32> index = { 0, 1, 2, 3, 4, 5 };
156 const VkBufferCreateInfo indexBufferInfo = makeBufferCreateInfo(index.size() * sizeof(deUint32), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
157 BufferWithMemory indexBuffer(vk, *m_device, memAlloc, indexBufferInfo, MemoryRequirement::HostVisible);
158 deMemcpy(indexBuffer.getAllocation().getHostPtr(), index.data(), index.size() * sizeof(deUint32));
159 flushAlloc(vk, *m_device, indexBuffer.getAllocation());
160
161 // create indirect buffer
162 const vk::VkDrawIndexedIndirectCommand drawIndirectCommand
163 {
164 (deUint32)index.size(), // indexCount
165 1u, // instanceCount
166 oobFirstIndex, // firstIndex
167 0u, // vertexOffset
168 0u, // firstInstance
169 };
170 const VkBufferCreateInfo indirectBufferInfo = makeBufferCreateInfo(sizeof(drawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
171 BufferWithMemory indirectBuffer(vk, *m_device, memAlloc, indirectBufferInfo, MemoryRequirement::HostVisible);
172 if ((m_mode == TM_DRAW_INDEXED_INDIRECT) || (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT))
173 {
174 deMemcpy(indirectBuffer.getAllocation().getHostPtr(), &drawIndirectCommand, sizeof(drawIndirectCommand));
175 flushAlloc(vk, *m_device, indirectBuffer.getAllocation());
176 }
177
178 // create indirect count buffer
179 const VkBufferCreateInfo indirectCountBufferInfo = makeBufferCreateInfo(sizeof(deUint32), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
180 BufferWithMemory indirectCountBuffer(vk, *m_device, memAlloc, indirectCountBufferInfo, MemoryRequirement::HostVisible);
181 if (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT)
182 {
183 *(reinterpret_cast<deUint32*>(indirectCountBuffer.getAllocation().getHostPtr())) = 1;
184 flushAlloc(vk, *m_device, indirectCountBuffer.getAllocation());
185 }
186
187 // create output buffer that will be used to read rendered image
188 const VkDeviceSize outputBufferSize = renderSize.x()* renderSize.y()* tcu::getPixelSize(mapVkFormat(colorFormat));
189 const VkBufferCreateInfo outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
190 BufferWithMemory outputBuffer(vk, *m_device, memAlloc, outputBufferInfo, MemoryRequirement::HostVisible);
191
192 // create color buffer
193 VkExtent3D imageExtent = makeExtent3D(renderSize.x(), renderSize.y(), 1u);
194 const VkImageCreateInfo imageCreateInfo
195 {
196 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
197 DE_NULL, // const void* pNext;
198 0u, // VkImageCreateFlags flags;
199 VK_IMAGE_TYPE_2D, // VkImageType imageType;
200 colorFormat, // VkFormat format;
201 imageExtent, // VkExtent3D extent;
202 1u, // deUint32 mipLevels;
203 1u, // deUint32 arrayLayers;
204 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
205 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
206 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
207 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
208 0u, // deUint32 queueFamilyIndexCount;
209 DE_NULL, // const deUint32* pQueueFamilyIndices;
210 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
211 };
212 const VkImageSubresourceRange colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
213 ImageWithMemory colorImage(vk, *m_device, memAlloc, imageCreateInfo, MemoryRequirement::Any);
214 Move<VkImageView> colorImageView = makeImageView(vk, *m_device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
215
216 // create shader modules, renderpass, framebuffer and pipeline
217 Move<VkShaderModule> vertShaderModule = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("vert"), 0);
218 Move<VkShaderModule> fragShaderModule = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("frag"), 0);
219 Move<VkRenderPass> renderPass = makeRenderPass(vk, *m_device, colorFormat);
220 Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, *m_device, DE_NULL);
221 Move<VkFramebuffer> framebuffer = makeFramebuffer(vk, *m_device, *renderPass, *colorImageView, renderSize.x(), renderSize.y());
222 Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(vk, *m_device, *pipelineLayout,
223 *vertShaderModule, DE_NULL, DE_NULL, DE_NULL, *fragShaderModule,
224 *renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
225
226 Move<VkCommandPool> cmdPool = createCommandPool(vk, *m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
227 vk::Move<vk::VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, *m_device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
228
229 beginCommandBuffer(vk, *cmdBuffer);
230
231 // transition colorbuffer layout
232 VkImageMemoryBarrier imageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT,
233 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
234 colorImage.get(), colorSRR);
235 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
236
237 const VkRect2D renderArea = makeRect2D(0, 0, renderSize.x(), renderSize.y());
238 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
239
240 const VkDeviceSize vBuffOffset = 0;
241 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
242 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer.get(), &vBuffOffset);
243 vk.cmdBindIndexBuffer(*cmdBuffer, indexBuffer.get(), 0, VK_INDEX_TYPE_UINT32);
244
245 // we will draw all points at index 0
246 if (m_mode == TM_DRAW_INDEXED)
247 vk.cmdDrawIndexed(*cmdBuffer, (deUint32)index.size(), 1, oobFirstIndex, 0, 0);
248 else if (m_mode == TM_DRAW_INDEXED_INDIRECT)
249 vk.cmdDrawIndexedIndirect(*cmdBuffer, indirectBuffer.get(), 0, 1, 0);
250 else if (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT)
251 vk.cmdDrawIndexedIndirectCount(*cmdBuffer, indirectBuffer.get(), 0, indirectCountBuffer.get(), 0, 1, sizeof(VkDrawIndexedIndirectCommand));
252 else if (m_mode == TM_DRAW_MULTI_INDEXED)
253 {
254 #ifndef CTS_USES_VULKANSC
255 VkMultiDrawIndexedInfoEXT indexInfo[]
256 {
257 { oobFirstIndex, 3, 0 },
258 { oobFirstIndex - 3, 3, 0 },
259 };
260 vk.cmdDrawMultiIndexedEXT(*cmdBuffer, 2, indexInfo, 1, 0, sizeof(VkMultiDrawIndexedInfoEXT), DE_NULL);
261 #endif // CTS_USES_VULKANSC
262 }
263
264 endRenderPass(vk, *cmdBuffer);
265
266 // wait till data is transfered to image
267 imageBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
268 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
269 colorImage.get(), colorSRR);
270 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
271
272 // read back color image
273 const VkImageSubresourceLayers colorSL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
274 const VkBufferImageCopy copyRegion = makeBufferImageCopy(imageExtent, colorSL);
275 vk.cmdCopyImageToBuffer(*cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffer.get(), 1u, ©Region);
276
277 auto bufferBarrier = makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_HOST_READ_BIT, outputBuffer.get(), 0u, VK_WHOLE_SIZE);
278
279 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0u, 0u, 0u, 1u, &bufferBarrier, 0u, 0u);
280
281 endCommandBuffer(vk, *cmdBuffer);
282
283 VkQueue queue;
284 vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &queue);
285 submitCommandsAndWait(vk, *m_device, queue, *cmdBuffer);
286
287 // for robustBufferAccess (the original feature) OOB access will return undefined value;
288 // we can only expect that above drawing will be executed without errors (we can't expect any specific result)
289 if (m_robustnessVersion < 2u)
290 return tcu::TestStatus::pass("Pass");
291
292 // get output buffer
293 invalidateAlloc(vk, *m_device, outputBuffer.getAllocation());
294 const tcu::TextureFormat resultFormat = mapVkFormat(colorFormat);
295 tcu::ConstPixelBufferAccess outputAccess(resultFormat, renderSize.x(), renderSize.y(), 1u, outputBuffer.getAllocation().getHostPtr());
296
297 // for VK_EXT_robustness2 OOB access should return 0 and we can verify
298 // that single fragment is drawn in the middle-top part of the image
299 tcu::UVec4 expectedValue(51, 255, 127, 255);
300 bool fragmentFound = false;
301
302 for (deUint32 x = 0u; x < renderSize.x(); ++x)
303 for (deUint32 y = 0u; y < renderSize.y(); ++y)
304 {
305 tcu::UVec4 pixel = outputAccess.getPixelUint(x, y, 0);
306
307 if (tcu::boolAll(tcu::lessThan(tcu::absDiff(pixel, expectedValue), tcu::UVec4(2))))
308 {
309 if (fragmentFound)
310 {
311 m_context.getTestContext().getLog()
312 << tcu::TestLog::Message << "Expected single fragment with: " << expectedValue
313 << " color, got more, second at " << tcu::UVec2(x, y) << tcu::TestLog::EndMessage
314 << tcu::TestLog::Image("Result", "Result", outputAccess);
315 return tcu::TestStatus::fail("Fail");
316 }
317 else if ((y < 3) && (x > 5) && (x < 10))
318 fragmentFound = true;
319 else
320 {
321 m_context.getTestContext().getLog()
322 << tcu::TestLog::Message << "Expected fragment in the middle-top of the image, got at: "
323 << tcu::UVec2(x, y) << tcu::TestLog::EndMessage
324 << tcu::TestLog::Image("Result", "Result", outputAccess);
325 return tcu::TestStatus::fail("Fail");
326 }
327 }
328 }
329
330 if (fragmentFound)
331 return tcu::TestStatus::pass("Pass");
332 return tcu::TestStatus::fail("Fail");
333 }
334
335 class DrawIndexedTestCase : public vkt::TestCase
336 {
337 public:
338
339 DrawIndexedTestCase (tcu::TestContext& testContext,
340 const std::string& name,
341 TestMode mode,
342 deUint32 robustnessVersion);
343
344 virtual ~DrawIndexedTestCase (void) = default;
345
346 void checkSupport (Context& context) const override;
347 TestInstance* createInstance (Context& context) const override;
348 void initPrograms (SourceCollections& programCollection) const override;
349
350 protected:
351 void createDeviceAndDriver (Context& context,
352 Move<VkDevice>& device,
353 DeviceDriverPtr& driver) const;
354 const TestMode m_testMode;
355 const deUint32 m_robustnessVersion;
356 };
357
DrawIndexedTestCase(tcu::TestContext & testContext,const std::string & name,TestMode mode,deUint32 robustnessVersion)358 DrawIndexedTestCase::DrawIndexedTestCase(tcu::TestContext& testContext,
359 const std::string& name,
360 TestMode mode,
361 deUint32 robustnessVersion)
362
363 : vkt::TestCase (testContext, name)
364 , m_testMode (mode)
365 , m_robustnessVersion (robustnessVersion)
366 {}
367
checkSupport(Context & context) const368 void DrawIndexedTestCase::checkSupport (Context& context) const
369 {
370 if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getDeviceFeatures().robustBufferAccess)
371 TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
372
373 if (m_testMode == TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT)
374 context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
375 if (m_testMode == TestMode::TM_DRAW_MULTI_INDEXED)
376 context.requireDeviceFunctionality("VK_EXT_multi_draw");
377 if (m_robustnessVersion == 2)
378 {
379 context.requireDeviceFunctionality("VK_EXT_robustness2");
380
381 const auto& vki = context.getInstanceInterface();
382 const auto physicalDevice = context.getPhysicalDevice();
383
384 VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure();
385 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure(&robustness2Features);
386
387 vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
388
389 if (!robustness2Features.robustBufferAccess2)
390 TCU_THROW(NotSupportedError, "robustBufferAccess2 not supported");
391 }
392 }
393
createDeviceAndDriver(Context & context,Move<VkDevice> & device,DeviceDriverPtr & driver) const394 void DrawIndexedTestCase::createDeviceAndDriver (Context& context, Move<VkDevice>& device, DeviceDriverPtr& driver) const
395 {
396 VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
397 features2.features.robustBufferAccess = DE_TRUE;
398
399 void** nextPtr = &features2.pNext;
400
401 #ifndef CTS_USES_VULKANSC
402 VkPhysicalDeviceMultiDrawFeaturesEXT multiDrawFeatures = initVulkanStructure();
403 if (m_testMode == TestMode::TM_DRAW_MULTI_INDEXED)
404 {
405 multiDrawFeatures.multiDraw = DE_TRUE;
406 addToChainVulkanStructure(&nextPtr, multiDrawFeatures);
407 }
408 #endif // CTS_USES_VULKANSC
409
410 VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure();
411 if (m_robustnessVersion > 1u)
412 {
413 robustness2Features.robustBufferAccess2 = DE_TRUE;
414 addToChainVulkanStructure(&nextPtr, robustness2Features);
415 }
416
417 deUint32 apiVersion = context.getUsedApiVersion();
418 VkPhysicalDeviceVulkan12Features vulkan12Features = initVulkanStructure();
419 if ((m_testMode == TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT) && (apiVersion > VK_MAKE_API_VERSION(0, 1, 1, 0)))
420 {
421 vulkan12Features.drawIndirectCount = DE_TRUE;
422 addToChainVulkanStructure(&nextPtr, vulkan12Features);
423 }
424
425 device = createRobustBufferAccessDevice(context, &features2);
426 driver =
427 #ifndef CTS_USES_VULKANSC
428 DeviceDriverPtr(new DeviceDriver(context.getPlatformInterface(), context.getInstance(), *device, context.getUsedApiVersion()));
429 #else
430 DeviceDriverPtr(new DeviceDriverSC(context.getPlatformInterface(), context.getInstance(), *device, context.getTestContext().getCommandLine(),
431 context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties(), context.getUsedApiVersion()),
432 vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
433 #endif // CTS_USES_VULKANSC
434 }
435
createInstance(Context & context) const436 TestInstance* DrawIndexedTestCase::createInstance(Context& context) const
437 {
438 Move<VkDevice> device;
439 DeviceDriverPtr deviceDriver;
440 createDeviceAndDriver(context, device, deviceDriver);
441 return new DrawIndexedInstance(context, device, deviceDriver, m_testMode, m_robustnessVersion);
442 }
443
initPrograms(SourceCollections & sourceCollections) const444 void DrawIndexedTestCase::initPrograms (SourceCollections& sourceCollections) const
445 {
446 std::string vertexSource(
447 "#version 450\n"
448 "layout(location = 0) in vec4 inPosition;\n"
449 "void main(void)\n"
450 "{\n"
451 "\tgl_Position = inPosition;\n"
452 "\tgl_PointSize = 1.0;\n"
453 "}\n");
454 sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSource);
455
456 std::string fragmentSource(
457 "#version 450\n"
458 "precision highp float;\n"
459 "layout(location = 0) out vec4 fragColor;\n"
460 "void main (void)\n"
461 "{\n"
462 "\tfragColor = vec4(0.2, 1.0, 0.5, 1.0);\n"
463 "}\n");
464
465 sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragmentSource);
466 }
467
468 class BindIndexBuffer2Instance : public vkt::TestInstance
469 {
470 public:
471 BindIndexBuffer2Instance (Context& c,
472 Move<VkDevice> device,
473 DeviceDriverPtr driver,
474 const TestParams& params);
475 virtual ~BindIndexBuffer2Instance (void) = default;
476
477 virtual tcu::TestStatus iterate (void) override;
478
479 protected:
480 const Move<VkDevice> m_device;
481 const DeviceDriverPtr m_driver;
482 const TestParams m_params;
483 VkPhysicalDevice m_physDevice;
484 SimpleAllocator m_allocator;
485
486 protected:
getDeviceInterface() const487 inline const DeviceInterface& getDeviceInterface () const { return *m_driver; }
getDevice() const488 inline VkDevice getDevice () const { return *m_device; }
getPhysicalDevice() const489 inline VkPhysicalDevice getPhysicalDevice () const { return m_physDevice; }
getAllocator()490 inline Allocator& getAllocator () { return m_allocator; }
491 VkQueue getQueue () const;
492 };
493
BindIndexBuffer2Instance(Context & c,Move<VkDevice> device,DeviceDriverPtr driver,const TestParams & params)494 BindIndexBuffer2Instance::BindIndexBuffer2Instance (Context& c,
495 Move<VkDevice> device,
496 DeviceDriverPtr driver,
497 const TestParams& params)
498 : vkt::TestInstance (c)
499 , m_device (device)
500 , m_driver (driver)
501 , m_params (params)
502 , m_physDevice (chooseDevice(c.getInstanceInterface(), c.getInstance(), c.getTestContext().getCommandLine()))
503 , m_allocator (getDeviceInterface(), getDevice(), getPhysicalDeviceMemoryProperties(c.getInstanceInterface(), m_physDevice))
504 {
505 }
506
getQueue() const507 VkQueue BindIndexBuffer2Instance::getQueue () const
508 {
509 VkQueue queue = DE_NULL;
510 getDeviceInterface().getDeviceQueue(getDevice(), m_context.getUniversalQueueFamilyIndex(), 0, &queue);
511 return queue;
512 }
513
514 class BindIndexBuffer2TestCase : public DrawIndexedTestCase
515 {
516 public:
517 BindIndexBuffer2TestCase (tcu::TestContext& testContext,
518 const std::string& name,
519 const TestParams& params);
520 ~BindIndexBuffer2TestCase (void) = default;
521
522 void checkSupport (Context& context) const override;
523 TestInstance* createInstance (Context& context) const override;
524 void initPrograms (SourceCollections& programs) const override;
525
526 protected:
527 const OOTypes m_ooType;
528 const deUint32 m_leadingCount;
529 };
530
BindIndexBuffer2TestCase(tcu::TestContext & testContext,const std::string & name,const TestParams & params)531 BindIndexBuffer2TestCase::BindIndexBuffer2TestCase (tcu::TestContext& testContext,
532 const std::string& name,
533 const TestParams& params)
534 : DrawIndexedTestCase (testContext, name, params.mode, 2)
535 , m_ooType (params.ooType)
536 , m_leadingCount (params.leadingCount)
537 {
538 }
539
540 #ifdef CTS_USES_VULKANSC
541 #define DEPENDENT_MAINTENANCE_5_EXTENSION_NAME "VK_KHR_maintenance5"
542 #else
543 #define DEPENDENT_MAINTENANCE_5_EXTENSION_NAME VK_KHR_MAINTENANCE_5_EXTENSION_NAME
544 #endif
545
checkSupport(Context & context) const546 void BindIndexBuffer2TestCase::checkSupport (Context& context) const
547 {
548 DrawIndexedTestCase::checkSupport(context);
549 context.requireDeviceFunctionality(DEPENDENT_MAINTENANCE_5_EXTENSION_NAME);
550 }
551
initPrograms(SourceCollections & programs) const552 void BindIndexBuffer2TestCase::initPrograms (SourceCollections& programs) const
553 {
554 const std::string vertexSource(
555 "#version 450\n"
556 "layout(location = 0) in vec4 inPosition;\n"
557 "void main(void) {\n"
558 " gl_Position = inPosition;\n"
559 " gl_PointSize = 1.0;\n"
560 "}\n");
561 programs.glslSources.add("vert") << glu::VertexSource(vertexSource);
562
563 const std::string fragmentSource(
564 "#version 450\n"
565 "layout(location = 0) out vec4 fragColor;\n"
566 "void main (void) {\n"
567 " fragColor = vec4(1.0);\n"
568 "}\n");
569 programs.glslSources.add("frag") << glu::FragmentSource(fragmentSource);
570 }
571
createInstance(Context & context) const572 TestInstance* BindIndexBuffer2TestCase::createInstance (Context& context) const
573 {
574 TestParams params;
575 Move<VkDevice> device;
576 DeviceDriverPtr deviceDriver;
577 createDeviceAndDriver(context, device, deviceDriver);
578
579 params.mode = m_testMode;
580 params.ooType = m_ooType;
581 params.leadingCount = m_leadingCount;
582
583 return new BindIndexBuffer2Instance(context, device, deviceDriver, params);
584 }
585
iterate(void)586 tcu::TestStatus BindIndexBuffer2Instance::iterate (void)
587 {
588 const DeviceInterface& vk = this->getDeviceInterface();
589 const VkDevice device = this->getDevice();
590 Allocator& allocator = this->getAllocator();
591 const VkQueue queue = this->getQueue();
592 const deUint32 queueFamilyIdx = m_context.getUniversalQueueFamilyIndex();
593 tcu::TestLog& log = m_context.getTestContext().getLog();
594
595 const VkFormat colorFormat { VK_FORMAT_R32G32B32A32_SFLOAT };
596 const tcu::UVec2 renderSize { 64, 64 };
597 const std::vector<VkViewport> viewports { makeViewport(renderSize) };
598 const std::vector<VkRect2D> scissors { makeRect2D(renderSize) };
599
600 // build vertices data
601 std::vector<tcu::Vec4> vertices;
602
603 // first triangle in 2nd quarter, it should not be drawn
604 vertices.emplace_back(-1.0f, 0.1f, 0.0f, 1.0f);
605 vertices.emplace_back(-1.0f, 1.0f, 0.0f, 1.0f);
606 vertices.emplace_back(-0.1f, 0.1f, 0.0f, 1.0f);
607
608 // second triangle in 2nd quarter, it should not be drawn
609 vertices.emplace_back(-0.1f, 0.1f, 0.0f, 1.0f);
610 vertices.emplace_back(-1.0f, 1.0f, 0.0f, 1.0f);
611 vertices.emplace_back(-0.1f, 1.0f, 0.0f, 1.0f);
612
613 // first triangle in 3rd quarter, it must be drawn
614 vertices.emplace_back(0.0f, -1.0f, 0.0f, 1.0f);
615 vertices.emplace_back(-1.0f, -1.0f, 0.0f, 1.0f);
616 vertices.emplace_back(-1.0f, 0.0f, 0.0f, 1.0f);
617
618 // second triangle in 3rd quarter if robustness works as expected,
619 // otherwise will be drawn in 1st quarter as well
620 vertices.emplace_back(0.0f, -1.0f, 0.0f, 1.0f);
621 vertices.emplace_back(-1.0f, 0.0f, 0.0f, 1.0f);
622 vertices.emplace_back(1.0f, 1.0f, 0.0f, 1.0f);
623
624 // create vertex buffer
625 const VkBufferCreateInfo vertexBufferInfo = makeBufferCreateInfo(vertices.size() * sizeof(tcu::Vec4), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
626 BufferWithMemory vertexBuffer(vk, device, allocator, vertexBufferInfo, MemoryRequirement::HostVisible);
627 deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertices.data(), vertices.size() * sizeof(tcu::Vec4));
628
629 // build index data
630 const deUint32 leadingCount = m_params.leadingCount;
631 std::vector<deUint32> indices (leadingCount * 6 + 6);
632 for (deUint32 j = 0; j < leadingCount; ++j)
633 for (deUint32 k = 0; k < 6; ++k)
634 {
635 indices[j * 6 + k] = k;
636 }
637 std::iota(std::next(indices.begin(), (leadingCount * 6)), indices.end(), 6u);
638
639 const deUint32 firstIndex = 0;
640 const deUint32 indexCount = 6;
641 const VkDeviceSize bindingOffset = leadingCount * 6 * sizeof(deUint32);
642 VkDeviceSize bindingSize = 6 * sizeof(deUint32);
643 VkDeviceSize allocSize = indices.size() * sizeof(deUint32);
644 switch (m_params.ooType)
645 {
646 case OOTypes::OO_NONE:
647 // default values already set
648 break;
649 case OOTypes::OO_INDEX:
650 indices.back() = 33; // out of range index
651 break;
652 case OOTypes::OO_SIZE:
653 bindingSize = 5 * sizeof(deUint32);
654 break;
655 case OOTypes::OO_WHOLE_SIZE:
656 bindingSize = VK_WHOLE_SIZE;
657 allocSize = (indices.size() - 1) * sizeof(deUint32);
658 break;
659 }
660
661 // create index buffer
662 const VkBufferCreateInfo indexBufferInfo = makeBufferCreateInfo(allocSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
663 BufferWithMemory indexBuffer(vk, device, allocator, indexBufferInfo, MemoryRequirement::HostVisible);
664 deMemcpy(indexBuffer.getAllocation().getHostPtr(), indices.data(), size_t(allocSize));
665
666 // create indirect buffer
667 const vk::VkDrawIndexedIndirectCommand drawIndirectCommand
668 {
669 indexCount, // indexCount
670 1u, // instanceCount
671 firstIndex, // firstIndex
672 0u, // vertexOffset
673 0u, // firstInstance
674 };
675 const VkBufferCreateInfo indirectBufferInfo = makeBufferCreateInfo(sizeof(drawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
676 BufferWithMemory indirectBuffer(vk, *m_device, allocator, indirectBufferInfo, MemoryRequirement::HostVisible);
677 if ((m_params.mode == TM_DRAW_INDEXED_INDIRECT) || (m_params.mode == TM_DRAW_INDEXED_INDIRECT_COUNT))
678 {
679 deMemcpy(indirectBuffer.getAllocation().getHostPtr(), &drawIndirectCommand, sizeof(drawIndirectCommand));
680 }
681
682 // create indirect count buffer
683 const VkBufferCreateInfo indirectCountBufferInfo = makeBufferCreateInfo(sizeof(deUint32), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
684 BufferWithMemory indirectCountBuffer(vk, *m_device, allocator, indirectCountBufferInfo, MemoryRequirement::HostVisible);
685 if (m_params.mode == TM_DRAW_INDEXED_INDIRECT_COUNT)
686 {
687 *static_cast<deUint32*>(indirectCountBuffer.getAllocation().getHostPtr()) = 1u;
688 }
689
690 // create output buffer that will be used to read rendered image
691 const VkDeviceSize outputBufferSize = renderSize.x() * renderSize.y() * tcu::getPixelSize(mapVkFormat(colorFormat));
692 const VkBufferCreateInfo outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
693 BufferWithMemory outputBuffer (vk, device, allocator, outputBufferInfo, MemoryRequirement::HostVisible);
694
695 // create color buffer
696 const VkExtent3D imageExtent = makeExtent3D(renderSize.x(), renderSize.y(), 1u);
697 const VkImageCreateInfo imageCreateInfo
698 {
699 VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // VkStructureType sType;
700 DE_NULL, // const void* pNext;
701 0u, // VkImageCreateFlags flags;
702 VK_IMAGE_TYPE_2D, // VkImageType imageType;
703 colorFormat, // VkFormat format;
704 imageExtent, // VkExtent3D extent;
705 1u, // deUint32 mipLevels;
706 1u, // deUint32 arrayLayers;
707 VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples;
708 VK_IMAGE_TILING_OPTIMAL, // VkImageTiling tiling;
709 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VkImageUsageFlags usage;
710 VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode sharingMode;
711 0u, // deUint32 queueFamilyIndexCount;
712 DE_NULL, // const deUint32* pQueueFamilyIndices;
713 VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout initialLayout;
714 };
715 const tcu::Vec4 clearColor (0.0f, 0.0f, 0.0f, 1.0f);
716 const VkImageSubresourceRange colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
717 ImageWithMemory colorImage (vk, *m_device, allocator, imageCreateInfo, MemoryRequirement::Any);
718 Move<VkImageView> colorImageView = makeImageView(vk, *m_device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
719
720 // create shader modules, renderpass, framebuffer and pipeline
721 Move<VkShaderModule> vertShaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("vert"), 0);
722 Move<VkShaderModule> fragShaderModule = createShaderModule(vk, device, m_context.getBinaryCollection().get("frag"), 0);
723 Move<VkRenderPass> renderPass = makeRenderPass(vk, device, colorFormat);
724 Move<VkPipelineLayout> pipelineLayout = makePipelineLayout(vk, device);
725 Move<VkFramebuffer> framebuffer = makeFramebuffer(vk, device, *renderPass, *colorImageView, renderSize.x(), renderSize.y());
726 Move<VkPipeline> graphicsPipeline = makeGraphicsPipeline(vk, device, *pipelineLayout,
727 *vertShaderModule, DE_NULL, DE_NULL, DE_NULL, *fragShaderModule,
728 *renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
729
730 Move<VkCommandPool> cmdPool = createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIdx);
731 vk::Move<vk::VkCommandBuffer> cmdBuffer = allocateCommandBuffer(vk, device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
732
733 beginCommandBuffer(vk, *cmdBuffer);
734
735 // transition colorbuffer layout
736 VkImageMemoryBarrier imageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT,
737 VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
738 colorImage.get(), colorSRR);
739 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
740
741 const VkRect2D renderArea = makeRect2D(0, 0, renderSize.x(), renderSize.y());
742 beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, clearColor);
743
744 vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
745 vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer.get(), &static_cast<const VkDeviceSize&>(0));
746
747 #ifndef CTS_USES_VULKANSC
748 vk.cmdBindIndexBuffer2KHR(*cmdBuffer, indexBuffer.get(), bindingOffset, bindingSize, VK_INDEX_TYPE_UINT32);
749 #else
750 DE_UNREF(bindingOffset);
751 DE_UNREF(bindingSize);
752 #endif
753
754 // we will draw all points at index 0
755 switch (m_params.mode)
756 {
757 case TM_DRAW_INDEXED:
758 vk.cmdDrawIndexed(*cmdBuffer, indexCount, 1u, firstIndex, 0, 0);
759 break;
760
761 case TM_DRAW_INDEXED_INDIRECT:
762 vk.cmdDrawIndexedIndirect(*cmdBuffer, indirectBuffer.get(), 0, 1, deUint32(sizeof(drawIndirectCommand)));
763 break;
764
765 case TM_DRAW_INDEXED_INDIRECT_COUNT:
766 vk.cmdDrawIndexedIndirectCount(*cmdBuffer, indirectBuffer.get(), 0, indirectCountBuffer.get(), 0, 1, deUint32(sizeof(drawIndirectCommand)));
767 break;
768
769 case TM_DRAW_MULTI_INDEXED:
770 #ifndef CTS_USES_VULKANSC
771 {
772 const VkMultiDrawIndexedInfoEXT indexInfo [/* { firstIndex, indexCount, vertexOffset } */]
773 {
774 { firstIndex+3, 3, 0 },
775 { firstIndex, 3, 0 },
776 };
777 vk.cmdDrawMultiIndexedEXT(*cmdBuffer, DE_LENGTH_OF_ARRAY(indexInfo), indexInfo, 1, 0, sizeof(VkMultiDrawIndexedInfoEXT), DE_NULL);
778 }
779 #endif
780 break;
781 }
782
783 endRenderPass(vk, *cmdBuffer);
784
785 // wait till data is transfered to image
786 imageBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
787 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
788 colorImage.get(), colorSRR);
789 vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
790
791 // read back color image
792 const VkImageSubresourceLayers colorSL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
793 const VkBufferImageCopy copyRegion = makeBufferImageCopy(imageExtent, colorSL);
794 vk.cmdCopyImageToBuffer(*cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffer.get(), 1u, ©Region);
795
796 endCommandBuffer(vk, *cmdBuffer);
797 submitCommandsAndWait(vk, device, queue, *cmdBuffer);
798
799 // get output buffer
800 invalidateAlloc(vk, device, outputBuffer.getAllocation());
801 const tcu::TextureFormat resultFormat = mapVkFormat(colorFormat);
802 tcu::ConstPixelBufferAccess resultAccess(resultFormat, renderSize.x(), renderSize.y(), 1u, outputBuffer.getAllocation().getHostPtr());
803
804
805 // neither one triangle should be drawn in the second quarter, they are omitted by the offset or the firstIndex parameters
806 const tcu::Vec4 p11 = resultAccess.getPixel((1 * renderSize.x()) / 8, (5 * renderSize.y()) / 8);
807 const tcu::Vec4 p12 = resultAccess.getPixel((3 * renderSize.x()) / 8, (7 * renderSize.y()) / 8);
808 const bool c1 = p11.x() == clearColor.x() && p11.y() == clearColor.y() && p11.z() == clearColor.z()
809 && p12.x() == clearColor.x() && p12.y() == clearColor.y() && p12.z() == clearColor.z();
810
811 // small triangle in the third quarter must be drawn always
812 const tcu::Vec4 p2 = resultAccess.getPixel((1 * renderSize.x()) / 8, (1 * renderSize.y()) / 8);
813 const bool c2 = p2.x() != clearColor.x() && p2.y() != clearColor.y() && p2.z() != clearColor.z();
814
815 // if robustness works, then the origin of coordinate system will be read in shader instead of a value that an index points (1,1)
816 const tcu::Vec4 p3 = resultAccess.getPixel((3 * renderSize.x()) / 4, (3 * renderSize.y()) / 4);
817 const bool c3 = p3.x() == clearColor.x() && p3.y() == clearColor.y() && p3.z() == clearColor.z();
818
819 bool verdict = false;
820 switch (m_params.ooType)
821 {
822 case OOTypes::OO_NONE:
823 verdict = c1 && c2 && !c3;
824 break;
825 default:
826 verdict = c1 && c2 && c3;
827 break;
828 }
829
830 log << tcu::TestLog::ImageSet("Result", "")
831 << tcu::TestLog::Image(std::to_string(m_params.mode), "", resultAccess)
832 << tcu::TestLog::EndImageSet;
833 return (*(verdict ? &tcu::TestStatus::pass : &tcu::TestStatus::fail))(std::string());
834 }
835
createCmdBindIndexBuffer2Tests(tcu::TestContext & testCtx)836 tcu::TestCaseGroup* createCmdBindIndexBuffer2Tests (tcu::TestContext& testCtx)
837 {
838 const std::pair<const char*, TestMode> modes[]
839 {
840 { "draw_indexed", TestMode::TM_DRAW_INDEXED },
841 { "draw_indexed_indirect", TestMode::TM_DRAW_INDEXED_INDIRECT },
842 { "draw_indexed_indirect_count", TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT },
843 { "draw_multi_indexed", TestMode::TM_DRAW_MULTI_INDEXED },
844 };
845
846 const std::pair<std::string, OOTypes> OutOfTypes[]
847 {
848 { "oo_none", OOTypes::OO_NONE },
849 { "oo_index", OOTypes::OO_INDEX },
850 { "oo_size", OOTypes::OO_SIZE },
851 { "oo_whole_size", OOTypes::OO_WHOLE_SIZE },
852 };
853
854 const deUint32 offsets[] = { 0, 100 };
855
856 // Test access outside of the buffer with using the vkCmdBindIndexBuffer2 function from VK_KHR_maintenance5 extension.
857 de::MovePtr<tcu::TestCaseGroup> gRoot(new tcu::TestCaseGroup(testCtx, "bind_index_buffer2"));
858 for (deUint32 offset : offsets)
859 {
860 de::MovePtr<tcu::TestCaseGroup> gOffset(new tcu::TestCaseGroup(testCtx, ("offset_" + std::to_string(offset)).c_str(), ""));
861 for (const auto& mode : modes)
862 {
863 de::MovePtr<tcu::TestCaseGroup> gMode(new tcu::TestCaseGroup(testCtx, mode.first, ""));
864 for (const auto& ooType : OutOfTypes)
865 {
866 TestParams p;
867 p.mode = mode.second;
868 p.ooType = ooType.second;
869 p.leadingCount = offset;
870 gMode->addChild(new BindIndexBuffer2TestCase(testCtx, ooType.first, p));
871 }
872 gOffset->addChild(gMode.release());
873 }
874 gRoot->addChild(gOffset.release());
875 }
876
877 return gRoot.release();
878 }
879
createIndexAccessTests(tcu::TestContext & testCtx)880 tcu::TestCaseGroup* createIndexAccessTests(tcu::TestContext& testCtx)
881 {
882 de::MovePtr<tcu::TestCaseGroup> indexAccessTests(new tcu::TestCaseGroup(testCtx, "index_access", "Test access outside of the buffer for indices"));
883
884 struct TestConfig
885 {
886 std::string name;
887 TestMode mode;
888 };
889
890 const std::vector<TestConfig> testConfigs
891 {
892 { "draw_indexed", TestMode::TM_DRAW_INDEXED },
893 { "draw_indexed_indirect", TestMode::TM_DRAW_INDEXED_INDIRECT },
894 { "draw_indexed_indirect_count", TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT },
895 { "draw_multi_indexed", TestMode::TM_DRAW_MULTI_INDEXED },
896 };
897
898 const deUint32 robustnessVersion = 2;
899 for (const auto& c : testConfigs)
900 {
901 std::string name = c.name + "_" + std::to_string(robustnessVersion);
902 indexAccessTests->addChild(new DrawIndexedTestCase(testCtx, name, c.mode, robustnessVersion));
903 }
904
905 return indexAccessTests.release();
906 }
907
908 } // robustness
909 } // vkt
910