Skip to content

Commit

Permalink
PicoGraphics: Support multiple layers in more types.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gadgetoid committed Oct 24, 2024
1 parent 5e0682b commit be24eb5
Show file tree
Hide file tree
Showing 9 changed files with 158 additions and 67 deletions.
22 changes: 13 additions & 9 deletions drivers/st7735/st7735.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,17 +165,21 @@ namespace pimoroni {

// Native 16-bit framebuffer update
void ST7735::update(PicoGraphics *graphics) {
command(reg::RAMWR);
gpio_put(dc, 1); // data mode
gpio_put(cs, 0);
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) {
command(reg::RAMWR, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
command(reg::RAMWR);
gpio_put(dc, 1); // data mode
gpio_put(cs, 0);

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

void ST7735::set_backlight(uint8_t brightness) {
Expand Down
38 changes: 21 additions & 17 deletions drivers/st7789/st7789.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,26 +282,30 @@ namespace pimoroni {
void ST7789::update(PicoGraphics *graphics) {
uint8_t cmd = reg::RAMWR;

gpio_put(dc, 0); // command mode
gpio_put(cs, 0);
if(spi) { // SPI Bus
spi_write_blocking(spi, &cmd, 1);
} else { // Parallel Bus
write_blocking_parallel(&cmd, 1);
}
if(graphics->pen_type == PicoGraphics::PEN_RGB565 && graphics->layers == 1) { // Display buffer is screen native
command(cmd, width * height * sizeof(uint16_t), (const char*)graphics->frame_buffer);
} else {
gpio_put(dc, 0); // command mode
gpio_put(cs, 0);
if(spi) { // SPI Bus
spi_write_blocking(spi, &cmd, 1);
} else { // Parallel Bus
write_blocking_parallel(&cmd, 1);
}

gpio_put(dc, 1); // data mode
gpio_put(dc, 1); // data mode

graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
write_blocking_dma((const uint8_t*)data, length);
}
else {
dma_channel_wait_for_finish_blocking(st_dma);
}
});
graphics->frame_convert(PicoGraphics::PEN_RGB565, [this](void *data, size_t length) {
if (length > 0) {
write_blocking_dma((const uint8_t*)data, length);
}
else {
dma_channel_wait_for_finish_blocking(st_dma);
}
});

gpio_put(cs, 1);
gpio_put(cs, 1);
}
}

void ST7789::set_backlight(uint8_t brightness) {
Expand Down
1 change: 1 addition & 0 deletions libraries/pico_graphics/pico_graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace pimoroni {

void PicoGraphics::set_layer(uint l) {
this->layer = l;
this->layer_offset = this->bounds.w * this->bounds.h * l;
};
uint PicoGraphics::get_layer() {
return this->layer;
Expand Down
2 changes: 2 additions & 0 deletions libraries/pico_graphics/pico_graphics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ namespace pimoroni {
}
}

constexpr operator bool() {return r || g || b;};
constexpr RGB operator+ (const RGB& c) const {return RGB(r + c.r, g + c.g, b + c.b);}
constexpr RGB& operator+=(const RGB& c) {r += c.r; g += c.g; b += c.b; return *this;}
constexpr RGB& operator-=(const RGB& c) {r -= c.r; g -= c.g; b -= c.b; return *this;}
Expand Down Expand Up @@ -228,6 +229,7 @@ namespace pimoroni {

uint layers = 1;
uint layer = 0;
uint layer_offset = 0;

typedef std::function<void(void *data, size_t length)> conversion_callback_func;
typedef std::function<RGB565()> next_pixel_func;
Expand Down
45 changes: 35 additions & 10 deletions libraries/pico_graphics/pico_graphics_pen_p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ namespace pimoroni {

// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset / 2;
uint8_t *f = &buf[i / 2];

uint8_t o = (~i & 0b1) * 4; // bit offset within byte
Expand All @@ -74,6 +75,7 @@ namespace pimoroni {

// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset / 2;
uint8_t *f = &buf[i / 2];

// doubled up color value, so the color is stored in both nibbles
Expand Down Expand Up @@ -144,16 +146,39 @@ namespace pimoroni {
uint8_t *src = (uint8_t *)frame_buffer;
uint8_t o = 4;

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;

return cache[b];
});
if(this->layers > 1) {

uint offset = this->bounds.w * this->bounds.h / 2;

frame_convert_rgb565(callback, [&]() {
uint8_t b = 0;

// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
uint8_t c = *(src + offset * (layer - 1));
b = (c >> o) & 0xf; // bit value shifted to position
if (b) break;
}

// Increment to next 4-bit entry
o ^= 4;
if (o != 0) src++;

return cache[b];
});
} else {
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;

return cache[b];
});
}
}
}
}
80 changes: 63 additions & 17 deletions libraries/pico_graphics/pico_graphics_pen_p8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ namespace pimoroni {
}
void PicoGraphics_PenP8::set_pixel(const Point &p) {
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}

void PicoGraphics_PenP8::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];

