23void RenderFlow::ensureRing() {
24 if (slots_.size() != maxEvents_) slots_.resize(maxEvents_);
29 if (
n == maxEvents_ && slots_.size() ==
n)
return;
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];
37 slots_ = std::move(neu);
43void RenderFlow::retireSlot(
size_t physical) {
45 if (old.
id == 0)
return;
47 dataDeps_.erase(old.
id);
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);
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);
64 const std::string& detail) {
68 if (count_ < maxEvents_) {
69 phys = physicalIndex(count_);
74 head_ = (head_ + 1) % maxEvents_;
77 RenderEvent& e = slots_[phys];
78 e.id = nextEventId_++;
82 e.parentId = lastEventId_;
83 e.passId = passStack_.empty() ? 0 : passStack_.back();
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)];
102 passStack_.push_back(
id);
108 if (!passStack_.empty()) passStack_.pop_back();
116 const std::string k =
kind ?
kind :
"resource";
119 lastBind_[k +
"|" +
n] =
id;
120 if (!
n.empty()) lastBind_[
"*|" +
n] =
id;
127 if (newest().
passId) dataDeps_[
id].push_back(newest().
passId);
129 auto linkRecent = [&](
const char*
kind) {
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;
137 if (best) dataDeps_[
id].push_back(best);
139 linkRecent(
"texture");
140 linkRecent(
"shader");
143 linkRecent(
"canvas");
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);
153 if (newest().
passId) dataDeps_[
id].push_back(newest().
passId);
155 for (
size_t i = count_; i-- > 0;) {
157 if (e.
id ==
id)
continue;
160 dataDeps_[
id].push_back(e.
id);
168 if (
c.eventId && event(
c.eventId))
return c.eventId;
169 for (
size_t i = count_; i-- > 0;) {
172 return count_ == 0 ? 0 : (*this)[count_ - 1].id;
177 const uint32_t
seed = findSeed(
c);
179 result.
summary =
"empty render slice";
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);
191 if (!
c.resource.empty()) {
192 auto it = lastBind_.find(
"*|" +
c.resource);
193 if (it != lastBind_.end()) enqueue(it->second);
197 const uint32_t
id = q.front();
203 auto dit = dataDeps_.find(
id);
204 if (dit != dataDeps_.end()) {
205 for (uint32_t dep : dit->second) enqueue(dep);
209 result.
eventIds.assign(visited.begin(), visited.end());
211 for (uint32_t
id : result.
eventIds) {
216 for (
size_t i = 0; i < count_; ++i) {
224 std::ostringstream
os;
225 os <<
"render slice: " << result.
eventIds.size() <<
" events, pass depth "
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()) {
241 for (
size_t i = 0; i < slice.
passes.size(); ++i)
242 os <<
" #" << i <<
' ' << slice.
passes[i] <<
"\n";
244 os <<
"\n-- Relevant render events --\n";
245 if (slice.
path.empty()) {
249 for (
const auto& e : slice.
path) {
250 const char*
kind =
"?";
261 os <<
" [" <<
kind <<
"] " << e.name;
262 if (!e.detail.empty())
os <<
" (" << e.detail <<
")";
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
void setMaxEvents(size_t n)
void frameBegin() override
void bind(const char *kind, const char *name) override
void error(const char *message) override
RenderSliceResult sliceBackward(const RenderSliceCriterion &c={}) const
void passBegin(const char *name) override
void passEnd(const char *name) override
std::vector< std::string > passes
std::vector< uint32_t > eventIds
std::vector< RenderEvent > path