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