while(l--) {
Expand Down Expand Up @@ -103,26 +105,70 @@ namespace pimoroni {
}

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];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
}
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;

if(layers > 1) {
// The size of a single layer
uint offset = this->bounds.w * this->bounds.h;

if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
}

frame_convert_rgb565(callback, [&]() {
// Check the *palette* index, rather than the colour
// Thus palette entry 0 is *always* transparent
uint8_t c = 0;

// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}

// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
src++;

frame_convert_rgb565(callback, [&]() {
return cache[*src++];
});
} else if (type == PEN_RGB888) {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;
return cache[c];
});
} else if (type == PEN_RGB888) {
frame_convert_rgb888(callback, [&]() {
// Check the *palette* index, rather than the colour
// Thus palette entry 0 is *always* transparent
uint8_t c = 0;

frame_convert_rgb888(callback, [&]() {
return palette[*src++].to_rgb888();
});
// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}

src++;

return palette[c].to_rgb888();
});
}
} else {
if(type == PEN_RGB565) {
// Cache the RGB888 palette as RGB565
RGB565 cache[palette_size];
for(auto i = 0u; i < palette_size; i++) {
cache[i] = palette[i].to_rgb565();
}

frame_convert_rgb565(callback, [&]() {
return cache[*src++];
});
} else if (type == PEN_RGB888) {
frame_convert_rgb888(callback, [&]() {
return palette[*src++].to_rgb888();
});
}
}
}
}
27 changes: 18 additions & 9 deletions libraries/pico_graphics/pico_graphics_pen_rgb332.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ namespace pimoroni {
}
void PicoGraphics_PenRGB332::set_pixel(const Point &p) {
uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB332::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;
buf += p.y * bounds.w + p.x;

while(l--) {
Expand All @@ -40,7 +40,7 @@ namespace pimoroni {
if(!bounds.contains(p)) return;

uint8_t *buf = (uint8_t *)frame_buffer;
buf += buffer_size(this->bounds.w, this->bounds.h) * layer;
buf += this->layer_offset;

RGB332 blended = RGB(buf[p.y * bounds.w + p.x]).blend(RGB(color), a).to_rgb332();

Expand Down Expand Up @@ -99,14 +99,23 @@ namespace pimoroni {
// Treat our void* frame_buffer as uint8_t
uint8_t *src = (uint8_t *)frame_buffer;

if(this->layers > 1) {
// Assume only two layers for now
uint8_t *src_layer2 = src + buffer_size(this->bounds.w, this->bounds.h);
if(this->layers > 1) {
// The size of a single layer
uint offset = this->bounds.w * this->bounds.h;

frame_convert_rgb565(callback, [&]() {
RGB565 c1 = rgb332_to_rgb565_lut[*src++];
RGB565 c2 = rgb332_to_rgb565_lut[*src_layer2++];
return c2 ? c2 : c1;
uint8_t c = 0;

// Iterate through layers in reverse order
// Return the first nonzero (not transparent) pixel
for(auto layer = this->layers; layer > 0; layer--) {
c = *(src + offset * (layer - 1));
if (c) break;
}

src++;

return rgb332_to_rgb565_lut[c];
});
} else {
frame_convert_rgb565(callback, [&]() {
Expand Down
8 changes: 3 additions & 5 deletions libraries/pico_graphics/pico_graphics_pen_rgb565.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ namespace pimoroni {
void PicoGraphics_PenRGB565::set_pixel(const Point &p) {
uint16_t *buf = (uint16_t *)frame_buffer;
// We can't use buffer_size because our pointer is uint16_t
buf += this->bounds.w * this->bounds.h * layer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB565::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint16_t *buf = (uint16_t *)frame_buffer;
// We can't use buffer_size because our pointer is uint16_t
buf += this->bounds.w * this->bounds.h * layer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];

while(l--) {
Expand All @@ -45,10 +45,8 @@ namespace pimoroni {

if(layers > 1) {
// Assume only two layers for now
uint16_t *src_layer2 = src;

// We can't use buffer_size because our pointer is uint16_t
src_layer2 += this->bounds.w * this->bounds.h * layer;
uint16_t *src_layer2 = src + this->bounds.w * this->bounds.h;

frame_convert_rgb565(callback, [&]() {
RGB565 c1 = *src++;
Expand Down
2 changes: 2 additions & 0 deletions libraries/pico_graphics/pico_graphics_pen_rgb888.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ namespace pimoroni {
}
void PicoGraphics_PenRGB888::set_pixel(const Point &p) {
uint32_t *buf = (uint32_t *)frame_buffer;
buf += this->layer_offset;
buf[p.y * bounds.w + p.x] = color;
}
void PicoGraphics_PenRGB888::set_pixel_span(const Point &p, uint l) {
// pointer to byte in framebuffer that contains this pixel
uint32_t *buf = (uint32_t *)frame_buffer;
buf += this->layer_offset;
buf = &buf[p.y * bounds.w + p.x];

while(l--) {
Expand Down

0 comments on commit be24eb5

Please sign in to comment.