From cae3015b66ab340cf585fb224745e73ae6c53ae6 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:03:59 +0300 Subject: [PATCH 1/7] genesys: Use new image pipeline for format and CIS reordering --- backend/genesys.cc | 96 -------------------------- backend/genesys_conv_hlp.cc | 132 ------------------------------------ backend/genesys_device.cc | 1 - backend/genesys_device.h | 1 - backend/genesys_gl124.cc | 3 - backend/genesys_gl646.cc | 3 - backend/genesys_gl841.cc | 3 - backend/genesys_gl843.cc | 3 - backend/genesys_gl846.cc | 3 - backend/genesys_gl847.cc | 3 - backend/genesys_low.cc | 13 ++++ 11 files changed, 13 insertions(+), 248 deletions(-) diff --git a/backend/genesys.cc b/backend/genesys.cc index af3afbc9e..3a8f27e05 100644 --- a/backend/genesys.cc +++ b/backend/genesys.cc @@ -3445,7 +3445,6 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio uint8_t *work_buffer_src; uint8_t *work_buffer_dst; unsigned int dst_lines; - unsigned int step_1_mode; Genesys_Buffer *src_buffer; Genesys_Buffer *dst_buffer; @@ -3547,101 +3546,6 @@ Problems with the first approach: src_buffer = &(dev->read_buffer); -/* maybe reorder components/bytes */ - if (dev->session.pipeline_needs_reorder) { - if (depth == 1) { - throw SaneException("Can't reorder single bit data\n"); - } - - dst_buffer = &(dev->lines_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size() - dst_buffer->avail()) - bytes = dst_buffer->size() - dst_buffer->avail(); - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: reordering %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - - if (channels == 3) - { - step_1_mode = 0; - - if (depth == 16) { - step_1_mode |= 1; - } - - if (dev->model->is_cis) { - step_1_mode |= 2; - } - - if (dev->model->line_mode_color_order == ColorOrder::BGR) { - step_1_mode |= 4; - } - - switch (step_1_mode) - { - case 1: /* RGB, chunky, 16 bit */ -#ifdef WORDS_BIGENDIAN - genesys_reorder_components_endian_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels, 3); - break; -#endif /*WORDS_BIGENDIAN */ - case 0: /* RGB, chunky, 8 bit */ - break; - case 2: /* RGB, cis, 8 bit */ - genesys_reorder_components_cis_8(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - case 3: /* RGB, cis, 16 bit */ - genesys_reorder_components_cis_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - case 4: /* BGR, chunky, 8 bit */ - genesys_reorder_components_bgr_8(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - case 5: /* BGR, chunky, 16 bit */ - genesys_reorder_components_bgr_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - case 6: /* BGR, cis, 8 bit */ - genesys_reorder_components_cis_bgr_8(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - case 7: /* BGR, cis, 16 bit */ - genesys_reorder_components_cis_bgr_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels); - break; - } - } - else - { -#ifdef WORDS_BIGENDIAN - if (depth == 16) - { - genesys_reorder_components_endian_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels, 1); - } -#endif /*WORDS_BIGENDIAN */ - } - - dst_buffer->produce(bytes); - src_buffer->consume(bytes); - } - src_buffer = dst_buffer; - } - // maybe reverse effects of ccd layout if (dev->session.pipeline_needs_ccd) { diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc index 7982625a7..17e2e61f3 100644 --- a/backend/genesys_conv_hlp.cc +++ b/backend/genesys_conv_hlp.cc @@ -45,138 +45,6 @@ * Conversion filters for genesys backend */ -static void FUNC_NAME(genesys_reorder_components_cis) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int pixels) -{ - DBG_HELPER(dbg); - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { - -#ifndef DOUBLE_BYTE - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[0]++; - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; - *dst++ = *src[2]++; -# else - *dst++ = src[0][1]; - *dst++ = src[0][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[2][1]; - *dst++ = src[2][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } -} - -static void FUNC_NAME(genesys_reorder_components_cis_bgr) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int pixels) -{ - DBG_HELPER(dbg); - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { -#ifndef DOUBLE_BYTE - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[2]++; - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; - *dst++ = *src[0]++; -# else - *dst++ = src[2][1]; - *dst++ = src[2][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[0][1]; - *dst++ = src[0][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } -} - -static void FUNC_NAME(genesys_reorder_components_bgr) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int pixels) -{ - DBG_HELPER(dbg); - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels; c++) { - -#ifndef DOUBLE_BYTE - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - src += 3; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = src[2 * 2 + 0]; - *dst++ = src[2 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; -# else - *dst++ = src[2 * 2 + 1]; - *dst++ = src[2 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; -# endif - src += 3 * 2; -#endif - - } -} - #if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) static void FUNC_NAME(genesys_reorder_components_endian) (uint8_t* src_data, uint8_t* dst_data, unsigned int lines, unsigned int pixels, diff --git a/backend/genesys_device.cc b/backend/genesys_device.cc index 8129bb752..3a8abdc20 100644 --- a/backend/genesys_device.cc +++ b/backend/genesys_device.cc @@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device() void Genesys_Device::clear() { read_buffer.clear(); - lines_buffer.clear(); shrink_buffer.clear(); out_buffer.clear(); binarize_buffer.clear(); diff --git a/backend/genesys_device.h b/backend/genesys_device.h index 819877eee..de225e48d 100644 --- a/backend/genesys_device.h +++ b/backend/genesys_device.h @@ -282,7 +282,6 @@ struct Genesys_Device SANE_Bool needs_home_ta = 0; Genesys_Buffer read_buffer; - Genesys_Buffer lines_buffer; Genesys_Buffer shrink_buffer; Genesys_Buffer out_buffer; diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc index 3cf6b736f..9b78e3ee5 100644 --- a/backend/genesys_gl124.cc +++ b/backend/genesys_gl124.cc @@ -1053,9 +1053,6 @@ static void gl124_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc index d4727d71e..701476fed 100644 --- a/backend/genesys_gl646.cc +++ b/backend/genesys_gl646.cc @@ -718,9 +718,6 @@ static void gl646_setup_registers(Genesys_Device* dev, dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc index 2f713ad0d..2ddbba6db 100644 --- a/backend/genesys_gl841.cc +++ b/backend/genesys_gl841.cc @@ -1875,9 +1875,6 @@ dummy \ scanned lines dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc index 30b9931f2..3a07af523 100644 --- a/backend/genesys_gl843.cc +++ b/backend/genesys_gl843.cc @@ -1292,9 +1292,6 @@ static void gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc index 03c31d82e..752b47945 100644 --- a/backend/genesys_gl846.cc +++ b/backend/genesys_gl846.cc @@ -918,9 +918,6 @@ static void gl846_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc index d1131419e..4b66498ed 100644 --- a/backend/genesys_gl847.cc +++ b/backend/genesys_gl847.cc @@ -928,9 +928,6 @@ static void gl847_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(session.buffer_size_lines); - dev->shrink_buffer.clear(); dev->shrink_buffer.alloc(session.buffer_size_shrink); diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 9b88e7b9b..b65ec422a 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1501,6 +1501,19 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) get_fake_usb_buffer_model(session), read_data_from_usb); } + if (dev->model->is_cis && session.params.channels == 3) { + dev->pipeline.push_node(dev->model->line_mode_color_order); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR888) { + dev->pipeline.push_node(PixelFormat::RGB888); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) { + dev->pipeline.push_node(PixelFormat::RGB161616); + } + + auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data) { (void) size; // will be always equal to dev->pipeline.get_output_row_bytes() From 0b1bfa3f1201b5cfa9e93ecbc4fcf00a57d6b63d Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:00 +0300 Subject: [PATCH 2/7] genesys: Swap 16-bit pixel endian on big endian machines --- backend/genesys_conv_hlp.cc | 19 ------ backend/genesys_image_pipeline.cc | 23 +++++++ backend/genesys_image_pipeline.h | 17 +++++ backend/genesys_low.cc | 6 ++ .../backend/genesys/tests_image_pipeline.cc | 67 ++++++++++++++++++- 5 files changed, 111 insertions(+), 21 deletions(-) diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc index 17e2e61f3..7f993256e 100644 --- a/backend/genesys_conv_hlp.cc +++ b/backend/genesys_conv_hlp.cc @@ -45,25 +45,6 @@ * Conversion filters for genesys backend */ -#if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) -static void FUNC_NAME(genesys_reorder_components_endian) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels * channels; c++) { - *dst++ = src[1]; - *dst++ = src[0]; - src += 2; - } -} -#endif /*defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN)*/ - - static void FUNC_NAME(genesys_reverse_ccd) (uint8_t* src_data, uint8_t* dst_data, unsigned int lines, unsigned int components_per_line, unsigned int *ccd_shift, unsigned int component_count) diff --git a/backend/genesys_image_pipeline.cc b/backend/genesys_image_pipeline.cc index 25e55d5e1..555805460 100644 --- a/backend/genesys_image_pipeline.cc +++ b/backend/genesys_image_pipeline.cc @@ -210,6 +210,29 @@ ImagePipelineNodeDeinterleaveLines::ImagePipelineNodeDeinterleaveLines( interleaved_lines, pixels_per_chunk) {} +ImagePipelineNodeSwap16BitEndian::ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source) : + source_(source), + needs_swapping_{false} +{ + if (get_pixel_format_depth(source_.get_format()) == 16) { + needs_swapping_ = true; + } else { + DBG(DBG_info, "%s: this pipeline node does nothing for non 16-bit formats", __func__); + } +} + +void ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data) +{ + source_.get_next_row_data(out_data); + if (needs_swapping_) { + std::size_t pixels = get_row_bytes() / 2; + for (std::size_t i = 0; i < pixels; ++i) { + std::swap(*out_data, *(out_data + 1)); + out_data += 2; + } + } +} + ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source, ColorOrder color_order) : source_(source), diff --git a/backend/genesys_image_pipeline.h b/backend/genesys_image_pipeline.h index 4bb456fdd..df5fa93d7 100644 --- a/backend/genesys_image_pipeline.h +++ b/backend/genesys_image_pipeline.h @@ -248,6 +248,23 @@ public: std::size_t pixels_per_chunk); }; +// A pipeline that swaps bytes in 16-bit components on big-endian systems +class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode +{ +public: + ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + void get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + bool needs_swapping_ = false; +}; + // A pipeline node that merges 3 mono lines into a color channel class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode { diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index b65ec422a..39a4b13e0 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1501,6 +1501,12 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) get_fake_usb_buffer_model(session), read_data_from_usb); } +#ifdef WORDS_BIGENDIAN + if (get_pixel_format_depth(format) == 16) { + dev->pipeline.push_node(); + } +#endif + if (dev->model->is_cis && session.params.channels == 3) { dev->pipeline.push_node(dev->model->line_mode_color_order); } diff --git a/testsuite/backend/genesys/tests_image_pipeline.cc b/testsuite/backend/genesys/tests_image_pipeline.cc index 3cc2ecd24..5ebc0def8 100644 --- a/testsuite/backend/genesys/tests_image_pipeline.cc +++ b/testsuite/backend/genesys/tests_image_pipeline.cc @@ -175,7 +175,7 @@ void test_node_desegment_1_line() ASSERT_EQ(out_data, expected_data); } -void test_node_deinterleave_lines() +void test_node_deinterleave_lines_i8() { using Data = std::vector; @@ -203,6 +203,67 @@ void test_node_deinterleave_lines() ASSERT_EQ(out_data, expected_data); } +void test_node_deinterleave_lines_rgb888() +{ + using Data = std::vector; + + Data in_data = { + 1, 2, 3, 7, 8, 9, 13, 14, 15, 19, 20, 21, + 4, 5, 6, 10, 11, 12, 16, 17, 18, 22, 23, 24, + }; + + ImagePipelineStack stack; + stack.push_first_node(4, 2, PixelFormat::RGB888, + std::move(in_data)); + stack.push_node(2, 1); + + ASSERT_EQ(stack.get_output_width(), 8u); + ASSERT_EQ(stack.get_output_height(), 1u); + ASSERT_EQ(stack.get_output_row_bytes(), 24u); + ASSERT_EQ(stack.get_output_format(), PixelFormat::RGB888); + + auto out_data = stack.get_all_data(); + + Data expected_data; + expected_data.resize(24, 0); + std::iota(expected_data.begin(), expected_data.end(), 1); // will fill with 1, 2, 3, ..., 20 + + ASSERT_EQ(out_data, expected_data); +} + +void test_node_swap_16bit_endian() +{ + using Data = std::vector; + + Data in_data = { + 0x10, 0x20, 0x30, 0x11, 0x21, 0x31, + 0x12, 0x22, 0x32, 0x13, 0x23, 0x33, + 0x14, 0x24, 0x34, 0x15, 0x25, 0x35, + 0x16, 0x26, 0x36, 0x17, 0x27, 0x37, + }; + + ImagePipelineStack stack; + stack.push_first_node(4, 1, PixelFormat::RGB161616, + std::move(in_data)); + stack.push_node(); + + ASSERT_EQ(stack.get_output_width(), 4u); + ASSERT_EQ(stack.get_output_height(), 1u); + ASSERT_EQ(stack.get_output_row_bytes(), 24u); + ASSERT_EQ(stack.get_output_format(), PixelFormat::RGB161616); + + auto out_data = stack.get_all_data(); + + Data expected_data = { + 0x20, 0x10, 0x11, 0x30, 0x31, 0x21, + 0x22, 0x12, 0x13, 0x32, 0x33, 0x23, + 0x24, 0x14, 0x15, 0x34, 0x35, 0x25, + 0x26, 0x16, 0x17, 0x36, 0x37, 0x27, + }; + + ASSERT_EQ(out_data, expected_data); +} + void test_node_merge_mono_lines() { using Data = std::vector; @@ -335,7 +396,9 @@ void test_image_pipeline() test_node_buffered_callable_source(); test_node_format_convert(); test_node_desegment_1_line(); - test_node_deinterleave_lines(); + test_node_deinterleave_lines_i8(); + test_node_deinterleave_lines_rgb888(); + test_node_swap_16bit_endian(); test_node_merge_mono_lines(); test_node_split_mono_lines(); test_node_component_shift_lines(); From bf7e890fa4d6c17d2313d3eaf0f90d68c9ae98cd Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:01 +0300 Subject: [PATCH 3/7] genesys: Use new image pipeline for CCD line shifts and unstagger --- backend/genesys.cc | 78 +------------------------------------ backend/genesys_conv_hlp.cc | 64 ------------------------------ backend/genesys_device.cc | 1 - backend/genesys_device.h | 1 - backend/genesys_gl124.cc | 3 -- backend/genesys_gl646.cc | 3 -- backend/genesys_gl841.cc | 3 -- backend/genesys_gl843.cc | 3 -- backend/genesys_gl846.cc | 3 -- backend/genesys_gl847.cc | 3 -- backend/genesys_low.cc | 11 ++++++ 11 files changed, 12 insertions(+), 161 deletions(-) diff --git a/backend/genesys.cc b/backend/genesys.cc index 3a8f27e05..a65717de9 100644 --- a/backend/genesys.cc +++ b/backend/genesys.cc @@ -3439,9 +3439,8 @@ static void genesys_fill_read_buffer(Genesys_Device* dev) static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destination, size_t* len) { DBG_HELPER(dbg); - size_t bytes, extra; + size_t bytes; unsigned int channels, depth, src_pixels; - unsigned int ccd_shift[12], shift_count; uint8_t *work_buffer_src; uint8_t *work_buffer_dst; unsigned int dst_lines; @@ -3489,31 +3488,6 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio ((dev->read_bytes_left_after_deseg + dev->read_buffer.avail()) * 8UL) / (src_pixels * channels * depth)); - if (channels == 1) - { - ccd_shift[0] = 0; - ccd_shift[1] = dev->current_setup.stagger; - shift_count = 2; - } - else - { - ccd_shift[0] = - ((dev->ld_shift_r * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[1] = - ((dev->ld_shift_g * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[2] = - ((dev->ld_shift_b * dev->settings.yres) / - dev->motor.base_ydpi); - - ccd_shift[3] = ccd_shift[0] + dev->current_setup.stagger; - ccd_shift[4] = ccd_shift[1] + dev->current_setup.stagger; - ccd_shift[5] = ccd_shift[2] + dev->current_setup.stagger; - - shift_count = 6; - } - /* convert data */ /* @@ -3546,56 +3520,6 @@ Problems with the first approach: src_buffer = &(dev->read_buffer); - // maybe reverse effects of ccd layout - if (dev->session.pipeline_needs_ccd) - { - // should not happen with depth == 1. - if (depth == 1) { - throw SaneException("Can't reverse ccd single bit data\n"); - } - - dst_buffer = &(dev->shrink_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - - extra = - (dev->current_setup.max_shift * src_pixels * channels * depth) / 8; - -/*extra bytes are reserved, and should not be consumed*/ - if (bytes < extra) - bytes = 0; - else - bytes -= extra; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size() - dst_buffer->avail()) - bytes = dst_buffer->size() - dst_buffer->avail(); - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: un-ccd-ing %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - - if (depth == 8) { - genesys_reverse_ccd_8(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels * channels, ccd_shift, shift_count); - } else { - genesys_reverse_ccd_16(work_buffer_src, work_buffer_dst, dst_lines, - src_pixels * channels, ccd_shift, shift_count); - } - dst_buffer->produce(bytes); - src_buffer->consume(bytes); - } - src_buffer = dst_buffer; - } - // maybe shrink(or enlarge) lines if (dev->session.pipeline_needs_shrink) { diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc index 7f993256e..ad6ef98d4 100644 --- a/backend/genesys_conv_hlp.cc +++ b/backend/genesys_conv_hlp.cc @@ -45,70 +45,6 @@ * Conversion filters for genesys backend */ -static void FUNC_NAME(genesys_reverse_ccd) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, unsigned int components_per_line, - unsigned int *ccd_shift, unsigned int component_count) -{ - DBG_HELPER(dbg); - unsigned int x, y, c; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - COMPONENT_TYPE *srcp; - COMPONENT_TYPE *dstp; - unsigned int pitch = components_per_line; - unsigned int ccd_shift_pitch[12]; - unsigned int *csp; - - for (c = 0; c < component_count; c++) - ccd_shift_pitch[c] = ccd_shift[c] * pitch; - -/* - * cache efficiency: - we are processing a single line component_count times, so it should fit - into the cpu cache for maximum efficiency. our lines take - maximum 252kb(3 channels, 16bit, 2400dpi, full gl841 shading range) - * instruction efficiency: - the innermost loop runs long and consists of 3 adds, one compare, - 2 derefences. - */ -/* - for (y = 0; y < lines; y++) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count; c++) { - srcp = src + c + *csp++; - dstp = dst + c; - for (x = 0; x < pitch; x += component_count) { - *dstp = *srcp; - srcp += component_count; - dstp += component_count; - } - } - dst += pitch; - src += pitch; - } - */ -/* - * cache efficency: - here only line_dist_pitch needs to stay in cache. 12*4 = 48 bytes - * instruction efficiency: - we have a short running inner loop, consisting of 4 incs, 2 compare, 1 add, - 2 dereference and 1 indexed dereference. - the enclosing loop is long running, consisting of 1 add, 1 compare. - */ - srcp = src; - dstp = dst; - for (y = 0; y < lines; y++) { - for (x = 0; x < pitch; x += component_count) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count && c + x < pitch; c++) { - *dstp = srcp[*csp++]; - dstp++; - srcp++; - } - } - } -} - static void FUNC_NAME(genesys_shrink_lines) (uint8_t* src_data, uint8_t* dst_data, unsigned int lines, unsigned int src_pixels, unsigned int dst_pixels, diff --git a/backend/genesys_device.cc b/backend/genesys_device.cc index 3a8abdc20..e497a1a96 100644 --- a/backend/genesys_device.cc +++ b/backend/genesys_device.cc @@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device() void Genesys_Device::clear() { read_buffer.clear(); - shrink_buffer.clear(); out_buffer.clear(); binarize_buffer.clear(); local_buffer.clear(); diff --git a/backend/genesys_device.h b/backend/genesys_device.h index de225e48d..b6983626d 100644 --- a/backend/genesys_device.h +++ b/backend/genesys_device.h @@ -282,7 +282,6 @@ struct Genesys_Device SANE_Bool needs_home_ta = 0; Genesys_Buffer read_buffer; - Genesys_Buffer shrink_buffer; Genesys_Buffer out_buffer; // buffer for digital lineart from gray data diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc index 9b78e3ee5..16e5702ef 100644 --- a/backend/genesys_gl124.cc +++ b/backend/genesys_gl124.cc @@ -1053,9 +1053,6 @@ static void gl124_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc index 701476fed..3e4874191 100644 --- a/backend/genesys_gl646.cc +++ b/backend/genesys_gl646.cc @@ -718,9 +718,6 @@ static void gl646_setup_registers(Genesys_Device* dev, dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc index 2ddbba6db..b678809aa 100644 --- a/backend/genesys_gl841.cc +++ b/backend/genesys_gl841.cc @@ -1875,9 +1875,6 @@ dummy \ scanned lines dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc index 3a07af523..32606df77 100644 --- a/backend/genesys_gl843.cc +++ b/backend/genesys_gl843.cc @@ -1292,9 +1292,6 @@ static void gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc index 752b47945..27f9f3f9d 100644 --- a/backend/genesys_gl846.cc +++ b/backend/genesys_gl846.cc @@ -918,9 +918,6 @@ static void gl846_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc index 4b66498ed..c7cd1cc38 100644 --- a/backend/genesys_gl847.cc +++ b/backend/genesys_gl847.cc @@ -928,9 +928,6 @@ static void gl847_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(session.buffer_size_shrink); - dev->out_buffer.clear(); dev->out_buffer.alloc(session.buffer_size_out); diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 39a4b13e0..83568774f 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1519,6 +1519,17 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) dev->pipeline.push_node(PixelFormat::RGB161616); } + if (session.max_color_shift_lines > 0 && session.params.channels == 3) { + std::size_t shift_r = (dev->ld_shift_r * session.params.yres) / dev->motor.base_ydpi; + std::size_t shift_g = (dev->ld_shift_g * session.params.yres) / dev->motor.base_ydpi; + std::size_t shift_b = (dev->ld_shift_b * session.params.yres) / dev->motor.base_ydpi; + dev->pipeline.push_node(shift_r, shift_g, shift_b); + } + + if (session.num_staggered_lines > 0) { + std::vector shifts{0, session.num_staggered_lines}; + dev->pipeline.push_node(shifts); + } auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data) { From cd712f9f9942c424ee1c554f81ba8fa038ed41c7 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:02 +0300 Subject: [PATCH 4/7] genesys: Use new image pipeline for row scaling --- backend/Makefile.am | 2 +- backend/genesys.cc | 51 ----------- backend/genesys_conv.cc | 139 ------------------------------ backend/genesys_conv_hlp.cc | 105 ---------------------- backend/genesys_device.cc | 1 - backend/genesys_device.h | 1 - backend/genesys_gl124.cc | 3 - backend/genesys_gl646.cc | 3 - backend/genesys_gl841.cc | 3 - backend/genesys_gl843.cc | 3 - backend/genesys_gl846.cc | 3 - backend/genesys_gl847.cc | 3 - backend/genesys_image_pipeline.cc | 65 ++++++++++++++ backend/genesys_image_pipeline.h | 19 ++++ backend/genesys_low.cc | 4 + 15 files changed, 89 insertions(+), 316 deletions(-) delete mode 100644 backend/genesys_conv_hlp.cc diff --git a/backend/Makefile.am b/backend/Makefile.am index 22d06496b..f3747417b 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -520,7 +520,7 @@ libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += genesys.conf.in # TODO: Why are this distributed but not compiled? -EXTRA_DIST += genesys_conv.cc genesys_conv_hlp.cc +EXTRA_DIST += genesys_conv.cc libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 diff --git a/backend/genesys.cc b/backend/genesys.cc index a65717de9..a8a79922c 100644 --- a/backend/genesys.cc +++ b/backend/genesys.cc @@ -3442,10 +3442,7 @@ static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destinatio size_t bytes; unsigned int channels, depth, src_pixels; uint8_t *work_buffer_src; - uint8_t *work_buffer_dst; - unsigned int dst_lines; Genesys_Buffer *src_buffer; - Genesys_Buffer *dst_buffer; if (dev->read_active != SANE_TRUE) { @@ -3520,54 +3517,6 @@ Problems with the first approach: src_buffer = &(dev->read_buffer); - // maybe shrink(or enlarge) lines - if (dev->session.pipeline_needs_shrink) { - - dst_buffer = &(dev->out_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - -/*lines in input*/ - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - - /* how many lines can be processed here? */ - /* we are greedy. we work as much as possible */ - bytes = dst_buffer->size() - dst_buffer->avail(); - - if (dst_lines > (bytes * 8) / (dev->settings.requested_pixels * channels * depth)) { - dst_lines = (bytes * 8) / (dev->settings.requested_pixels * channels * depth); - } - - bytes = (dst_lines * dev->settings.requested_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: shrinking %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - if (depth == 1) - genesys_shrink_lines_1(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - else if (depth == 8) - genesys_shrink_lines_8(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - else - genesys_shrink_lines_16(work_buffer_src, work_buffer_dst, dst_lines, src_pixels, - dev->settings.requested_pixels, channels); - - /* we just consumed this many bytes*/ - bytes = (dst_lines * src_pixels * channels * depth) / 8; - src_buffer->consume(bytes); - - /* we just created this many bytes*/ - bytes = (dst_lines * dev->settings.requested_pixels * channels * depth) / 8; - dst_buffer->produce(bytes); - } - src_buffer = dst_buffer; - } - /* move data to destination */ bytes = src_buffer->avail(); if (bytes > *len) diff --git a/backend/genesys_conv.cc b/backend/genesys_conv.cc index 14b852e8a..6ccc791cb 100644 --- a/backend/genesys_conv.cc +++ b/backend/genesys_conv.cc @@ -46,37 +46,6 @@ * Conversion filters for genesys backend */ - -/*8 bit*/ -#define SINGLE_BYTE -#define BYTES_PER_COMPONENT 1 -#define COMPONENT_TYPE uint8_t - -#define FUNC_NAME(f) f ## _8 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef SINGLE_BYTE - -/*16 bit*/ -#define DOUBLE_BYTE -#define BYTES_PER_COMPONENT 2 -#define COMPONENT_TYPE uint16_t - -#define FUNC_NAME(f) f ## _16 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef DOUBLE_BYTE - static void genesys_reverse_bits(uint8_t* src_data, uint8_t* dst_data, size_t bytes) { DBG_HELPER(dbg); @@ -195,114 +164,6 @@ static void genesys_gray_lineart(Genesys_Device* dev, } } -/** @brief shrink or grow scanned data to fit the final scan size - * This function shrinks the scanned data it the required resolution is lower than the hardware one, - * or grows it in case it is the opposite like when motor resolution is higher than - * sensor's one. - */ -static void genesys_shrink_lines_1(uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, - unsigned int src_pixels, unsigned int dst_pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3], val; - uint8_t *src = (uint8_t *) src_data; - uint8_t *dst = (uint8_t *) dst_data; - - /* choose between case where me must reduce or grow the scanned data */ - if (src_pixels > dst_pixels) - { - /* shrink data */ - /* TODO action must be taken at bit level, no bytes */ - src_pixels /= 8; - dst_pixels /= 8; - /*take first _byte_ */ - for (y = 0; y < lines; y++) - { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) - { - while (cnt < src_pixels && src_x < src_pixels) - { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] = *src++; - src_x++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - } - } - } - else - { - /* common case where y res is double x res */ - for (y = 0; y < lines; y++) - { - if (2 * src_pixels == dst_pixels) - { - /* double and interleave on line */ - for (c = 0; c < src_pixels/8; c++) - { - /* first 4 bits */ - val = 0; - val |= (*src & 0x80) >> 0; /* X___ ____ --> X___ ____ */ - val |= (*src & 0x80) >> 1; /* X___ ____ --> _X__ ____ */ - val |= (*src & 0x40) >> 1; /* _X__ ____ --> __X_ ____ */ - val |= (*src & 0x40) >> 2; /* _X__ ____ --> ___X ____ */ - val |= (*src & 0x20) >> 2; /* __X_ ____ --> ____ X___ */ - val |= (*src & 0x20) >> 3; /* __X_ ____ --> ____ _X__ */ - val |= (*src & 0x10) >> 3; /* ___X ____ --> ____ __X_ */ - val |= (*src & 0x10) >> 4; /* ___X ____ --> ____ ___X */ - *dst = val; - dst++; - - /* last for bits */ - val = 0; - val |= (*src & 0x08) << 4; /* ____ X___ --> X___ ____ */ - val |= (*src & 0x08) << 3; /* ____ X___ --> _X__ ____ */ - val |= (*src & 0x04) << 3; /* ____ _X__ --> __X_ ____ */ - val |= (*src & 0x04) << 2; /* ____ _X__ --> ___X ____ */ - val |= (*src & 0x02) << 2; /* ____ __X_ --> ____ X___ */ - val |= (*src & 0x02) << 1; /* ____ __X_ --> ____ _X__ */ - val |= (*src & 0x01) << 1; /* ____ ___X --> ____ __X_ */ - val |= (*src & 0x01) << 0; /* ____ ___X --> ____ ___X */ - *dst = val; - dst++; - src++; - } - } - else - { - /* TODO: since depth is 1, we must interpolate bit within bytes */ - DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) - { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while (cnt < dst_pixels && dst_x < dst_pixels) - { - cnt += src_pixels; - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - } -} - - /** Look in image for likely left/right/bottom paper edges, then crop image. */ static void genesys_crop(Genesys_Scanner* s) diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc deleted file mode 100644 index ad6ef98d4..000000000 --- a/backend/genesys_conv_hlp.cc +++ /dev/null @@ -1,105 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005 Pierre Willenbrock - - This file is part of the SANE package. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. - - As a special exception, the authors of SANE give permission for - additional uses of the libraries contained in this release of SANE. - - The exception is that, if you link a SANE library with other files - to produce an executable, this does not by itself cause the - resulting executable to be covered by the GNU General Public - License. Your use of that executable is in no way restricted on - account of linking the SANE library code into it. - - This exception does not, however, invalidate any other reasons why - the executable file might be covered by the GNU General Public - License. - - If you submit changes to SANE to the maintainers to be included in - a subsequent release, you agree by submitting the changes that - those changes may be distributed with this exception intact. - - If you write modifications of your own for SANE, it is your choice - whether to permit this exception to apply to your modifications. - If you do not wish that, delete this exception notice. -*/ - -/* - * Conversion filters for genesys backend - */ - -static void FUNC_NAME(genesys_shrink_lines) (uint8_t* src_data, uint8_t* dst_data, - unsigned int lines, - unsigned int src_pixels, unsigned int dst_pixels, - unsigned int channels) -{ - DBG_HELPER(dbg); - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3]; - unsigned int count; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - - if (src_pixels > dst_pixels) { -/*average*/ - for (c = 0; c < channels; c++) - avg[c] = 0; - for(y = 0; y < lines; y++) { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) { - count = 0; - while (cnt < src_pixels && src_x < src_pixels) { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] += *src++; - src_x++; - count++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) { - *dst++ = avg[c] / count; - avg[c] = 0; - } - } - } - } else { -/*interpolate. copy pixels*/ - for(y = 0; y < lines; y++) { - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while ((cnt < dst_pixels || src_x + 1 == src_pixels) && - dst_x < dst_pixels) { - cnt += src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } -} diff --git a/backend/genesys_device.cc b/backend/genesys_device.cc index e497a1a96..c09f41c44 100644 --- a/backend/genesys_device.cc +++ b/backend/genesys_device.cc @@ -55,7 +55,6 @@ Genesys_Device::~Genesys_Device() void Genesys_Device::clear() { read_buffer.clear(); - out_buffer.clear(); binarize_buffer.clear(); local_buffer.clear(); diff --git a/backend/genesys_device.h b/backend/genesys_device.h index b6983626d..acf80a7e1 100644 --- a/backend/genesys_device.h +++ b/backend/genesys_device.h @@ -282,7 +282,6 @@ struct Genesys_Device SANE_Bool needs_home_ta = 0; Genesys_Buffer read_buffer; - Genesys_Buffer out_buffer; // buffer for digital lineart from gray data Genesys_Buffer binarize_buffer; diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc index 16e5702ef..57e9d1510 100644 --- a/backend/genesys_gl124.cc +++ b/backend/genesys_gl124.cc @@ -1053,9 +1053,6 @@ static void gl124_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__, diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc index 3e4874191..c4b333d10 100644 --- a/backend/genesys_gl646.cc +++ b/backend/genesys_gl646.cc @@ -718,9 +718,6 @@ static void gl646_setup_registers(Genesys_Device* dev, dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); /* scan bytes to read */ diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc index b678809aa..e810b7918 100644 --- a/backend/genesys_gl841.cc +++ b/backend/genesys_gl841.cc @@ -1875,9 +1875,6 @@ dummy \ scanned lines dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc index 32606df77..727a91734 100644 --- a/backend/genesys_gl843.cc +++ b/backend/genesys_gl843.cc @@ -1292,9 +1292,6 @@ static void gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - build_image_pipeline(dev, session); dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc index 27f9f3f9d..7b0d3006b 100644 --- a/backend/genesys_gl846.cc +++ b/backend/genesys_gl846.cc @@ -918,9 +918,6 @@ static void gl846_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegmented bytes to read = %lu\n", __func__, diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc index c7cd1cc38..21ea22ea2 100644 --- a/backend/genesys_gl847.cc +++ b/backend/genesys_gl847.cc @@ -928,9 +928,6 @@ static void gl847_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sens dev->read_buffer.clear(); dev->read_buffer.alloc(session.buffer_size_read); - dev->out_buffer.clear(); - dev->out_buffer.alloc(session.buffer_size_out); - dev->read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; DBG(DBG_info, "%s: desegment bytes to read = %lu\n", __func__, diff --git a/backend/genesys_image_pipeline.cc b/backend/genesys_image_pipeline.cc index 555805460..e580a216f 100644 --- a/backend/genesys_image_pipeline.cc +++ b/backend/genesys_image_pipeline.cc @@ -451,6 +451,71 @@ ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source, ImagePipelineNodeExtract::~ImagePipelineNodeExtract() {} +ImagePipelineNodeScaleRows::ImagePipelineNodeScaleRows(ImagePipelineNode& source, + std::size_t width) : + source_(source), + width_{width} +{ + cached_line_.resize(source_.get_row_bytes()); +} + +void ImagePipelineNodeScaleRows::get_next_row_data(std::uint8_t* out_data) +{ + auto src_width = source_.get_width(); + auto dst_width = width_; + + source_.get_next_row_data(cached_line_.data()); + + const auto* src_data = cached_line_.data(); + auto format = get_format(); + auto channels = get_pixel_channels(format); + + if (src_width > dst_width) { + // average + std::uint32_t counter = src_width / 2; + unsigned src_x = 0; + for (unsigned dst_x = 0; dst_x < dst_width; dst_x++) { + unsigned avg[3] = {0, 0, 0}; + unsigned count = 0; + while (counter < src_width && src_x < src_width) { + counter += dst_width; + + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + + src_x++; + count++; + } + counter -= src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c] / count, format); + } + } + } else { + // interpolate and copy pixels + std::uint32_t counter = dst_width / 2; + unsigned dst_x = 0; + + for (unsigned src_x = 0; src_x < src_width; src_x++) { + unsigned avg[3] = {0, 0, 0}; + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + while ((counter < dst_width || src_x + 1 == src_width) && dst_x < dst_width) { + counter += src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c], format); + } + dst_x++; + } + counter -= dst_width; + } + } +} + void ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data) { while (current_line_ < offset_y_) { diff --git a/backend/genesys_image_pipeline.h b/backend/genesys_image_pipeline.h index df5fa93d7..2a45914f0 100644 --- a/backend/genesys_image_pipeline.h +++ b/backend/genesys_image_pipeline.h @@ -383,6 +383,25 @@ private: std::vector cached_line_; }; +// A pipeline node that scales rows to the specified width by using a point filter +class ImagePipelineNodeScaleRows : public ImagePipelineNode +{ +public: + ImagePipelineNodeScaleRows(ImagePipelineNode& source, std::size_t width); + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + void get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t width_ = 0; + + std::vector cached_line_; +}; + class ImagePipelineStack { public: diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 83568774f..88bf7eb70 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1531,6 +1531,10 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) dev->pipeline.push_node(shifts); } + if (session.output_pixels != session.params.get_requested_pixels()) { + dev->pipeline.push_node(session.params.get_requested_pixels()); + } + auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data) { (void) size; // will be always equal to dev->pipeline.get_output_row_bytes() From 9cd1de5c5268a89b20c21e2777229bde08f8e3d6 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:03 +0300 Subject: [PATCH 5/7] genesys: Add a way to debug image pipelines --- backend/genesys_image_pipeline.cc | 41 +++++++++++++++++++++++++++++++ backend/genesys_image_pipeline.h | 23 ++++++++++++++--- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/backend/genesys_image_pipeline.cc b/backend/genesys_image_pipeline.cc index e580a216f..e13870b9f 100644 --- a/backend/genesys_image_pipeline.cc +++ b/backend/genesys_image_pipeline.cc @@ -44,6 +44,7 @@ #define DEBUG_DECLARE_ONLY #include "genesys_image_pipeline.h" +#include "genesys_low.h" #include ImagePipelineNode::~ImagePipelineNode() {} @@ -560,6 +561,36 @@ void ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data) current_line_++; } +ImagePipelineNodeDebug::ImagePipelineNodeDebug(ImagePipelineNode& source, + const std::string& path) : + source_(source), + path_{path}, + buffer_{source_.get_row_bytes()} +{} + +ImagePipelineNodeDebug::~ImagePipelineNodeDebug() +{ + catch_all_exceptions(__func__, [&]() + { + if (buffer_.empty()) + return; + + auto format = get_format(); + buffer_.linearize(); + sanei_genesys_write_pnm_file(path_.c_str(), buffer_.get_front_row_ptr(), + get_pixel_format_depth(format), + get_pixel_channels(format), + get_width(), buffer_.height()); + }); +} + +void ImagePipelineNodeDebug::get_next_row_data(std::uint8_t* out_data) +{ + buffer_.push_back(); + source_.get_next_row_data(out_data); + std::memcpy(buffer_.get_back_row_ptr(), out_data, get_row_bytes()); +} + std::size_t ImagePipelineStack::get_input_width() const { ensure_node_exists(); @@ -615,6 +646,16 @@ void ImagePipelineStack::ensure_node_exists() const } } +void ImagePipelineStack::clear() +{ + // we need to destroy the nodes back to front, so that the destructors still have valid + // references to sources + for (auto it = nodes_.rbegin(); it != nodes_.rend(); ++it) { + it->reset(); + } + nodes_.clear(); +} + std::vector ImagePipelineStack::get_all_data() { auto row_bytes = get_output_row_bytes(); diff --git a/backend/genesys_image_pipeline.h b/backend/genesys_image_pipeline.h index 2a45914f0..73d5865d4 100644 --- a/backend/genesys_image_pipeline.h +++ b/backend/genesys_image_pipeline.h @@ -402,6 +402,24 @@ private: std::vector cached_line_; }; +class ImagePipelineNodeDebug : public ImagePipelineNode +{ +public: + ImagePipelineNodeDebug(ImagePipelineNode& source, const std::string& path); + ~ImagePipelineNodeDebug() override; + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + void get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::string path_; + RowBuffer buffer_; +}; + class ImagePipelineStack { public: @@ -417,10 +435,7 @@ public: PixelFormat get_output_format() const; std::size_t get_output_row_bytes() const; - void clear() - { - nodes_.clear(); - } + void clear(); template void push_first_node(Args&&... args) From 41addb973065b0b8e68f975ae060df49ebe57ded Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:04 +0300 Subject: [PATCH 6/7] genesys: Fix debug identifiers --- backend/genesys_low.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 88bf7eb70..45138cb2c 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -2232,7 +2232,7 @@ void run_functions_at_backend_exit() void debug_dump(unsigned level, const Genesys_Settings& settings) { - DBG(level, "settings:\n" + DBG(level, "Genesys_Settings:\n" "Resolution X/Y : %u / %u dpi\n" "Lines : %u\n" "Pixels per line : %u\n" @@ -2248,7 +2248,7 @@ void debug_dump(unsigned level, const Genesys_Settings& settings) void debug_dump(unsigned level, const SetupParams& params) { - DBG(level, "settings:\n" + DBG(level, "SetupParams:\n" "Resolution X/Y : %u / %u dpi\n" "Lines : %u\n" "Pixels per line : %u\n" From bee1179e0efa7a00d45bddaedd74f5819ee1ad74 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Fri, 13 Sep 2019 17:04:05 +0300 Subject: [PATCH 7/7] genesys: Print debug images of intermediate pipeline output --- backend/genesys_low.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc index 45138cb2c..cf8bb3020 100644 --- a/backend/genesys_low.cc +++ b/backend/genesys_low.cc @@ -1462,6 +1462,10 @@ static FakeBufferModel get_fake_usb_buffer_model(const ScanSession& session) void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) { + static unsigned s_pipeline_index = 0; + + s_pipeline_index++; + auto format = create_pixel_format(session.params.depth, dev->model->is_cis ? 1 : session.params.channels, dev->model->line_mode_color_order); @@ -1507,6 +1511,12 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) } #endif + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_0_after_swap.pnm"); + } + if (dev->model->is_cis && session.params.channels == 3) { dev->pipeline.push_node(dev->model->line_mode_color_order); } @@ -1526,11 +1536,23 @@ void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) dev->pipeline.push_node(shift_r, shift_g, shift_b); } + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_1_after_shift.pnm"); + } + if (session.num_staggered_lines > 0) { std::vector shifts{0, session.num_staggered_lines}; dev->pipeline.push_node(shifts); } + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_2_after_stagger.pnm"); + } + if (session.output_pixels != session.params.get_requested_pixels()) { dev->pipeline.push_node(session.params.get_requested_pixels()); }