Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/core/codestream/ojph_codeblock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,85 @@ namespace ojph {
zero_block = true;
}

//////////////////////////////////////////////////////////////////////////
void codeblock::decode_row(codeblock* blocks, ui32 count)
{
if (count == 0)
return;

// No batched path (the active ISA provides none, or 64-bit codeblocks):
// decode each block individually, preserving the exact 1-way behaviour.
codeblock_fun& f = blocks[0].codeblock_functions;
if (f.decode_cb32_batch == NULL || blocks[0].precision != BUF32)
{
for (ui32 i = 0; i < count; ++i)
blocks[i].decode();
return;
}

// Gather the decodable blocks of this row into parallel arrays and hand
// them to the batched decoder in windows. All blocks in a subband row
// share height (cb_size.h) and stride; only width and the coded data
// differ. Zero blocks (no coded passes) are marked directly and left
// out of the batch.
const ui32 WIN = 64;
ui8* coded[WIN];
ui32* dec[WIN];
ui32 mmsb[WIN], npass[WIN], len1[WIN], len2[WIN], wid[WIN], orig[WIN];
bool res[WIN];

const ui32 height = blocks[0].cb_size.h;
const ui32 stride = blocks[0].stride;
const bool sc = blocks[0].stripe_causal;
ui32 filled = 0;

for (ui32 i = 0; i <= count; ++i)
{
if (i < count)
{
codeblock& cb = blocks[i];
coded_cb_header* cc = cb.coded_cb;
if (cc->pass_length[0] > 0 && cc->num_passes > 0 &&
cc->next_coded != NULL)
{
coded[filled] = cc->next_coded->buf +
coded_cb_header::prefix_buf_size;
dec[filled] = cb.buf32;
mmsb[filled] = cc->missing_msbs;
npass[filled] = cc->num_passes;
len1[filled] = cc->pass_length[0];
len2[filled] = cc->pass_length[1];
wid[filled] = cb.cb_size.w;
orig[filled] = i;
++filled;
}
else
cb.zero_block = true;
}

// Flush when the window is full or at the end of the row.
if (filled == WIN || (i == count && filled > 0))
{
f.decode_cb32_batch(filled, coded, dec, mmsb, npass, len1, len2,
wid, height, stride, sc, res);
for (ui32 j = 0; j < filled; ++j)
{
if (!res[j])
{
codeblock& cb = blocks[orig[j]];
if (cb.resilient == true) {
OJPH_INFO(0x000300A2, "Error decoding a codeblock.");
cb.zero_block = true;
}
else
OJPH_ERROR(0x000300A2, "Error decoding a codeblock.");
}
}
filled = 0;
}
}
}


//////////////////////////////////////////////////////////////////////////
void codeblock::pull_line(line_buf *line)
Expand Down
4 changes: 4 additions & 0 deletions src/core/codestream/ojph_codeblock.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ namespace ojph {
void recreate(const size& cb_size, coded_cb_header* coded_cb);

void decode();
// Decode a whole subband row of codeblocks. Uses the batched (N-way
// interleaved) block decoder when the active ISA provides one, else
// decodes each block individually.
static void decode_row(codeblock* blocks, ui32 count);
void pull_line(line_buf *line);

private:
Expand Down
2 changes: 2 additions & 0 deletions src/core/codestream/ojph_codeblock_fun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ namespace ojph {

// Default path, no acceleration. We may change this later
decode_cb32 = ojph_decode_codeblock32;
decode_cb32_batch = NULL; // set only by ISAs that provide a batch path
find_max_val32 = gen_find_max_val32;
mem_clear = gen_mem_clear;
if (reversible) {
Expand Down Expand Up @@ -210,6 +211,7 @@ namespace ojph {
#ifndef OJPH_DISABLE_AVX2
if (get_cpu_ext_level() >= X86_CPU_EXT_LEVEL_AVX2) {
decode_cb32 = ojph_decode_codeblock_avx2;
decode_cb32_batch = ojph_decode_codeblock_avx2_batch;
find_max_val32 = avx2_find_max_val32;
if (reversible) {
tx_to_cb32 = avx2_rev_tx_to_cb32;
Expand Down
11 changes: 11 additions & 0 deletions src/core/codestream/ojph_codeblock_fun.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ namespace ojph {
ui32 missing_msbs, ui32 num_passes, ui32 lengths1, ui32 lengths2,
ui32 width, ui32 height, ui32 stride, bool stripe_causal);

// define the batched (multi-codeblock) decoder function signature
typedef void (*cb_decoder_batch_fun32)(ui32 n,
ui8* const* coded_data, ui32* const* decoded_data,
const ui32* missing_msbs, const ui32* num_passes,
const ui32* lengths1, const ui32* lengths2,
const ui32* widths, ui32 height, ui32 stride,
bool stripe_causal, bool* results);

typedef bool (*cb_decoder_fun64)(ui8* coded_data, ui64* decoded_data,
ui32 missing_msbs, ui32 num_passes, ui32 lengths1, ui32 lengths2,
ui32 width, ui32 height, ui32 stride, bool stripe_causal);
Expand Down Expand Up @@ -113,6 +121,9 @@ namespace ojph {
cb_decoder_fun32 decode_cb32;
cb_decoder_fun64 decode_cb64;

// optional batched 32-bit decoder (NULL if the active ISA has none)
cb_decoder_batch_fun32 decode_cb32_batch;

// a pointer to the encoder function
cb_encoder_fun32 encode_cb32;
cb_encoder_fun64 encode_cb64;
Expand Down
4 changes: 3 additions & 1 deletion src/core/codestream/ojph_subband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,10 @@ namespace ojph {
cb_size.w = cbx1 - cbx0;
blocks[i].recreate(cb_size,
coded_cbs + i + cur_cb_row * num_blocks.w);
blocks[i].decode();
}
// Decode the whole row at once so the batched (N-way interleaved)
// block decoder can overlap independent codeblocks' VLC/MEL chains.
codeblock::decode_row(blocks, num_blocks.w);
++cur_cb_row;
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/core/coding/ojph_block_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ namespace ojph {
ui32 missing_msbs, ui32 num_passes, ui32 lengths1, ui32 lengths2,
ui32 width, ui32 height, ui32 stride, bool stripe_causal);

// AVX2 batched decoder: N-way interleaves the step-1 VLC/MEL chains of
// same-width codeblocks in a subband row. Parallel arrays of length n;
// height/stride shared. results[k] receives each block's success flag.
void
ojph_decode_codeblock_avx2_batch(ui32 n,
ui8* const* coded_data, ui32* const* decoded_data,
const ui32* missing_msbs, const ui32* num_passes,
const ui32* lengths1, const ui32* lengths2,
const ui32* widths, ui32 height, ui32 stride,
bool stripe_causal, bool* results);

// WASM SIMD-accelerated decoder
bool
ojph_decode_codeblock_wasm(ui8* coded_data, ui32* decoded_data,
Expand Down
Loading
Loading