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(cs, 0);
graphics->scanline_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
spi_write_blocking(spi, (const uint8_t*)data, length);
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)data, length);
}
});
gpio_put(cs, 1);

Wyświetl plik

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

Wyświetl plik

@ -154,8 +154,10 @@ namespace pimoroni {
spi_write_blocking(spi, &reg, 1);
gpio_put(DC, 1); // data mode
graphics->scanline_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) {
spi_write_blocking(spi, (const uint8_t*)buf, length);
graphics->frame_convert(PicoGraphics::PEN_P4, [this](void *buf, size_t length) {
if (length > 0) {
spi_write_blocking(spi, (const uint8_t*)buf, length);
}
});
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 RGB565 &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::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;
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;
//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 RGB565 &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);
void set_font(const bitmap::font_t *font);
@ -252,6 +253,9 @@ namespace pimoroni {
void polygon(const std::vector<Point> &points);
void triangle(Point p1, Point p2, Point p3);
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 {
@ -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 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) {
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 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) {
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 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) {
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 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) {
return w * h;
}

Wyświetl plik

@ -90,7 +90,7 @@ namespace pimoroni {
color = candidate_cache[cache_key][dither16_pattern[pattern_index]];
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) {
uint8_t row_buf[bounds.w / 2];
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]];
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) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
@ -134,28 +134,18 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
uint8_t o = 4;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA
// while we're preparing the next row
uint16_t row_buf[2][bounds.w];
for(auto y = 0; y < bounds.h; y++) {
/*if(scanline_interrupt != nullptr) {
scanline_interrupt(y);
// Cache the RGB888 palette as RGB565
for(auto i = 0u; i < 16; i++) {
cache[i] = palette[i].to_rgb565();
}
}*/
frame_convert_rgb565(callback, [&]() {
uint8_t c = *src;
uint8_t b = (c >> o) & 0xf; // bit value shifted to position
// Increment to next 4-bit entry
o ^= 4;
if (o != 0) ++src;
for(auto x = 0; x < bounds.w; x++) {
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));
}
return cache[b];
});
}
}
}

Wyświetl plik

@ -98,7 +98,7 @@ namespace pimoroni {
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) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
@ -109,16 +109,9 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA
// while we're preparing the next row
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));
}
frame_convert_rgb565(callback, [&]() {
return cache[*src++];
});
}
}
}

Wyświetl plik

@ -78,24 +78,15 @@ namespace pimoroni {
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) {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
// Allocate two per-row temporary buffers, as the callback may transfer by DMA
// while we're preparing the next row
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));
}
frame_convert_rgb565(callback, [&]() {
return rgb332_to_rgb565_lut[*src++];
});
}
}
void PicoGraphics_PenRGB332::sprite(void* data, const Point &sprite, const Point &dest, const int scale, const int transparent) {