diff --git a/src/diff.S b/src/diff.S index b11a1500..ab71794e 100644 --- a/src/diff.S +++ b/src/diff.S @@ -1,5 +1,8 @@ #include #include +#include "output_common/render_method.h" + +#ifdef RENDER_METHOD_LCD .text .align 4 @@ -152,3 +155,5 @@ epd_apply_line_mask_VE: .loop_end_mask: retw.n + +#endif \ No newline at end of file diff --git a/src/highlevel.c b/src/highlevel.c index 0617bbe5..4bc63efe 100644 --- a/src/highlevel.c +++ b/src/highlevel.c @@ -43,7 +43,7 @@ EpdiyHighlevelState epd_hl_init(const EpdWaveform* waveform) { assert(state.difference_fb != NULL); state.dirty_lines = malloc(epd_height() * sizeof(bool)); assert(state.dirty_lines != NULL); - state.dirty_columns = heap_caps_aligned_alloc(16, epd_width() / 2, MALLOC_CAP_INTERNAL); + state.dirty_columns = heap_caps_aligned_alloc(16, epd_width() / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); assert(state.dirty_columns != NULL); state.waveform = waveform; diff --git a/src/output_common/line_queue.c b/src/output_common/line_queue.c index 3d0cf3db..c0a2ae7a 100644 --- a/src/output_common/line_queue.c +++ b/src/output_common/line_queue.c @@ -10,7 +10,7 @@ static inline int ceil_div(int x, int y) { return x / y + (x % y != 0); } /// Initialize the line queue and allocate memory. -LineQueue_t lq_init(int queue_len, int element_size) { +LineQueue_t lq_init(int queue_len, int element_size, bool use_mask) { LineQueue_t queue; queue.element_size = element_size; queue.size = queue_len; @@ -27,9 +27,14 @@ LineQueue_t lq_init(int queue_len, int element_size) { assert(queue.bufs[i] != NULL); } - queue.mask_buffer_len = elem_buf_size; - queue.mask_buffer = heap_caps_aligned_alloc(16, elem_buf_size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); - assert(queue.mask_buffer != NULL); + if (use_mask) { + queue.mask_buffer_len = elem_buf_size; + queue.mask_buffer = heap_caps_aligned_alloc(16, elem_buf_size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL); + assert(queue.mask_buffer != NULL); + } else { + queue.mask_buffer_len = 0; + queue.mask_buffer = NULL; + } return queue; } diff --git a/src/output_common/line_queue.h b/src/output_common/line_queue.h index 77e03ebe..b9c3cc5e 100644 --- a/src/output_common/line_queue.h +++ b/src/output_common/line_queue.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -22,7 +23,7 @@ typedef struct { } LineQueue_t; /// Initialize the line queue and allocate memory. -LineQueue_t lq_init(int queue_len, int element_size); +LineQueue_t lq_init(int queue_len, int element_size, bool use_mask); /// Deinitialize the line queue and free memory. void lq_free(LineQueue_t* queue); diff --git a/src/output_common/lut.S b/src/output_common/lut.S index ed022ec7..bc0e5c63 100644 --- a/src/output_common/lut.S +++ b/src/output_common/lut.S @@ -1,5 +1,8 @@ #include #include +#include "render_method.h" + +#ifdef RENDER_METHOD_LCD .text .align 4 @@ -139,3 +142,4 @@ calc_epd_input_1ppB_1k_S3_VE: movi.n a2, 0 // return status ESP_OK retw.n +#endif \ No newline at end of file diff --git a/src/output_i2s/render_i2s.c b/src/output_i2s/render_i2s.c index f4a6629e..77b5f77e 100644 --- a/src/output_i2s/render_i2s.c +++ b/src/output_i2s/render_i2s.c @@ -382,10 +382,6 @@ void IRAM_ATTR i2s_fetch_frame_data(RenderContext_t *ctx, int thread_id) { memcpy(buf, lp, lq->element_size); - if (line_start_x > 0 || line_end_x < ctx->display_width) { - //mask_line_buffer(line_buf, line_bytes, line_start_x, line_end_x); - } - lq_commit(lq); if (shifted) { diff --git a/src/render.c b/src/render.c index 2b9e6232..464b33fa 100644 --- a/src/render.c +++ b/src/render.c @@ -87,6 +87,27 @@ static inline int rounded_display_height() { return (((epd_height() + 7) / 8) * 8); } + +/** +* Populate an output line mask from line dirtyness with one nibble per pixel. +* If the dirtyness data is NULL, set the mask to neutral. +*/ +static void populate_line_mask(uint8_t* line_mask, const uint8_t* dirty_columns, int mask_len) { + if (dirty_columns == NULL) { + memset(line_mask, 0xFF, mask_len); + } else { + assert(epd_width() / 4 <= mask_len); + for (int c = 0; c < epd_width() / 2; c += 2) { + uint8_t mask = 0; + mask |= (dirty_columns[c + 1] & 0xF0) != 0 ? 0xC0 : 0x00; + mask |= (dirty_columns[c + 1] & 0x0F) != 0 ? 0x30 : 0x00; + mask |= (dirty_columns[c] & 0xF0) != 0 ? 0x0C : 0x00; + mask |= (dirty_columns[c] & 0x0F) != 0 ? 0x03 : 0x00; + line_mask[c / 2] = mask; + } + } +} + // FIXME: fix misleading naming: // area -> buffer dimensions // crop -> area taken out of buffer @@ -135,6 +156,7 @@ enum EpdDrawError IRAM_ATTR epd_draw_base( return EPD_DRAW_INVALID_CROP; } +#ifdef RENDER_METHOD_LCD if (mode & MODE_PACKING_1PPB_DIFFERENCE && render_context.conversion_lut_size > 1 << 10) { ESP_LOGI( "epdiy", @@ -142,6 +164,7 @@ enum EpdDrawError IRAM_ATTR epd_draw_base( render_context.conversion_lut_size ); } +#endif render_context.area = area; render_context.crop_to = crop_to; @@ -166,21 +189,9 @@ enum EpdDrawError IRAM_ATTR epd_draw_base( #ifdef RENDER_METHOD_I2S i2s_do_update(&render_context); #elif defined(RENDER_METHOD_LCD) - for (int i = 0; i < NUM_RENDER_THREADS; i++) { LineQueue_t* queue = &render_context.line_queues[i]; - if (drawn_columns == NULL) { - memset(queue->mask_buffer, 0xFF, queue->mask_buffer_len); - } else { - for (int c = 0; c < epd_width() / 2; c += 2) { - uint8_t mask = 0; - mask |= (drawn_columns[c + 1] & 0xF0) != 0 ? 0xC0 : 0x00; - mask |= (drawn_columns[c + 1] & 0x0F) != 0 ? 0x30 : 0x00; - mask |= (drawn_columns[c] & 0xF0) != 0 ? 0x0C : 0x00; - mask |= (drawn_columns[c] & 0x0F) != 0 ? 0x03 : 0x00; - queue->mask_buffer[c / 2] = mask; - } - } + populate_line_mask(queue->mask_buffer, drawn_columns, queue->mask_buffer_len); } lcd_do_update(&render_context); @@ -297,13 +308,15 @@ void epd_renderer_init(enum EpdInitOptions options) { } #ifdef RENDER_METHOD_LCD + bool use_lq_mask = true; size_t queue_elem_size = render_context.display_width / 4; #elif defined(RENDER_METHOD_I2S) + bool use_lq_mask = false; size_t queue_elem_size = epd_width(); #endif for (int i = 0; i < NUM_RENDER_THREADS; i++) { - render_context.line_queues[i] = lq_init(queue_len, queue_elem_size); + render_context.line_queues[i] = lq_init(queue_len, queue_elem_size, use_lq_mask); render_context.feed_line_buffers[i] = (uint8_t*)heap_caps_malloc( render_context.display_width, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL ); @@ -363,12 +376,14 @@ static bool interlace_line( int fb_width ) { uint32_t dirty = 0; - uint32_t to_addr = (uint32_t)to; + int unaligned_start = 0; + int unaligned_len = fb_width; - int unaligned_start; - int unaligned_len; +// use Vector Extensions with the ESP32-S3 +#ifdef RENDER_METHOD_LCD // since display horizontal resolutions should be divisible by 16, // only one end should be unaligned by 8 bytes (16 pixels) + uint32_t to_addr = (uint32_t)to; if (to_addr % 16 > 0) { unaligned_start = 0; unaligned_len = (16 - (to_addr % 16)) * 2; @@ -382,13 +397,13 @@ static bool interlace_line( to + alignment_offset, from + alignment_offset, interlaced + alignment_offset * 2, col_dirtyness + alignment_offset, fb_width ); - +#endif for (int x = unaligned_start; x < unaligned_start + unaligned_len; x++) { uint8_t t = *(to + x / 2); uint8_t f = *(from + x / 2); - col_dirtyness[x / 2] |= (t ^ f); t = (x % 2) ? (t >> 4) : (t & 0x0f); f = (x % 2) ? (f >> 4) : (f & 0x0f); + col_dirtyness[x / 2] |= (t ^ f); dirty |= (t ^ f); interlaced[x] = (t << 4) | f; }