SubmitPlanner
Splits a path trace into GPU submissions that each fit the submit budget, down to a tile of one sample.
| Group | construct |
In the namespace construct::pathtrace. Declared in src/libs/libconstruct/construct/pathtrace/SubmitPlanner.hpp.
Detailed description
gpu-timeout-recovery §GTR-D1. A GPU submission that runs past the Windows GPU timeout (2 s) makes Windows reset the engine and remove the device. The smallest submission used to be one sample of the full image, and one sample of a 113-material scene at 768 × 432 ran past it on 2026-10-08 (§GTR-F1).
Sample 0 is the measuring sample: it is cut into tiles of kProbeEdge, each its own submission, and the planner keeps the worst cost per pixel-sample they show. The first plan of 2026-10-12 sized every tile from the first one alone, and on mathilde64 that tile was empty sky: 1.1 us per pixel-sample against 19.2 us over the spheres, so the planned tiles took 944 ms (§GTR-F7). From the worst cost the tile edge is chosen so that one tile of one sample costs at most half the submit budget, and as many tiles go into one submission as fit the budget, never more than the engine's uniform slots.
A submission over the budget halves the next one, its tile count or, at one tile, its tile edge; past half the GPU timeout the edge halves too and the planner warns. A host cuts the tiles still left in a sample to a smaller edge (cut()), so a sample's tiles always cover the image once.
A submission lasts at least as long as its slowest pixel's path, because a tile's wavefronts run side by side (§GTR-F10). When one pixel's path is over the budget, no tile meets it, and halving the tile keeps the time and does fewer pixels. So the first submission after a halving checks it: when the halved tile took more than two thirds of the whole one's time, the shrink did not pay. The edge goes back, the planner is at its floor and warns once, and from then on the plan is sized by the GPU timeout, not the budget: one tile per submission, and the timeout guard still halves a tile past half the timeout. The two tiles of the check give a floor and a cost per pixel above it; every submission at the floor can raise that cost, never lower it. The edge grows by the square root of two (twice the pixels) while the bigger tile's predicted cost, floor plus the worst cost per pixel, stays under a third of the timeout. When the floor is under the budget, which happens when a short slice of the GPU pacer found it and the budget grew after, the ceiling is the budget instead, and a tile over it steps back once (rendering-revamp §RVI-P4). A rule on the last submission's own time grew on cheap tiles of empty sky to the whole image, and then took 1.3 s over the spheres (next13, 2026-10-15).
Member function documentation
cut
[static] QList<QRect> SubmitPlanner::cut(const QRect &tile, int edge)
tile cut into tiles of at most edge, row by row.
describe
QString SubmitPlanner::describe() const
The plan in one line: tile edge, tiles per submission, cost.
probeTile
QRect SubmitPlanner::probeTile() const
The first tile of sample 0: kProbeEdge a side at the top-left.
recordProbe
void SubmitPlanner::recordProbe(double ms)
Records the probe's measured time ms.
recordSubmission
void SubmitPlanner::recordSubmission(double ms, qint64 pixelSamples)
Adapts the plan to a submission of pixelSamples pixel-samples that took ms.
sampleCompleted
void SubmitPlanner::sampleCompleted()
Ends a sample; the first plans from the worst cost it saw.
tilesOfSample
QList<QRect> SubmitPlanner::tilesOfSample(int edge) const
The tiles of one sample at edge, row by row, covering the image once.