()
| 290 | } |
| 291 | |
| 292 | function tryRenderOnce(): void { |
| 293 | if (!options.isRunning()) return; |
| 294 | if (options.getLifecycleBusy() === "stop") return; |
| 295 | if (options.dirtyTracker.getFlags() === 0) return; |
| 296 | const maxInFlight = |
| 297 | options.config.maxFramesInFlight + (options.getInteractiveBudget() > 0 ? 1 : 0); |
| 298 | if (options.getFramesInFlight() >= maxInFlight) return; |
| 299 | const mode = options.getMode(); |
| 300 | if (mode === null) return; |
| 301 | |
| 302 | if (PERF_ENABLED) { |
| 303 | const scheduleWaitStartMs = options.getScheduleWaitStartMs(); |
| 304 | if (scheduleWaitStartMs !== null) { |
| 305 | perfMarkEnd("schedule_wait", scheduleWaitStartMs); |
| 306 | options.setScheduleWaitStartMs(null); |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | const dirtyVersionStart = options.dirtyTracker.snapshotVersions(); |
| 311 | const snapshot = options.getCommittedState(); |
| 312 | const hooks = { |
| 313 | enterRender: () => { |
| 314 | options.setInRender(true); |
| 315 | }, |
| 316 | exitRender: () => { |
| 317 | options.setInRender(false); |
| 318 | }, |
| 319 | }; |
| 320 | |
| 321 | if (mode === "raw") { |
| 322 | const drawFn = options.getDrawFn(); |
| 323 | if (!drawFn) return; |
| 324 | |
| 325 | const renderStartMs = monotonicNowMs(); |
| 326 | const submitToken = perfMarkStart("submit_frame"); |
| 327 | const res = options.rawRenderer.submitFrame(drawFn, hooks); |
| 328 | perfMarkEnd("submit_frame", submitToken); |
| 329 | if (!res.ok) { |
| 330 | options.fatalNowOrEnqueue(res.code, res.detail); |
| 331 | return; |
| 332 | } |
| 333 | if (!emitInternalRenderMetrics(monotonicNowMs() - renderStartMs)) return; |
| 334 | |
| 335 | const submitStartMs = PERF_ENABLED ? submitToken : null; |
| 336 | const buildEndMs = PERF_ENABLED ? perfNow() : null; |
| 337 | options.setFramesInFlight(options.getFramesInFlight() + 1); |
| 338 | if (options.getInteractiveBudget() > 0) { |
| 339 | options.setInteractiveBudget(options.getInteractiveBudget() - 1); |
| 340 | } |
| 341 | scheduleFrameSettlement(res.inFlight, submitStartMs, buildEndMs); |
| 342 | options.dirtyTracker.clearConsumedFlags( |
| 343 | DIRTY_RENDER | DIRTY_LAYOUT | DIRTY_VIEW, |
| 344 | dirtyVersionStart, |
| 345 | ); |
| 346 | return; |
| 347 | } |
| 348 | |
| 349 | const viewFn = options.getViewFn(); |
nothing calls this directly
no test coverage detected