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

View file

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

View file

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