Skip to content

Commit a96dfcc

Browse files
facontidavideclaude
andcommitted
Wavefront decode: reconstruct 4 rows in parallel dependency chains
Prediction reconstruction is serial along a row (the left neighbour must be decoded first), but row y+1 at column c only needs row y up to column c. Processing 4 rows along a skewed diagonal therefore runs 4 independent dependency chains that the out-of-order core overlaps. Pure decoder-side change: bitstream and results are identical (all 49 tests pass, corpus round trips bit-exact). Measured on a 60-frame 1920x1200 corpus, decode throughput: 32FC1 922 -> 1196 MB/s (portable) 842 -> 1198 MB/s (-march=native) 16UC1 538 -> 731 MB/s (portable) 485 -> 736 MB/s (-march=native) R=2/4/8 were swept; R=4 is the sweet spot (R=8 gains nothing and adds register pressure). Encode and compression ratio unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8bee105 commit a96dfcc

1 file changed

Lines changed: 51 additions & 6 deletions

File tree

dpred_image_transport/src/depth_codec.cpp

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,12 @@ void predict_pack(const uint16_t * vals, uint32_t w, uint32_t h, uint8_t * lo, u
168168
}
169169
}
170170

171-
// Inverse of predict_pack. Reconstruction is inherently serial along a row
172-
// (each prediction needs the value just decoded), but branchless MED keeps
173-
// the dependency chain tight.
171+
// Inverse of predict_pack. Reconstruction is serial along a row (each
172+
// prediction needs the value just decoded), but row y+1 at column c only
173+
// needs row y up to column c: processing R rows along a skewed diagonal
174+
// ("wavefront") therefore runs R independent dependency chains that the
175+
// out-of-order core overlaps. Pure decoder-side optimization: the format
176+
// and the results are identical to the serial scan.
174177
void predict_unpack(const uint8_t * lo, const uint8_t * hi, uint32_t w, uint32_t h, uint16_t * vals)
175178
{
176179
const auto unstep = [&](size_t i, int32_t pred) -> uint16_t {
@@ -180,13 +183,55 @@ void predict_unpack(const uint8_t * lo, const uint8_t * hi, uint32_t w, uint32_t
180183
vals[i] = k;
181184
return k;
182185
};
183-
if (w && h) {
184-
unstep(0, 0);
186+
if (w == 0 || h == 0) {
187+
return;
185188
}
189+
// First row: pure left-prediction chain.
190+
unstep(0, 0);
186191
for (uint32_t x = 1; x < w; ++x) {
187192
unstep(x, vals[x - 1]);
188193
}
189-
for (uint32_t y = 1; y < h; ++y) {
194+
195+
constexpr uint32_t R = 4; // interleaved rows = parallel dependency chains
196+
uint32_t y = 1;
197+
if (w >= 2 * R) {
198+
for (; y + R <= h; y += R) {
199+
uint16_t left[R] = {};
200+
// Ramp-up: row y+r starts one diagonal step after row y+r-1, which
201+
// keeps the in-strip dependency satisfied (row r reads row r-1 one
202+
// step behind).
203+
for (uint32_t t = 0; t < R; ++t) {
204+
for (uint32_t r = 0; r <= t; ++r) {
205+
const uint32_t c = t - r;
206+
const size_t row = static_cast<size_t>(y + r) * w;
207+
const uint16_t * up = vals + row - w;
208+
left[r] = (c == 0) ?
209+
unstep(row, up[0]) :
210+
unstep(row + c, med_predict(left[r], up[c], up[c - 1]));
211+
}
212+
}
213+
// Steady state: all R chains active, no bounds checks.
214+
for (uint32_t t = R; t < w; ++t) {
215+
for (uint32_t r = 0; r < R; ++r) {
216+
const uint32_t c = t - r;
217+
const size_t row = static_cast<size_t>(y + r) * w;
218+
const uint16_t * up = vals + row - w;
219+
left[r] = unstep(row + c, med_predict(left[r], up[c], up[c - 1]));
220+
}
221+
}
222+
// Drain: finish the trailing columns of the lower rows.
223+
for (uint32_t t = w; t < w + R - 1; ++t) {
224+
for (uint32_t r = t - w + 1; r < R; ++r) {
225+
const uint32_t c = t - r;
226+
const size_t row = static_cast<size_t>(y + r) * w;
227+
const uint16_t * up = vals + row - w;
228+
left[r] = unstep(row + c, med_predict(left[r], up[c], up[c - 1]));
229+
}
230+
}
231+
}
232+
}
233+
// Remaining rows (strip remainder, or narrow images): serial scan.
234+
for (; y < h; ++y) {
190235
const size_t row = static_cast<size_t>(y) * w;
191236
int32_t left = unstep(row, vals[row - w]);
192237
const uint16_t * up = vals + row - w;

0 commit comments

Comments
 (0)