layers: lx464 Add drawtime validation of bound buffer memory.
authorMark Young <marky@lunarg.com>
Mon, 11 Apr 2016 23:45:37 +0000 (17:45 -0600)
committerTobin Ehlis <tobine@google.com>
Thu, 14 Apr 2016 22:21:21 +0000 (16:21 -0600)
Add a drawtime check to validate that storage or uniform buffers
have valid memory bound to them at draw time before using.

Change-Id: Ia0a07f221dfcb2ea4315e4f52ee04d7cdda22cf7

layers/core_validation.cpp

index ce15dd9..a51d7bd 100644 (file)
@@ -2736,42 +2736,80 @@ static bool validate_and_update_drawtime_descriptor_state(
                     switch (set_node->pDescriptorUpdates[i]->sType) {
                     case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
                         pWDS = (VkWriteDescriptorSet *)set_node->pDescriptorUpdates[i];
-                        if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
+
+                        // Verify uniform and storage buffers actually are bound to valid memory at draw time.
+                        if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) ||
+                            (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
+                            (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) ||
                             (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
                             for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
-                                bufferSize = dev_data->bufferMap[pWDS->pBufferInfo[j].buffer].createInfo.size;
-                                uint32_t dynOffset = pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex];
-                                if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) {
-                                    if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) {
+                                auto buffer_node = dev_data->bufferMap.find(pWDS->pBufferInfo[j].buffer);
+                                if (buffer_node == dev_data->bufferMap.end()) {
+                                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                                                      reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
+                                                      DRAWSTATE_INVALID_BUFFER, "DS",
+                                                      "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index #%u"
+                                                      " is not defined!  Has vkCreateBuffer been called?",
+                                                      reinterpret_cast<const uint64_t &>(set_node->set),
+                                                      string_VkDescriptorType(pWDS->descriptorType),
+                                                      reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
+                                } else {
+                                    auto mem_entry = dev_data->memObjMap.find(buffer_node->second.mem);
+                                    if (mem_entry == dev_data->memObjMap.end()) {
                                         result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
                                                           VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
                                                           reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
-                                                          DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
-                                                          "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of "
-                                                          "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". "
-                                                          "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64
-                                                          ") which has a size of %#" PRIxLEAST64 ".",
-                                                          reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
-                                                          pWDS->pBufferInfo[j].offset,
-                                                          reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
+                                                          DRAWSTATE_INVALID_BUFFER, "DS",
+                                                          "VkDescriptorSet (%#" PRIxLEAST64 ") %s (%#" PRIxLEAST64 ") at index"
+                                                          " #%u, has no memory bound to it!",
+                                                          reinterpret_cast<const uint64_t &>(set_node->set),
+                                                          string_VkDescriptorType(pWDS->descriptorType),
+                                                          reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), i);
                                     }
-                                } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) > bufferSize) {
-                                    result |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
-                                                      VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
-                                                      reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
-                                                      DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
-                                                      "VkDescriptorSet (%#" PRIxLEAST64
-                                                      ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
-                                                      "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
-                                                      " from its update, this oversteps its buffer "
-                                                      "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
-                                                      reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
-                                                      pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
-                                                      reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
                                 }
-                                dynOffsetIndex++;
+                                // If it's a dynamic buffer, make sure the offsets are within the buffer.
+                                if ((pWDS->descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) ||
+                                    (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)) {
+                                    bufferSize = dev_data->bufferMap[pWDS->pBufferInfo[j].buffer].createInfo.size;
+                                    uint32_t dynOffset =
+                                        pCB->lastBound[VK_PIPELINE_BIND_POINT_GRAPHICS].dynamicOffsets[dynOffsetIndex];
+                                    if (pWDS->pBufferInfo[j].range == VK_WHOLE_SIZE) {
+                                        if ((dynOffset + pWDS->pBufferInfo[j].offset) > bufferSize) {
+                                            result |= log_msg(
+                                                dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                                VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                                                reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
+                                                DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
+                                                "VkDescriptorSet (%#" PRIxLEAST64 ") bound as set #%u has range of "
+                                                "VK_WHOLE_SIZE but dynamic offset %#" PRIxLEAST32 ". "
+                                                "combined with offset %#" PRIxLEAST64 " oversteps its buffer (%#" PRIxLEAST64
+                                                ") which has a size of %#" PRIxLEAST64 ".",
+                                                reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
+                                                pWDS->pBufferInfo[j].offset,
+                                                reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
+                                        }
+                                    } else if ((dynOffset + pWDS->pBufferInfo[j].offset + pWDS->pBufferInfo[j].range) >
+                                               bufferSize) {
+                                        result |=
+                                            log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
+                                                    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT,
+                                                    reinterpret_cast<const uint64_t &>(set_node->set), __LINE__,
+                                                    DRAWSTATE_DYNAMIC_OFFSET_OVERFLOW, "DS",
+                                                    "VkDescriptorSet (%#" PRIxLEAST64
+                                                    ") bound as set #%u has dynamic offset %#" PRIxLEAST32 ". "
+                                                    "Combined with offset %#" PRIxLEAST64 " and range %#" PRIxLEAST64
+                                                    " from its update, this oversteps its buffer "
+                                                    "(%#" PRIxLEAST64 ") which has a size of %#" PRIxLEAST64 ".",
+                                                    reinterpret_cast<const uint64_t &>(set_node->set), i, dynOffset,
+                                                    pWDS->pBufferInfo[j].offset, pWDS->pBufferInfo[j].range,
+                                                    reinterpret_cast<const uint64_t &>(pWDS->pBufferInfo[j].buffer), bufferSize);
+                                    }
+                                    dynOffsetIndex++;
+                                }
                             }
-                        } else if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
+                        }
+                        if (pWDS->descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE) {
                             for (uint32_t j = 0; j < pWDS->descriptorCount; ++j) {
                                 pCB->updateImages.insert(pWDS->pImageInfo[j].imageView);
                             }