layers: Improve DrawState write descriptor update
authorTobin Ehlis <tobin@lunarg.com>
Tue, 27 Oct 2015 18:25:35 +0000 (12:25 -0600)
committerTobin Ehlis <tobin@lunarg.com>
Wed, 28 Oct 2015 15:19:47 +0000 (09:19 -0600)
Validate that stageFlags are the same for a single write update.
Validate that all sampler updates from a single write update are either immutable or non-immutable.
Refactor update contents check to have a loop per switch case instead of switching for each loop iteration.
Added two new validation errors:

DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH
DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE

layers/draw_state.cpp
layers/draw_state.h
layers/vk_validation_layer_details.md

index c9db5bb..2bc0a09 100755 (executable)
@@ -782,12 +782,12 @@ static VkBool32 getUpdateEndIndex(layer_data* my_data, const VkDevice device, co
     return skipCall;
 }
 // Verify that the descriptor type in the update struct matches what's expected by the layout
-static VkBool32 validateUpdateType(layer_data* my_data, const VkDevice device, const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct)
+static VkBool32 validateUpdateConsistency(layer_data* my_data, const VkDevice device, const LAYOUT_NODE* pLayout, const GENERIC_HEADER* pUpdateStruct, uint32_t startIndex, uint32_t endIndex)
 {
     // First get actual type of update
     VkBool32 skipCall = VK_FALSE;
     VkDescriptorType actualType;
-    uint32_t i = 0, startIndex = 0, endIndex = 0;
+    uint32_t i = 0;
     switch (pUpdateStruct->sType)
     {
         case VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET:
@@ -801,14 +801,19 @@ static VkBool32 validateUpdateType(layer_data* my_data, const VkDevice device, c
             skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, 0, 0, DRAWSTATE_INVALID_UPDATE_STRUCT, "DS",
                     "Unexpected UPDATE struct of type %s (value %u) in vkUpdateDescriptors() struct tree", string_VkStructureType(pUpdateStruct->sType), pUpdateStruct->sType);
     }
-    skipCall |= getUpdateStartIndex(my_data, device, pLayout, pUpdateStruct, &startIndex);
-    skipCall |= getUpdateEndIndex(my_data, device, pLayout, pUpdateStruct, &endIndex);
     if (VK_FALSE == skipCall) {
+        // Set first stageFlags as reference and verify that all other updates match it
+        VkShaderStageFlags refStageFlags = pLayout->stageFlags[startIndex];
         for (i = startIndex; i <= endIndex; i++) {
             if (pLayout->descriptorTypes[i] != actualType) {
                 skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, 0, 0, DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH, "DS",
-                        "Descriptor update type of %s has descriptor type %s that does not match overlapping binding descriptor type of %s!",
-                        string_VkStructureType(pUpdateStruct->sType), string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i]));
+                    "Write descriptor update has descriptor type %s that does not match overlapping binding descriptor type of %s!",
+                    string_VkDescriptorType(actualType), string_VkDescriptorType(pLayout->descriptorTypes[i]));
+            }
+            if (pLayout->stageFlags[i] != refStageFlags) {
+                skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, (VkDbgObjectType) 0, 0, 0, DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH, "DS",
+                    "Write descriptor update has stageFlags %x that do not match overlapping binding descriptor stageFlags of %x!",
+                    refStageFlags, pLayout->stageFlags[i]);
             }
         }
     }
