载入中...
搜索中...
未找到
RenderFlow.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <queue>
5#include <sstream>
6
7namespace eve::dev {
8
9RenderFlow::RenderFlow() = default;
10
11RenderFlow::~RenderFlow() = default;
12
14 head_ = 0;
15 count_ = 0;
16 passStack_.clear();
17 nextEventId_ = 1;
18 lastEventId_ = 0;
19 lastBind_.clear();
20 dataDeps_.clear();
21}
22
23void RenderFlow::ensureRing() {
24 if (slots_.size() != maxEvents_) slots_.resize(maxEvents_);
25}
26
28 n = n < 16 ? 16 : n;
29 if (n == maxEvents_ && slots_.size() == n) return;
30
31 const size_t keep = count_ < n ? count_ : n;
32 const size_t drop = count_ - keep;
33 std::vector<RenderEvent> neu(n);
34 for (size_t i = 0; i < drop; ++i) retireSlot(physicalIndex(i));
35 for (size_t i = 0; i < keep; ++i) neu[i] = (*this)[drop + i];
36
37 slots_ = std::move(neu);
38 head_ = 0;
39 count_ = keep;
40 maxEvents_ = n;
41}
42
43void RenderFlow::retireSlot(size_t physical) {
44 RenderEvent& old = slots_[physical];
45 if (old.id == 0) return;
46
47 dataDeps_.erase(old.id);
48
49 if (old.kind == RenderEventKind::Bind) {
50 const std::string k = old.name + "|" + old.detail;
51 auto it = lastBind_.find(k);
52 if (it != lastBind_.end() && it->second == old.id) lastBind_.erase(it);
53 if (!old.detail.empty()) {
54 const std::string star = std::string("*|") + old.detail;
55 auto sit = lastBind_.find(star);
56 if (sit != lastBind_.end() && sit->second == old.id) lastBind_.erase(sit);
57 }
58 }
59
60 old = RenderEvent{};
61}
62
63uint32_t RenderFlow::append(RenderEventKind kind, const std::string& name,
64 const std::string& detail) {
65 ensureRing();
66
67 size_t phys;
68 if (count_ < maxEvents_) {
69 phys = physicalIndex(count_);
70 ++count_;
71 } else {
72 phys = head_;
73 retireSlot(phys);
74 head_ = (head_ + 1) % maxEvents_;
75 }
76
77 RenderEvent& e = slots_[phys];
78 e.id = nextEventId_++;
79 e.kind = kind;
80 e.name = name;
81 e.detail = detail;
82 e.parentId = lastEventId_;
83 e.passId = passStack_.empty() ? 0 : passStack_.back();
84 lastEventId_ = e.id;
85 return e.id;
86}
87
88const RenderEvent* RenderFlow::event(uint32_t id) const {
89 if (id == 0 || count_ == 0) return nullptr;
90 const uint32_t first = (*this)[0].id;
91 const uint32_t last = (*this)[count_ - 1].id;
92 if (id < first || id > last) return nullptr;
93 return &(*this)[static_cast<size_t>(id - first)];
94}
95
97
98void RenderFlow::frameEnd() { append(RenderEventKind::FrameEnd, "frame", ""); }
99
100void RenderFlow::passBegin(const char* name) {
101 const uint32_t id = append(RenderEventKind::PassBegin, name ? name : "", "");
102 passStack_.push_back(id);
103 newest().passId = id;
104}
105
106void RenderFlow::passEnd(const char* name) {
107 append(RenderEventKind::PassEnd, name ? name : "", "");
108 if (!passStack_.empty()) passStack_.pop_back();
109}
110
111void RenderFlow::target(const char* name) {
112 append(RenderEventKind::Target, "target", name ? name : "");
113}
114
115void RenderFlow::bind(const char* kind, const char* name) {
116 const std::string k = kind ? kind : "resource";
117 const std::string n = name ? name : "";
118 const uint32_t id = append(RenderEventKind::Bind, k, n);
119 lastBind_[k + "|" + n] = id;
120 if (!n.empty()) lastBind_["*|" + n] = id;
121}
122
123void RenderFlow::draw(const char* api, const char* detail) {
124 const uint32_t id = append(RenderEventKind::Draw, api ? api : "draw", detail ? detail : "");
125 // Data-flow: draw depends on enclosing pass + any binds whose name appears in detail,
126 // and the most recent binds of common kinds (texture/shader/mesh/font).
127 if (newest().passId) dataDeps_[id].push_back(newest().passId);
128
129 auto linkRecent = [&](const char* kind) {
130 uint32_t best = 0;
131 const std::string prefix = std::string(kind) + "|";
132 for (const auto& kv : lastBind_) {
133 if (kv.first.rfind(prefix, 0) == 0) {
134 if (kv.second > best && event(kv.second)) best = kv.second;
135 }
136 }
137 if (best) dataDeps_[id].push_back(best);
138 };
139 linkRecent("texture");
140 linkRecent("shader");
141 linkRecent("mesh");
142 linkRecent("font");
143 linkRecent("canvas");
144
145 if (detail && detail[0]) {
146 auto it = lastBind_.find(std::string("*|") + detail);
147 if (it != lastBind_.end() && event(it->second)) dataDeps_[id].push_back(it->second);
148 }
149}
150
151void RenderFlow::error(const char* message) {
152 const uint32_t id = append(RenderEventKind::Error, "error", message ? message : "");
153 if (newest().passId) dataDeps_[id].push_back(newest().passId);
154 // Error depends on the immediately preceding draw/bind in the same pass.
155 for (size_t i = count_; i-- > 0;) {
156 const RenderEvent& e = (*this)[i];
157 if (e.id == id) continue;
160 dataDeps_[id].push_back(e.id);
161 break;
162 }
163 if (e.kind == RenderEventKind::PassBegin) break;
164 }
165}
166
167uint32_t RenderFlow::findSeed(const RenderSliceCriterion& c) const {
168 if (c.eventId && event(c.eventId)) return c.eventId;
169 for (size_t i = count_; i-- > 0;) {
170 if ((*this)[i].kind == RenderEventKind::Error) return (*this)[i].id;
171 }
172 return count_ == 0 ? 0 : (*this)[count_ - 1].id;
173}
174
176 RenderSliceResult result;
177 const uint32_t seed = findSeed(c);
178 if (!seed) {
179 result.summary = "empty render slice";
180 return result;
181 }
182
183 std::unordered_set<uint32_t> visited;
184 std::queue<uint32_t> q;
185 auto enqueue = [&](uint32_t id) {
186 if (!event(id)) return;
187 if (visited.insert(id).second) q.push(id);
188 };
189 enqueue(seed);
190
191 if (!c.resource.empty()) {
192 auto it = lastBind_.find("*|" + c.resource);
193 if (it != lastBind_.end()) enqueue(it->second);
194 }
195
196 while (!q.empty()) {
197 const uint32_t id = q.front();
198 q.pop();
199 const RenderEvent* e = event(id);
200 if (!e) continue;
201 enqueue(e->parentId);
202 enqueue(e->passId);
203 auto dit = dataDeps_.find(id);
204 if (dit != dataDeps_.end()) {
205 for (uint32_t dep : dit->second) enqueue(dep);
206 }
207 }
208
209 result.eventIds.assign(visited.begin(), visited.end());
210 std::sort(result.eventIds.begin(), result.eventIds.end());
211 for (uint32_t id : result.eventIds) {
212 if (const RenderEvent* e = event(id)) result.path.push_back(*e);
213 }
214
215 // Reconstruct pass nesting at seed from retained window.
216 for (size_t i = 0; i < count_; ++i) {
217 const RenderEvent& e = (*this)[i];
218 if (e.id > seed) break;
219 if (e.kind == RenderEventKind::PassBegin) result.passes.push_back(e.name);
220 else if (e.kind == RenderEventKind::PassEnd && !result.passes.empty())
221 result.passes.pop_back();
222 }
223
224 std::ostringstream os;
225 os << "render slice: " << result.eventIds.size() << " events, pass depth "
226 << result.passes.size();
227 result.summary = os.str();
228 return result;
229}
230
231std::string RenderFlow::formatErrorReport(const std::string& errorMessage,
232 const RenderSliceCriterion& c) const {
233 const RenderSliceResult slice = sliceBackward(c);
234 std::ostringstream os;
235 os << "=== Render Pipeline Trace ===\n";
236 os << "Error: " << errorMessage << "\n";
237 os << "\n-- Active passes --\n";
238 if (slice.passes.empty()) {
239 os << " (none)\n";
240 } else {
241 for (size_t i = 0; i < slice.passes.size(); ++i)
242 os << " #" << i << ' ' << slice.passes[i] << "\n";
243 }
244 os << "\n-- Relevant render events --\n";
245 if (slice.path.empty()) {
246 os << " (none)\n";
247 } else {
248 size_t shown = 0;
249 for (const auto& e : slice.path) {
250 const char* kind = "?";
251 switch (e.kind) {
252 case RenderEventKind::FrameBegin: kind = "frame+"; break;
253 case RenderEventKind::FrameEnd: kind = "frame-"; break;
254 case RenderEventKind::PassBegin: kind = "pass+"; break;
255 case RenderEventKind::PassEnd: kind = "pass-"; break;
256 case RenderEventKind::Target: kind = "target"; break;
257 case RenderEventKind::Bind: kind = "bind"; break;
258 case RenderEventKind::Draw: kind = "draw"; break;
259 case RenderEventKind::Error: kind = "error"; break;
260 }
261 os << " [" << kind << "] " << e.name;
262 if (!e.detail.empty()) os << " (" << e.detail << ")";
263 os << "\n";
264 if (++shown >= 48) {
265 os << " ...\n";
266 break;
267 }
268 }
269 }
270 os << "\n" << slice.summary << "\n";
271 return os.str();
272}
273
274} // namespace eve::dev
uint32_t seed
Tok kind
std::string id
glm::vec3 n
Definition Grass.cpp:64
std::ostringstream & os
uint32_t c
const char * name
Definition RockMesh.cpp:21
void target(const char *name) override
void draw(const char *api, const char *detail) override
const RenderEvent * event(uint32_t id) const
std::string formatErrorReport(const std::string &errorMessage, const RenderSliceCriterion &c={}) const
~RenderFlow() override
void setMaxEvents(size_t n)
void frameBegin() override
void bind(const char *kind, const char *name) override
void error(const char *message) override
void frameEnd() override
RenderSliceResult sliceBackward(const RenderSliceCriterion &c={}) const
void passBegin(const char *name) override
void passEnd(const char *name) override
RenderEventKind kind
std::vector< std::string > passes
std::vector< uint32_t > eventIds
std::vector< RenderEvent > path