This commit is contained in:
Phillip Burgess 2023-01-15 10:16:15 -08:00 committed by ladyada
parent 18119d4d88
commit bd5cfef670
2 changed files with 104 additions and 4 deletions

View file

@ -49,14 +49,14 @@ DVIGFX16::DVIGFX16(const uint16_t w, const uint16_t h,
const struct dvi_serialiser_cfg &c)
: PicoDVI(t, v, c), GFXcanvas16(w, h) {}
static void scanline_callback_GFX16(void) {
((DVIGFX16 *)gfxptr)->_scanline_callback();
}
DVIGFX16::~DVIGFX16(void) {
gfxptr = NULL;
}
static void scanline_callback_GFX16(void) {
((DVIGFX16 *)gfxptr)->_scanline_callback();
}
void DVIGFX16::_scanline_callback(void) {
// Discard any scanline pointers passed back
uint16_t *bufptr;
@ -82,3 +82,79 @@ bool DVIGFX16::begin(void) {
}
return false;
}
// DVIGFX8 (8-bit, color-indexed framebuffer) is all manner of dirty pool.
// PicoDVI seems to have some palette support but I couldn't grasp the DMA
// stuff going on, so just doing a brute force thing here for now: in
// addition to the 8-bit framebuffer, two 16-bit (RGB565) scanlines are
// allocated...then, in the scanline callback, pixels are mapped from the
// 8-bit framebuffer through the palette into one of these buffers, allowing
// use of the same dvi_scanbuf_main_16bpp handler as DVIGFX16 above. Not
// optimal, sure...but not pessimal either. The allocation of those 16-bit
// scanlines is weird(tm) though. Rather than a separate malloc (which
// creates a nasty can of worms if that fails after a successful framebuffer
// allocation...unlikely but not impossible), the framebuffer size is
// tweaked so that W*H is always an even number, plus 4 extra 8-bit
// scanlines are added: thus two 16-bit scanlines, word-aligned. That extra
// memory is for us, but allocated by GFX as part of the framebuffer all at
// once. On calling begin(), 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.
DVIGFX8::DVIGFX8(const uint16_t w, const uint16_t h,
const struct dvi_timing &t, vreg_voltage v,
const struct dvi_serialiser_cfg &c)
: PicoDVI(t, v, c), GFXcanvas8(w, ((h + 1) & ~1) + 4) {
}
DVIGFX8::~DVIGFX8(void) {
gfxptr = NULL;
}
static void scanline_callback_GFX8(void) {
((DVIGFX8 *)gfxptr)->_scanline_callback();
}
void __not_in_flash_func(DVIGFX8::_scanline_callback)(void) {
// Idea: try doing the bufptr remove/add stuff first, THEN do the palette
// lookup afterward (for next scanline), so less of a race.
// Discard any scanline pointers passed back
uint8_t *b8 = &getBuffer()[WIDTH * scanline];
uint16_t *b16 = row565[foo];
for (int i=0; i<WIDTH; i++) b16[i] = palette[b8[i]];
while (queue_try_remove_u32(&dvi0.q_colour_free, &b16))
;
b16 = row565[foo];
queue_add_blocking_u32(&dvi0.q_colour_valid, &b16);
foo = (foo + 1) & 1;
scanline = (scanline + 1) % HEIGHT;
}
bool DVIGFX8::begin(void) {
uint8_t *bufptr = getBuffer();
if ((bufptr)) {
gfxptr = this;
HEIGHT -= 4; // Clip rows used by 16bpp scanlines (still word aligned)
row565[0] = (uint16_t *)&bufptr[WIDTH * HEIGHT];
row565[1] = row565[0] + WIDTH;
HEIGHT &= ~1; // Then clip extra row (if any) that made W*H even
setRotation(rotation); // So HEIGHT also affects _height
memset(palette, 0, sizeof palette);
//mainloop = mainloop8;
mainloop = dvi_scanbuf_main_16bpp; // in libdvi
dvi0.scanline_callback = scanline_callback_GFX8;
PicoDVI::begin();
for (int i=0; i<WIDTH; i++) {
row565[0][i] = palette[bufptr[i]];
row565[1][i] = palette[bufptr[i + WIDTH]];
}
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;
}

View file

@ -37,3 +37,27 @@ public:
protected:
uint16_t scanline = 2; // First 2 scanlines are set up before DVI start
};
class DVIGFX8 : public PicoDVI, public GFXcanvas8 {
public:
DVIGFX8(const uint16_t w = 320, const uint16_t h = 240,
const struct dvi_timing &t = dvi_timing_640x480p_60hz,
vreg_voltage v = VREG_VOLTAGE_1_10,
const struct dvi_serialiser_cfg &c = pimoroni_demo_hdmi_cfg);
~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 foo = 1;
};