blob: bff15a6b701bc2898aa9e58740f89b523906907d [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
Jeremy Gebbene83bd442021-09-02 11:18:03 -060034// NOTE: The functions below are only called from the RENDER_PASS_STATE constructor, and use const_cast<> to set up
35// members that never change after construction is finished.
Jeremy Gebben88f58142021-06-01 10:07:52 -060036static void RecordRenderPassDAG(const VkRenderPassCreateInfo2 *pCreateInfo, RENDER_PASS_STATE *render_pass) {
Jeremy Gebbene83bd442021-09-02 11:18:03 -060037 auto &subpass_to_node = const_cast<RENDER_PASS_STATE::DAGNodeVec &>(render_pass->subpass_to_node);
Jeremy Gebben88f58142021-06-01 10:07:52 -060038 subpass_to_node.resize(pCreateInfo->subpassCount);
Jeremy Gebbene83bd442021-09-02 11:18:03 -060039 auto &self_dependencies = const_cast<RENDER_PASS_STATE::SelfDepVec &>(render_pass->self_dependencies);
Jeremy Gebben88f58142021-06-01 10:07:52 -060040 self_dependencies.resize(pCreateInfo->subpassCount);
Jeremy Gebbene83bd442021-09-02 11:18:03 -060041 auto &subpass_dependencies = const_cast<RENDER_PASS_STATE::SubpassGraphVec &>(render_pass->subpass_dependencies);
Jeremy Gebben88f58142021-06-01 10:07:52 -060042 subpass_dependencies.resize(pCreateInfo->subpassCount);
43
44 for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
45 subpass_to_node[i].pass = i;
46 self_dependencies[i].clear();
47 subpass_dependencies[i].pass = i;
48 }
49 for (uint32_t i = 0; i < pCreateInfo->dependencyCount; ++i) {
50 const auto &dependency = pCreateInfo->pDependencies[i];
51 const auto src_subpass = dependency.srcSubpass;
52 const auto dst_subpass = dependency.dstSubpass;
53 if ((dependency.srcSubpass != VK_SUBPASS_EXTERNAL) && (dependency.dstSubpass != VK_SUBPASS_EXTERNAL)) {
54 if (dependency.srcSubpass == dependency.dstSubpass) {
55 self_dependencies[dependency.srcSubpass].push_back(i);
56 } else {
57 subpass_to_node[dependency.dstSubpass].prev.push_back(dependency.srcSubpass);
58 subpass_to_node[dependency.srcSubpass].next.push_back(dependency.dstSubpass);
59 }
60 }
61 if (src_subpass == VK_SUBPASS_EXTERNAL) {
62 assert(dst_subpass != VK_SUBPASS_EXTERNAL); // this is invalid per VUID-VkSubpassDependency-srcSubpass-00865
63 subpass_dependencies[dst_subpass].barrier_from_external.emplace_back(&dependency);
64 } else if (dst_subpass == VK_SUBPASS_EXTERNAL) {
65 subpass_dependencies[src_subpass].barrier_to_external.emplace_back(&dependency);
66 } else if (dependency.srcSubpass != dependency.dstSubpass) {
67 // ignore self dependencies in prev and next
68 subpass_dependencies[src_subpass].next[&subpass_dependencies[dst_subpass]].emplace_back(&dependency);
69 subpass_dependencies[dst_subpass].prev[&subpass_dependencies[src_subpass]].emplace_back(&dependency);
70 }
71 }
72
73 //
74 // Determine "asynchrononous" subpassess
75 // syncronization is only interested in asyncronous stages *earlier* that the current one... so we'll only look towards those.
76 // 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
77 // small and the K for |= from the prev is must less than for set, we'll accept the brute force.
78 std::vector<std::vector<bool>> pass_depends(pCreateInfo->subpassCount);
79 for (uint32_t i = 1; i < pCreateInfo->subpassCount; ++i) {
80 auto &depends = pass_depends[i];
81 depends.resize(i);
82 auto &subpass_dep = subpass_dependencies[i];
83 for (const auto &prev : subpass_dep.prev) {
84 const auto prev_pass = prev.first->pass;
85 const auto &prev_depends = pass_depends[prev_pass];
86 for (uint32_t j = 0; j < prev_pass; j++) {
87 depends[j] = depends[j] | prev_depends[j];
88 }
89 depends[prev_pass] = true;
90 }
91 for (uint32_t pass = 0; pass < subpass_dep.pass; pass++) {
92 if (!depends[pass]) {
93 subpass_dep.async.push_back(pass);
94 }
95 }
96 }
97}
98
99static VkSubpassDependency2 ImplicitDependencyFromExternal(uint32_t subpass) {
100 VkSubpassDependency2 from_external = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
101 nullptr,
102 VK_SUBPASS_EXTERNAL,
103 subpass,
104 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
105 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
106 0,
107 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
108 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
109 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
110 0,
111 0};
112 return from_external;
113}
114
115static VkSubpassDependency2 ImplicitDependencyToExternal(uint32_t subpass) {
116 VkSubpassDependency2 to_external = {VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
117 nullptr,
118 subpass,
119 VK_SUBPASS_EXTERNAL,
120 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
121 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
122 VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
123 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
124 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
125 0,
126 0,
127 0};
128 return to_external;
129}
130
131struct AttachmentTracker { // This is really only of local interest, but a bit big for a lambda
132 RENDER_PASS_STATE *const rp;
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600133 RENDER_PASS_STATE::SubpassVec &first;
134 RENDER_PASS_STATE::FirstIsTransitionVec &first_is_transition;
135 RENDER_PASS_STATE::SubpassVec &last;
136 RENDER_PASS_STATE::TransitionVec &subpass_transitions;
137 RENDER_PASS_STATE::FirstReadMap &first_read;
Jeremy Gebben88f58142021-06-01 10:07:52 -0600138 const uint32_t attachment_count;
139 std::vector<VkImageLayout> attachment_layout;
140 std::vector<std::vector<VkImageLayout>> subpass_attachment_layout;
141 explicit AttachmentTracker(RENDER_PASS_STATE *render_pass)
142 : rp(render_pass),
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600143 first(const_cast<RENDER_PASS_STATE::SubpassVec &>(rp->attachment_first_subpass)),
144 first_is_transition(const_cast<RENDER_PASS_STATE::FirstIsTransitionVec &>(rp->attachment_first_is_transition)),
145 last(const_cast<RENDER_PASS_STATE::SubpassVec &>(rp->attachment_last_subpass)),
146 subpass_transitions(const_cast<RENDER_PASS_STATE::TransitionVec &>(rp->subpass_transitions)),
147 first_read(const_cast<RENDER_PASS_STATE::FirstReadMap &>(rp->attachment_first_read)),
Jeremy Gebben88f58142021-06-01 10:07:52 -0600148 attachment_count(rp->createInfo.attachmentCount),
149 attachment_layout(),
150 subpass_attachment_layout() {
151 first.resize(attachment_count, VK_SUBPASS_EXTERNAL);
152 first_is_transition.resize(attachment_count, false);
153 last.resize(attachment_count, VK_SUBPASS_EXTERNAL);
154 subpass_transitions.resize(rp->createInfo.subpassCount + 1); // Add an extra for EndRenderPass
155 attachment_layout.reserve(attachment_count);
156 subpass_attachment_layout.resize(rp->createInfo.subpassCount);
157 for (auto &subpass_layouts : subpass_attachment_layout) {
158 subpass_layouts.resize(attachment_count, kInvalidLayout);
159 }
160
161 for (uint32_t j = 0; j < attachment_count; j++) {
162 attachment_layout.push_back(rp->createInfo.pAttachments[j].initialLayout);
163 }
164 }
165
166 void Update(uint32_t subpass, const VkAttachmentReference2 *attach_ref, uint32_t count, bool is_read) {
167 if (nullptr == attach_ref) return;
168 for (uint32_t j = 0; j < count; ++j) {
169 const auto attachment = attach_ref[j].attachment;
170 if (attachment != VK_ATTACHMENT_UNUSED) {
171 const auto layout = attach_ref[j].layout;
172 // Take advantage of the fact that insert won't overwrite, so we'll only write the first time.
173 first_read.emplace(attachment, is_read);
174 if (first[attachment] == VK_SUBPASS_EXTERNAL) {
175 first[attachment] = subpass;
176 const auto initial_layout = rp->createInfo.pAttachments[attachment].initialLayout;
177 if (initial_layout != layout) {
178 subpass_transitions[subpass].emplace_back(VK_SUBPASS_EXTERNAL, attachment, initial_layout, layout);
179 first_is_transition[attachment] = true;
180 }
181 }
182 last[attachment] = subpass;
183
184 for (const auto &prev : rp->subpass_dependencies[subpass].prev) {
185 const auto prev_pass = prev.first->pass;
186 const auto prev_layout = subpass_attachment_layout[prev_pass][attachment];
187 if ((prev_layout != kInvalidLayout) && (prev_layout != layout)) {
188 subpass_transitions[subpass].emplace_back(prev_pass, attachment, prev_layout, layout);
189 }
190 }
191 attachment_layout[attachment] = layout;
192 }
193 }
194 }
195 void FinalTransitions() {
196 auto &final_transitions = subpass_transitions[rp->createInfo.subpassCount];
197
198 for (uint32_t attachment = 0; attachment < attachment_count; ++attachment) {
199 const auto final_layout = rp->createInfo.pAttachments[attachment].finalLayout;
200 // Add final transitions for attachments that were used and change layout.
201 if ((last[attachment] != VK_SUBPASS_EXTERNAL) && final_layout != attachment_layout[attachment]) {
202 final_transitions.emplace_back(last[attachment], attachment, attachment_layout[attachment], final_layout);
203 }
204 }
205 }
206};
207
208static void InitRenderPassState(RENDER_PASS_STATE *render_pass) {
209 auto create_info = render_pass->createInfo.ptr();
210
211 RecordRenderPassDAG(create_info, render_pass);
212
213 AttachmentTracker attachment_tracker(render_pass);
214
215 for (uint32_t subpass_index = 0; subpass_index < create_info->subpassCount; ++subpass_index) {
216 const VkSubpassDescription2 &subpass = create_info->pSubpasses[subpass_index];
217 attachment_tracker.Update(subpass_index, subpass.pColorAttachments, subpass.colorAttachmentCount, false);
218 attachment_tracker.Update(subpass_index, subpass.pResolveAttachments, subpass.colorAttachmentCount, false);
219 attachment_tracker.Update(subpass_index, subpass.pDepthStencilAttachment, 1, false);
220 attachment_tracker.Update(subpass_index, subpass.pInputAttachments, subpass.inputAttachmentCount, true);
221 }
222 attachment_tracker.FinalTransitions();
223
224 // Add implicit dependencies
225 for (uint32_t attachment = 0; attachment < attachment_tracker.attachment_count; attachment++) {
226 const auto first_use = attachment_tracker.first[attachment];
227 if (first_use != VK_SUBPASS_EXTERNAL) {
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600228 auto &subpass_dep = const_cast<SubpassDependencyGraphNode &>(render_pass->subpass_dependencies[first_use]);
Jeremy Gebben88f58142021-06-01 10:07:52 -0600229 if (subpass_dep.barrier_from_external.size() == 0) {
230 // Add implicit from barrier if they're aren't any
231 subpass_dep.implicit_barrier_from_external.reset(
232 new VkSubpassDependency2(ImplicitDependencyFromExternal(first_use)));
233 subpass_dep.barrier_from_external.emplace_back(subpass_dep.implicit_barrier_from_external.get());
234 }
235 }
236
237 const auto last_use = attachment_tracker.last[attachment];
238 if (last_use != VK_SUBPASS_EXTERNAL) {
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600239 auto &subpass_dep = const_cast<SubpassDependencyGraphNode &>(render_pass->subpass_dependencies[first_use]);
Jeremy Gebben88f58142021-06-01 10:07:52 -0600240 if (render_pass->subpass_dependencies[last_use].barrier_to_external.size() == 0) {
241 // Add implicit to barrier if they're aren't any
242 subpass_dep.implicit_barrier_to_external.reset(new VkSubpassDependency2(ImplicitDependencyToExternal(last_use)));
243 subpass_dep.barrier_to_external.emplace_back(subpass_dep.implicit_barrier_to_external.get());
244 }
245 }
246 }
247}
248
249RENDER_PASS_STATE::RENDER_PASS_STATE(VkRenderPass rp, VkRenderPassCreateInfo2 const *pCreateInfo)
250 : BASE_NODE(rp, kVulkanObjectTypeRenderPass), createInfo(pCreateInfo) {
251 InitRenderPassState(this);
252}
253
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600254static safe_VkRenderPassCreateInfo2 ConvertCreateInfo(const VkRenderPassCreateInfo &create_info) {
255 safe_VkRenderPassCreateInfo2 create_info_2;
256 ConvertVkRenderPassCreateInfoToV2KHR(create_info, &create_info_2);
257 return create_info_2;
258}
259
Jeremy Gebben88f58142021-06-01 10:07:52 -0600260RENDER_PASS_STATE::RENDER_PASS_STATE(VkRenderPass rp, VkRenderPassCreateInfo const *pCreateInfo)
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600261 : BASE_NODE(rp, kVulkanObjectTypeRenderPass), createInfo(ConvertCreateInfo(*pCreateInfo)) {
Jeremy Gebben88f58142021-06-01 10:07:52 -0600262 InitRenderPassState(this);
263}
264
Jeremy Gebben11af9792021-08-20 10:20:09 -0600265bool RENDER_PASS_STATE::UsesColorAttachment(uint32_t subpass_num) const {
266 bool result = false;
267
268 if (subpass_num < createInfo.subpassCount) {
269 const auto &subpass = createInfo.pSubpasses[subpass_num];
270
271 for (uint32_t i = 0; i < subpass.colorAttachmentCount; ++i) {
272 if (subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
273 result = true;
274 break;
275 }
276 }
277 }
278 return result;
279}
280
281bool RENDER_PASS_STATE::UsesDepthStencilAttachment(uint32_t subpass_num) const {
282 bool result = false;
283 if (subpass_num < createInfo.subpassCount) {
284 const auto &subpass = createInfo.pSubpasses[subpass_num];
285 if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
286 result = true;
287 }
288 }
289 return result;
290}
291
Jeremy Gebben88f58142021-06-01 10:07:52 -0600292FRAMEBUFFER_STATE::FRAMEBUFFER_STATE(VkFramebuffer fb, const VkFramebufferCreateInfo *pCreateInfo,
293 std::shared_ptr<RENDER_PASS_STATE> &&rpstate,
294 std::vector<std::shared_ptr<IMAGE_VIEW_STATE>> &&attachments)
Jeremy Gebbene83bd442021-09-02 11:18:03 -0600295 : BASE_NODE(fb, kVulkanObjectTypeFramebuffer),
296 createInfo(pCreateInfo),
297 rp_state(rpstate),
298 attachments_view_state(std::move(attachments)) {
299 for (auto &a : attachments_view_state) {
Jeremy Gebben88f58142021-06-01 10:07:52 -0600300 a->AddParent(this);
301 }
Jeremy Gebben88f58142021-06-01 10:07:52 -0600302}
303
304void FRAMEBUFFER_STATE::Destroy() {
305 for (auto& view: attachments_view_state) {
306 view->RemoveParent(this);
307 }
308 attachments_view_state.clear();
309 BASE_NODE::Destroy();
310}
311