| // Copyright 2023 The Wuffs Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
| // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
| // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your | |
| // option. This file may not be copied, modified, or distributed | |
| // except according to those terms. | |
| // | |
| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| pri func decoder.decode_mcu!(dst: ptr base.pixel_buffer, workbuf: slice base.u8, mx: base.u32[..= 0x1FFF], my: base.u32[..= 0x1FFF]) base.u32, | |
| choosy, | |
| { | |
| var ret : base.u32 | |
| var bits : base.u64 | |
| var n_bits : base.u32 | |
| var csel : base.u8[..= 3] | |
| var r : base.io_reader | |
| var pos : base.u32 | |
| // etc_bl and etc_blm1 are the Huffman code's "bit length" and "bit length | |
| // minus 1" for the DC (first) and AC (later) components. | |
| var dc_h : base.u8[..= 3] | |
| var dc_symbol : base.u32[..= 0x0F] | |
| var dc_ht_fast : base.u32 | |
| var dc_bl : base.u32 | |
| var dc_code : base.u32 | |
| var dc_blm1 : base.u32[..= 15] | |
| var dc_ht_slow : base.u32 | |
| var dc_value : base.u16 | |
| var dc_extend : base.u16 | |
| var ac_huff_table_fast : nptr roarray[256] base.u16 | |
| var ac_h : base.u8[..= 7] | |
| var ac_symbol : base.u32[..= 0xFF] | |
| var ac_ht_fast : base.u32 | |
| var ac_bl : base.u32 | |
| var ac_code : base.u32 | |
| var ac_blm1 : base.u32[..= 15] | |
| var ac_ht_slow : base.u32 | |
| var ac_value : base.u16 | |
| var ac_extend : base.u16 | |
| var ac_rrrr : base.u32[..= 15] | |
| var ac_ssss : base.u32[..= 15] | |
| var z : base.u32[..= 79] // 79 = 63 + 15 + 1. | |
| var mcb : base.u32[..= 9] | |
| var stride : base.u64[..= 0x1_0008] | |
| var offset : base.u64 | |
| bits = this.bitstream_bits | |
| n_bits = this.bitstream_n_bits | |
| if this.bitstream_ri > this.bitstream_wi { | |
| return 2 // Internal error. | |
| } | |
| io_bind (io: r, data: this.bitstream_buffer[this.bitstream_ri .. this.bitstream_wi], history_position: this.bitstream_ri as base.u64) { | |
| while.goto_done true {{ | |
| while.block this.mcu_current_block < this.mcu_num_blocks { | |
| assert this.mcu_current_block < 10 via "a < b: a < c; c <= b"(c: this.mcu_num_blocks) | |
| while.dc_component this.mcu_zig_index <= 0, | |
| inv this.mcu_current_block < 10, | |
| { | |
| this.mcu_blocks[.. 1].bulk_memset!(byte_value: 0) | |
| // Load at least 56 bits. We only need 8 bytes (for the | |
| // peek_u64be call), but ask for 264 to be consistent with the | |
| // other "another fill_bitstream call" requests, in this method | |
| // (decode_mcu) and its other variants. | |
| if r.length() < 264 { | |
| ret = 1 // Request another fill_bitstream call. | |
| break.goto_done | |
| } | |
| bits |= r.peek_u64be() >> (n_bits & 63) | |
| r.skip_u32_fast!(actual: (63 - (n_bits & 63)) >> 3, worst_case: 8) | |
| n_bits |= 56 | |
| // Read the Huffman-encoded dc_symbol, up to 16 bits long. | |
| dc_h = this.mcu_blocks_dc_hselector[this.mcu_current_block] | |
| dc_ht_fast = this.huff_tables_fast[dc_h][bits >> 56] as base.u32 | |
| dc_bl = dc_ht_fast >> 8 | |
| if n_bits >= dc_bl { | |
| dc_symbol = 0x0F & dc_ht_fast | |
| dc_extend = EXTEND[dc_symbol] | |
| bits ~mod<<= (dc_bl & 63) | |
| n_bits -= dc_bl | |
| } else { | |
| dc_code = (bits >> 55) as base.u32 | |
| dc_blm1 = 8 | |
| bits ~mod<<= 9 | |
| n_bits ~mod-= 9 | |
| while true, | |
| inv this.mcu_current_block < 10, | |
| { | |
| dc_ht_slow = this.huff_tables_slow[dc_h][dc_blm1] | |
| if dc_code < (dc_ht_slow >> 8) { | |
| dc_symbol = 0x0F & (this.huff_tables_symbols[dc_h][0xFF & (dc_code ~mod+ dc_ht_slow)] as base.u32) | |
| dc_extend = EXTEND[dc_symbol] | |
| break | |
| } | |
| dc_code = (dc_code ~mod<< 1) | ((bits >> 63) as base.u32) | |
| bits ~mod<<= 1 | |
| n_bits ~mod-= 1 | |
| dc_blm1 = (dc_blm1 + 1) & 15 | |
| if dc_blm1 == 0 { | |
| dc_symbol = 0 | |
| dc_extend = EXTEND[dc_symbol] | |
| break | |
| } | |
| } | |
| } | |
| // Process the dc_value in the next dc_symbol (up to 15) bits. | |
| // | |
| // The dc_value is shifted by (64 - dc_symbol) in two steps, | |
| // because we want to shift by 64 (not 0) when dc_symbol is 0. | |
| dc_value = (((bits >> 32) >> (32 - dc_symbol)) & 0xFFFF) as base.u16 | |
| dc_value ~mod+= dc_extend & | |
| (((this.util.sign_extend_rshift_u64(a: bits, n: 63) & 0xFFFF) as base.u16) ^ 0xFFFF) | |
| bits ~mod<<= dc_symbol | |
| n_bits ~mod-= dc_symbol | |
| csel = this.scan_comps_cselector[this.mcu_blocks_sselector[this.mcu_current_block]] | |
| this.mcu_previous_dc_values[csel] ~mod+= dc_value | |
| this.mcu_blocks[0][0] = | |
| this.mcu_previous_dc_values[csel] | |
| this.mcu_zig_index = 1 | |
| break.dc_component | |
| }.dc_component | |
| // Ensure that we have enough bits for this iteration of the | |
| // while.block loop body. Worst case, there are 64 components and | |
| // each one needs (16 + 15) bits (round that up to 4 bytes), so we | |
| // need (64 * 4) = 256 bytes available. 8 more bytes of slack means | |
| // that we can always call peek_u64be. | |
| if r.length() < 264 { | |
| ret = 1 // Request another fill_bitstream call. | |
| break.goto_done | |
| } | |
| // Ensure the informal "the lower bound on the number of loaded | |
| // bits is at least 16" loop pre-condition below. | |
| if n_bits < 16 { | |
| bits |= r.peek_u64be() >> (n_bits & 63) | |
| // Skip these lines that are normally part of "load more bits". | |
| // It's unnecessary, just for the informal (NB > 16) below, and | |
| // skipping it avoids a small but negative performance impact. | |
| // | |
| // r.skip_u32_fast!( etc ) | |
| // n_bits |= 56 | |
| } | |
| z = 1 | |
| this.mcu_zig_index = 0 | |
| ac_h = this.mcu_blocks_ac_hselector[this.mcu_current_block] | |
| ac_huff_table_fast = this.huff_tables_fast[ac_h][..] as ptr array[256] base.u16 | |
| while.ac_components z < 64, | |
| inv this.mcu_current_block < 10, | |
| inv ac_huff_table_fast <> nullptr, | |
| { | |
| // Use the high bits of the bits variable to look up the | |
| // Huffman table. Conceptually, we should do this *after* | |
| // "Load at least 56 bits" below (at "LOOK-UP" further below), | |
| // but it is noticably faster to do it beforehand: | |
| // https://github.com/google/wuffs/commit/d9c7740ea6c4a450401c393787838436895b87bb | |
| // | |
| // Earlier look-up is OK because there is a informal loop | |
| // pre-condition (informal means not enforced by the Wuffs | |
| // compiler) that (NB >= 16) here, where NB is "the number of | |
| // loaded bits in the bits variable". It is literally n_bits | |
| // for almost all loop iterations, but it can be higher on the | |
| // first iteration, set up by "Ensure the informal" above. | |
| // | |
| // For subsequent iterations, the "Load at least 56 bits" below | |
| // does what it says. The Huffman code consumes up to 16 bits | |
| // and processing the Huffman symbol's ssss nibble consumes up | |
| // to 15 bits. (56 - 16 - 15) = 25 >= 16 so at the end of the | |
| // loop body, (n_bits >= 16). | |
| // | |
| // This 16 bound has some slack, as (NB >= 8) is all we need | |
| // when ac_huff_table_fast has (1 << 8) entries, but a bound of | |
| // 16 (the longest JPEG Huffman code bit length) won't need to | |
| // change even if, in the future, the look-up table size grows. | |
| ac_ht_fast = ac_huff_table_fast[bits >> 56] as base.u32 | |
| // Load at least 56 bits. | |
| // | |
| // TODO: eliminate this bounds check entirely. | |
| if r.length() < 8 { | |
| ret = 2 // Internal error. | |
| break.goto_done | |
| } | |
| bits |= r.peek_u64be() >> (n_bits & 63) | |
| r.skip_u32_fast!(actual: (63 - (n_bits & 63)) >> 3, worst_case: 8) | |
| n_bits |= 56 | |
| // Read the Huffman-encoded ac_symbol, up to 16 bits long. | |
| // | |
| // LOOK-UP: "ac_ht_fast = etc" conceptually happens here, just | |
| // before deriving ac_bl from ac_ht_fast. | |
| ac_bl = ac_ht_fast >> 8 | |
| if n_bits >= ac_bl { | |
| ac_symbol = 0xFF & ac_ht_fast | |
| bits ~mod<<= (ac_bl & 63) | |
| n_bits -= ac_bl | |
| } else { | |
| ac_code = (bits >> 55) as base.u32 | |
| ac_blm1 = 8 | |
| bits ~mod<<= 9 | |
| n_bits ~mod-= 9 | |
| while true, | |
| inv this.mcu_current_block < 10, | |
| inv ac_huff_table_fast <> nullptr, | |
| inv z < 64, | |
| { | |
| ac_ht_slow = this.huff_tables_slow[ac_h][ac_blm1] | |
| if ac_code < (ac_ht_slow >> 8) { | |
| ac_symbol = this.huff_tables_symbols[ac_h][0xFF & (ac_code ~mod+ ac_ht_slow)] as base.u32 | |
| break | |
| } | |
| ac_code = (ac_code ~mod<< 1) | ((bits >> 63) as base.u32) | |
| bits ~mod<<= 1 | |
| n_bits ~mod-= 1 | |
| ac_blm1 = (ac_blm1 + 1) & 15 | |
| if ac_blm1 == 0 { | |
| ac_symbol = 0 | |
| break | |
| } | |
| } | |
| } | |
| // Split the 8-bit ac_symbol into two 4-bit halves, per section | |
| // F.2.2.2 "Decoding procedure for AC coefficients". | |
| ac_rrrr = ac_symbol >> 4 | |
| z += ac_rrrr + 1 | |
| ac_ssss = ac_symbol & 15 | |
| ac_extend = EXTEND[ac_ssss] | |
| // Process the ac_value in the next ac_ssss (up to 15) bits. | |
| if ac_ssss > 0 { | |
| ac_value = ((bits >> (64 - ac_ssss)) & 0xFFFF) as base.u16 | |
| ac_value ~mod+= ac_extend & | |
| (((this.util.sign_extend_rshift_u64(a: bits, n: 63) & 0xFFFF) as base.u16) ^ 0xFFFF) | |
| bits ~mod<<= ac_ssss | |
| n_bits ~mod-= ac_ssss | |
| this.mcu_blocks[0][UNZIG[z]] = | |
| ac_value | |
| } else if ac_rrrr < 15 { | |
| break.ac_components | |
| } | |
| }.ac_components | |
| assert this.mcu_current_block < 10 | |
| mcb = this.mcu_current_block | |
| this.mcu_current_block += 1 | |
| if this.test_only_interrupt_decode_mcu { | |
| break.goto_done | |
| } | |
| // Apply IDCT. | |
| if not this.swizzle_immediately { | |
| csel = this.scan_comps_cselector[this.mcu_blocks_sselector[mcb]] | |
| stride = this.components_workbuf_widths[csel] as base.u64 | |
| offset = this.mcu_blocks_offset[mcb] + | |
| ((this.mcu_blocks_mx_mul[mcb] as base.u64) * (args.mx as base.u64)) + | |
| ((this.mcu_blocks_my_mul[mcb] as base.u64) * (args.my as base.u64)) | |
| if offset <= args.workbuf.length() { | |
| this.decode_idct!( | |
| dst_buffer: args.workbuf[offset ..], | |
| dst_stride: stride, | |
| q: this.components_tq[csel] as base.u32) | |
| } | |
| } else if this.num_components == 1 { | |
| this.decode_idct!( | |
| dst_buffer: this.swizzle_immediately_buffer[.. 64], | |
| dst_stride: 8, | |
| q: this.components_tq[csel] as base.u32) | |
| this.swizzle_immediately_status = this.swizzle_gray!( | |
| dst: args.dst, | |
| workbuf: this.swizzle_immediately_buffer[.. 64], | |
| x0: (args.mx + 0) * 8, | |
| x1: (args.mx + 1) * 8, | |
| y0: (args.my + 0) * 8, | |
| y1: (args.my + 1) * 8, | |
| stride: 8) | |
| if not this.swizzle_immediately_status.is_ok() { | |
| ret = 3 // Swizzling failure. | |
| break.goto_done | |
| } | |
| break.block | |
| } else { | |
| csel = this.scan_comps_cselector[this.mcu_blocks_sselector[mcb]] | |
| stride = 8 * (this.components_h[csel] as base.u64) | |
| this.decode_idct!( | |
| dst_buffer: this.swizzle_immediately_buffer[this.swizzle_immediately_b_offsets[mcb] ..], | |
| dst_stride: stride, | |
| q: this.components_tq[csel] as base.u32) | |
| if this.mcu_current_block < this.mcu_num_blocks { | |
| continue.block | |
| } | |
| this.swizzle_immediately_status = this.swizzle_colorful!( | |
| dst: args.dst, | |
| workbuf: this.util.empty_slice_u8(), | |
| x0: (args.mx + 0) * 8 * (this.max_incl_components_h as base.u32), | |
| x1: (args.mx + 1) * 8 * (this.max_incl_components_h as base.u32), | |
| y0: (args.my + 0) * 8 * (this.max_incl_components_v as base.u32), | |
| y1: (args.my + 1) * 8 * (this.max_incl_components_v as base.u32)) | |
| if not this.swizzle_immediately_status.is_ok() { | |
| ret = 3 // Swizzling failure. | |
| break.goto_done | |
| } | |
| break.block | |
| } | |
| }.block | |
| this.mcu_current_block = 0 | |
| break.goto_done | |
| }}.goto_done | |
| pos = (r.position() & 0xFFFF_FFFF) as base.u32 | |
| if pos > this.bitstream_wi { | |
| ret = 2 // Internal error. | |
| } else { | |
| assert pos <= 0x800 via "a <= b: a <= c; c <= b"(c: this.bitstream_wi) | |
| this.bitstream_ri = pos | |
| } | |
| } | |
| this.bitstream_bits = bits | |
| this.bitstream_n_bits = n_bits | |
| return ret | |
| } |