Pico Graphics: Use fixed size buffer for frame conversion

pull/422/head
Mike Bell 2022-08-23 23:07:13 +01:00
rodzic f341c15fa7
commit 7f330d1a04
9 zmienionych plików z 78 dodań i 68 usunięć

Wyświetl plik

@ -172,8 +172,10 @@ namespace pimoroni {
gpio_put(dc, 1); // data mode gpio_put(dc, 1); // data mode
gpio_put(cs, 0); gpio_put(cs, 0);
graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
spi_write_blocking(spi, (const uint8_t*)data, length); if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)data, length);
}
}); });
gpio_put(cs, 1); gpio_put(cs, 1);

Wyświetl plik

@ -290,8 +290,10 @@ namespace pimoroni {
spi_write_blocking(spi, &cmd, 1); spi_write_blocking(spi, &cmd, 1);
gpio_put(dc, 1); // data mode gpio_put(dc, 1); // data mode
graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) { graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
spi_write_blocking(spi, (const uint8_t*)data, length); if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)data, length);
}
}); });
gpio_put(cs, 1); gpio_put(cs, 1);
@ -301,16 +303,12 @@ namespace pimoroni {
write_blocking_parallel(&cmd, 1); write_blocking_parallel(&cmd, 1);
gpio_put(dc, 1); // data mode gpio_put(dc, 1); // data mode
int scanline = 0; graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this, scanline](void *data, size_t length) mutable { write_blocking_parallel_dma((const uint8_t*)data, length);
write_blocking_parallel_dma((const uint8_t*)data, length); }
else {
// Stall on the last scanline since "data" goes out of scope and is lost dma_channel_wait_for_finish_blocking(parallel_dma);
scanline++;
if(scanline == height) {
while (dma_channel_is_busy(parallel_dma))
;
} }
}); });

Wyświetl plik

@ -154,8 +154,10 @@ namespace pimoroni {
spi_write_blocking(spi, &reg, 1); spi_write_blocking(spi, &reg, 1);
gpio_put(DC, 1); // data mode gpio_put(DC, 1); // data mode
graphics->scanline_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) { graphics->frame_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) {
spi_write_blocking(spi, (const uint8_t*)buf, length); if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)buf, length);
}
}); });
gpio_put(CS, 1); gpio_put(CS, 1);

Wyświetl plik

@ -10,7 +10,7 @@ namespace pimoroni {
void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB &c) {};
void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const RGB565 &c) {};
void PicoGraphics::set_pixel_dither(const Point &p, const uint8_t &c) {}; void PicoGraphics::set_pixel_dither(const Point &p, const uint8_t &c) {};
void PicoGraphics::scanline_convert(PenType type, conversion_callback_func callback) {}; void PicoGraphics::frame_convert(PenType type, conversion_callback_func callback) {};
void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {}; void PicoGraphics::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {};
void PicoGraphics::set_dimensions(int width, int height) { void PicoGraphics::set_dimensions(int width, int height) {
@ -333,4 +333,34 @@ namespace pimoroni {
} }
} }
} }
// Common function for frame buffer conversion to 565 pixel format
void PicoGraphics::frame_convert_rgb565(conversion_callback_func callback, next_pixel_func get_next_pixel)
{
// Allocate two temporary buffers, as the callback may transfer by DMA
// while we're preparing the next part of the row
const int BUF_LEN = 64;
uint16_t row_buf[2][BUF_LEN];
int buf_idx = 0;
for(auto y = 0; y < bounds.h; y++) {
for(auto x = 0; x < bounds.w; x++) {
int buf_entry = x & (BUF_LEN - 1);
row_buf[buf_idx][buf_entry] = get_next_pixel();
if (buf_entry == BUF_LEN - 1) {
callback(row_buf[buf_idx], BUF_LEN * sizeof(RGB565));
buf_idx ^= 1;
}
}
if ((bounds.w & (BUF_LEN - 1)) != 0) {
// Callback to the driver with the remaining row data
callback(row_buf[buf_idx], (bounds.w & (BUF_LEN - 1)) * sizeof(RGB565));
buf_idx ^= 1;
}
}
// Callback with zero length to ensure previous buffer is fully written
callback(row_buf[buf_idx], 0);
}
} }