@@ -1001,75 +1006,82 @@ static VkBool32 validateUpdateContents(const layer_data* my_data, const VkWriteD
     VkImageLayout* pImageLayout = NULL;
     VkDescriptorBufferInfo* pBufferInfo = NULL;
     VkBool32 immutable = VK_FALSE;
-    // TODO : Can refactor this to only switch once and then have loop inside of switch case
-    for (uint32_t i=0; i<pWDS->count; ++i) {
-        switch (pWDS->descriptorType) {
-            case VK_DESCRIPTOR_TYPE_SAMPLER:
+    uint32_t i = 0;
+    // For given update type, verify that update contents are correct
+    switch (pWDS->descriptorType) {
+        case VK_DESCRIPTOR_TYPE_SAMPLER:
+            for (i=0; i<pWDS->count; ++i) {
                 skipCall |= validateSampler(my_data, &(pWDS->pImageInfo[i].sampler), immutable);
-                break;
-            case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+            }
+            break;
+        case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
+            for (i=0; i<pWDS->count; ++i) {
                 if (NULL == pLayoutBinding->pImmutableSamplers) {
                     pSampler = &(pWDS->pImageInfo[i].sampler);
+                    if (immutable) {
+                        skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_SAMPLER, pSampler->handle, 0, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
+                            "vkUpdateDescriptorSets: Update #%u is not an immutable sampler %#" PRIxLEAST64 ", but previous update(s) from this "
+                            "VkWriteDescriptorSet struct used an immutable sampler. All updates from a single struct must either "
+                            "use immutable or non-immutable samplers.", i, pSampler->handle);
+                    }
                 } else {
+                    if (i>0 && !immutable) {
+                        skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_SAMPLER, pSampler->handle, 0, DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, "DS",
+                            "vkUpdateDescriptorSets: Update #%u is an immutable sampler, but previous update(s) from this "
+                            "VkWriteDescriptorSet struct used a non-immutable sampler. All updates from a single struct must either "
+                            "use immutable or non-immutable samplers.", i);
+                    }
                     immutable = VK_TRUE;
                     pSampler = &(pLayoutBinding->pImmutableSamplers[i]);
                 }
                 skipCall |= validateSampler(my_data, pSampler, immutable);
-                // Intentionally fall through here to also validate image stuff
-            case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
-            case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
-            case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+            }
+            // Intentionally fall through here to also validate image stuff
+        case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
+        case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
+        case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
+            for (i=0; i<pWDS->count; ++i) {
                 skipCall |= validateImageView(my_data, &(pWDS->pImageInfo[i].imageView), pWDS->pImageInfo[i].imageLayout);
-                break;
-            case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
-            case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+            }
+            break;
+        case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
+        case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
+            for (i=0; i<pWDS->count; ++i) {
                 skipCall |= validateBufferView(my_data, &(pWDS->pTexelBufferView[i]));
-                break;
-            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
-            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
-            case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
-            case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+            }
+            break;
+        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
+        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
+        case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
+        case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
+            for (i=0; i<pWDS->count; ++i) {
                 skipCall |= validateBufferInfo(my_data, &(pWDS->pBufferInfo[i]));
-                break;
-        }
+            }
+            break;
     }
     return skipCall;
 }
