GCC Code Coverage Report


ernie/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
221 / 264
83.7%
Branches:
155 / 217
71.4%
Functions:
14 / 14, 1 excl
100.0%

graph/dependencies.cpp
Line Branch Exec Source
1 // SPDX-License-Identifier: BSD-3-Clause
2 /// @file dependencies.cpp
3 /// @brief Uses as stages, accesses and layouts, and the barriers a pass order needs.
4 #include "ernie/graph/dependencies.h"
5
6 #include <algorithm>
7 #include <cstddef>
8
9 namespace ernie::graph {
10 namespace {
11
12 constexpr VkAccessFlags2 kWriteAccess =
13 VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT |
14 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
15 VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_2_HOST_WRITE_BIT | VK_ACCESS_2_MEMORY_WRITE_BIT |
16 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR;
17
18 /// A pass's accesses to one resource, merged.
19 struct Merged {
20 std::uint32_t resource = 0;
21 UseState state;
22 Layers layers;
23 bool valid = true;
24 };
25
26 /// What a resource's earlier accesses left to synchronize with.
27 1130 struct ResourceState {
28 VkPipelineStageFlags2 writeStages = VK_PIPELINE_STAGE_2_NONE;
29 VkAccessFlags2 writeAccess = VK_ACCESS_2_NONE;
30 /// Stages that read since the last write.
31 VkPipelineStageFlags2 readStages = VK_PIPELINE_STAGE_2_NONE;
32 /// The stage and access pairs the last write is visible to.
33 std::vector<UseState> visible;
34 VkImageLayout layout = VK_IMAGE_LAYOUT_GENERAL;
35 /// Whether it holds content, and whether this graph wrote it.
36 bool written = false;
37 bool writtenHere = false;
38 bool touched = false;
39 };
40
41 920 VkPipelineStageFlags2 ShaderStages(Kind kind) {
42
3/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 395 times.
✓ Branch 3 taken 508 times.
920 switch (kind) {
43 case Kind::Compute:
44 return VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
45 17 case Kind::Raster:
46 // Vertex shaders sample too, such as terrain heights.
47 17 return VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT;
48 ✗ case Kind::RayTracing:
49 ✗ return VK_PIPELINE_STAGE_2_RAY_TRACING_SHADER_BIT_KHR;
50 case Kind::Copy:
51 case Kind::Build:
52 break;
53 }
54 395 return VK_PIPELINE_STAGE_2_NONE;
55 }
56
57 48 std::uint64_t LayerEnd(Layers layers) {
58
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
48 return layers.count == Layers::kAll ? ~std::uint64_t{0}
59 2 : std::uint64_t{layers.first} + layers.count;
60 }
61
62 24 Layers Union(Layers a, Layers b) {
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 const std::uint32_t first = std::min(a.first, b.first);
64
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 23 times.
24 const std::uint64_t end = std::max(LayerEnd(a), LayerEnd(b));
65
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 time.
24 if (end == ~std::uint64_t{0}) {
66 23 return {first, Layers::kAll};
67 }
68 1 return {first, static_cast<std::uint32_t>(end - first)};
69 }
70
71 /// The layout two uses in one pass share, or undefined if none.
72 2 VkImageLayout Combine(VkImageLayout a, VkImageLayout b) {
73
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if (a == b) {
74 return a;
75 }
76 // Attachments that are read as depth, and sampled too, share the read-only depth layout.
77 1 const auto depthRead = [](VkImageLayout l) {
78 1 return l == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL || l == VK_IMAGE_LAYOUT_GENERAL;
79 };
80
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (depthRead(a) && depthRead(b)) {
81 ✗ return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL;
82 }
83 return VK_IMAGE_LAYOUT_UNDEFINED;
84 }
85
86 433 bool Covers(const std::vector<UseState>& visible, const UseState& use) {
87 433 return std::ranges::any_of(visible, [&](const UseState& seen) {
88
3/4
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
31 return (use.stages & ~seen.stages) == 0 && (use.access & ~seen.access) == 0;
89 433 });
90 }
91
92 268 std::vector<Merged> Merge(const DependencyPass& pass, std::span<const DependencyResource> resources,
93 std::vector<std::string>& errors) {
94 268 std::vector<Merged> merged;
95
2/2
✓ Branch 0 taken 912 times.
✓ Branch 1 taken 268 times.
1180 for (const DependencyAccess& access : pass.accesses) {
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 912 times.
912 if (access.resource >= resources.size()) {
97
0/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ errors.push_back("pass '" + pass.name + "' uses an unknown resource");
98 888 continue;
99 }
100
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 908 times.
912 const DependencyResource& resource = resources[access.resource];
101 912 const UseState state = ToState(pass.kind, access.use, resource.image);
102
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 908 times.
912 if (state.stages == VK_PIPELINE_STAGE_2_NONE) {
103
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
16 errors.push_back("pass '" + pass.name + "' cannot use " +
104
5/8
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
20 (resource.image ? "image '" : "buffer '") + resource.name + "' as " +
105 ToString(access.use));
106 4 continue;
107 }
108 908 const auto it = std::ranges::find(merged, access.resource, &Merged::resource);
109
2/2
✓ Branch 0 taken 884 times.
✓ Branch 1 taken 24 times.
908 if (it == merged.end()) {
110
1/2
✓ Branch 1 taken 884 times.
✗ Branch 2 not taken.
884 merged.push_back({access.resource, state, access.layers});
111 884 continue;
112 }
113 24 it->state.stages |= state.stages;
114 24 it->state.access |= state.access;
115
4/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 21 times.
24 it->state.writes = it->state.writes || state.writes;
116
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
24 it->state.reads = it->state.reads || state.reads;
117 24 it->layers = Union(it->layers, access.layers);
118
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (resource.image) {
119 2 const VkImageLayout layout = Combine(it->state.layout, state.layout);
120
3/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
2 if (layout == VK_IMAGE_LAYOUT_UNDEFINED && it->valid) {
121
3/6
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 time.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 time.
✗ Branch 8 not taken.
3 errors.push_back("pass '" + pass.name + "' uses image '" + resource.name +
122 "' in conflicting layouts");
123 1 it->valid = false;
124 }
125 2 it->state.layout = layout;
126 }
127 }
128 268 return merged;
129 ✗ }
130
131 565 void Initialize(ResourceState& state, const DependencyResource& resource) {
132
3/3
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 108 times.
565 switch (resource.origin) {
133 454 case Origin::Imported:
134 // Anything before the graph may have written it.
135 454 state.writeStages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
136 454 state.writeAccess = VK_ACCESS_2_MEMORY_WRITE_BIT;
137 454 state.written = true;
138 454 break;
139 3 case Origin::Recycled:
140 // An earlier graph's reads may still be running.
141 3 state.readStages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
142 3 break;
143 case Origin::Fresh:
144 break;
145 }
146 565 }
147
148 1083 void AddBarrier(Dependency& batch, const DependencyResource& resource, std::uint32_t index,
149 VkPipelineStageFlags2 srcStages, VkAccessFlags2 srcAccess, const Merged& use,
150 VkImageLayout oldLayout) {
151 1083 Barrier barrier{.resource = index,
152 .srcStages = srcStages,
153 .srcAccess = srcAccess,
154 1083 .dstStages = use.state.stages,
155 1083 .dstAccess = use.state.access};
156
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 1034 times.
1083 if (resource.image) {
157 49 barrier.oldLayout = oldLayout;
158 49 barrier.newLayout = use.state.layout;
159 // Layer ranges narrow memory barriers only; layouts change for the whole image.
160
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 5 times.
49 barrier.layers = oldLayout == use.state.layout ? use.layers : Layers{};
161 49 batch.images.push_back(barrier);
162 } else {
163 1034 batch.buffers.push_back(barrier);
164 }
165 1083 }
166
167 883 void Analyze(const Merged& use, const DependencyResource& resource, ResourceState& state,
168 Dependency& before) {
169 883 const std::uint32_t index = use.resource;
170 883 state.touched = true;
171
4/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 842 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 36 times.
883 const bool layoutChange = resource.image && use.state.layout != state.layout;
172 883 if (layoutChange) {
173 5 AddBarrier(before, resource, index, state.writeStages | state.readStages, state.writeAccess,
174 use, state.layout);
175 5 state.layout = use.state.layout;
176
2/2
✓ Branch 0 taken 445 times.
✓ Branch 1 taken 433 times.
878 } else if (use.state.writes) {
177 445 const VkPipelineStageFlags2 src = state.writeStages | state.readStages;
178
2/2
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 96 times.
445 if (src != VK_PIPELINE_STAGE_2_NONE) {
179 349 AddBarrier(before, resource, index, src, state.writeAccess, use, state.layout);
180 }
181
2/2
✓ Branch 1 taken 406 times.
✓ Branch 2 taken 27 times.
433 } else if (!Covers(state.visible, use.state)) {
182
2/2
✓ Branch 0 taken 404 times.
✓ Branch 1 taken 2 times.
406 if (state.writeStages != VK_PIPELINE_STAGE_2_NONE) {
183 404 AddBarrier(before, resource, index, state.writeStages, state.writeAccess, use,
184 state.layout);
185 }
186 406 state.visible.push_back(use.state);
187 }
188
2/2
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 436 times.
883 if (use.state.writes) {
189 447 state.writeStages = use.state.stages;
190 447 state.writeAccess = use.state.access & kWriteAccess;
191 447 state.readStages = VK_PIPELINE_STAGE_2_NONE;
192 447 state.visible.clear();
193 447 state.written = true;
194 447 state.writtenHere = true;
195 } else {
196
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 433 times.
436 if (layoutChange) {
197 // The transition is a write ordered before these stages and already available.
198 3 state.writeStages = use.state.stages;
199 3 state.writeAccess = VK_ACCESS_2_NONE;
200 3 state.readStages = VK_PIPELINE_STAGE_2_NONE;
201 3 state.visible.assign(1, use.state);
202 }
203 436 state.readStages |= use.state.stages;
204 }
205 883 }
206
207 57 void Finish(std::span<const DependencyResource> resources, std::span<const ResourceState> states,
208 Dependency& after) {
209
2/2
✓ Branch 0 taken 565 times.
✓ Branch 1 taken 57 times.
622 for (std::size_t i = 0; i < resources.size(); ++i) {
210
2/2
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 111 times.
565 const DependencyResource& resource = resources[i];
211 565 const ResourceState& state = states[i];
212
4/4
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 435 times.
565 if (resource.origin != Origin::Imported || !state.touched) {
213 130 continue;
214 }
215 435 const auto index = static_cast<std::uint32_t>(i);
216 435 Merged use{.resource = index,
217 .state = {.stages = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
218 .access = kAnyAccess,
219 435 .layout = VK_IMAGE_LAYOUT_GENERAL}};
220
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 421 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
435 if (resource.image && state.layout != VK_IMAGE_LAYOUT_GENERAL) {
221 // Back in the general layout, as every import enters.
222 ✗ AddBarrier(after, resource, index, state.writeStages | state.readStages,
223 ✗ state.writeAccess, use, state.layout);
224
3/4
✓ Branch 0 taken 325 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 325 times.
✗ Branch 3 not taken.
435 } else if (state.writtenHere && state.writeAccess != VK_ACCESS_2_NONE) {
225
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 13 times.
325 if (!resource.image) {
226 // Readbacks: the host reads once the ticket is reached.
227 312 use.state.stages |= VK_PIPELINE_STAGE_2_HOST_BIT;
228 312 use.state.access |= VK_ACCESS_2_HOST_READ_BIT;
229 }
230 325 AddBarrier(after, resource, index, state.writeStages, state.writeAccess, use,
231 325 state.layout);
232 }
233 }
234 57 }
235
236 } // namespace
237
238 920 UseState ToState(Kind kind, Use use, bool image) {
239 920 const VkPipelineStageFlags2 shader = ShaderStages(kind);
240 920 const VkPipelineStageFlags2 transfer = VK_PIPELINE_STAGE_2_ALL_TRANSFER_BIT;
241 920 const VkPipelineStageFlags2 build = VK_PIPELINE_STAGE_2_ACCELERATION_STRUCTURE_BUILD_BIT_KHR;
242 920 const VkPipelineStageFlags2 depth =
243 VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT;
244 920 const bool raster = kind == Kind::Raster;
245
2/2
✓ Branch 0 taken 867 times.
✓ Branch 1 taken 53 times.
920 const VkImageLayout general = image ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED;
246 920 UseState s;
247
16/19
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 316 times.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 12 times.
✓ Branch 10 taken 195 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 1 time.
✗ Branch 13 not taken.
✓ Branch 14 taken 92 times.
✓ Branch 15 taken 45 times.
✓ Branch 16 taken 51 times.
✓ Branch 17 taken 28 times.
✗ Branch 18 not taken.
920 switch (use) {
248 12 case Use::Sampled:
249
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 time.
12 if (image) {
250 11 s = {shader, VK_ACCESS_2_SHADER_SAMPLED_READ_BIT, general, false, true};
251 }
252 break;
253 316 case Use::StorageRead:
254 316 s = {shader, VK_ACCESS_2_SHADER_STORAGE_READ_BIT, general, false, true};
255 316 break;
256 114 case Use::StorageWrite:
257 114 s = {shader, VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT, general, true, false};
258 114 break;
259 46 case Use::StorageReadWrite:
260 46 s = {shader, VK_ACCESS_2_SHADER_STORAGE_READ_BIT | VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
261 general, true, true};
262 46 break;
263 3 case Use::ColorWrite:
264
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 if (image && raster) {
265 2 return {VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
266 VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
267 2 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, false};
268 }
269 1 return {};
270 1 case Use::ColorReadWrite:
271
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (image && raster) {
272 1 return {VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
273 VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
274 1 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true, true};
275 }
276 ✗ return {};
277 1 case Use::DepthWrite:
278
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (image && raster) {
279 1 return {depth, VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
280 1 VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, true, false};
281 }
282 ✗ return {};
283 ✗ case Use::DepthReadWrite:
284
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (image && raster) {
285 ✗ return {depth,
286 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
287 VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
288 ✗ VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, true, true};
289 }
290 ✗ return {};
291 1 case Use::DepthRead:
292
1/2
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
1 if (image && raster) {
293 1 return {depth, VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
294 1 VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, false, true};
295 }
296 ✗ return {};
297 12 case Use::CopySrc:
298 12 return {transfer, VK_ACCESS_2_TRANSFER_READ_BIT, general, false, true};
299 195 case Use::CopyDst:
300 195 return {transfer, VK_ACCESS_2_TRANSFER_WRITE_BIT, general, true, false};
301 2 case Use::Uniform:
302
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!image) {
303 2 s = {shader, VK_ACCESS_2_UNIFORM_READ_BIT, general, false, true};
304 }
305 break;
306 1 case Use::Indirect:
307
2/6
✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 if (!image && (kind == Kind::Compute || raster || kind == Kind::RayTracing)) {
308 1 return {VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT, VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT,
309 1 general, false, true};
310 }
311 ✗ return {};
312 ✗ case Use::HostRead:
313
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ if (!image) {
314 ✗ return {VK_PIPELINE_STAGE_2_HOST_BIT, VK_ACCESS_2_HOST_READ_BIT, general, false, true};
315 }
316 ✗ return {};
317 92 case Use::BuildInput:
318
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 if (!image && kind == Kind::Build) {
319 92 return {build,
320 VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR,
321 92 general, false, true};
322 }
323 ✗ return {};
324 45 case Use::BuildScratch:
325 // Read and written within the build; what it held before never matters.
326
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 if (!image && kind == Kind::Build) {
327 45 return {build,
328 VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR |
329 VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR,
330 45 general, true, false};
331 }
332 ✗ return {};
333 51 case Use::BuildOutput:
334
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1 time.
51 if (!image && kind == Kind::Build) {
335 50 return {build, VK_ACCESS_2_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, general, true, false};
336 }
337 1 return {};
338 28 case Use::Trace:
339
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (!image) {
340 28 s = {shader, VK_ACCESS_2_ACCELERATION_STRUCTURE_READ_BIT_KHR, general, false, true};
341 }
342 break;
343 }
344 // Shader uses need a pass that has shaders.
345
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 517 times.
518 if (shader == VK_PIPELINE_STAGE_2_NONE) {
346 1 return {};
347 }
348 517 return s;
349 }
350
351 57 PassDependencies ComputeDependencies(std::span<const DependencyResource> resources,
352 std::span<const DependencyPass> passes) {
353 57 PassDependencies dependencies;
354
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 std::vector<ResourceState> states(resources.size());
355
2/2
✓ Branch 0 taken 565 times.
✓ Branch 1 taken 57 times.
622 for (std::size_t i = 0; i < resources.size(); ++i) {
356 565 Initialize(states[i], resources[i]);
357 }
358
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 dependencies.passes.resize(passes.size());
359
2/2
✓ Branch 0 taken 268 times.
✓ Branch 1 taken 57 times.
325 for (std::size_t p = 0; p < passes.size(); ++p) {
360
1/2
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
268 const DependencyPass& pass = passes[p];
361
3/4
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 884 times.
✓ Branch 4 taken 268 times.
1152 for (const Merged& use : Merge(pass, resources, dependencies.errors)) {
362
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 380 times.
884 const DependencyResource& resource = resources[use.resource];
363
2/2
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 380 times.
884 ResourceState& state = states[use.resource];
364
4/4
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 380 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 501 times.
884 if (use.state.reads && !state.written) {
365
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
9 dependencies.errors.push_back("pass '" + pass.name + "' reads '" + resource.name +
366 "', which no earlier pass writes and which is "
367 "not imported");
368 }
369
2/2
✓ Branch 0 taken 883 times.
✓ Branch 1 taken 1 time.
884 if (use.valid) {
370
1/2
✓ Branch 1 taken 883 times.
✗ Branch 2 not taken.
883 Analyze(use, resource, state, dependencies.passes[p]);
371 }
372 268 }
373 }
374
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 Finish(resources, states, dependencies.after);
375 57 return dependencies;
376 57 }
377
378 20 const char* ToString(Use use) {
379
8/19
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 time.
20 switch (use) {
380 case Use::Sampled:
381 return "Sampled";
382 3 case Use::StorageRead:
383 3 return "StorageRead";
384 5 case Use::StorageWrite:
385 5 return "StorageWrite";
386 ✗ case Use::StorageReadWrite:
387 ✗ return "StorageReadWrite";
388 1 case Use::ColorWrite:
389 1 return "ColorWrite";
390 ✗ case Use::ColorReadWrite:
391 ✗ return "ColorReadWrite";
392 ✗ case Use::DepthWrite:
393 ✗ return "DepthWrite";
394 ✗ case Use::DepthReadWrite:
395 ✗ return "DepthReadWrite";
396 ✗ case Use::DepthRead:
397 ✗ return "DepthRead";
398 ✗ case Use::CopySrc:
399 ✗ return "CopySrc";
400 ✗ case Use::CopyDst:
401 ✗ return "CopyDst";
402 ✗ case Use::Uniform:
403 ✗ return "Uniform";
404 ✗ case Use::Indirect:
405 ✗ return "Indirect";
406 ✗ case Use::HostRead:
407 ✗ return "HostRead";
408 3 case Use::BuildInput:
409 3 return "BuildInput";
410 2 case Use::BuildScratch:
411 2 return "BuildScratch";
412 3 case Use::BuildOutput:
413 3 return "BuildOutput";
414 2 case Use::Trace:
415 2 return "Trace";
416 }
417 ✗ return "?";
418 }
419
420 } // namespace ernie::graph
421