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