blob: e7598ffecbf6216fb56b0ce592025a87a3398e5e [file] [log] [blame]
Jeremy Gebben88f58142021-06-01 10:07:52 -06001/* 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 * Author: Jeremy Gebben <jeremyg@lunarg.com>
27 */
28#include "render_pass_state.h"
29#include "convert_to_renderpass2.h"
30#include "image_state.h"
31
32static const VkImageLayout kInvalidLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
33
34static void RecordRenderPassDAG(const VkRenderPassCreateInfo2 *pCreateInfo, RENDER_PASS_STATE *render_pass) {
35 auto &subpass_to_node = render_pass->subpassToNode;
36 subpass_to_node.resize(pCreateInfo->subpassCount);
37 auto &self_dependencies = render_pass->self_dependencies;
38 self_dependencies.resize(pCreateInfo->subpassCount);
39 auto &subpass_dependencies = render_pass->subpass_dependencies;
40 subpass_dependencies.resize(pCreateInfo->subpassCount);
41
42 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
43 subpass_to_node[i].pass = i;
44 self_dependencies[i].clear();
45 subpass_dependencies[i].pass = i;
46 }
47 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
48 const auto &dependency = pCreateInfo->pDependencies[i];
49 const auto src_subpass = dependency.srcSubpass;
50 const auto dst_subpass = dependency.dstSubpass;
51 if ((dependency.srcSubpass != VK_SUBPASS_EXTERNAL) && (dependency.dstSubpass != VK_SUBPASS_EXTERNAL)) {
52 if (dependency.srcSubpass == dependency.dstSubpass) {
53 self_dependencies[dependency.srcSubpass].push_back(i);
54 } else {
55 subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
56 subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
57 }
58 }
59 if (src_subpass == VK_SUBPASS_EXTERNAL) {
60 assert(dst_subpass != VK_SUBPASS_EXTERNAL); // this is invalid per VUID-VkSubpassDependency-srcSubpass-00865
61 subpass_dependencies[dst_subpass].barrier_from_external.emplace_back(&dependency);
62 } else if (dst_subpass == VK_SUBPASS_EXTERNAL) {
63 subpass_dependencies[src_subpass].barrier_to_external.emplace_back(&dependency);
64 } else if (dependency.srcSubpass != dependency.dstSubpass) {
65 // ignore self dependencies in prev and next
66 subpass_dependencies[src_subpass].next[&subpass_dependencies[dst_subpass]].emplace_back(&dependency);
67 subpass_dependencies[dst_subpass].prev[&subpass_dependencies[src_subpass]].emplace_back(&dependency);
68 }
69 }
70
71 //
72 // Determine "asynchrononous" subpassess
73 // syncronization is only interested in asyncronous stages *earlier* that the current one... so we'll only look towards those.
74 // NOTE: This is O(N^3), which we could shrink to O(N^2logN) using sets instead of arrays, but given that N is likely to be
75 // small and the K for |= from the prev is must less than for set, we'll accept the brute force.
76 std::vector<std::vector<bool>> pass_depends(pCreateInfo->subpassCount);
77 for (uint32_t i = 1; i < pCreateInfo->subpassCount; ++i) {
78 auto &depends = pass_depends[i];
79 depends.resize(i);
80 auto &subpass_dep = subpass_dependencies[i];
81 for (const auto &prev : subpass_dep.prev) {
82 const auto prev_pass = prev.first->pass;
83 const auto &prev_depends = pass_depends[prev_pass];
84 for (uint32_t j = 0; j < prev_pass; j++) {
85 depends[j] = depends[j] | prev_depends[j];
86 }
87 depends[prev_pass] = true;
88 }
89 for (uint32_t pass = 0; pass < subpass_dep.pass; pass++) {
90 if (!depends[pass]) {
91 subpass_dep.async.push_back(pass);
92 }
93 }
94 }
95}
96
97static VkSubpassDependency2 ImplicitDependencyFromExternal(uint32_t subpass) {
98 VkSubpassDependency2 from_external = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
99 nullptr,
100 VK_SUBPASS_EXTERNAL,
101 subpass,
102 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
103 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
104 0,
105 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
106 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
107 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
108 0,
109 0};
110 return from_external;
111}
112
113static VkSubpassDependency2 ImplicitDependencyToExternal(uint32_t subpass) {
114 VkSubpassDependency2 to_external = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
115 nullptr,
116 subpass,
117 VK_SUBPASS_EXTERNAL,
118 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
119 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
120 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
121 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
122 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
123 0,
124 0,
125 0};
126 return to_external;
127}
128
129struct AttachmentTracker { // This is really only of local interest, but a bit big for a lambda
130 RENDER_PASS_STATE *const rp;
131 std::vector<uint32_t> &first;
132 std::vector<bool> &first_is_transition;
133 std::vector<uint32_t> &last;
134 std::vector<std::vector<RENDER_PASS_STATE::AttachmentTransition>> &subpass_transitions;
135 layer_data::unordered_map<uint32_t, bool> &first_read;
136 const uint32_t attachment_count;
137 std::vector<VkImageLayout> attachment_layout;
138 std::vector<std::vector<VkImageLayout>> subpass_attachment_layout;
139 explicit AttachmentTracker(RENDER_PASS_STATE *render_pass)
140 : rp(render_pass),
141 first(rp->attachment_first_subpass),
142 first_is_transition(rp->attachment_first_is_transition),
143 last(rp->attachment_last_subpass),
144 subpass_transitions(rp->subpass_transitions),
145 first_read(rp->attachment_first_read),
146 attachment_count(rp->createInfo.attachmentCount),
147 attachment_layout(),
148 subpass_attachment_layout() {
149 first.resize(attachment_count, VK_SUBPASS_EXTERNAL);
150 first_is_transition.resize(attachment_count, false);
151 last.resize(attachment_count, VK_SUBPASS_EXTERNAL);
152 subpass_transitions.resize(rp->createInfo.subpassCount + 1); // Add an extra for EndRenderPass
153 attachment_layout.reserve(attachment_count);
154 subpass_attachment_layout.resize(rp->createInfo.subpassCount);
155 for (auto &subpass_layouts : subpass_attachment_layout) {
156 subpass_layouts.resize(attachment_count, kInvalidLayout);
157 }
158
159 for (uint32_t j = 0; j < attachment_count; j++) {
160 attachment_layout.push_back(rp->createInfo.pAttachments[j].initialLayout);
161 }
162 }
163
164 void Update(uint32_t subpass, const VkAttachmentReference2 *attach_ref, uint32_t count, bool is_read) {
165 if (nullptr == attach_ref) return;
166 for (uint32_t j = 0; j < count; ++j) {
167 const auto attachment = attach_ref[j].attachment;
168 if (attachment != VK_ATTACHMENT_UNUSED) {
169 const auto layout = attach_ref[j].layout;
170 // Take advantage of the fact that insert won't overwrite, so we'll only write the first time.
171 first_read.emplace(attachment, is_read);
172 if (first[attachment] == VK_SUBPASS_EXTERNAL) {
173 first[attachment] = subpass;
174 const auto initial_layout = rp->createInfo.pAttachments[attachment].initialLayout;
175 if (initial_layout != layout) {
176 subpass_transitions[subpass].emplace_back(VK_SUBPASS_EXTERNAL, attachment, initial_layout, layout);
177 first_is_transition[attachment] = true;
178 }
179 }
180 last[attachment] = subpass;
181
182 for (const auto &prev : rp->subpass_dependencies[subpass].prev) {
183 const auto prev_pass = prev.first->pass;
184 const auto prev_layout = subpass_attachment_layout[prev_pass][attachment];
185 if ((prev_layout != kInvalidLayout) && (prev_layout != layout)) {
186 subpass_transitions[subpass].emplace_back(prev_pass, attachment, prev_layout, layout);
187 }
188 }
189 attachment_layout[attachment] = layout;
190 }
191 }
192 }
193 void FinalTransitions() {
194 auto &final_transitions = subpass_transitions[rp->createInfo.subpassCount];
195
196 for (uint32_t attachment = 0; attachment < attachment_count; ++attachment) {
197 const auto final_layout = rp->createInfo.pAttachments[attachment].finalLayout;
198 // Add final transitions for attachments that were used and change layout.
199 if ((last[attachment] != VK_SUBPASS_EXTERNAL) && final_layout != attachment_layout[attachment]) {
200 final_transitions.emplace_back(last[attachment], attachment, attachment_layout[attachment], final_layout);
201 }
202 }
203 }
204};
205
206static void InitRenderPassState(RENDER_PASS_STATE *render_pass) {
207 auto create_info = render_pass->createInfo.ptr();
208
209 RecordRenderPassDAG(create_info, render_pass);
210
211 AttachmentTracker attachment_tracker(render_pass);
212
213 for (uint32_t subpass_index = 0; subpass_index < create_info->subpassCount; ++subpass_index) {
214 const VkSubpassDescription2 &subpass = create_info->pSubpasses[subpass_index];
215 attachment_tracker.Update(subpass_index, subpass.pColorAttachments, subpass.colorAttachmentCount, false);
216 attachment_tracker.Update(subpass_index, subpass.pResolveAttachments, subpass.colorAttachmentCount, false);
217 attachment_tracker.Update(subpass_index, subpass.pDepthStencilAttachment, 1, false);
218 attachment_tracker.Update(subpass_index, subpass.pInputAttachments, subpass.inputAttachmentCount, true);
219 }
220 attachment_tracker.FinalTransitions();
221
222 // Add implicit dependencies
223 for (uint32_t attachment = 0; attachment < attachment_tracker.attachment_count; attachment++) {
224 const auto first_use = attachment_tracker.first[attachment];
225 if (first_use != VK_SUBPASS_EXTERNAL) {
226 auto &subpass_dep = render_pass->subpass_dependencies[first_use];
227 if (subpass_dep.barrier_from_external.size() == 0) {
228 // Add implicit from barrier if they're aren't any
229 subpass_dep.implicit_barrier_from_external.reset(
230 new VkSubpassDependency2(ImplicitDependencyFromExternal(first_use)));
231 subpass_dep.barrier_from_external.emplace_back(subpass_dep.implicit_barrier_from_external.get());
232 }
233 }
234
235 const auto last_use = attachment_tracker.last[attachment];
236 if (last_use != VK_SUBPASS_EXTERNAL) {
237 auto &subpass_dep = render_pass->subpass_dependencies[last_use];
238 if (render_pass->subpass_dependencies[last_use].barrier_to_external.size() == 0) {
239 // Add implicit to barrier if they're aren't any
240 subpass_dep.implicit_barrier_to_external.reset(new VkSubpassDependency2(ImplicitDependencyToExternal(last_use)));
241 subpass_dep.barrier_to_external.emplace_back(subpass_dep.implicit_barrier_to_external.get());
242 }
243 }
244 }
245}
246
247RENDER_PASS_STATE::RENDER_PASS_STATE(VkRenderPass rp, VkRenderPassCreateInfo2 const *pCreateInfo)
248 : BASE_NODE(rp, kVulkanObjectTypeRenderPass), createInfo(pCreateInfo) {
249 InitRenderPassState(this);
250}
251
252RENDER_PASS_STATE::RENDER_PASS_STATE(VkRenderPass rp, VkRenderPassCreateInfo const *pCreateInfo)
253 : BASE_NODE(rp, kVulkanObjectTypeRenderPass) {
254 ConvertVkRenderPassCreateInfoToV2KHR(*pCreateInfo, &createInfo);
255 InitRenderPassState(this);
256}
257
Jeremy Gebben11af9792021-08-20 10:20:09 -0600258bool RENDER_PASS_STATE::UsesColorAttachment(uint32_t subpass_num) const {
259 bool result = false;
260
261 if (subpass_num < createInfo.subpassCount) {
262 const auto &subpass = createInfo.pSubpasses[subpass_num];
263
264 for (uint32_t i = 0; i < subpass.colorAttachmentCount; ++i) {
265 if (subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
266 result = true;
267 break;
268 }
269 }
270 }
271 return result;
272}
273
274bool RENDER_PASS_STATE::UsesDepthStencilAttachment(uint32_t subpass_num) const {
275 bool result = false;
276 if (subpass_num < createInfo.subpassCount) {
277 const auto &subpass = createInfo.pSubpasses[subpass_num];
278 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
279 result = true;
280 }
281 }
282 return result;
283}
284
Jeremy Gebben88f58142021-06-01 10:07:52 -0600285FRAMEBUFFER_STATE::FRAMEBUFFER_STATE(VkFramebuffer fb, const VkFramebufferCreateInfo *pCreateInfo,
286 std::shared_ptr<RENDER_PASS_STATE> &&rpstate,
287 std::vector<std::shared_ptr<IMAGE_VIEW_STATE>> &&attachments)
288 : BASE_NODE(fb, kVulkanObjectTypeFramebuffer), createInfo(pCreateInfo), rp_state(rpstate) {
289 for (auto &a : attachments) {
290 a->AddParent(this);
291 }
292 attachments_view_state = std::move(attachments);
293}
294
295void FRAMEBUFFER_STATE::Destroy() {
296 for (auto& view: attachments_view_state) {
297 view->RemoveParent(this);
298 }
299 attachments_view_state.clear();
300 BASE_NODE::Destroy();
301}
302