Remove separate 8x2 class; double-buffered is a constructor arg
This commit is contained in:
parent
e36890e453
commit
1acf442ffa
4 changed files with 54 additions and 131 deletions
|
|
@ -3,12 +3,8 @@
|
|||
|
||||
#include <PicoDVI.h>
|
||||
|
||||
// Double-buffered 8-bit and 1-bit are declared a little differently...
|
||||
// 8-bit requires a distinct class for double-buffering, as its memory
|
||||
// requirements are unique, while 1-bit has an extra constructor
|
||||
// argument to enable or disable this.
|
||||
// 8-bit currently supports 320x240 and 400x240 resolutions only.
|
||||
DVIGFX8x2 display(DVI_RES_400x240p60, pimoroni_demo_hdmi_cfg);
|
||||
DVIGFX8 display(DVI_RES_400x240p60, true, pimoroni_demo_hdmi_cfg);
|
||||
|
||||
#define N_BALLS 100 // 1-254 (not 255)
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <PicoDVI.h>
|
||||
|
||||
// 8-bit currently supports 320x240 and 400x240 resolutions only.
|
||||
DVIGFX8 display(DVI_RES_400x240p60, pimoroni_demo_hdmi_cfg);
|
||||
DVIGFX8 display(DVI_RES_400x240p60, false, pimoroni_demo_hdmi_cfg);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
|
|
|||
147
src/PicoDVI.cpp
147
src/PicoDVI.cpp
|
|
@ -118,19 +118,31 @@ bool DVIGFX16::begin(void) {
|
|||
// us, but allocated by GFX as part of the framebuffer all at once. The
|
||||
// HEIGHT value is de-tweaked to the original value so clipping won't allow
|
||||
// any drawing operations to spill into the 16-bit scanlines.
|
||||
// This requires latest Adafruit_GFX as double-buffered mode plays games with
|
||||
// the canvas pointer, wasn't possible until that was made protected (vs
|
||||
// private). Drawing and palette-setting operations ONLY apply to the "back"
|
||||
// state. Call swap() to switch the front/back buffers at the next vertical
|
||||
// sync, for flicker-free and tear-free animation.
|
||||
|
||||
DVIGFX8::DVIGFX8(const DVIresolution r, const struct dvi_serialiser_cfg &c,
|
||||
vreg_voltage v)
|
||||
DVIGFX8::DVIGFX8(const DVIresolution r, const bool d,
|
||||
const struct dvi_serialiser_cfg &c, vreg_voltage v)
|
||||
: PicoDVI(dvispec[r].timing, c, v),
|
||||
GFXcanvas8(dvispec[r].width, ((dvispec[r].height + 1) & ~1) + 4) {
|
||||
GFXcanvas8(
|
||||
dvispec[r].width,
|
||||
(d ? (dvispec[r].height * 2) : ((dvispec[r].height + 1) & ~1)) + 4),
|
||||
dbuf(d) {
|
||||
HEIGHT = _height = dvispec[r].height;
|
||||
buffer_save = buffer;
|
||||
dvi_vertical_repeat = dvispec[r].v_rep;
|
||||
dvi_monochrome_tmds = false;
|
||||
}
|
||||
|
||||
DVIGFX8::~DVIGFX8(void) { gfxptr = NULL; }
|
||||
DVIGFX8::~DVIGFX8(void) {
|
||||
buffer = buffer_save; // Restore pointer so canvas destructor works
|
||||
gfxptr = NULL;
|
||||
}
|
||||
|
||||
static void scanline_callback_GFX8(void) {
|
||||
static void __not_in_flash_func(scanline_callback_GFX8)(void) {
|
||||
((DVIGFX8 *)gfxptr)->_scanline_callback();
|
||||
}
|
||||
|
||||
|
|
@ -141,19 +153,32 @@ void __not_in_flash_func(DVIGFX8::_scanline_callback)(void) {
|
|||
b16 = row565[rowidx]; // Next row to send
|
||||
queue_add_blocking_u32(&dvi0.q_colour_valid, &b16); // Send it
|
||||
|
||||
scanline = (scanline + 1) % HEIGHT; // Next scanline
|
||||
uint8_t *b8 = &getBuffer()[WIDTH * scanline]; // New src
|
||||
rowidx = (rowidx + 1) & 1; // Swap row565[] bufs
|
||||
b16 = row565[rowidx]; // New dest
|
||||
if (++scanline >= HEIGHT) { // Next scanline...end of screen reached?
|
||||
if (swap_wait) { // Swap buffers?
|
||||
back_index = 1 - back_index; // Yes plz
|
||||
buffer = buffer_save + WIDTH * HEIGHT * back_index;
|
||||
swap_wait = 0;
|
||||
}
|
||||
scanline = 0;
|
||||
}
|
||||
|
||||
// Refresh from front buffer
|
||||
uint8_t *b8 = buffer_save + WIDTH * scanline; // New src
|
||||
if (dbuf)
|
||||
b8 += WIDTH * HEIGHT * (1 - back_index);
|
||||
rowidx = (rowidx + 1) & 1; // Swap row565[] bufs
|
||||
b16 = row565[rowidx]; // New dest
|
||||
uint16_t *p16 = dbuf ? palette[1 - back_index] : palette[0];
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
b16[i] = palette[b8[i]];
|
||||
b16[i] = p16[b8[i]];
|
||||
}
|
||||
|
||||
bool DVIGFX8::begin(void) {
|
||||
uint8_t *bufptr = getBuffer();
|
||||
if ((bufptr)) {
|
||||
gfxptr = this;
|
||||
row565[0] = (uint16_t *)&bufptr[(WIDTH * HEIGHT + 1) & ~1];
|
||||
row565[0] = (uint16_t *)&bufptr[dbuf ? WIDTH * HEIGHT * 2
|
||||
: (WIDTH * HEIGHT + 1) & ~1];
|
||||
row565[1] = row565[0] + WIDTH;
|
||||
memset(palette, 0, sizeof palette);
|
||||
// mainloop = mainloop8;
|
||||
|
|
@ -172,100 +197,24 @@ bool DVIGFX8::begin(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// DVIGFX8x2 (8-bit, color-indexed, double-buffered for animation)
|
||||
// requires latest Adafruit_GFX as it plays games with the canvas pointer,
|
||||
// wasn't possible until that was made protected (vs private). This is very
|
||||
// similar to DVIGFX8 but effectively has two canvases and palettes ("front"
|
||||
// and "back"). Drawing and palette-setting operations ONLY apply to the
|
||||
// "back" state. Call swap() to switch the front/back buffers at the next
|
||||
// vertical sync, for flicker-free and tear-free animation.
|
||||
void DVIGFX8::swap(bool copy_framebuffer, bool copy_palette) {
|
||||
if (dbuf) {
|
||||
// Request buffer swap at next frame end, wait for it to happen.
|
||||
for (swap_wait = 1; swap_wait;)
|
||||
;
|
||||
|
||||
DVIGFX8x2::DVIGFX8x2(const DVIresolution r, const struct dvi_serialiser_cfg &c,
|
||||
vreg_voltage v)
|
||||
: PicoDVI(dvispec[r].timing, c, v),
|
||||
GFXcanvas8(dvispec[r].width, dvispec[r].height * 2 + 4) {
|
||||
HEIGHT = _height = dvispec[r].height;
|
||||
buffer_save = buffer;
|
||||
dvi_vertical_repeat = dvispec[r].v_rep;
|
||||
dvi_monochrome_tmds = false;
|
||||
}
|
||||
|
||||
DVIGFX8x2::~DVIGFX8x2(void) {
|
||||
buffer = buffer_save; // Restore pointer so canvas destructor works
|
||||
gfxptr = NULL;
|
||||
}
|
||||
|
||||
static void scanline_callback_GFX8x2(void) {
|
||||
((DVIGFX8x2 *)gfxptr)->_scanline_callback();
|
||||
}
|
||||
|
||||
void __not_in_flash_func(DVIGFX8x2::_scanline_callback)(void) {
|
||||
uint16_t *b16;
|
||||
while (queue_try_remove_u32(&dvi0.q_colour_free, &b16))
|
||||
; // Discard returned pointer(s)
|
||||
b16 = row565[rowidx]; // Next row to send
|
||||
queue_add_blocking_u32(&dvi0.q_colour_valid, &b16); // Send it
|
||||
|
||||
if (++scanline >= HEIGHT) { // Next scanline...end of screen reached?
|
||||
if (swap_wait) { // Swap buffers?
|
||||
back_index = 1 - back_index; // Yes plz
|
||||
buffer = buffer_save + WIDTH * HEIGHT * back_index;
|
||||
swap_wait = 0;
|
||||
if ((copy_framebuffer)) {
|
||||
uint32_t bufsize = WIDTH * HEIGHT;
|
||||
memcpy(buffer_save + bufsize * back_index,
|
||||
buffer_save + bufsize * (1 - back_index), bufsize);
|
||||
}
|
||||
scanline = 0;
|
||||
}
|
||||
// Refresh from front buffer
|
||||
uint8_t *b8 = buffer_save + WIDTH * HEIGHT * (1 - back_index) +
|
||||
WIDTH * scanline; // New src
|
||||
rowidx = (rowidx + 1) & 1; // Swap row565[] bufs
|
||||
b16 = row565[rowidx]; // New dest
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
b16[i] = palette[1 - back_index][b8[i]];
|
||||
}
|
||||
|
||||
bool DVIGFX8x2::begin(void) {
|
||||
uint8_t *bufptr = getBuffer();
|
||||
if ((bufptr)) {
|
||||
gfxptr = this;
|
||||
row565[0] = (uint16_t *)&bufptr[WIDTH * HEIGHT * 2];
|
||||
row565[1] = row565[0] + WIDTH;
|
||||
memset(palette, 0, sizeof palette);
|
||||
// mainloop = mainloop8;
|
||||
mainloop = dvi_scanbuf_main_16bpp; // in libdvi
|
||||
dvi0.scanline_callback = scanline_callback_GFX8x2;
|
||||
PicoDVI::begin();
|
||||
bufptr += WIDTH * HEIGHT; // Initial front buffer is index 1
|
||||
// No need to initialize the row565 buffer contents as that memory is
|
||||
// cleared on canvas alloc, and the initial palette state is also all 0.
|
||||
uint16_t *b16 = row565[0];
|
||||
queue_add_blocking_u32(&dvi0.q_colour_valid, &b16);
|
||||
b16 = row565[1];
|
||||
queue_add_blocking_u32(&dvi0.q_colour_valid, &b16);
|
||||
wait_begin = false; // Set core 1 in motion
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DVIGFX8x2::swap(bool copy_framebuffer, bool copy_palette) {
|
||||
|
||||
// Request buffer swap at next frame end, wait for it to happen.
|
||||
for (swap_wait = 1; swap_wait;)
|
||||
;
|
||||
|
||||
if ((copy_framebuffer)) {
|
||||
uint32_t bufsize = WIDTH * HEIGHT;
|
||||
memcpy(buffer_save + bufsize * back_index,
|
||||
buffer_save + bufsize * (1 - back_index), bufsize);
|
||||
}
|
||||
|
||||
if ((copy_palette)) {
|
||||
memcpy(palette[back_index], palette[1 - back_index], sizeof(palette[0]));
|
||||
if ((copy_palette)) {
|
||||
memcpy(palette[back_index], palette[1 - back_index], sizeof(palette[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1-bit WIP --------
|
||||
|
||||
DVIGFX1::DVIGFX1(const DVIresolution r, const bool d,
|
||||
const struct dvi_serialiser_cfg &c, vreg_voltage v)
|
||||
: PicoDVI(dvispec[r].timing, c, v),
|
||||
|
|
|
|||
|
|
@ -55,34 +55,11 @@ protected:
|
|||
|
||||
class DVIGFX8 : public PicoDVI, public GFXcanvas8 {
|
||||
public:
|
||||
DVIGFX8(const DVIresolution res = DVI_RES_400x240p60,
|
||||
DVIGFX8(const DVIresolution res = DVI_RES_400x240p60, const bool dbuf = false,
|
||||
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
|
||||
vreg_voltage v = VREG_VOLTAGE_1_20);
|
||||
~DVIGFX8(void);
|
||||
bool begin(void);
|
||||
uint16_t *getPalette(void) { return palette; }
|
||||
void setColor(uint8_t idx, uint16_t color) { palette[idx] = color; }
|
||||
void setColor(uint8_t idx, uint8_t red, uint8_t green, uint8_t blue) {
|
||||
palette[idx] = ((red & 0xF8) << 8) | ((green & 0xFC) << 3) | (blue >> 3);
|
||||
}
|
||||
uint16_t getColor(uint8_t idx) { return palette[idx]; }
|
||||
|
||||
void _scanline_callback(void);
|
||||
|
||||
protected:
|
||||
uint16_t palette[256];
|
||||
uint16_t *row565[2]; // 2 scanlines of 16-bit RGB565 data
|
||||
uint16_t scanline = 2; // First 2 scanlines are set up before DVI start
|
||||
uint8_t rowidx = 1; // Alternate 0/1 for which row565[] is active
|
||||
};
|
||||
|
||||
class DVIGFX8x2 : public PicoDVI, public GFXcanvas8 {
|
||||
public:
|
||||
DVIGFX8x2(const DVIresolution res = DVI_RES_400x240p60,
|
||||
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg,
|
||||
vreg_voltage v = VREG_VOLTAGE_1_20);
|
||||
~DVIGFX8x2(void);
|
||||
bool begin(void);
|
||||
uint16_t *getPalette(void) { return palette[back_index]; }
|
||||
void setColor(uint8_t idx, uint16_t color) {
|
||||
palette[back_index][idx] = color;
|
||||
|
|
@ -97,13 +74,14 @@ public:
|
|||
void _scanline_callback(void);
|
||||
|
||||
protected:
|
||||
uint16_t palette[2][256]; // Double-buffered palette
|
||||
uint16_t palette[2][256]; // [2] for double-buffering
|
||||
uint16_t *row565[2]; // 2 scanlines of 16-bit RGB565 data
|
||||
uint16_t scanline = 2; // First 2 scanlines are set up before DVI start
|
||||
uint8_t rowidx = 1; // Alternate 0/1 for which row565[] is active
|
||||
bool dbuf = false; // True if double-buffered
|
||||
uint8_t *buffer_save; // Original canvas buffer pointer
|
||||
uint8_t back_index = 0; // Which of 2 buffers receives draw ops
|
||||
volatile bool swap_wait = 0; // For syncronizing front/back buffer swap
|
||||
volatile bool swap_wait = 0; // For synchronizing fromt/back buffer swap
|
||||
};
|
||||
|
||||
class DVIGFX1 : public PicoDVI, public GFXcanvas1 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue