Ensure robustness for OOB index buffer accesses
authorPiotr Byszewski <piotr.byszewski@mobica.com>
Thu, 15 Sep 2022 15:56:45 +0000 (17:56 +0200)
committerMatthew Netsch <quic_mnetsch@quicinc.com>
Thu, 1 Dec 2022 23:41:39 +0000 (23:41 +0000)
Test out of bounds firstIndex parameter
passed to vkCmdDrawIndexed, vkCmdDrawIndexedIndirect,
vkCmdDrawIndexedIndirectCount and vkCmdDrawMultiIndexedEXT.

VK-GL-CTS issue: 3670

Components: Vulkan

New tests:
dEQP-VK.robustness.index_access.*

Change-Id: I9f6a8b7c15b7c5a2b1ad0edd71d2f4eccea00dad

AndroidGen.mk
android/cts/main/vk-master-2022-03-01/robustness.txt
android/cts/main/vk-master/robustness.txt
android/cts/main/vksc-main/robustness.txt
external/vulkancts/modules/vulkan/robustness/CMakeLists.txt
external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.cpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.hpp [new file with mode: 0644]
external/vulkancts/modules/vulkan/robustness/vktRobustnessTests.cpp
external/vulkancts/mustpass/main/vk-default/robustness.txt
external/vulkancts/mustpass/main/vksc-default/robustness.txt

index 21b4597..b23f039 100644 (file)
@@ -408,6 +408,7 @@ LOCAL_SRC_FILES := \
        external/vulkancts/modules/vulkan/robustness/vktRobustness1VertexAccessTests.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessBufferAccessTests.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessExtsTests.cpp \
+       external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessTests.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessUtil.cpp \
        external/vulkancts/modules/vulkan/robustness/vktRobustnessVertexAccessTests.cpp \
index 0987e2f..43b8840 100644 (file)
@@ -9497,3 +9497,11 @@ dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.don
 dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.dontunroll.nonvolatile.sampled_image.no_fmt_qual.img.samples_1.2d_array.comp
 dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.dontunroll.nonvolatile.sampled_image.no_fmt_qual.img.samples_1.2d_array.frag
 dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.dontunroll.nonvolatile.sampled_image.no_fmt_qual.img.samples_1.2d_array.vert
+dEQP-VK.robustness.index_access.draw_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_1
+dEQP-VK.robustness.index_access.draw_multi_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_2
+dEQP-VK.robustness.index_access.draw_multi_indexed_2
index fa81284..3dde135 100644 (file)
@@ -55267,6 +55267,14 @@ dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.don
 dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.dontunroll.nonvolatile.sampled_image.no_fmt_qual.img.samples_1.2d_array.vert
 dEQP-VK.robustness.non_robust_buffer_access.unexecuted_oob_underflow
 dEQP-VK.robustness.non_robust_buffer_access.unexecuted_oob_overflow