Wyświetl plik

@ -172,6 +172,7 @@ namespace pimoroni {
Rect clip; Rect clip;
typedef std::function<void(void *data, size_t length)> conversion_callback_func; typedef std::function<void(void *data, size_t length)> conversion_callback_func;
typedef std::function<RGB565()> next_pixel_func;
//typedef std::function<void(int y)> scanline_interrupt_func; //typedef std::function<void(int y)> scanline_interrupt_func;
//scanline_interrupt_func scanline_interrupt = nullptr; //scanline_interrupt_func scanline_interrupt = nullptr;
@ -225,7 +226,7 @@ namespace pimoroni {
virtual void set_pixel_dither(const Point &p, const RGB &c); virtual void set_pixel_dither(const Point &p, const RGB &c);
virtual void set_pixel_dither(const Point &p, const RGB565 &c); virtual void set_pixel_dither(const Point &p, const RGB565 &c);
virtual void set_pixel_dither(const Point &p, const uint8_t &c); virtual void set_pixel_dither(const Point &p, const uint8_t &c);
virtual void scanline_convert(PenType type, conversion_callback_func callback); virtual void frame_convert(PenType type, conversion_callback_func callback);
virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent); virtual void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent);
void set_font(const bitmap::font_t *font); void set_font(const bitmap::font_t *font);
@ -252,6 +253,9 @@ namespace pimoroni {
void polygon(const std::vector<Point> &points); void polygon(const std::vector<Point> &points);
void triangle(Point p1, Point p2, Point p3); void triangle(Point p1, Point p2, Point p3);
void line(Point p1, Point p2); void line(Point p1, Point p2);
protected:
void frame_convert_rgb565(conversion_callback_func callback, next_pixel_func get_next_pixel);
}; };
class PicoGraphics_Pen1Bit : public PicoGraphics { class PicoGraphics_Pen1Bit : public PicoGraphics {
@ -325,7 +329,7 @@ namespace pimoroni {
void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates); void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates);
void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB &c) override;
void scanline_convert(PenType type, conversion_callback_func callback) override; void frame_convert(PenType type, conversion_callback_func callback) override;
static size_t buffer_size(uint w, uint h) { static size_t buffer_size(uint w, uint h) {
return (w * h / 8) * 3; return (w * h / 8) * 3;
} }
@ -354,7 +358,7 @@ namespace pimoroni {
void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates); void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates);
void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB &c) override;
void scanline_convert(PenType type, conversion_callback_func callback) override; void frame_convert(PenType type, conversion_callback_func callback) override;
static size_t buffer_size(uint w, uint h) { static size_t buffer_size(uint w, uint h) {
return w * h / 2; return w * h / 2;
} }
@ -383,7 +387,7 @@ namespace pimoroni {
void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates); void get_dither_candidates(const RGB &col, const RGB *palette, size_t len, std::array<uint8_t, 16> &candidates);
void set_pixel_dither(const Point &p, const RGB &c) override; void set_pixel_dither(const Point &p, const RGB &c) override;
void scanline_convert(PenType type, conversion_callback_func callback) override; void frame_convert(PenType type, conversion_callback_func callback) override;
static size_t buffer_size(uint w, uint h) { static size_t buffer_size(uint w, uint h) {
return w * h; return w * h;
} }
@ -404,7 +408,7 @@ namespace pimoroni {
void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override; void sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) override;
void scanline_convert(PenType type, conversion_callback_func callback) override; void frame_convert(PenType type, conversion_callback_func callback) override;
static size_t buffer_size(uint w, uint h) { static size_t buffer_size(uint w, uint h) {
return w * h; return w * h;
} }

Wyświetl plik

