kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Pico Graphics: Use fixed size buffer for frame conversion
rodzic
f341c15fa7
commit
7f330d1a04
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -154,8 +154,10 @@ namespace pimoroni {
|
|||
spi_write_blocking(spi, ®, 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Ładowanie…
Reference in New Issue