allow multiple schedules for temporal dithering

(however, there's no code yet to generate such schedules)
This commit is contained in:
Jeff Epler 2025-03-09 14:02:49 -05:00
parent 39bc663b26
commit 68c24fcc00
3 changed files with 29 additions and 22 deletions

View file

@ -86,8 +86,9 @@ struct schedule_entry {
};
using schedule = std::vector<schedule_entry>;
using schedule_sequence = std::vector<schedule>;
schedule make_simple_schedule(int n_planes, int pixels_across) {
schedule_sequence make_simple_schedule(int n_planes, int pixels_across) {
schedule result;
uint32_t max_count = 1 << n_planes;
while (max_count < pixels_across)
@ -96,7 +97,7 @@ schedule make_simple_schedule(int n_planes, int pixels_across) {
for (int i = 0; i < n_planes; i++) {
result.emplace_back(10 - i, max_count >> i);
}
return result;
return {result};
}
struct matrix_geometry {
@ -115,10 +116,10 @@ struct matrix_geometry {
matrix_geometry(size_t pixels_across, size_t n_addr_lines, size_t width,
size_t height, matrix_map map, size_t n_lanes,
const std::vector<schedule_entry> schedule)
const schedule_sequence &schedules)
: pixels_across(pixels_across), n_addr_lines(n_addr_lines),
n_lanes(n_lanes), width(width), height(height),
map(map), schedule{schedule} {
map(map), schedules{schedules} {
size_t pixels_down = n_lanes << n_addr_lines;
if (map.size() != pixels_down * pixels_across) {
throw std::range_error(
@ -127,7 +128,7 @@ struct matrix_geometry {
}
size_t pixels_across, n_addr_lines, n_lanes;
std::vector<schedule_entry> schedule;
schedule_sequence schedules;
size_t width, height;
matrix_map map;
};

View file

@ -49,6 +49,7 @@ template <class pinout = adafruit_matrix_bonnet_pinout,
class colorspace = colorspace_rgb888>
struct piomatter : piomatter_base {
using buffer_type = std::vector<uint32_t>;
using bufseq_type = std::vector<buffer_type>;
piomatter(std::span<typename colorspace::data_type const> framebuffer,
const matrix_geometry &geometry)
: framebuffer(framebuffer), geometry{geometry}, converter{},
@ -63,9 +64,13 @@ struct piomatter : piomatter_base {
void show() override {
int buffer_idx = manager.get_free_buffer();
auto &buffer = buffers[buffer_idx];
auto &bufseq = buffers[buffer_idx];
bufseq.resize(geometry.schedules.size());
auto converted = converter.convert(framebuffer);
protomatter_render_rgb10<pinout>(buffer, geometry, converted.data());
for (size_t i = 0; i < geometry.schedules.size(); i++) {
protomatter_render_rgb10<pinout>(
bufseq[i], geometry, geometry.schedules[i], converted.data());
}
manager.put_filled_buffer(buffer_idx);
}
@ -161,26 +166,27 @@ struct piomatter : piomatter_base {
}
void blit_thread() {
const uint32_t *databuf = nullptr;
size_t datasize = 0;
int old_buffer_idx = buffer_manager::no_buffer;
int cur_buffer_idx = buffer_manager::no_buffer;
int buffer_idx;
int seq_idx = -1;
uint64_t t0, t1;
t0 = monotonicns64();
while ((buffer_idx = manager.get_filled_buffer()) !=
buffer_manager::exit_request) {
if (buffer_idx != buffer_manager::no_buffer) {
const auto &buffer = buffers[buffer_idx];
databuf = &buffer[0];
datasize = buffer.size() * sizeof(*databuf);
if (old_buffer_idx != buffer_manager::no_buffer) {
manager.put_free_buffer(old_buffer_idx);
if (cur_buffer_idx != buffer_manager::no_buffer) {
manager.put_free_buffer(cur_buffer_idx);
}
old_buffer_idx = buffer_idx;
cur_buffer_idx = buffer_idx;
}
if (datasize) {
if (cur_buffer_idx != buffer_manager::no_buffer) {
const auto &cur_buf = buffers[cur_buffer_idx];
seq_idx = (seq_idx + 1) % cur_buf.size();
const auto &data = cur_buf[seq_idx];
auto datasize = sizeof(uint32_t) * data.size();
auto dataptr = const_cast<uint32_t *>(&data[0]);
pio_sm_xfer_data_large(pio, sm, PIO_DIR_TO_SM, datasize,
(uint32_t *)databuf);
dataptr);
t1 = monotonicns64();
if (t0 != t1) {
fps = 1e9 / (t1 - t0);
@ -195,7 +201,7 @@ struct piomatter : piomatter_base {
PIO pio = NULL;
int sm = -1;
std::span<typename colorspace::data_type const> framebuffer;
buffer_type buffers[3];
bufseq_type buffers[3];
buffer_manager manager{};
matrix_geometry geometry;
colorspace converter;

View file

@ -132,7 +132,7 @@ struct colorspace_rgb10 {
template <typename pinout>
void protomatter_render_rgb10(std::vector<uint32_t> &result,
const matrix_geometry &matrixmap,
const uint32_t *pixels) {
const schedule &sched, const uint32_t *pixels) {
result.clear();
int data_count = 0;
@ -194,8 +194,8 @@ void protomatter_render_rgb10(std::vector<uint32_t> &result,
uint32_t addr_bits = calc_addr_bits(prev_addr);
for (size_t addr = 0; addr < n_addr; addr++) {
uint32_t active_time = matrixmap.schedule.back().active_time;
for (auto &schedule_ent : matrixmap.schedule) {
uint32_t active_time = sched.back().active_time;
for (auto &schedule_ent : sched) {
uint32_t r_mask = 1 << (20 + schedule_ent.shift);
uint32_t g_mask = 1 << (10 + schedule_ent.shift);
uint32_t b_mask = 1 << (0 + schedule_ent.shift);