@ -90,7 +90,7 @@ namespace pimoroni {
color = candidate_cache[cache_key][dither16_pattern[pattern_index]]; color = candidate_cache[cache_key][dither16_pattern[pattern_index]];
set_pixel(p); set_pixel(p);
} }
void PicoGraphics_Pen3Bit::scanline_convert(PenType type, conversion_callback_func callback) { void PicoGraphics_Pen3Bit::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_P4) { if(type == PEN_P4) {
uint8_t row_buf[bounds.w / 2]; uint8_t row_buf[bounds.w / 2];
uint offset = (bounds.w * bounds.h) / 8; uint offset = (bounds.w * bounds.h) / 8;

Wyświetl plik

@ -124,7 +124,7 @@ namespace pimoroni {
color = candidate_cache[cache_key][dither16_pattern[pattern_index]]; color = candidate_cache[cache_key][dither16_pattern[pattern_index]];
set_pixel(p); set_pixel(p);
} }
void PicoGraphics_PenP4::scanline_convert(PenType type, conversion_callback_func callback) { void PicoGraphics_PenP4::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_RGB565) { if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565 // Cache the RGB888 palette as RGB565
RGB565 cache[palette_size]; RGB565 cache[palette_size];
@ -134,28 +134,18 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t // Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer; uint8_t *src = (uint8_t *)frame_buffer;
uint8_t o = 4;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA frame_convert_rgb565(callback, [&]() {
// while we're preparing the next row uint8_t c = *src;
uint16_t row_buf[2][bounds.w]; uint8_t b = (c >> o) & 0xf; // bit value shifted to position
for(auto y = 0; y < bounds.h; y++) {
/*if(scanline_interrupt != nullptr) { // Increment to next 4-bit entry
scanline_interrupt(y); o ^= 4;
// Cache the RGB888 palette as RGB565 if (o != 0) ++src;
for(auto i = 0u; i < 16; i++) {
cache[i] = palette[i].to_rgb565();
}
}*/
for(auto x = 0; x < bounds.w; x++) { return cache[b];
uint8_t c = src[(bounds.w * y / 2) + (x / 2)]; });
uint8_t o = (~x & 0b1) * 4; // bit offset within byte
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
row_buf[y & 1][x] = cache[b];
}
// Callback to the driver with the row data
callback(row_buf[y & 1], bounds.w * sizeof(RGB565));
}
} }
} }
} }

Wyświetl plik

@ -98,7 +98,7 @@ namespace pimoroni {
set_pixel(p); set_pixel(p);
} }
void PicoGraphics_PenP8::scanline_convert(PenType type, conversion_callback_func callback) { void PicoGraphics_PenP8::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_RGB565) { if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565 // Cache the RGB888 palette as RGB565
RGB565 cache[palette_size]; RGB565 cache[palette_size];
@ -109,16 +109,9 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t // Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer; uint8_t *src = (uint8_t *)frame_buffer;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA frame_convert_rgb565(callback, [&]() {
// while we're preparing the next row return cache[*src++];
uint16_t row_buf[2][bounds.w]; });
for(auto y = 0; y < bounds.h; y++) {
for(auto x = 0; x < bounds.w; x++) {
row_buf[y & 1][x] = cache[src[bounds.w * y + x]];
}
// Callback to the driver with the row data
callback(row_buf[y & 1], bounds.w * sizeof(RGB565));
}
} }
} }
} }

Wyświetl plik

@ -78,24 +78,15 @@ namespace pimoroni {
set_pixel(p); set_pixel(p);
} }
void PicoGraphics_PenRGB332::scanline_convert(PenType type, conversion_callback_func callback) { void PicoGraphics_PenRGB332::frame_convert(PenType type, conversion_callback_func callback) {
if(type == PEN_RGB565) { if(type == PEN_RGB565) {
// Treat our void* frame_buffer as uint8_t // Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer; uint8_t *src = (uint8_t *)frame_buffer;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA frame_convert_rgb565(callback, [&]() {
// while we're preparing the next row return rgb332_to_rgb565_lut[*src++];
uint16_t row_buf[2][bounds.w]; });
for(auto y = 0; y < bounds.h; y++) {
for(auto x = 0; x < bounds.w; x++) {
row_buf[y & 1][x] = rgb332_to_rgb565_lut[*src];
src++;
}
// Callback to the driver with the row data
callback(row_buf[y & 1], bounds.w * sizeof(RGB565));
}
} }
} }
void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) { void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {