Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2015-2022 The Khronos Group Inc. |
| 2 | * Copyright (c) 2015-2022 Valve Corporation |
| 3 | * Copyright (c) 2015-2022 LunarG, Inc. |
| 4 | * Copyright (C) 2015-2022 Google Inc. |
Jeremy Gebben | 04f247e | 2021-05-14 08:46:52 -0600 | [diff] [blame] | 5 | * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. |
| 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 | * Author: Courtney Goeltzenleuchter <courtneygo@google.com> |
| 20 | * Author: Tobin Ehlis <tobine@google.com> |
| 21 | * Author: Chris Forbes <chrisf@ijw.co.nz> |
| 22 | * Author: Mark Lobodzinski <mark@lunarg.com> |
| 23 | * Author: Dave Houlton <daveh@lunarg.com> |
| 24 | * Author: John Zulauf <jzulauf@lunarg.com> |
| 25 | * Author: Tobias Hector <tobias.hector@amd.com> |
| 26 | * Author: Jeremy Gebben <jeremyg@lunarg.com> |
| 27 | */ |
| 28 | #pragma once |
| 29 | |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 30 | #include "vulkan/vulkan.h" |
Jeremy Gebben | 04f247e | 2021-05-14 08:46:52 -0600 | [diff] [blame] | 31 | #include "vk_object_types.h" |
| 32 | #include "vk_layer_data.h" |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 33 | #include "vk_layer_logging.h" |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 34 | #include "vk_layer_utils.h" |
Jeremy Gebben | 04f247e | 2021-05-14 08:46:52 -0600 | [diff] [blame] | 35 | |
| 36 | #include <atomic> |
| 37 | |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 38 | // Intentionally ignore VulkanTypedHandle::node, it is optional |
Jeremy Gebben | a4fc674 | 2022-09-15 14:57:30 -0600 | [diff] [blame] | 39 | inline bool operator==(const VulkanTypedHandle &a, const VulkanTypedHandle &b) noexcept { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 40 | return a.handle == b.handle && a.type == b.type; |
| 41 | } |
| 42 | namespace std { |
| 43 | template <> |
| 44 | struct hash<VulkanTypedHandle> { |
Jeremy Gebben | a4fc674 | 2022-09-15 14:57:30 -0600 | [diff] [blame] | 45 | size_t operator()(VulkanTypedHandle obj) const noexcept { return hash<uint64_t>()(obj.handle) ^ hash<uint32_t>()(obj.type); } |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 46 | }; |
| 47 | } // namespace std |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 48 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 49 | // inheriting from enable_shared_from_this<> adds a method, shared_from_this(), which |
| 50 | // returns a shared_ptr version of the current object. It requires the object to |
| 51 | // be created with std::make_shared<> and it MUST NOT be used from the constructor |
| 52 | class BASE_NODE : public std::enable_shared_from_this<BASE_NODE> { |
Jeremy Gebben | 04f247e | 2021-05-14 08:46:52 -0600 | [diff] [blame] | 53 | public: |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 54 | // Parent nodes are stored as weak_ptrs to avoid cyclic memory dependencies. |
| 55 | // Because weak_ptrs cannot safely be used as hash keys, the parents are stored |
| 56 | // in a map keyed by VulkanTypedHandle. This also allows looking for specific |
| 57 | // parent types without locking every weak_ptr. |
| 58 | using NodeMap = layer_data::unordered_map<VulkanTypedHandle, std::weak_ptr<BASE_NODE>>; |
| 59 | using NodeList = small_vector<std::shared_ptr<BASE_NODE>, 4, uint32_t>; |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 60 | |
| 61 | template <typename Handle> |
Jeremy Gebben | 8f58bbd | 2021-11-03 08:26:30 -0600 | [diff] [blame] | 62 | BASE_NODE(Handle h, VulkanObjectType t) : handle_(h, t), destroyed_(false) {} |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 63 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 64 | // because shared_from_this() does not work from the constructor, this 2nd phase |
| 65 | // constructor is where a state object should call AddParent() on its child nodes. |
| 66 | // It is called as part of ValidationStateTracker::Add() |
| 67 | virtual void LinkChildNodes() {} |
| 68 | |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 69 | virtual ~BASE_NODE(); |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 70 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 71 | // Because state objects are reference counted, they may outlive the vulkan objects |
| 72 | // they represent. Destroy() is called when the vulkan object is destroyed, so that |
| 73 | // it can be cleaned up before all references are gone. It also triggers notifications |
| 74 | // to parent objects. |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 75 | virtual void Destroy(); |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 76 | |
| 77 | bool Destroyed() const { return destroyed_; } |
| 78 | |
Jeremy Gebben | a08da23 | 2022-02-01 15:14:52 -0700 | [diff] [blame] | 79 | // returns true if this vulkan object or any it uses have been destroyed |
| 80 | virtual bool Invalid() const { return Destroyed(); } |
| 81 | |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 82 | const VulkanTypedHandle &Handle() const { return handle_; } |
Jeremy Gebben | c9a2403 | 2021-11-02 11:36:08 -0600 | [diff] [blame] | 83 | VulkanObjectType Type() const { return handle_.type; } |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 84 | |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 85 | virtual bool InUse() const; |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 86 | |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 87 | virtual bool AddParent(BASE_NODE *parent_node); |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 88 | virtual void RemoveParent(BASE_NODE *parent_node); |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 89 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 90 | // Invalidate is called on a state object to inform its parents that it |
| 91 | // is being destroyed (unlink == true) or otherwise becoming invalid (unlink == false) |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 92 | void Invalidate(bool unlink = true); |
| 93 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 94 | // Helper to let objects examine their immediate parents without holding the tree lock. |
| 95 | NodeMap ObjectBindings() const; |
| 96 | |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 97 | protected: |
John Zulauf | 5dea884 | 2022-04-12 14:05:47 -0600 | [diff] [blame] | 98 | template <typename Derived, typename Shared = std::shared_ptr<Derived>> |
| 99 | static Shared SharedFromThisImpl(Derived *derived) { |
| 100 | using Base = typename std::conditional<std::is_const<Derived>::value, const BASE_NODE, BASE_NODE>::type; |
| 101 | auto base = static_cast<Base *>(derived); |
| 102 | return std::static_pointer_cast<Derived>(base->shared_from_this()); |
| 103 | } |
| 104 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 105 | // Called recursively for every parent object of something that has become invalid |
Jeremy Gebben | 1069199 | 2022-01-06 20:34:57 -0700 | [diff] [blame] | 106 | virtual void NotifyInvalidate(const NodeList &invalid_nodes, bool unlink); |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 107 | |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 108 | // returns a copy of the current set of parents so that they can be walked |
| 109 | // without the tree lock held. If unlink == true, parent_nodes_ is also cleared. |
| 110 | NodeMap GetParentsForInvalidate(bool unlink); |
| 111 | |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 112 | VulkanTypedHandle handle_; |
| 113 | |
| 114 | // Set to true when the API-level object is destroyed, but this object may |
| 115 | // hang around until its shared_ptr refcount goes to zero. |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 116 | std::atomic<bool> destroyed_; |
| 117 | |
| 118 | private: |
| 119 | ReadLockGuard ReadLockTree() const { return ReadLockGuard(tree_lock_); } |
| 120 | WriteLockGuard WriteLockTree() { return WriteLockGuard(tree_lock_); } |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 121 | |
| 122 | // Set of immediate parent nodes for this object. For an in-use object, the |
| 123 | // parent nodes should form a tree with the root being a command buffer. |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 124 | NodeMap parent_nodes_; |
| 125 | // Lock guarding parent_nodes_, this lock MUST NOT be used for other purposes. |
| 126 | mutable ReadWriteLock tree_lock_; |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 127 | }; |
| 128 | |
| 129 | class REFCOUNTED_NODE : public BASE_NODE { |
| 130 | private: |
| 131 | // Track if command buffer is in-flight |
| 132 | std::atomic_int in_use_; |
| 133 | |
| 134 | public: |
| 135 | template <typename Handle> |
| 136 | REFCOUNTED_NODE(Handle h, VulkanObjectType t) : BASE_NODE(h, t), in_use_(0) { } |
Jeremy Gebben | 9efe1cf | 2021-05-15 20:05:09 -0600 | [diff] [blame] | 137 | |
| 138 | void BeginUse() { in_use_.fetch_add(1); } |
| 139 | |
| 140 | void EndUse() { in_use_.fetch_sub(1); } |
| 141 | |
| 142 | void ResetUse() { in_use_.store(0); } |
| 143 | |
Jeremy Gebben | 5570abe | 2021-05-16 18:35:13 -0600 | [diff] [blame] | 144 | bool InUse() const override { return (in_use_.load() > 0) || BASE_NODE::InUse(); } |
Jeremy Gebben | 04f247e | 2021-05-14 08:46:52 -0600 | [diff] [blame] | 145 | }; |