layers: Add tracking between sampler and cmd buffer
authorTobin Ehlis <tobine@google.com>
Wed, 17 Aug 2016 17:10:41 +0000 (11:10 -0600)
committerTobin Ehlis <tobine@google.com>
Wed, 24 Aug 2016 00:41:47 +0000 (18:41 -0600)
Update SAMPLER_NODE to inherit from BASE_NODE and keep track of
cb_bindings for sampler.
At draw time, add any bindings between cmd buffer and samplers that
are connected to active descriptors.
At DestroySampler() time, set CB_INVALID for any cmd buffers in
cb_bindings.
Also includes some additional plumbing to prepare for connecting
images/buffers that are tied to descriptor sets to cmd buffers that
those sets are bound to.

layers/core_validation.cpp
layers/core_validation_error_enums.h
layers/core_validation_types.h
layers/descriptor_sets.cpp
layers/descriptor_sets.h

index 38e4b2f..da54af7 100644 (file)
@@ -517,7 +517,13 @@ static bool update_cmd_buf_and_mem_references(layer_data *dev_data, const VkComm
     return skip_call;
 }
 
-// Create binding link between given iamge node and command buffer node
+// Create binding link between given sampler and command buffer node
+void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *cb_node, SAMPLER_NODE *sampler_node) {
+    sampler_node->cb_bindings.insert(cb_node);
+    cb_node->object_bindings.insert({reinterpret_cast<uint64_t &>(sampler_node->sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT});
+}
+
+// Create binding link between given image node and command buffer node
 static bool addCommandBufferBindingImage(layer_data *dev_data, GLOBAL_CB_NODE *cb_node, IMAGE_NODE *img_node, const char *apiName) {
     bool skip_call = false;
     // Skip validation if this image was created through WSI
@@ -668,6 +674,8 @@ static const char *object_type_to_string(VkDebugReportObjectTypeEXT type) {
         return "query pool";
     case VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT:
         return "pipeline";
+    case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT:
+        return "sampler";
     default:
         return "unknown";
     }
@@ -3943,6 +3951,12 @@ static void removeCommandBufferBinding(layer_data *dev_data, VK_OBJECT const *ob
             set_node->RemoveBoundCommandBuffer(cb_node);
         break;
     }
+    case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
+        auto sampler_node = getSamplerNode(dev_data, reinterpret_cast<const VkSampler &>(object->handle));
+        if (sampler_node)
+            sampler_node->cb_bindings.erase(cb_node);
+        break;
+    }
     default:
         assert(0); // unhandled object type
     }
@@ -4478,6 +4492,17 @@ static bool ValidateAndIncrementBoundObjects(layer_data const *dev_data, GLOBAL_
             }
             break;
         }
+        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
+            auto sampler_node = getSamplerNode(dev_data, reinterpret_cast<VkSampler &>(obj.handle));
+            if (!sampler_node) {
+                skip_call |= log_msg(dev_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT,
+                                     obj.handle, __LINE__, DRAWSTATE_INVALID_SAMPLER, "DS",
+                                     "Cannot submit cmd buffer using deleted sampler 0x%" PRIx64 ".", obj.handle);
+            } else {
+                sampler_node->in_use.fetch_add(1);
+            }
+            break;
+        }
         default:
             // TODO : Merge handling of other objects types into this code
             break;
@@ -4571,6 +4596,11 @@ static void DecrementBoundResources(layer_data const *dev_data, GLOBAL_CB_NODE c
             set_node->in_use.fetch_sub(1);
             break;
         }
+        case VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT: {
+            auto sampler_node = getSamplerNode(dev_data, reinterpret_cast<VkSampler &>(obj.handle));
+            sampler_node->in_use.fetch_sub(1);
+            break;
+        }
         default:
             // TODO : Merge handling of other objects types into this code
             break;
@@ -5701,8 +5731,18 @@ DestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const Vk
 
 VKAPI_ATTR void VKAPI_CALL
 DestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator) {
-    // TODO : Clean up any internal data structures using this obj.
-    get_my_data_ptr(get_dispatch_key(device), layer_data_map)->device_dispatch_table->DestroySampler(device, sampler, pAllocator);
+    layer_data *dev_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+    // TODO : Add detection for in-flight sampler
+    std::unique_lock<std::mutex> lock(global_lock);
+    auto sampler_node = getSamplerNode(dev_data, sampler);
+    if (sampler_node) {
+        // Any bound cmd buffers are now invalid
+        invalidateCommandBuffers(sampler_node->cb_bindings,
+                                 {reinterpret_cast<uint64_t &>(sampler), VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT});
+        dev_data->samplerMap.erase(sampler);
+    }
+    lock.unlock();
+    dev_data->device_dispatch_table->DestroySampler(device, sampler, pAllocator);
 }
 
 VKAPI_ATTR void VKAPI_CALL
index e58b294..8ceba84 100644 (file)
@@ -63,6 +63,7 @@ enum DRAW_STATE_ERROR {
     DRAWSTATE_INVALID_QUERY,                 // Invalid Query
     DRAWSTATE_INVALID_FENCE,                 // Invalid Fence
     DRAWSTATE_INVALID_EVENT,                 // Invalid Event
+    DRAWSTATE_INVALID_SAMPLER,               // Invalid Sampler
     DRAWSTATE_VTX_INDEX_OUT_OF_BOUNDS,       // binding in vkCmdBindVertexData() too
                                              // large for PSO's
                                              // pVertexBindingDescriptions array
index 6ac0bd7..bb41ec2 100644 (file)
@@ -159,7 +159,7 @@ class BUFFER_NODE : public BASE_NODE {
     };
 };
 
-struct SAMPLER_NODE {
+struct SAMPLER_NODE : public BASE_NODE {
     VkSampler sampler;
     VkSamplerCreateInfo createInfo;
 
@@ -657,6 +657,7 @@ VkSwapchainKHR getSwapchainFromImage(const layer_data *, VkImage);
 SWAPCHAIN_NODE *getSwapchainNode(const layer_data *, VkSwapchainKHR);
 void invalidateCommandBuffers(std::unordered_set<GLOBAL_CB_NODE *>, VK_OBJECT);
 bool ValidateMemoryIsBoundToBuffer(const layer_data *, const BUFFER_NODE *, const char *);
+void AddCommandBufferBindingSampler(GLOBAL_CB_NODE *, SAMPLER_NODE *);
 }
 
 #endif // CORE_VALIDATION_TYPES_H_
index 38915b6..c07f505 100644 (file)
@@ -638,6 +638,13 @@ void cvdescriptorset::DescriptorSet::BindCommandBuffer(GLOBAL_CB_NODE *cb_node,
     //  check active descriptor slots based on last bound state for this CB
     // For the active slots, use set# to look up descriptorSet from boundDescriptorSets, and bind all of that descriptor set's
     // resources
+    for (auto binding : bindings) {
+        auto start_idx = p_layout_->GetGlobalStartIndexFromBinding(binding);
+        auto end_idx = p_layout_->GetGlobalEndIndexFromBinding(binding);
+        for (uint32_t i = start_idx; i <= end_idx; ++i) {
+            descriptors_[i]->BindCommandBuffer(device_data_, cb_node);
+        }
+    }
 }
 
 cvdescriptorset::SamplerDescriptor::SamplerDescriptor() : sampler_(VK_NULL_HANDLE), immutable_(false) {
@@ -815,6 +822,14 @@ void cvdescriptorset::SamplerDescriptor::CopyUpdate(const Descriptor *src) {
     updated = true;
 }
 
+void cvdescriptorset::SamplerDescriptor::BindCommandBuffer(const core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+    if (!immutable_) {
+        auto sampler_node = getSamplerNode(dev_data, sampler_);
+        if (sampler_node)
+            core_validation::AddCommandBufferBindingSampler(cb_node, sampler_node);
+    }
+}
+
 cvdescriptorset::ImageSamplerDescriptor::ImageSamplerDescriptor()
     : sampler_(VK_NULL_HANDLE), immutable_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
     updated = false;
@@ -852,6 +867,16 @@ void cvdescriptorset::ImageSamplerDescriptor::CopyUpdate(const Descriptor *src)
     image_layout_ = image_layout;
 }
 
+void cvdescriptorset::ImageSamplerDescriptor::BindCommandBuffer(const core_validation::layer_data *dev_data,
+                                                                GLOBAL_CB_NODE *cb_node) {
+    if (!immutable_) {
+        auto sampler_node = getSamplerNode(dev_data, sampler_);
+        if (sampler_node)
+            core_validation::AddCommandBufferBindingSampler(cb_node, sampler_node);
+    }
+    // TODO : add cb_binding for image
+}
+
 cvdescriptorset::ImageDescriptor::ImageDescriptor(const VkDescriptorType type)
     : storage_(false), image_view_(VK_NULL_HANDLE), image_layout_(VK_IMAGE_LAYOUT_UNDEFINED) {
     updated = false;
@@ -875,6 +900,10 @@ void cvdescriptorset::ImageDescriptor::CopyUpdate(const Descriptor *src) {
     image_layout_ = image_layout;
 }
 
+void cvdescriptorset::ImageDescriptor::BindCommandBuffer(const core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+    // TODO : bind image and cmd buffer
+}
+
 cvdescriptorset::BufferDescriptor::BufferDescriptor(const VkDescriptorType type)
     : storage_(false), dynamic_(false), buffer_(VK_NULL_HANDLE), offset_(0), range_(0) {
     updated = false;
@@ -904,6 +933,10 @@ void cvdescriptorset::BufferDescriptor::CopyUpdate(const Descriptor *src) {
     range_ = buff_desc->range_;
 }
 
+void cvdescriptorset::BufferDescriptor::BindCommandBuffer(const core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+    // TODO : bind buffer and cmd buffer
+}
+
 cvdescriptorset::TexelDescriptor::TexelDescriptor(const VkDescriptorType type) : buffer_view_(VK_NULL_HANDLE), storage_(false) {
     updated = false;
     descriptor_class = TexelBuffer;
@@ -920,6 +953,11 @@ void cvdescriptorset::TexelDescriptor::CopyUpdate(const Descriptor *src) {
     updated = true;
     buffer_view_ = static_cast<const TexelDescriptor *>(src)->buffer_view_;
 }
+
+void cvdescriptorset::TexelDescriptor::BindCommandBuffer(const core_validation::layer_data *dev_data, GLOBAL_CB_NODE *cb_node) {
+    // TODO : bind buffer and cmd buffer
+}
+
 // This is a helper function that iterates over a set of Write and Copy updates, pulls the DescriptorSet* for updated
 //  sets, and then calls their respective Validate[Write|Copy]Update functions.
 // If the update hits an issue for which the callback returns "true", meaning that the call down the chain should
index 42c5895..92eb09a 100644 (file)
@@ -149,6 +149,8 @@ class Descriptor {
     virtual ~Descriptor(){};
     virtual void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) = 0;
     virtual void CopyUpdate(const Descriptor *) = 0;
+    // Create binding between resources of this descriptor and given cb_node
+    virtual void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) = 0;
     virtual DescriptorClass GetClass() const { return descriptor_class; };
     // Special fast-path check for SamplerDescriptors that are immutable
     virtual bool IsImmutableSampler() const { return false; };
@@ -170,6 +172,7 @@ class SamplerDescriptor : public Descriptor {
     SamplerDescriptor(const VkSampler *);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
+    void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsImmutableSampler() const override { return immutable_; };
     VkSampler GetSampler() const { return sampler_; }
 
@@ -185,6 +188,7 @@ class ImageSamplerDescriptor : public Descriptor {
     ImageSamplerDescriptor(const VkSampler *);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
+    void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsImmutableSampler() const override { return immutable_; };
     VkSampler GetSampler() const { return sampler_; }
     VkImageView GetImageView() const { return image_view_; }
@@ -202,6 +206,7 @@ class ImageDescriptor : public Descriptor {
     ImageDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
+    void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsStorage() const override { return storage_; }
     VkImageView GetImageView() const { return image_view_; }
     VkImageLayout GetImageLayout() const { return image_layout_; }
@@ -217,6 +222,7 @@ class TexelDescriptor : public Descriptor {
     TexelDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
+    void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsStorage() const override { return storage_; }
     VkBufferView GetBufferView() const { return buffer_view_; }
 
@@ -230,6 +236,7 @@ class BufferDescriptor : public Descriptor {
     BufferDescriptor(const VkDescriptorType);
     void WriteUpdate(const VkWriteDescriptorSet *, const uint32_t) override;
     void CopyUpdate(const Descriptor *) override;
+    void BindCommandBuffer(const core_validation::layer_data *, GLOBAL_CB_NODE *) override;
     virtual bool IsDynamic() const override { return dynamic_; }
     virtual bool IsStorage() const override { return storage_; }
     VkBuffer GetBuffer() const { return buffer_; }