+dEQP-VK.robustness.index_access.draw_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_1
+dEQP-VK.robustness.index_access.draw_multi_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_2
+dEQP-VK.robustness.index_access.draw_multi_indexed_2
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.comp
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.frag
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.vert
index 5fe06e2..c9f32d9 100644 (file)
@@ -19644,6 +19644,14 @@ dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_0
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_16_single_buffer
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_30_middle_of_buffer
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_8_middle_of_buffer_separate
+dEQP-VKSC.robustness.index_access.draw_indexed_1
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_1
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_count_1
+dEQP-VKSC.robustness.index_access.draw_multi_indexed_1
+dEQP-VKSC.robustness.index_access.draw_indexed_2
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_2
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_count_2
+dEQP-VKSC.robustness.index_access.draw_multi_indexed_2
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.comp
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.frag
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.vert
index 0213172..87201a6 100644 (file)
@@ -16,6 +16,8 @@ set(DEQP_VK_ROBUSTNESS_SRCS
        vktRobustnessUtil.hpp
        vktRobustnessVertexAccessTests.cpp
        vktRobustnessVertexAccessTests.hpp
+       vktRobustnessIndexAccessTests.cpp
+       vktRobustnessIndexAccessTests.hpp
        vktNonRobustBufferAccessTests.hpp
        vktNonRobustBufferAccessTests.cpp
        vktRobustnessExtsTests.cpp
diff --git a/external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.cpp b/external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.cpp
new file mode 100644 (file)
index 0000000..48a6894
--- /dev/null
@@ -0,0 +1,472 @@
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2022 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Robust Index Buffer Access Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "vktRobustnessIndexAccessTests.hpp"
+#include "vkBufferWithMemory.hpp"
+#include "vkImageWithMemory.hpp"
+#include "vktRobustnessUtil.hpp"
+#include "vktTestCaseUtil.hpp"
+#include "vkBuilderUtil.hpp"
+#include "vkImageUtil.hpp"
+#include "vkMemUtil.hpp"
+#include "vkPrograms.hpp"
+#include "vkQueryUtil.hpp"
+#include "vkDeviceUtil.hpp"
+#include "vkBarrierUtil.hpp"
+#include "vkRef.hpp"
+#include "vkRefUtil.hpp"
+#include "vkTypeUtil.hpp"
+#include "vkObjUtil.hpp"
+#include "vkCmdUtil.hpp"
+#include "tcuTestLog.hpp"
+#include "deMath.h"
+#include "tcuVectorUtil.hpp"
+#include "deUniquePtr.hpp"
+#include <vector>
+
+namespace vkt
+{
+namespace robustness
+{
+
+using namespace vk;
+
+#ifndef CTS_USES_VULKANSC
+typedef de::MovePtr<vk::DeviceDriver> DeviceDriverPtr;
+#else
+typedef de::MovePtr<vk::DeviceDriverSC, vk::DeinitDeviceDeleter> DeviceDriverPtr;
+#endif // CTS_USES_VULKANSC
+
+enum TestMode
+{
+       TM_DRAW_INDEXED                                 = 0,
+       TM_DRAW_INDEXED_INDIRECT,
+       TM_DRAW_INDEXED_INDIRECT_COUNT,
+       TM_DRAW_MULTI_INDEXED,
+};
+
+class DrawIndexedInstance : public vkt::TestInstance
+{
+public:
+                                                               DrawIndexedInstance             (Context&                                                                               context,
+                                                                                                                std::shared_ptr<CustomInstanceWrapper>                 instanceWrapper,
+                                                                                                                Move<VkDevice>                                                                 device,
+                                                                                                                DeviceDriverPtr                                                                deviceDriver,
+                                                                                                                TestMode                                                                               mode,
+                                                                                                                deUint32                                                                               robustnessVersion);
+
+       virtual                                         ~DrawIndexedInstance    (void) = default;
+
+       virtual tcu::TestStatus         iterate                                 (void);
+
+protected:
+
+       std::shared_ptr<CustomInstanceWrapper>          m_instanceWrapper;
+       Move<VkDevice>                                                          m_device;
+       DeviceDriverPtr                                                         m_deviceDriver;
+       TestMode                                                                        m_mode;
+       deUint32                                                                        m_robustnessVersion;
+};
+
+DrawIndexedInstance::DrawIndexedInstance(Context&                                                              context,
+                                                                                std::shared_ptr<CustomInstanceWrapper> instanceWrapper,
+                                                                                Move<VkDevice>                                                 device,
+                                                                                DeviceDriverPtr                                                deviceDriver,
+                                                                                TestMode                                                               mode,
+                                                                                deUint32                                                               robustnessVersion)
+       : vkt::TestInstance                     (context)
+       , m_instanceWrapper                     (instanceWrapper)
+       , m_device                                      (device)
+       , m_deviceDriver                        (deviceDriver)
+       , m_mode                                        (mode)
+       , m_robustnessVersion           (robustnessVersion)
+{
+}
+
+tcu::TestStatus DrawIndexedInstance::iterate(void)
+{
+       const DeviceInterface&  vk                                      = *m_deviceDriver;
+       const deUint32                  queueFamilyIndex        = m_context.getUniversalQueueFamilyIndex();
+       const VkPhysicalDevice  physicalDevice          = chooseDevice(m_instanceWrapper->instance.getDriver(), m_instanceWrapper->instance, m_context.getTestContext().getCommandLine());
+       SimpleAllocator                 memAlloc                        (vk, *m_device, getPhysicalDeviceMemoryProperties(m_instanceWrapper->instance.getDriver(), physicalDevice));
+
+       // this is testsed - first index in index buffer is outside of bounds
+       const deUint32                                  oobFirstIndex = std::numeric_limits<deUint32>::max() - 100;
+
+       const VkFormat                                  colorFormat     { VK_FORMAT_R8G8B8A8_UNORM };
+       const tcu::UVec2                                renderSize      { 16 };
+       const std::vector<VkViewport>   viewports       { makeViewport(renderSize) };
+       const std::vector<VkRect2D>             scissors        { makeRect2D(renderSize) };
+
+       // create vertex buffer
+       const std::vector<float> vertices
+       {
+                0.0f, -0.8f,    0.0f, 1.0f,
+                0.0f,  0.8f,    0.0f, 1.0f,
+                0.8f, -0.8f,    0.0f, 1.0f,
+                0.8f,  0.8f,    0.0f, 1.0f,
+               -0.8f, -0.8f,    0.0f, 1.0f,
+               -0.8f,  0.8f,    0.0f, 1.0f,
+       };
+       const VkBufferCreateInfo vertexBufferInfo = makeBufferCreateInfo(vertices.size() * sizeof(float), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       BufferWithMemory vertexBuffer(vk, *m_device, memAlloc, vertexBufferInfo, MemoryRequirement::HostVisible);
+       deMemcpy(vertexBuffer.getAllocation().getHostPtr(), vertices.data(), vertices.size() * sizeof(float));
+       flushAlloc(vk, *m_device, vertexBuffer.getAllocation());
+
+       // create index buffer for 6 points
+       // 4--0--2
+       // |  |  |
+       // 5--1--3
+       const std::vector<deUint32> index = { 0, 1, 2, 3, 4, 5 };
+       const VkBufferCreateInfo indexBufferInfo = makeBufferCreateInfo(index.size() * sizeof(deUint32), VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       BufferWithMemory indexBuffer(vk, *m_device, memAlloc, indexBufferInfo, MemoryRequirement::HostVisible);
+       deMemcpy(indexBuffer.getAllocation().getHostPtr(), index.data(), index.size() * sizeof(deUint32));
+       flushAlloc(vk, *m_device, indexBuffer.getAllocation());
+
+       // create indirect buffer
+       const vk::VkDrawIndexedIndirectCommand drawIndirectCommand
+       {
+               (deUint32)index.size(), // indexCount
+               1u,                                             // instanceCount
+               oobFirstIndex,                  // firstIndex
+               0u,                                             // vertexOffset
+               0u,                                             // firstInstance
+       };
+       const VkBufferCreateInfo indirectBufferInfo = makeBufferCreateInfo(sizeof(drawIndirectCommand), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       BufferWithMemory indirectBuffer(vk, *m_device, memAlloc, indirectBufferInfo, MemoryRequirement::HostVisible);
+       if ((m_mode == TM_DRAW_INDEXED_INDIRECT) || (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT))
+       {
+               deMemcpy(indirectBuffer.getAllocation().getHostPtr(), &drawIndirectCommand, sizeof(drawIndirectCommand));
+               flushAlloc(vk, *m_device, indirectBuffer.getAllocation());
+       }
+
+       // create indirect count buffer
+       const VkBufferCreateInfo indirectCountBufferInfo = makeBufferCreateInfo(sizeof(deUint32), VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       BufferWithMemory indirectCountBuffer(vk, *m_device, memAlloc, indirectCountBufferInfo, MemoryRequirement::HostVisible);
+       if (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT)
+       {
+               *(reinterpret_cast<deUint32*>(indirectCountBuffer.getAllocation().getHostPtr())) = 1;
+               flushAlloc(vk, *m_device, indirectCountBuffer.getAllocation());
+       }
+
+       // create output buffer that will be used to read rendered image
+       const VkDeviceSize outputBufferSize = renderSize.x()* renderSize.y()* tcu::getPixelSize(mapVkFormat(colorFormat));
+       const VkBufferCreateInfo outputBufferInfo = makeBufferCreateInfo(outputBufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
+       BufferWithMemory outputBuffer(vk, *m_device, memAlloc, outputBufferInfo, MemoryRequirement::HostVisible);
+
+       // create color buffer
+       VkExtent3D imageExtent = makeExtent3D(renderSize.x(), renderSize.y(), 1u);
+       const VkImageCreateInfo imageCreateInfo
+       {
+               VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,                                                                    //      VkStructureType                 sType;
+               DE_NULL,                                                                                                                                //      const void*                             pNext;
+               0u,                                                                                                                                             //      VkImageCreateFlags              flags;
+               VK_IMAGE_TYPE_2D,                                                                                                               //      VkImageType                             imageType;
+               colorFormat,                                                                                                                    //      VkFormat                                format;
+               imageExtent,                                                                                                                    //      VkExtent3D                              extent;
+               1u,                                                                                                                                             //      deUint32                                mipLevels;
+               1u,                                                                                                                                             //      deUint32                                arrayLayers;
+               VK_SAMPLE_COUNT_1_BIT,                                                                                                  //      VkSampleCountFlagBits   samples;
+               VK_IMAGE_TILING_OPTIMAL,                                                                                                //      VkImageTiling                   tiling;
+               VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,  //      VkImageUsageFlags               usage;
+               VK_SHARING_MODE_EXCLUSIVE,                                                                                              //      VkSharingMode                   sharingMode;
+               0u,                                                                                                                                             //      deUint32                                queueFamilyIndexCount;
+               DE_NULL,                                                                                                                                //      const deUint32*                 pQueueFamilyIndices;
+               VK_IMAGE_LAYOUT_UNDEFINED,                                                                                              //      VkImageLayout                   initialLayout;
+       };
+       const VkImageSubresourceRange colorSRR = makeImageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u);
+       ImageWithMemory colorImage(vk, *m_device, memAlloc, imageCreateInfo, MemoryRequirement::Any);
+       Move<VkImageView> colorImageView = makeImageView(vk, *m_device, colorImage.get(), VK_IMAGE_VIEW_TYPE_2D, colorFormat, colorSRR);
+
+       // create shader modules, renderpass, framebuffer and pipeline
+       Move<VkShaderModule>    vertShaderModule        = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("vert"), 0);
+       Move<VkShaderModule>    fragShaderModule        = createShaderModule(vk, *m_device, m_context.getBinaryCollection().get("frag"), 0);
+       Move<VkRenderPass>              renderPass                      = makeRenderPass(vk, *m_device, colorFormat);
+       Move<VkPipelineLayout>  pipelineLayout          = makePipelineLayout(vk, *m_device, DE_NULL);
+       Move<VkFramebuffer>             framebuffer                     = makeFramebuffer(vk, *m_device, *renderPass, *colorImageView, renderSize.x(), renderSize.y());
+       Move<VkPipeline>                graphicsPipeline        = makeGraphicsPipeline(vk, *m_device, *pipelineLayout,
+                                                                                                                                          *vertShaderModule, DE_NULL, DE_NULL, DE_NULL, *fragShaderModule,
+                                                                                                                                          *renderPass, viewports, scissors, VK_PRIMITIVE_TOPOLOGY_POINT_LIST);
+
+       Move<VkCommandPool>                             cmdPool         = createCommandPool(vk, *m_device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
+       vk::Move<vk::VkCommandBuffer>   cmdBuffer       = allocateCommandBuffer(vk, *m_device, *cmdPool, vk::VK_COMMAND_BUFFER_LEVEL_PRIMARY);
+
+       beginCommandBuffer(vk, *cmdBuffer);
+
+       // transition colorbuffer layout
+       VkImageMemoryBarrier imageBarrier = makeImageMemoryBarrier(0u, VK_ACCESS_SHADER_WRITE_BIT,
+                                                                                                                          VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
+                                                                                                                          colorImage.get(), colorSRR);
+       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
+
+       const VkRect2D renderArea = makeRect2D(0, 0, renderSize.x(), renderSize.y());
+       beginRenderPass(vk, *cmdBuffer, *renderPass, *framebuffer, renderArea, tcu::Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+
+       const VkDeviceSize vBuffOffset = 0;
+       vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *graphicsPipeline);
+       vk.cmdBindVertexBuffers(*cmdBuffer, 0, 1, &vertexBuffer.get(), &vBuffOffset);
+       vk.cmdBindIndexBuffer(*cmdBuffer, indexBuffer.get(), 0, VK_INDEX_TYPE_UINT32);
+
+       // we will draw all points at index 0
+       if (m_mode == TM_DRAW_INDEXED)
+               vk.cmdDrawIndexed(*cmdBuffer, (deUint32)index.size(), 1, oobFirstIndex, 0, 0);
+       else if (m_mode == TM_DRAW_INDEXED_INDIRECT)
+               vk.cmdDrawIndexedIndirect(*cmdBuffer, indirectBuffer.get(), 0, 1, 0);
+       else if (m_mode == TM_DRAW_INDEXED_INDIRECT_COUNT)
+               vk.cmdDrawIndexedIndirectCount(*cmdBuffer, indirectBuffer.get(), 0, indirectCountBuffer.get(), 0, 1, sizeof(VkDrawIndexedIndirectCommand));
+       else if (m_mode == TM_DRAW_MULTI_INDEXED)
+       {
+#ifndef CTS_USES_VULKANSC
+               VkMultiDrawIndexedInfoEXT indexInfo[]
+               {
+                       { oobFirstIndex, 3, 0 },
+                       { oobFirstIndex - 3, 3, 0 },
+               };
+               vk.cmdDrawMultiIndexedEXT(*cmdBuffer, 2, indexInfo, 1, 0, sizeof(VkMultiDrawIndexedInfoEXT), DE_NULL);
+#endif // CTS_USES_VULKANSC
+       }
+
+       endRenderPass(vk, *cmdBuffer);
+
+       // wait till data is transfered to image
+       imageBarrier = makeImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT,
+                                                                                 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                                                                                 colorImage.get(), colorSRR);
+       vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0u, 0u, 0u, 0u, 0u, 1u, &imageBarrier);
+
+       // read back color image
+       const VkImageSubresourceLayers colorSL = makeImageSubresourceLayers(VK_IMAGE_ASPECT_COLOR_BIT, 0u, 0u, 1u);
+       const VkBufferImageCopy copyRegion = makeBufferImageCopy(imageExtent, colorSL);
+       vk.cmdCopyImageToBuffer(*cmdBuffer, colorImage.get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outputBuffer.get(), 1u, &copyRegion);
+
+       endCommandBuffer(vk, *cmdBuffer);
+
+       VkQueue queue;
+       vk.getDeviceQueue(*m_device, queueFamilyIndex, 0, &queue);
+       submitCommandsAndWait(vk, *m_device, queue, *cmdBuffer);
+
+       // for robustBufferAccess (the original feature) OOB access will return undefined value;
+       // we can only expect that above drawing will be executed without errors (we can't expect any specific result)
+       if (m_robustnessVersion < 2u)
+               return tcu::TestStatus::pass("Pass");
+
+       // get output buffer
+       invalidateAlloc(vk, *m_device, outputBuffer.getAllocation());
+       const tcu::TextureFormat resultFormat = mapVkFormat(colorFormat);
+       tcu::ConstPixelBufferAccess outputAccess(resultFormat, renderSize.x(), renderSize.y(), 1u, outputBuffer.getAllocation().getHostPtr());
+
+       // for VK_EXT_robustness2 OOB access should return 0 and we can verify
+       // that single fragment is drawn in the middle-top part of the image
+       tcu::UVec4 expectedValue(51, 255, 127, 255);
+       bool fragmentFound = false;
+
+       for (deUint32 x = 0u; x < renderSize.x(); ++x)
+       for (deUint32 y = 0u; y < renderSize.y(); ++y)
+       {
+               tcu::UVec4 pixel = outputAccess.getPixelUint(x, y, 0);
+
+               if (tcu::boolAll(tcu::lessThan(tcu::absDiff(pixel, expectedValue), tcu::UVec4(2))))
+               {
+                       if (fragmentFound)
+                       {
+                               m_context.getTestContext().getLog()
+                                       << tcu::TestLog::Message << "Expected single fragment with: " << expectedValue
+                                       << " color, got more, second at " << tcu::UVec2(x, y) << tcu::TestLog::EndMessage
+                                       << tcu::TestLog::Image("Result", "Result", outputAccess);
+                               return tcu::TestStatus::fail("Fail");
+                       }
+                       else if ((y < 3) && (x > 5) && (x < 10))
+                               fragmentFound = true;
+                       else
+                       {
+                               m_context.getTestContext().getLog()
+                                       << tcu::TestLog::Message << "Expected fragment in the middle-top of the image, got at: "
+                                       << tcu::UVec2(x, y) << tcu::TestLog::EndMessage
+                                       << tcu::TestLog::Image("Result", "Result", outputAccess);
+                               return tcu::TestStatus::fail("Fail");
+                       }
+               }
+       }
+
+       if (fragmentFound)
+               return tcu::TestStatus::pass("Pass");
+       return tcu::TestStatus::fail("Fail");
+}
+
+class DrawIndexedTestCase : public vkt::TestCase
+{
+public:
+
+                                               DrawIndexedTestCase             (tcu::TestContext&              testContext,
+                                                                                                const std::string&             name,
+                                                                                                TestMode                               mode,
+                                                                                                deUint32                               robustnessVersion);
+
+       virtual                         ~DrawIndexedTestCase    (void) = default;
+
+       void                            checkSupport                    (Context& context) const override;
+       TestInstance*           createInstance                  (Context& context) const override;
+       void                            initPrograms                    (SourceCollections& programCollection) const override;
+
+protected:
+       const TestMode          m_testMode;
+       const deUint32          m_robustnessVersion;
+};
+
+DrawIndexedTestCase::DrawIndexedTestCase(tcu::TestContext&             testContext,
+                                                                                const std::string&             name,
+                                                                                TestMode                               mode,
+                                                                                deUint32                               robustnessVersion)
+
+       : vkt::TestCase                 (testContext, name, "")
+       , m_testMode                    (mode)
+       , m_robustnessVersion   (robustnessVersion)
+{}
+
+void DrawIndexedTestCase::checkSupport(Context& context) const
+{
+       if (context.isDeviceFunctionalitySupported("VK_KHR_portability_subset") && !context.getDeviceFeatures().robustBufferAccess)
+               TCU_THROW(NotSupportedError, "VK_KHR_portability_subset: robustBufferAccess not supported by this implementation");
+
+       if (m_testMode == TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT)
+               context.requireDeviceFunctionality("VK_KHR_draw_indirect_count");
+       if (m_testMode == TestMode::TM_DRAW_MULTI_INDEXED)
+               context.requireDeviceFunctionality("VK_EXT_multi_draw");
+       if (m_robustnessVersion == 2)
+       {
+               context.requireDeviceFunctionality("VK_EXT_robustness2");
+
+               const auto& vki                         = context.getInstanceInterface();
+               const auto      physicalDevice  = context.getPhysicalDevice();
+
+               VkPhysicalDeviceRobustness2FeaturesEXT  robustness2Features     = initVulkanStructure();
+               VkPhysicalDeviceFeatures2                               features2                       = initVulkanStructure(&robustness2Features);
+
+               vki.getPhysicalDeviceFeatures2(physicalDevice, &features2);
+
+               if (!robustness2Features.robustBufferAccess2)
+                       TCU_THROW(NotSupportedError, "robustBufferAccess2 not supported");
+       }
+}
+
+TestInstance* DrawIndexedTestCase::createInstance(Context& context) const
+{
+       VkPhysicalDeviceFeatures2 features2 = initVulkanStructure();
+       features2.features.robustBufferAccess = DE_TRUE;
+
+       void** nextPtr = &features2.pNext;
+
+#ifndef CTS_USES_VULKANSC
+       VkPhysicalDeviceMultiDrawFeaturesEXT multiDrawFeatures = initVulkanStructure();
+       if (m_testMode == TestMode::TM_DRAW_MULTI_INDEXED)
+       {
+               multiDrawFeatures.multiDraw = DE_TRUE;
+               addToChainVulkanStructure(&nextPtr, multiDrawFeatures);
+       }
+#endif // CTS_USES_VULKANSC
+
+       VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = initVulkanStructure();
+       if (m_robustnessVersion > 1u)
+       {
+               robustness2Features.robustBufferAccess2 = DE_TRUE;
+               addToChainVulkanStructure(&nextPtr, robustness2Features);
+       }
+
+       deUint32 apiVersion = context.getUsedApiVersion();
+       VkPhysicalDeviceVulkan12Features vulkan12Features = initVulkanStructure();
+       if ((m_testMode == TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT) && (apiVersion > VK_MAKE_API_VERSION(0, 1, 1, 0)))
+       {
+               vulkan12Features.drawIndirectCount = DE_TRUE;
+               addToChainVulkanStructure(&nextPtr, vulkan12Features);
+       }
+
+       std::shared_ptr<CustomInstanceWrapper> instanceWrapper(new CustomInstanceWrapper(context));
+       Move<VkDevice>  device = createRobustBufferAccessDevice(context, instanceWrapper->instance, instanceWrapper->instance.getDriver(), &features2);
+       DeviceDriverPtr deviceDriver =
+#ifndef CTS_USES_VULKANSC
+               DeviceDriverPtr(new DeviceDriver(context.getPlatformInterface(), instanceWrapper->instance, *device));
+#else
+               DeviceDriverPtr(new DeviceDriverSC(context.getPlatformInterface(), instanceWrapper->instance, *device, context.getTestContext().getCommandLine(),
+                                                                                  context.getResourceInterface(), context.getDeviceVulkanSC10Properties(), context.getDeviceProperties()),
+                                               vk::DeinitDeviceDeleter(context.getResourceInterface().get(), *device));
+#endif // CTS_USES_VULKANSC
+
+       return new DrawIndexedInstance(context, instanceWrapper, device, deviceDriver, m_testMode, m_robustnessVersion);
+}
+
+void DrawIndexedTestCase::initPrograms(SourceCollections& sourceCollections) const
+{
+       std::string vertexSource(
+               "#version 450\n"
+               "layout(location = 0) in vec4 inPosition;\n"
+               "void main(void)\n"
+               "{\n"
+               "\tgl_Position = inPosition;\n"
+               "\tgl_PointSize = 1.0;\n"
+               "}\n");
+       sourceCollections.glslSources.add("vert") << glu::VertexSource(vertexSource);
+
+       std::string fragmentSource(
+               "#version 450\n"
+               "precision highp float;\n"
+               "layout(location = 0) out vec4 fragColor;\n"
+               "void main (void)\n"
+               "{\n"
+               "\tfragColor = vec4(0.2, 1.0, 0.5, 1.0);\n"
+               "}\n");
+
+       sourceCollections.glslSources.add("frag") << glu::FragmentSource(fragmentSource);
+}
+
+tcu::TestCaseGroup* createIndexAccessTests(tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> indexAccessTests(new tcu::TestCaseGroup(testCtx, "index_access", "Test access outside of the buffer for indices"));
+
+       struct TestConfig
+       {
+               std::string             name;
+               TestMode                mode;
+       };
+
+       const std::vector<TestConfig> testConfigs
+       {
+               { "draw_indexed",                                       TestMode::TM_DRAW_INDEXED },
+               { "draw_indexed_indirect",                      TestMode::TM_DRAW_INDEXED_INDIRECT },
+               { "draw_indexed_indirect_count",        TestMode::TM_DRAW_INDEXED_INDIRECT_COUNT },
+               { "draw_multi_indexed",                         TestMode::TM_DRAW_MULTI_INDEXED },
+       };
+
+       for (deUint32 robustnessVersion = 1; robustnessVersion < 3; ++robustnessVersion)
+       {
+               for (const auto& c : testConfigs)
+               {
+                       std::string name = c.name + "_" + std::to_string(robustnessVersion);
+                       indexAccessTests->addChild(new DrawIndexedTestCase(testCtx, name, c.mode, robustnessVersion));
+               }
+       }
+
+       return indexAccessTests.release();
+}
+
+} // robustness
+} // vkt
diff --git a/external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.hpp b/external/vulkancts/modules/vulkan/robustness/vktRobustnessIndexAccessTests.hpp
new file mode 100644 (file)
index 0000000..9bd773c
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef _VKTROBUSTNESSINDEXACCESSTESTS_HPP
+#define _VKTROBUSTNESSINDEXACCESSTESTS_HPP
+/*------------------------------------------------------------------------
+ * Vulkan Conformance Tests
+ * ------------------------
+ *
+ * Copyright (c) 2022 The Khronos Group Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Robust Index Buffer Access Tests
+ *//*--------------------------------------------------------------------*/
+
+#include "tcuDefs.hpp"
+#include "vkDefs.hpp"
+#include "vktTestCase.hpp"
+
+namespace vkt
+{
+namespace robustness
+{
+
+tcu::TestCaseGroup* createIndexAccessTests (tcu::TestContext& testCtx);
+
+} // robustness
+} // vkt
+
+#endif // _VKTROBUSTNESSINDEXACCESSTESTS_HPP
index c84e706..8df838a 100644 (file)
@@ -26,6 +26,7 @@
 #include "vktRobustnessExtsTests.hpp"
 #include "vktRobustnessBufferAccessTests.hpp"
 #include "vktRobustnessVertexAccessTests.hpp"
+#include "vktRobustnessIndexAccessTests.hpp"
 #include "vktRobustBufferAccessWithVariablePointersTests.hpp"
 #include "vktNonRobustBufferAccessTests.hpp"
 #include "vktTestGroupUtil.hpp"
@@ -61,6 +62,7 @@ tcu::TestCaseGroup* createTests (tcu::TestContext& testCtx)
 
        robustnessTests->addChild(createBufferAccessTests(testCtx));
        robustnessTests->addChild(createVertexAccessTests(testCtx));
+       robustnessTests->addChild(createIndexAccessTests(testCtx));
 
        std::vector<tcu::TestNode*> children;
        robustnessTests->getChildren(children);
index fa81284..3dde135 100644 (file)
@@ -55267,6 +55267,14 @@ dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.don
 dEQP-VK.robustness.pipeline_robustness.image_robustness.push.notemplate.r64i.dontunroll.nonvolatile.sampled_image.no_fmt_qual.img.samples_1.2d_array.vert
 dEQP-VK.robustness.non_robust_buffer_access.unexecuted_oob_underflow
 dEQP-VK.robustness.non_robust_buffer_access.unexecuted_oob_overflow
+dEQP-VK.robustness.index_access.draw_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_1
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_1
+dEQP-VK.robustness.index_access.draw_multi_indexed_1
+dEQP-VK.robustness.index_access.draw_indexed_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_2
+dEQP-VK.robustness.index_access.draw_indexed_indirect_count_2
+dEQP-VK.robustness.index_access.draw_multi_indexed_2
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.comp
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.frag
 dEQP-VK.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.vert
index 5fe06e2..c9f32d9 100644 (file)
@@ -19644,6 +19644,14 @@ dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_0
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_16_single_buffer
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_30_middle_of_buffer
 dEQP-VKSC.robustness.robustness1_vertex_access.out_of_bounds_stride_8_middle_of_buffer_separate
+dEQP-VKSC.robustness.index_access.draw_indexed_1
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_1
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_count_1
+dEQP-VKSC.robustness.index_access.draw_multi_indexed_1
+dEQP-VKSC.robustness.index_access.draw_indexed_2
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_2
+dEQP-VKSC.robustness.index_access.draw_indexed_indirect_count_2
+dEQP-VKSC.robustness.index_access.draw_multi_indexed_2
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.comp
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.frag
 dEQP-VKSC.robustness.image_robustness.bind.notemplate.r32i.dontunroll.nonvolatile.storage_image.no_fmt_qual.img.samples_1.1d.vert