Skip to content

Commit

Permalink
wip: line masking
Browse files Browse the repository at this point in the history
  • Loading branch information
vroland committed Feb 1, 2024
1 parent 2dd05a7 commit 495a890
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 25 deletions.
5 changes: 5 additions & 0 deletions src/highlevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ enum EpdDrawError epd_hl_update_area(EpdiyHighlevelState* state, enum EpdDrawMod

t1 = esp_timer_get_time() / 1000;

diff_area.x = 0;
diff_area.y = 0;
diff_area.width = epd_width();
diff_area.height = epd_height();

int buf_width = epd_width();

for (int l=diff_area.y; l < diff_area.y + diff_area.height; l++) {
Expand Down
49 changes: 47 additions & 2 deletions src/output_common/line_queue.c
Original file line number Diff line number Diff line change
@@ -1,26 +1,71 @@
#include <string.h>
#include <esp_attr.h>
#include <stdlib.h>
#include <assert.h>
#include <esp_heap_caps.h>

#include "line_queue.h"

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 queue;
queue.element_size = element_size;
queue.size = queue_len;
queue.current = 0;
queue.last = 0;

int elem_buf_size = ceil_div(element_size, 16) * 16;

queue.bufs = calloc(queue.size, elem_buf_size);
assert(queue.bufs != NULL);

for (int i=0; i<queue.size; i++) {
queue.bufs[i] = heap_caps_aligned_alloc(16, elem_buf_size, MALLOC_CAP_INTERNAL);
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);

return queue;
}

/// Deinitialize the line queue and free memory.
void lq_free(LineQueue_t* queue) {
heap_caps_free(queue->bufs);
heap_caps_free(queue->mask_buffer);

for (int i=0; i<queue->size; i++) {
free(queue->bufs[i]);
}
}

uint8_t* IRAM_ATTR lq_current(LineQueue_t* queue) {
int current = atomic_load_explicit(&queue->current, memory_order_acquire);
int last = atomic_load_explicit(&queue->last, memory_order_acquire);

if ((current + 1) % queue->size == last) {
return NULL;
}
return &queue->buf[current * queue->element_size];
return queue->bufs[current];
}

void IRAM_ATTR lq_commit(LineQueue_t* queue) {

int current = atomic_load_explicit(&queue->current, memory_order_acquire);

if (current == queue->size - 1) {
queue->current = 0;
} else {
atomic_fetch_add(&queue->current, 1);
}

for (int i=0; i < queue->mask_buffer_len / 4; i++) {
((uint32_t*)(queue->bufs[current]))[i] &= ((uint32_t*)(queue->mask_buffer))[i];
}
}

int IRAM_ATTR lq_read(LineQueue_t* queue, uint8_t* dst) {
Expand All @@ -31,7 +76,7 @@ int IRAM_ATTR lq_read(LineQueue_t* queue, uint8_t* dst) {
return -1;
}

memcpy(dst, &queue->buf[last * queue->element_size], queue->element_size);
memcpy(dst, queue->bufs[last], queue->element_size);

if (last == queue->size - 1) {
queue->last = 0;
Expand Down
17 changes: 15 additions & 2 deletions src/output_common/line_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,28 @@
#include <stddef.h>


/// Circular line queue with atomic read / write operations.
/// Circular line queue with atomic read / write operations
/// and accelerated masking on the output buffer.
typedef struct {
int size;
atomic_int current;
atomic_int last;
uint8_t* buf;
uint8_t** bufs;
// size of an element
size_t element_size;
//size of the mask buffer
size_t mask_buffer_len;
// mask to appyl to the output buffer, NULL if none.
// mut be elem_buf_size long.
uint8_t* mask_buffer;
} LineQueue_t;

/// Initialize the line queue and allocate memory.
LineQueue_t lq_init(int queue_len, int element_size);

/// Deinitialize the line queue and free memory.
void lq_free(LineQueue_t* queue);

/// Pointer to the next empty element in the line queue.
///
/// NULL if the queue is currently full.
Expand Down
7 changes: 6 additions & 1 deletion src/output_common/lut.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,12 @@ static void IRAM_ATTR waveform_lut_static_from(
*/
__attribute__((optimize("O3")))
void mask_line_buffer(uint8_t* lb, int line_buf_len, int xmin, int xmax) {
#ifdef RENDER_METHOD_I2S
const int offset_table[4] = {2, 3, 0, 1};
#else
const int offset_table[4] = {0, 1, 2, 3};
#endif

// lower bound to where byte order is not an issue.
int memset_start = (xmin / 16) * 4;
int memset_end = min(((xmax + 15) / 16) * 4, line_buf_len);
Expand All @@ -458,7 +464,6 @@ void mask_line_buffer(uint8_t* lb, int line_buf_len, int xmin, int xmax) {
memset(lb, 0, memset_start);
memset(lb + memset_end, 0, line_buf_len - memset_end);

const int offset_table[4] = {2, 3, 0, 1};

// mask unused pixels at the start of the output interval
uint8_t line_start_mask = 0xFF << (2 * (xmin % 4));
Expand Down
59 changes: 39 additions & 20 deletions src/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <freertos/semphr.h>
#include <freertos/task.h>

#include "output_common/line_queue.h"
#include "output_common/lut.h"
#include "output_common/render_context.h"
#include "output_common/render_method.h"
#include "output_lcd/render_lcd.h"
Expand Down Expand Up @@ -157,9 +159,28 @@ enum EpdDrawError IRAM_ATTR epd_draw_base(
#ifdef RENDER_METHOD_I2S
i2s_do_update(&render_context);
#elif defined(RENDER_METHOD_LCD)
// int line_start_x = area.x + (horizontally_cropped ? crop_to.x : 0);
// int line_end_x = line_start_x + (horizontally_cropped ? crop_to.width : area.width);
// line_start_x = min(max(line_start_x, 0), ctx->display_width);
// line_end_x = min(max(line_end_x, 0), ctx->display_width);

for (int i=0; i < NUM_RENDER_THREADS; i++) {
LineQueue_t* queue = &render_context.line_queues[i];
memset(queue->mask_buffer, 0xFF, queue->mask_buffer_len);
mask_line_buffer(queue->mask_buffer, queue->mask_buffer_len, crop_to.x, crop_to.x + crop_to.width);
for (int i=0; i < queue->mask_buffer_len; i++) {
printf("%X", queue->mask_buffer[i]);
}
printf("\n");
}

lcd_do_update(&render_context);
#endif

if (render_context.error & EPD_DRAW_EMPTY_LINE_QUEUE) {
ESP_LOGE("epdiy", "line buffer underrun occurred!");
}

if (render_context.error != EPD_DRAW_SUCCESS) {
return render_context.error;
}
Expand Down Expand Up @@ -256,29 +277,28 @@ void epd_renderer_init(enum EpdInitOptions options) {
queue_len = 8;
}


if (render_context.conversion_lut == NULL) {
ESP_LOGE("epd", "could not allocate line mask!");
abort();
}


#ifdef RENDER_METHOD_LCD
size_t queue_elem_size = epd_width() / 4;
size_t queue_elem_size = render_context.display_width / 4;
#elif defined(RENDER_METHOD_I2S)
size_t queue_elem_size = epd_width();
#endif

ESP_LOGI("epdiy", "line bytes: %d", queue_elem_size);

for (int i = 0; i < NUM_RENDER_THREADS; i++) {
render_context.line_queues[i].size = queue_len;
render_context.line_queues[i].element_size = queue_elem_size;
render_context.line_queues[i].current = 0;
render_context.line_queues[i].last = 0;
render_context.line_queues[i].buf = (uint8_t *)heap_caps_malloc(
queue_len * queue_elem_size, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
assert(render_context.line_queues[i].buf != NULL);
render_context.line_queues[i] = lq_init(queue_len, queue_elem_size);
render_context.feed_line_buffers[i] = (uint8_t *)heap_caps_malloc(render_context.display_width, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
assert(render_context.feed_line_buffers[i] != NULL);
RTOS_ERROR_CHECK(xTaskCreatePinnedToCore(
render_thread, "epd_prep", 1 << 11, (void *)i,
render_thread, "epd_prep", 1 << 12, (void *)i,
configMAX_PRIORITIES, &render_context.feed_tasks[i], i));
if (render_context.line_queues[i].buf == NULL) {
ESP_LOGE("epd", "could not allocate line queue!");
abort();
}
}
}

Expand All @@ -288,6 +308,12 @@ void epd_renderer_deinit() {

epd_board->poweroff(epd_ctrl_state());

for (int i = 0; i < NUM_RENDER_THREADS; i++) {
vTaskDelete(render_context.feed_tasks[i]);
lq_free(&render_context.line_queues[i]);
vSemaphoreDelete(render_context.feed_done_smphr[i]);
}

#ifdef RENDER_METHOD_I2S
i2s_deinit();
#endif
Expand All @@ -298,13 +324,6 @@ void epd_renderer_deinit() {
epd_board->deinit();
}

for (int i = 0; i < NUM_RENDER_THREADS; i++) {
free(render_context.line_queues[i].buf);
free(render_context.feed_line_buffers[i]);
vSemaphoreDelete(render_context.feed_done_smphr[i]);
vTaskDelete(render_context.feed_tasks[i]);
}

free(render_context.conversion_lut);
free(render_context.line_threads);
vSemaphoreDelete(render_context.frame_done);
Expand Down

0 comments on commit 495a890

Please sign in to comment.