-
-// update DS mappings based on pUpdateArray
-// TODO : Verify we validate this spec req: All consecutive bindings updated via a single
-//  VkWriteDescriptorSet structure must have identical descriptorType and stageFlags,
-//  and must all either use immutable samplers or none must use immutable samplers.
-static VkBool32 dsUpdate(layer_data* my_data, VkDevice device, VkStructureType type, uint32_t updateCount, const void* pUpdateArray)
+// update DS mappings based on write and copy update arrays
+static VkBool32 dsUpdate(layer_data* my_data, VkDevice device, uint32_t writeCount, const VkWriteDescriptorSet* pWDS, uint32_t copyCount, const VkCopyDescriptorSet* pCDS)
 {
-    const VkWriteDescriptorSet *pWDS = NULL;
     VkBool32 skipCall = VK_FALSE;
 
-    if (type == VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET) {
-        pWDS = (const VkWriteDescriptorSet *)pUpdateArray;
-    } else {
-        // TODO : copy update validation is completely broken so just skip it for now
-        //  Need to add separate loop to verify copy array
-        return VK_FALSE;
-    }
-
     loader_platform_thread_lock_mutex(&globalLock);
     LAYOUT_NODE* pLayout = NULL;
     VkDescriptorSetLayoutCreateInfo* pLayoutCI = NULL;
-    // TODO : If pCIList is NULL, flag error
-    // Perform all updates
-    for (uint32_t i = 0; i < updateCount; i++) {
+    // Validate Write updates
+    for (uint32_t i = 0; i < writeCount; i++) {
         VkDescriptorSet ds = pWDS[i].destSet;
-        SET_NODE* pSet = my_data->setMap[ds.handle]; // getSetNode() without locking
+        SET_NODE* pSet = my_data->setMap[ds.handle];
         GENERIC_HEADER* pUpdate = (GENERIC_HEADER*) &pWDS[i];
         pLayout = pSet->pLayout;
         // First verify valid update struct
         if ((skipCall = validUpdateStruct(my_data, device, pUpdate)) == VK_TRUE) {
             break;
         }
-        // Make sure that binding is within bounds
         uint32_t binding = 0, endIndex = 0;
-        skipCall |= getUpdateBinding(my_data, device, pUpdate, &binding);
+        binding = pWDS[i].destBinding;
+        // Make sure that layout being updated has the binding being updated
         if (pLayout->createInfo.count < binding) {
             skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds.handle, 0, DRAWSTATE_INVALID_UPDATE_INDEX, "DS",
                     "Descriptor Set %p does not have binding to match update binding %u for update type %s!", ds, binding, string_VkStructureType(pUpdate->sType));
@@ -1077,15 +1089,16 @@ static VkBool32 dsUpdate(layer_data* my_data, VkDevice device, VkStructureType t
             // Next verify that update falls within size of given binding
             skipCall |= getUpdateEndIndex(my_data, device, pLayout, pUpdate, &endIndex);
             if (getBindingEndIndex(pLayout, binding) < endIndex) {
-                // TODO : Keep count of layout CI structs and size this string dynamically based on that count
                 pLayoutCI = &pLayout->createInfo;
                 string DSstr = vk_print_vkdescriptorsetlayoutcreateinfo(pLayoutCI, "{DS}    ");
                 skipCall |= log_msg(my_data->report_data, VK_DBG_REPORT_ERROR_BIT, VK_OBJECT_TYPE_DESCRIPTOR_SET, ds.handle, 0, DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS, "DS",
                         "Descriptor update type of %s is out of bounds for matching binding %u in Layout w/ CI:\n%s!", string_VkStructureType(pUpdate->sType), binding, DSstr.c_str());
             } else { // TODO : should we skip update on a type mismatch or force it?
-                // Layout bindings match w/ update ok, now verify that update is of the right type
-                if ((skipCall = validateUpdateType(my_data, device, pLayout, pUpdate)) == VK_FALSE) {
-                    // The update matches the layout, but need to make sure it's self-consistent as well
+                uint32_t startIndex;
+                skipCall |= getUpdateStartIndex(my_data, device, pLayout, pUpdate, &startIndex);
+                // Layout bindings match w/ update, now verify that update type & stageFlags are the same for entire update
+                if ((skipCall = validateUpdateConsistency(my_data, device, pLayout, pUpdate, startIndex, endIndex)) == VK_FALSE) {
+                    // The update is within bounds and consistent, but need to make sure contents make sense as well
                     if ((skipCall = validateUpdateContents(my_data, &pWDS[i], &pLayout->createInfo.pBinding[binding])) == VK_FALSE) {
                         // Update is good. Save the update info
                         // Create new update struct for this set's shadow copy
@@ -1099,9 +1112,6 @@ static VkBool32 dsUpdate(layer_data* my_data, VkDevice device, VkStructureType t
                             pNewNode->pNext = pSet->pUpdateStructs;
                             pSet->pUpdateStructs = pNewNode;
                             // Now update appropriate descriptor(s) to point to new Update node
-                            skipCall |= getUpdateEndIndex(my_data, device, pLayout, pUpdate, &endIndex);
-                            uint32_t startIndex;
-                            skipCall |= getUpdateStartIndex(my_data, device, pLayout, pUpdate, &startIndex);
                             for (uint32_t j = startIndex; j <= endIndex; j++) {
                                 assert(j<pSet->descriptorCount);
                                 pSet->ppDescriptors[j] = pNewNode;
@@ -2026,11 +2036,13 @@ VK_LAYER_EXPORT VkResult VKAPI vkCreateDescriptorSetLayout(VkDevice device, cons
         }
         if (totalCount > 0) {
             pNewNode->descriptorTypes.resize(totalCount);
+            pNewNode->stageFlags.resize(totalCount);
             uint32_t offset = 0;
             uint32_t j = 0;
             for (uint32_t i=0; i<pCreateInfo->count; i++) {
                 for (j = 0; j < pCreateInfo->pBinding[i].arraySize; j++) {
                     pNewNode->descriptorTypes[offset + j] = pCreateInfo->pBinding[i].descriptorType;
+                    pNewNode->stageFlags[offset + j] = pCreateInfo->pBinding[i].stageFlags;
                 }
                 offset += j;
             }
@@ -2195,10 +2207,9 @@ VK_LAYER_EXPORT VkResult VKAPI vkFreeDescriptorSets(VkDevice device, VkDescripto
 
 VK_LAYER_EXPORT void VKAPI vkUpdateDescriptorSets(VkDevice device, uint32_t writeCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t copyCount, const VkCopyDescriptorSet* pDescriptorCopies)
 {
-    // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when both updates return VK_FALSE
+    // dsUpdate will return VK_TRUE only if a bailout error occurs, so we want to call down tree when update returns VK_FALSE
     layer_data* dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
-    if (!dsUpdate(dev_data, device, VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, writeCount, pDescriptorWrites) &&
-        !dsUpdate(dev_data, device, VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET, copyCount, pDescriptorCopies)) {
+    if (!dsUpdate(dev_data, device, writeCount, pDescriptorWrites, copyCount, pDescriptorCopies)) {
         dev_data->device_dispatch_table->UpdateDescriptorSets(device, writeCount, pDescriptorWrites, copyCount, pDescriptorCopies);
     }
 }
index 9bd7ee2..8f7f2e9 100755 (executable)
@@ -45,6 +45,7 @@ typedef enum _DRAW_STATE_ERROR
     //DRAWSTATE_MISSING_DOT_PROGRAM,              // No "dot" program in order to generate png image
     DRAWSTATE_OUT_OF_MEMORY,                    // malloc failed
     DRAWSTATE_DESCRIPTOR_TYPE_MISMATCH,         // Type in layout vs. update are not the same
+    DRAWSTATE_DESCRIPTOR_STAGEFLAGS_MISMATCH,   // StageFlags in layout are not the same throughout a single VkWriteDescriptorSet update
     DRAWSTATE_DESCRIPTOR_UPDATE_OUT_OF_BOUNDS,  // Descriptors set for update out of bounds for corresponding layout section
     DRAWSTATE_DESCRIPTOR_POOL_EMPTY,            // Attempt to allocate descriptor from a pool with no more descriptors of that type available
     DRAWSTATE_CANT_FREE_FROM_NON_FREE_POOL,     // Invalid to call vkFreeDescriptorSets on Sets allocated from a NON_FREE Pool
@@ -75,6 +76,7 @@ typedef enum _DRAW_STATE_ERROR
     DRAWSTATE_MISSING_ATTACHMENT_REFERENCE,     // Attachment reference must be present in active subpass
     DRAWSTATE_INVALID_EXTENSION,
     DRAWSTATE_SAMPLER_DESCRIPTOR_ERROR,         // A Descriptor of *_SAMPLER type is being updated with an invalid or bad Sampler
+    DRAWSTATE_INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE, // Descriptors of *COMBINED_IMAGE_SAMPLER type are being updated where some, but not all, of the updates use immutable samplers
     DRAWSTATE_IMAGEVIEW_DESCRIPTOR_ERROR,       // A Descriptor of *_IMAGE or *_ATTACHMENT type is being updated with an invalid or bad ImageView
     DRAWSTATE_BUFFERVIEW_DESCRIPTOR_ERROR,      // A Descriptor of *_TEXEL_BUFFER type is being updated with an invalid or bad BufferView
     DRAWSTATE_BUFFERINFO_DESCRIPTOR_ERROR,      // A Descriptor of *_[UNIFORM|STORAGE]_BUFFER_[DYNAMIC] type is being updated with an invalid or bad BufferView
@@ -145,6 +147,7 @@ typedef struct _LAYOUT_NODE {
     uint32_t                        startIndex; // 1st index of this layout
     uint32_t                        endIndex; // last index of this layout
     vector<VkDescriptorType>        descriptorTypes; // Type per descriptor in this layout to verify correct updates
+    vector<VkShaderStageFlags>      stageFlags; // stageFlags per descriptor in this layout to verify correct updates
 } LAYOUT_NODE;
 // Store layouts and pushconstants for PipelineLayout
 struct PIPELINE_LAYOUT_NODE {
index beb4413..8d0eea2 100644 (file)
@@ -28,7 +28,8 @@ The DrawState layer tracks state leading into Draw cmds. This includes the Pipel
 | Cmd Buffer Begin | Check that BeginCommandBuffer was called for this command buffer when binding commands or calling end | NO_BEGIN_CMD_BUFFER | vkEndCommandBuffer vkCmdBindPipeline vkCmdSetViewport vkCmdSetLineWidth vkCmdSetDepthBias vkCmdSetBlendConstants vkCmdSetDepthBounds vkCmdSetStencilCompareMask vkCmdSetStencilWriteMask vkCmdSetStencilReference vkCmdBindDescriptorSets vkCmdBindIndexBuffer vkCmdBindVertexBuffers vkCmdDraw vkCmdDrawIndexed vkCmdDrawIndirect vkCmdDrawIndexedIndirect vkCmdDispatch vkCmdDispatchIndirect vkCmdCopyBuffer vkCmdCopyImage vkCmdBlitImage vkCmdCopyBufferToImage vkCmdCopyImageToBuffer vkCmdUpdateBuffer vkCmdFillBuffer vkCmdClearAttachments vkCmdClearColorImage vkCmdClearDepthStencilImage vkCmdResolveImage vkCmdSetEvent vkCmdResetEvent vkCmdWaitEvents vkCmdPipelineBarrier vkCmdBeginQuery vkCmdEndQuery vkCmdResetQueryPool vkCmdWriteTimestamp | NoBeginCmdBuffer | NA |
 | Cmd Buffer Submit Count | Verify that ONE_TIME submit cmdbuffer is not submitted multiple times | CMD_BUFFER_SINGLE_SUBMIT_VIOLATION | vkBeginCommandBuffer, vkQueueSubmit | CmdBufferTwoSubmits | NA |
 | Valid Secondary CmdBuffer | Validates that no primary command buffers are sent to vkCmdExecuteCommands() are | INVALID_SECONDARY_CMD_BUFFER | vkCmdExecuteCommands | ExecuteCommandsPrimaryCB | NA |
-| Descriptor Type | Verify Descriptor type in bound descriptor set layout matches descriptor type specified in update | DESCRIPTOR_TYPE_MISMATCH | vkUpdateDescriptorSets | DSTypeMismatch | With various DS API updates, need to revisit this code |
+| Descriptor Type | Verify Descriptor type in bound descriptor set layout matches descriptor type specified in update | DESCRIPTOR_TYPE_MISMATCH | vkUpdateDescriptorSets | DSTypeMismatch | NA |
+| Descriptor StageFlags | Verify all descriptors within a single write update have the same stageFlags | DESCRIPTOR_STAGEFLAGS_MISMATCH | vkUpdateDescriptorSets | NONE | Test this case |
 | DS Update Size | DS update out of bounds for given layout section | DESCRIPTOR_UPDATE_OUT_OF_BOUNDS | vkUpdateDescriptorSets | DSUpdateOutOfBounds | NA |
 | Descriptor Pool empty | Attempt to allocate descriptor type from descriptor pool when no more of that type are available to be allocated. | DESCRIPTOR_POOL_EMPTY | vkAllocDescriptorSets | AllocDescriptorFromEmptyPool | NA |
 | Free from NON_FREE Pool | It's invalid to call vkFreeDescriptorSets() on Sets that were allocated from a Pool created with NON_FREE usage. | CANT_FREE_FROM_NON_FREE_POOL | vkFreeDescriptorSets | None | NA |
@@ -51,6 +52,7 @@ The DrawState layer tracks state leading into Draw cmds. This includes the Pipel
 | Viewport and Scissors match | In PSO viewportCount and scissorCount must match. Also for each count that is non-zero, there corresponding data array ptr should be non-NULL. | VIEWPORT_SCISSOR_MISMATCH | vkCreateGraphicsPipelines vkCmdSetViewport vkCmdSetScissor | TODO | Implement validation test |
 | Valid Image Aspects for descriptor Updates | When updating ImageView for Descriptor Sets with layout of DEPTH_STENCIL type, the Image Aspect must not have both the DEPTH and STENCIL aspects set, but must have one of the two set. For COLOR_ATTACHMENT, aspect must have COLOR_BIT set. | INVALID_IMAGE_ASPECT | vkUpdateDescriptorSets | DepthStencilImageViewWithColorAspectBitError | This test hits Image layer error, but tough to create case that that skips that error and gets to DrawState error. |
 | Valid sampler descriptor Updates | An invalid sampler is used when updating SAMPLER descriptor. | SAMPLER_DESCRIPTOR_ERROR | vkUpdateDescriptorSets | SampleDescriptorUpdateError | Currently only making sure sampler handle is known, can add further validation for sampler parameters |
+| Immutable sampler update consistency | Within a single write update, all sampler updates must use either immutable samplers or non-immutable samplers, but not a combination of both. | INCONSISTENT_IMMUTABLE_SAMPLER_UPDATE | vkUpdateDescriptorSets | None | Write a test for this case |
 | Valid imageView descriptor Updates | An invalid imageView is used when updating *_IMAGE or *_ATTACHMENT descriptor. | IMAGEVIEW_DESCRIPTOR_ERROR | vkUpdateDescriptorSets | ImageViewDescriptorUpdateError | Currently only making sure imageView handle is known, can add further validation for imageView and underlying image parameters |
 | Valid bufferView descriptor Updates | An invalid bufferView is used when updating *_TEXEL_BUFFER descriptor. | BUFFERVIEW_DESCRIPTOR_ERROR | vkUpdateDescriptorSets | BufferViewDescriptorUpdateError | Currently only making sure bufferView handle is known, can add further validation for bufferView parameters |
 | Valid bufferInfo descriptor Updates | An invalid bufferInfo is used when updating *_UNIFORM_BUFFER* or *_STORAGE_BUFFER* descriptor. | BUFFERINFO_DESCRIPTOR_ERROR | vkUpdateDescriptorSets | TODO | Implement validation test |