1 /* Copyright (c) 2015-2021 The Khronos Group Inc.
2  * Copyright (c) 2015-2021 Valve Corporation
3  * Copyright (c) 2015-2021 LunarG, Inc.
4  * Copyright (C) 2015-2021 Google Inc.
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  */
27 #pragma once
28 #include "vk_layer_data.h"
29 #include "hash_util.h"
30 
31 // Types to store queue family ownership (QFO) Transfers
32 class COMMAND_POOL_STATE;
33 
34 template <typename Barrier>
IsTransferOp(const Barrier & barrier)35 inline bool IsTransferOp(const Barrier &barrier) {
36     return barrier.srcQueueFamilyIndex != barrier.dstQueueFamilyIndex;
37 }
38 
39 // specializations for barriers that cannot do queue family ownership transfers
40 template <>
IsTransferOp(const VkMemoryBarrier & barrier)41 constexpr bool IsTransferOp(const VkMemoryBarrier &barrier) {
42     return false;
43 }
44 template <>
IsTransferOp(const VkMemoryBarrier2KHR & barrier)45 constexpr bool IsTransferOp(const VkMemoryBarrier2KHR &barrier) {
46     return false;
47 }
48 template <>
IsTransferOp(const VkSubpassDependency2 & barrier)49 constexpr bool IsTransferOp(const VkSubpassDependency2 &barrier) {
50     return false;
51 }
52 
QueueFamilyIsExternal(const uint32_t queue_family_index)53 static inline bool QueueFamilyIsExternal(const uint32_t queue_family_index) {
54     return (queue_family_index == VK_QUEUE_FAMILY_EXTERNAL) || (queue_family_index == VK_QUEUE_FAMILY_FOREIGN_EXT);
55 }
56 
57 // Caution: Section 7.7.4 states that "If the values of srcQueueFamilyIndex and dstQueueFamilyIndex are equal, no ownership transfer
58 // is performed, and the barrier operates as if they were both set to VK_QUEUE_FAMILY_IGNORED."; this does not handle that case.
QueueFamilyIsIgnored(uint32_t queue_family_index)59 static inline bool QueueFamilyIsIgnored(uint32_t queue_family_index) { return queue_family_index == VK_QUEUE_FAMILY_IGNORED; }
60 
61 // Common to image and buffer memory barriers
62 template <typename Handle>
63 struct QFOTransferBarrierBase {
64     using HandleType = Handle;
65     Handle handle = VK_NULL_HANDLE;
66     uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
67     uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
68 
69     QFOTransferBarrierBase() = default;
QFOTransferBarrierBaseQFOTransferBarrierBase70     QFOTransferBarrierBase(const Handle &resource_handle, uint32_t src, uint32_t dst)
71         : handle(resource_handle), srcQueueFamilyIndex(src), dstQueueFamilyIndex(dst) {}
72 
base_hash_combinerQFOTransferBarrierBase73     hash_util::HashCombiner base_hash_combiner() const {
74         hash_util::HashCombiner hc;
75         hc << srcQueueFamilyIndex << dstQueueFamilyIndex << handle;
76         return hc;
77     }
78 
79     bool operator==(const QFOTransferBarrierBase<Handle> &rhs) const {
80         return (srcQueueFamilyIndex == rhs.srcQueueFamilyIndex) && (dstQueueFamilyIndex == rhs.dstQueueFamilyIndex) &&
81                (handle == rhs.handle);
82     }
83 };
84 
85 // Image barrier specific implementation
86 struct QFOImageTransferBarrier : public QFOTransferBarrierBase<VkImage> {
87     using BaseType = QFOTransferBarrierBase<VkImage>;
88     VkImageLayout oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
89     VkImageLayout newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
90     VkImageSubresourceRange subresourceRange;
91 
92     QFOImageTransferBarrier() = default;
QFOImageTransferBarrierQFOImageTransferBarrier93     QFOImageTransferBarrier(const VkImageMemoryBarrier &barrier)
94         : BaseType(barrier.image, barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex),
95           oldLayout(barrier.oldLayout),
96           newLayout(barrier.newLayout),
97           subresourceRange(barrier.subresourceRange) {}
QFOImageTransferBarrierQFOImageTransferBarrier98     QFOImageTransferBarrier(const VkImageMemoryBarrier2KHR &barrier)
99         : BaseType(barrier.image, barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex),
100           oldLayout(barrier.oldLayout),
101           newLayout(barrier.newLayout),
102           subresourceRange(barrier.subresourceRange) {}
hashQFOImageTransferBarrier103     size_t hash() const {
104         // Ignoring the layout information for the purpose of the hash, as we're interested in QFO release/acquisition w.r.t.
105         // the subresource affected, an layout transitions are current validated on another path
106         auto hc = base_hash_combiner() << subresourceRange;
107         return hc.Value();
108     }
109     bool operator==(const QFOImageTransferBarrier &rhs) const {
110         // Ignoring layout w.r.t. equality. See comment in hash above.
111         return (static_cast<BaseType>(*this) == static_cast<BaseType>(rhs)) && (subresourceRange == rhs.subresourceRange);
112     }
113     // TODO: codegen a comprehensive complie time type -> string (and or other traits) template family
BarrierNameQFOImageTransferBarrier114     static const char *BarrierName() { return "VkImageMemoryBarrier"; }
HandleNameQFOImageTransferBarrier115     static const char *HandleName() { return "VkImage"; }
116     // UNASSIGNED-VkImageMemoryBarrier-image-00001 QFO transfer image barrier must not duplicate QFO recorded in command buffer
ErrMsgDuplicateQFOInCBQFOImageTransferBarrier117     static const char *ErrMsgDuplicateQFOInCB() { return "UNASSIGNED-VkImageMemoryBarrier-image-00001"; }
118     // UNASSIGNED-VkImageMemoryBarrier-image-00002 QFO transfer image barrier must not duplicate QFO submitted in batch
ErrMsgDuplicateQFOInSubmitQFOImageTransferBarrier119     static const char *ErrMsgDuplicateQFOInSubmit() { return "UNASSIGNED-VkImageMemoryBarrier-image-00002"; }
120     // UNASSIGNED-VkImageMemoryBarrier-image-00003 QFO transfer image barrier must not duplicate QFO submitted previously
ErrMsgDuplicateQFOSubmittedQFOImageTransferBarrier121     static const char *ErrMsgDuplicateQFOSubmitted() { return "UNASSIGNED-VkImageMemoryBarrier-image-00003"; }
122     // UNASSIGNED-VkImageMemoryBarrier-image-00004 QFO acquire image barrier must have matching QFO release submitted previously
ErrMsgMissingQFOReleaseInSubmitQFOImageTransferBarrier123     static const char *ErrMsgMissingQFOReleaseInSubmit() { return "UNASSIGNED-VkImageMemoryBarrier-image-00004"; }
124 };
125 
126 // Buffer barrier specific implementation
127 struct QFOBufferTransferBarrier : public QFOTransferBarrierBase<VkBuffer> {
128     using BaseType = QFOTransferBarrierBase<VkBuffer>;
129     VkDeviceSize offset = 0;
130     VkDeviceSize size = 0;
131     QFOBufferTransferBarrier() = default;
QFOBufferTransferBarrierQFOBufferTransferBarrier132     QFOBufferTransferBarrier(const VkBufferMemoryBarrier &barrier)
133         : BaseType(barrier.buffer, barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex),
134           offset(barrier.offset),
135           size(barrier.size) {}
QFOBufferTransferBarrierQFOBufferTransferBarrier136     QFOBufferTransferBarrier(const VkBufferMemoryBarrier2KHR &barrier)
137         : BaseType(barrier.buffer, barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex),
138           offset(barrier.offset),
139           size(barrier.size) {}
hashQFOBufferTransferBarrier140     size_t hash() const {
141         auto hc = base_hash_combiner() << offset << size;
142         return hc.Value();
143     }
144     bool operator==(const QFOBufferTransferBarrier &rhs) const {
145         return (static_cast<BaseType>(*this) == static_cast<BaseType>(rhs)) && (offset == rhs.offset) && (size == rhs.size);
146     }
BarrierNameQFOBufferTransferBarrier147     static const char *BarrierName() { return "VkBufferMemoryBarrier"; }
HandleNameQFOBufferTransferBarrier148     static const char *HandleName() { return "VkBuffer"; }
149     // UNASSIGNED-VkImageMemoryBarrier-buffer-00001 QFO transfer buffer barrier must not duplicate QFO recorded in command buffer
ErrMsgDuplicateQFOInCBQFOBufferTransferBarrier150     static const char *ErrMsgDuplicateQFOInCB() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00001"; }
151     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00002 QFO transfer buffer barrier must not duplicate QFO submitted in batch
ErrMsgDuplicateQFOInSubmitQFOBufferTransferBarrier152     static const char *ErrMsgDuplicateQFOInSubmit() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00002"; }
153     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00003 QFO transfer buffer barrier must not duplicate QFO submitted previously
ErrMsgDuplicateQFOSubmittedQFOBufferTransferBarrier154     static const char *ErrMsgDuplicateQFOSubmitted() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00003"; }
155     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00004 QFO acquire buffer barrier must have matching QFO release submitted previously
ErrMsgMissingQFOReleaseInSubmitQFOBufferTransferBarrier156     static const char *ErrMsgMissingQFOReleaseInSubmit() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00004"; }
157 };
158 
159 template <typename TransferBarrier>
160 using QFOTransferBarrierHash = hash_util::HasHashMember<TransferBarrier>;
161 
162 // Command buffers store the set of barriers recorded
163 template <typename TransferBarrier>
164 using QFOTransferBarrierSet = layer_data::unordered_set<TransferBarrier, QFOTransferBarrierHash<TransferBarrier>>;
165 
166 template <typename TransferBarrier>
167 struct QFOTransferBarrierSets {
168     QFOTransferBarrierSet<TransferBarrier> release;
169     QFOTransferBarrierSet<TransferBarrier> acquire;
ResetQFOTransferBarrierSets170     void Reset() {
171         acquire.clear();
172         release.clear();
173     }
174 };
175 
176 // The layer_data stores the map of pending release barriers
177 template <typename TransferBarrier>
178 using GlobalQFOTransferBarrierMap =
179     layer_data::unordered_map<typename TransferBarrier::HandleType, QFOTransferBarrierSet<TransferBarrier>>;
180 
181 // Submit queue uses the Scoreboard to track all release/acquire operations in a batch.
182 template <typename TransferBarrier>
183 using QFOTransferCBScoreboard =
184     layer_data::unordered_map<TransferBarrier, const CMD_BUFFER_STATE *, QFOTransferBarrierHash<TransferBarrier>>;
185 
186 template <typename TransferBarrier>
187 struct QFOTransferCBScoreboards {
188     QFOTransferCBScoreboard<TransferBarrier> acquire;
189     QFOTransferCBScoreboard<TransferBarrier> release;
190 };
191