blob: 7df30e2d828c909cfa90dbb3071c07913b439d38 [file] [log] [blame]
Jeremy Gebben10691992022-01-06 20:34:57 -07001/* 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 Gebben04f247e2021-05-14 08:46:52 -06005 * 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 Gebben9efe1cf2021-05-15 20:05:09 -060030#include "vulkan/vulkan.h"
Jeremy Gebben04f247e2021-05-14 08:46:52 -060031#include "vk_object_types.h"
32#include "vk_layer_data.h"
Jeremy Gebben1dfbd172021-05-19 14:00:58 -060033#include "vk_layer_logging.h"
Jeremy Gebben610d3a62022-01-01 12:53:17 -070034#include "vk_layer_utils.h"
Jeremy Gebben04f247e2021-05-14 08:46:52 -060035
36#include <atomic>
37
Jeremy Gebben1dfbd172021-05-19 14:00:58 -060038// Intentionally ignore VulkanTypedHandle::node, it is optional
Jeremy Gebbena4fc6742022-09-15 14:57:30 -060039inline bool operator==(const VulkanTypedHandle &a, const VulkanTypedHandle &b) noexcept {
Jeremy Gebben1dfbd172021-05-19 14:00:58 -060040 return a.handle == b.handle && a.type == b.type;
41}
42namespace std {
43template <>
44struct hash<VulkanTypedHandle> {
Jeremy Gebbena4fc6742022-09-15 14:57:30 -060045 size_t operator()(VulkanTypedHandle obj) const noexcept { return hash<uint64_t>()(obj.handle) ^ hash<uint32_t>()(obj.type); }
Jeremy Gebben1dfbd172021-05-19 14:00:58 -060046};
47} // namespace std
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060048
Jeremy Gebben610d3a62022-01-01 12:53:17 -070049// 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
52class BASE_NODE : public std::enable_shared_from_this<BASE_NODE> {
Jeremy Gebben04f247e2021-05-14 08:46:52 -060053 public:
Jeremy Gebben610d3a62022-01-01 12:53:17 -070054 // 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 Gebben9efe1cf2021-05-15 20:05:09 -060060
61 template <typename Handle>
Jeremy Gebben8f58bbd2021-11-03 08:26:30 -060062 BASE_NODE(Handle h, VulkanObjectType t) : handle_(h, t), destroyed_(false) {}
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060063
Jeremy Gebben610d3a62022-01-01 12:53:17 -070064 // 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 Gebben10691992022-01-06 20:34:57 -070069 virtual ~BASE_NODE();
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060070
Jeremy Gebben610d3a62022-01-01 12:53:17 -070071 // 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 Gebben10691992022-01-06 20:34:57 -070075 virtual void Destroy();
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060076
77 bool Destroyed() const { return destroyed_; }
78
Jeremy Gebbena08da232022-02-01 15:14:52 -070079 // returns true if this vulkan object or any it uses have been destroyed
80 virtual bool Invalid() const { return Destroyed(); }
81
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060082 const VulkanTypedHandle &Handle() const { return handle_; }
Jeremy Gebbenc9a24032021-11-02 11:36:08 -060083 VulkanObjectType Type() const { return handle_.type; }
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -060084
Jeremy Gebben10691992022-01-06 20:34:57 -070085 virtual bool InUse() const;
Jeremy Gebben5570abe2021-05-16 18:35:13 -060086
Jeremy Gebben10691992022-01-06 20:34:57 -070087 virtual bool AddParent(BASE_NODE *parent_node);
Jeremy Gebben10691992022-01-06 20:34:57 -070088 virtual void RemoveParent(BASE_NODE *parent_node);
Jeremy Gebben5570abe2021-05-16 18:35:13 -060089
Jeremy Gebben610d3a62022-01-01 12:53:17 -070090 // 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 Gebben10691992022-01-06 20:34:57 -070092 void Invalidate(bool unlink = true);
93
Jeremy Gebben610d3a62022-01-01 12:53:17 -070094 // Helper to let objects examine their immediate parents without holding the tree lock.
95 NodeMap ObjectBindings() const;
96
Jeremy Gebben5570abe2021-05-16 18:35:13 -060097 protected:
John Zulauf5dea8842022-04-12 14:05:47 -060098 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 Gebben610d3a62022-01-01 12:53:17 -0700105 // Called recursively for every parent object of something that has become invalid
Jeremy Gebben10691992022-01-06 20:34:57 -0700106 virtual void NotifyInvalidate(const NodeList &invalid_nodes, bool unlink);
Jeremy Gebben5570abe2021-05-16 18:35:13 -0600107
Jeremy Gebben610d3a62022-01-01 12:53:17 -0700108 // 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 Gebben5570abe2021-05-16 18:35:13 -0600112 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 Gebben610d3a62022-01-01 12:53:17 -0700116 std::atomic<bool> destroyed_;
117
118 private:
119 ReadLockGuard ReadLockTree() const { return ReadLockGuard(tree_lock_); }
120 WriteLockGuard WriteLockTree() { return WriteLockGuard(tree_lock_); }
Jeremy Gebben5570abe2021-05-16 18:35:13 -0600121
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 Gebben610d3a62022-01-01 12:53:17 -0700124 NodeMap parent_nodes_;
125 // Lock guarding parent_nodes_, this lock MUST NOT be used for other purposes.
126 mutable ReadWriteLock tree_lock_;
Jeremy Gebben5570abe2021-05-16 18:35:13 -0600127};
128
129class REFCOUNTED_NODE : public BASE_NODE {
130private:
131 // Track if command buffer is in-flight
132 std::atomic_int in_use_;
133
134public:
135 template <typename Handle>
136 REFCOUNTED_NODE(Handle h, VulkanObjectType t) : BASE_NODE(h, t), in_use_(0) { }
Jeremy Gebben9efe1cf2021-05-15 20:05:09 -0600137
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 Gebben5570abe2021-05-16 18:35:13 -0600144 bool InUse() const override { return (in_use_.load() > 0) || BASE_NODE::InUse(); }
Jeremy Gebben04f247e2021-05-14 08:46:52 -0600145};