diff --git a/components/ctx/ctx_config.h b/components/ctx/ctx_config.h index 2da210588b2300b20109b059ee869544542da622..33864b1069afcb1ed5fad0664f5f99a1b4de6689 100644 --- a/components/ctx/ctx_config.h +++ b/components/ctx/ctx_config.h @@ -20,6 +20,7 @@ #define CTX_TVG_STDIO 0 #define CTX_DITHER 1 +#define CTX_ST3M_FB_INTERNAL_RAM 0 #define CTX_PDF 0 #define CTX_PROTOCOL_U8_COLOR 1 #define CTX_AVOID_CLIPPED_SUBDIVISION 0 @@ -28,7 +29,7 @@ #define CTX_32BIT_SEGMENTS 0 #define CTX_ENABLE_RGBA8 1 #define CTX_ENABLE_RGB8 1 -#define CTX_ENABLE_RGB332 0 +#define CTX_ENABLE_RGB332 1 #define CTX_ENABLE_RGB565 1 #define CTX_ENABLE_RGB565_BYTESWAPPED 1 #define CTX_ENABLE_CBRLE 0 diff --git a/components/flow3r_bsp/flow3r_bsp.h b/components/flow3r_bsp/flow3r_bsp.h index e5e84f6c072fec73ed97b946d46e31cc9c499342..d75a16d2f9595ed20aa8eb367925a44ad16a96a2 100644 --- a/components/flow3r_bsp/flow3r_bsp.h +++ b/components/flow3r_bsp/flow3r_bsp.h @@ -25,9 +25,9 @@ void flow3r_bsp_display_init(void); // performed simultaneously. void flow3r_bsp_display_send_fb(void *fb_data, int bits); -void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data, - int osd_x0, int osd_y0, int osd_x1, - int osd_y1); +void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale, + void *osd_data, int osd_x0, int osd_y0, + int osd_x1, int osd_y1); // Set display backlight, as integer percent value (from 0 to 100, clamped). // No-op if display hasn't been succesfully initialized. diff --git a/components/flow3r_bsp/flow3r_bsp_display.c b/components/flow3r_bsp/flow3r_bsp_display.c index 38983e1189ea86571f5481edc6c3cd4d99872ea0..9c78e1663c09024aee8347310e8cf732fd099b3f 100644 --- a/components/flow3r_bsp/flow3r_bsp_display.c +++ b/components/flow3r_bsp/flow3r_bsp_display.c @@ -36,16 +36,17 @@ void flow3r_bsp_display_init(void) { } } -void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data, - int osd_x0, int osd_y0, int osd_x1, - int osd_y1) { +void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, int scale, + void *osd_data, int osd_x0, int osd_y0, + int osd_x1, int osd_y1) { if (!gc9a01_initialized) { return; } static bool had_error = false; - esp_err_t ret = flow3r_bsp_gc9a01_blit_osd(&gc9a01, fb_data, bits, osd_data, - osd_x0, osd_y0, osd_x1, osd_y1); + esp_err_t ret = + flow3r_bsp_gc9a01_blit_osd(&gc9a01, fb_data, bits, scale, osd_data, + osd_x0, osd_y0, osd_x1, osd_y1); if (ret != ESP_OK) { if (!had_error) { ESP_LOGE(TAG, "display blit failed: %s", esp_err_to_name(ret)); @@ -60,7 +61,7 @@ void flow3r_bsp_display_send_fb_osd(void *fb_data, int bits, void *osd_data, } void flow3r_bsp_display_send_fb(void *fb_data, int bits) { - flow3r_bsp_display_send_fb_osd(fb_data, bits, NULL, 0, 0, 0, 0); + flow3r_bsp_display_send_fb_osd(fb_data, bits, 1, NULL, 0, 0, 0, 0); } void flow3r_bsp_display_set_backlight(uint8_t percent) { diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.c b/components/flow3r_bsp/flow3r_bsp_gc9a01.c index 1ad9ed215f72d9cc2ca166ae7ede4e8ce66abc23..8b40e0dc6752b20054af2374abf29ebb00e579c9 100644 --- a/components/flow3r_bsp/flow3r_bsp_gc9a01.c +++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.c @@ -106,6 +106,7 @@ typedef struct { int osd_y1; uint16_t *pal_16; int bits; + int scale; size_t left; size_t off; // current pixel offset in blit @@ -618,9 +619,12 @@ static inline uint16_t ctx_565_pack(uint8_t red, uint8_t green, uint8_t blue, #define U8_LERP(a, b, t) ((a) + ((((b) - (a)) * t + 256) >> 8)) +extern uint8_t st3m_pal[256 * 3]; +EXT_RAM_BSS_ATTR static uint16_t st3m_pal16[256]; + static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, int pix_count) { - int scale = 1; + int scale = blit->scale; const uint8_t *fb = blit->fb; const uint8_t *osd_fb = blit->osd_fb; unsigned int start_off = blit->off; @@ -631,37 +635,56 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, /* XXX : this code has room for optimization */ if (osd_fb && (start_off < blit->osd_y1 * 240)) switch (blit->bits) { case 8: + case 9: for (unsigned int i = start_off; i < end_off; i++) { int x = i % 240; int y = i / 240; int j = ((y / scale) * 240) + x / scale; - temp_blit[o++] = blit->pal_16[U8_LERP( - fb[j], osd_fb[i * 4 + 1], osd_fb[i * 4 + 3])]; + int idx = fb[j]; + uint8_t r = (((idx >> 5) & 7) * 255) / 7; + uint8_t g = (((idx >> 2) & 7) * 255) / 7; + uint8_t b = + ((((idx & 3) << 1) | ((idx >> 2) & 1)) * 255) / 7; + + uint8_t ya = osd_fb[j * 4 + 3]; + + r = U8_LERP(r, osd_fb[j * 4 + 0], ya); + g = U8_LERP(g, osd_fb[j * 4 + 1], ya); + b = U8_LERP(b, osd_fb[j * 4 + 2], ya); + + idx = ((ctx_sadd8(r, 15) >> 5) << 5) | + ((ctx_sadd8(g, 15) >> 5) << 2) | + (ctx_sadd8(b, 15) >> 6); + + temp_blit[o++] = blit->pal_16[idx]; } break; case 24: for (unsigned int i = start_off; i < end_off; i++) { - uint8_t Y = osd_fb[i * 2]; - uint8_t ya = osd_fb[i * 2 + 1]; int x = i % 240; int y = i / 240; int j = ((y / scale) * 240) + x / scale; - uint8_t r = U8_LERP(fb[j * 3 + 0], Y, ya); - uint8_t g = U8_LERP(fb[j * 3 + 1], Y, ya); - uint8_t b = U8_LERP(fb[j * 3 + 2], Y, ya); + uint8_t Y = osd_fb[j * 2]; + uint8_t ya = osd_fb[j * 2 + 1]; + j *= 3; + uint8_t r = U8_LERP(fb[j + 0], Y, ya); + uint8_t g = U8_LERP(fb[j + 1], Y, ya); + uint8_t b = U8_LERP(fb[j + 2], Y, ya); temp_blit[o++] = ctx_565_pack(r, g, b, 1); } break; case 32: for (unsigned int i = start_off; i < end_off; i++) { - uint8_t Y = osd_fb[i * 2]; - uint8_t Ya = osd_fb[i * 2 + 1]; int x = i % 240; int y = i / 240; int j = ((y / scale) * 240) + x / scale; - uint8_t r = U8_LERP(fb[j * 4 + 0], Y, Ya); - uint8_t g = U8_LERP(fb[j * 4 + 1], Y, Ya); - uint8_t b = U8_LERP(fb[j * 4 + 2], Y, Ya); + j *= 2; + uint8_t Y = osd_fb[j]; + uint8_t Ya = osd_fb[j + 1]; + j *= 2; + uint8_t r = U8_LERP(fb[j + 0], Y, Ya); + uint8_t g = U8_LERP(fb[j + 1], Y, Ya); + uint8_t b = U8_LERP(fb[j + 2], Y, Ya); temp_blit[o++] = ctx_565_pack(r, g, b, 1); } break; @@ -673,10 +696,11 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, uint32_t col = ctx_565_unpack_32(((uint16_t *)fb)[j], 1); uint8_t *rgba = (uint8_t *)&col; - uint8_t sr = osd_fb[i * 4]; - uint8_t sg = osd_fb[i * 4 + 1]; - uint8_t sb = osd_fb[i * 4 + 2]; - uint8_t sa = osd_fb[i * 4 + 3]; + j *= 4; + uint8_t sr = osd_fb[j]; + uint8_t sg = osd_fb[j + 1]; + uint8_t sb = osd_fb[j + 2]; + uint8_t sa = osd_fb[j + 3]; uint8_t dr = U8_LERP(rgba[0], sr, sa); uint8_t dg = U8_LERP(rgba[1], sg, sa); uint8_t db = U8_LERP(rgba[2], sb, sa); @@ -695,6 +719,7 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, } break; case 8: + case 9: for (unsigned int i = start_off; i < end_off; i++) { int x = i % 240; int y = i / 240; @@ -724,18 +749,21 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, // blit->osd_fb = NULL; // blit->fb += ((end_off*blit->bits)/8); } - } else { + } + + else { // not scaled if (osd_fb && (start_off < blit->osd_y1 * 240)) switch (blit->bits) { -#if 0 - case 1: - for (unsigned int i = 0; i < pix_count; i++) - temp_blit[o++] = blit->pal_16[(fb[i / 8] >> ((i & 7))) & 0x1]; - break; - case 2: - for (unsigned int i = 0; i < pix_count; i++) - temp_blit[o++] = - blit->pal_16[(fb[i / 4] >> ((i & 3) * 2)) & 0x3]; - break; +#if 1 + case 1: + for (unsigned int i = start_off; i < end_off; i++) + temp_blit[o++] = + blit->pal_16[(fb[i / 8] >> ((i & 7))) & 0x1]; + break; + case 2: + for (unsigned int i = start_off; i < end_off; i++) + temp_blit[o++] = + blit->pal_16[(fb[i / 4] >> ((i & 3) * 2)) & 0x3]; + break; #endif case 4: for (unsigned int i = start_off; i < end_off; i++) { @@ -748,6 +776,26 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, temp_blit[o++] = blit->pal_16[U8_LERP( fb[i], osd_fb[i * 4 + 1], osd_fb[i * 4 + 3])]; break; + case 9: + for (unsigned int i = start_off; i < end_off; i++) { + int idx = fb[i]; + uint8_t r = (((idx >> 5) & 7) * 255) / 7; + uint8_t g = (((idx >> 2) & 7) * 255) / 7; + uint8_t b = + ((((idx & 3) << 1) | ((idx >> 2) & 1)) * 255) / 7; + uint8_t ya = osd_fb[i * 4 + 3]; + + r = U8_LERP(r, osd_fb[i * 4 + 0], ya); + g = U8_LERP(g, osd_fb[i * 4 + 1], ya); + b = U8_LERP(b, osd_fb[i * 4 + 2], ya); + + idx = ((ctx_sadd8(r, 15) >> 5) << 5) | + ((ctx_sadd8(g, 15) >> 5) << 2) | + (ctx_sadd8(b, 15) >> 6); + + temp_blit[o++] = blit->pal_16[idx]; + } + break; case 24: for (unsigned int i = start_off; i < end_off; i++) { uint8_t y = osd_fb[i * 2]; @@ -810,6 +858,7 @@ static void flow3r_bsp_prep_blit(flow3r_bsp_gc9a01_blit_t *blit, } break; case 8: + case 9: for (unsigned int i = start_off; i < end_off; i++) temp_blit[o++] = blit->pal_16[fb[i]]; break; @@ -837,7 +886,9 @@ static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) { size = SPI_MAX_DMA_LEN; } unsigned int pix_count = size / 2; - size_t osize = pix_count * blit->bits / 8; + int bits = blit->bits; + if (bits == 9) bits = 8; + size_t osize = pix_count * bits / 8; blit->gc9a01_tx.gc9a01 = blit->gc9a01; blit->gc9a01_tx.dc = 1; @@ -875,9 +926,9 @@ static esp_err_t flow3r_bsp_gc9a01_blit_next(flow3r_bsp_gc9a01_blit_t *blit) { static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01, flow3r_bsp_gc9a01_blit_t *blit, const uint16_t *fb, int bits, - const void *osd_fb, int osd_x0, - int osd_y0, int osd_x1, - int osd_y1) { + int scale, const void *osd_fb, + int osd_x0, int osd_y0, + int osd_x1, int osd_y1) { memset(blit, 0, sizeof(flow3r_bsp_gc9a01_blit_t)); blit->gc9a01 = gc9a01; @@ -888,10 +939,11 @@ static esp_err_t flow3r_bsp_gc9a01_blit_start(flow3r_bsp_gc9a01_t *gc9a01, blit->osd_x1 = osd_x1; blit->osd_y0 = osd_y0; blit->osd_y1 = osd_y1; + blit->scale = scale; blit->left = 2 * 240 * 240; // left in native bytes (16bpp) if (bits < 16) { - uint8_t *pal_24 = ((uint8_t *)fb) + 240 * 240 * 2 - 3 * 256; - blit->pal_16 = (uint16_t *)(pal_24 - 256 * 2); + uint8_t *pal_24 = st3m_pal; + blit->pal_16 = st3m_pal16; for (int i = 0; i < 256; i++) blit->pal_16[i] = ctx_565_pack(pal_24[i * 3 + 0], pal_24[i * 3 + 1], pal_24[i * 3 + 2], 1); @@ -915,12 +967,12 @@ static esp_err_t flow3r_bsp_gc9a01_blit_wait_done( } esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01, - const void *fb, int bits, + const void *fb, int bits, int scale, const void *osd_fb, int osd_x0, int osd_y0, int osd_x1, int osd_y1) { flow3r_bsp_gc9a01_blit_t blit; esp_err_t res = flow3r_bsp_gc9a01_blit_start( - gc9a01, &blit, fb, bits, osd_fb, osd_x0, osd_y0, osd_x1, osd_y1); + gc9a01, &blit, fb, bits, scale, osd_fb, osd_x0, osd_y0, osd_x1, osd_y1); if (res != ESP_OK) { return res; } @@ -940,5 +992,5 @@ esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01, esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01, const void *fb, int bits) { - return flow3r_bsp_gc9a01_blit_osd(gc9a01, fb, bits, NULL, 0, 0, 0, 0); + return flow3r_bsp_gc9a01_blit_osd(gc9a01, fb, bits, 1, NULL, 0, 0, 0, 0); } diff --git a/components/flow3r_bsp/flow3r_bsp_gc9a01.h b/components/flow3r_bsp/flow3r_bsp_gc9a01.h index 6ad1d631648f144b8a043ad9820eb0b6eef61e50..dfc2d197184c3ed059271cc1791d3dcb0de70a19 100644 --- a/components/flow3r_bsp/flow3r_bsp_gc9a01.h +++ b/components/flow3r_bsp/flow3r_bsp_gc9a01.h @@ -70,7 +70,7 @@ esp_err_t flow3r_bsp_gc9a01_init(flow3r_bsp_gc9a01_t *gc9a01, esp_err_t flow3r_bsp_gc9a01_blit_full(flow3r_bsp_gc9a01_t *gc9a01, const void *fb, int bits); esp_err_t flow3r_bsp_gc9a01_blit_osd(flow3r_bsp_gc9a01_t *gc9a01, - const void *fb, int bits, + const void *fb, int bits, int scale, const void *osd_fb, int osd_x0, int osd_y0, int osd_x1, int osd_y1); diff --git a/components/micropython/usermodule/mp_sys_display.c b/components/micropython/usermodule/mp_sys_display.c index 61f981a9e5b24350b44d4e96a8448cbd368766f3..806ed1ae1a9c2c277e7f76dace7bc84caa96a108 100644 --- a/components/micropython/usermodule/mp_sys_display.c +++ b/components/micropython/usermodule/mp_sys_display.c @@ -78,6 +78,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_ctx_obj, mp_ctx); STATIC mp_obj_t mp_fb(mp_obj_t mode_in) { int mode = mp_obj_get_int(mode_in); int size = 240 * 240 * st3m_gfx_bpp(mode) / 8; + if (mode == st3m_gfx_palette) size = 256 * 3; return mp_obj_new_bytearray_by_ref(size, st3m_gfx_fb(mode)); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_fb_obj, mp_fb); @@ -122,6 +123,26 @@ STATIC const mp_rom_map_elem_t mp_module_sys_display_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_set_palette), MP_ROM_PTR(&mp_set_palette_obj) }, { MP_ROM_QSTR(MP_QSTR_set_backlight), MP_ROM_PTR(&mp_set_backlight_obj) }, { MP_ROM_QSTR(MP_QSTR_overlay_clip), MP_ROM_PTR(&mp_overlay_clip_obj) }, + + { MP_ROM_QSTR(MP_QSTR_default), MP_ROM_INT((int)st3m_gfx_default) }, + { MP_ROM_QSTR(MP_QSTR_rgb332), MP_ROM_INT((int)st3m_gfx_rgb332) }, + { MP_ROM_QSTR(MP_QSTR_sepia), MP_ROM_INT((int)st3m_gfx_sepia) }, + { MP_ROM_QSTR(MP_QSTR_cool), MP_ROM_INT((int)st3m_gfx_cool) }, + { MP_ROM_QSTR(MP_QSTR_low_latency), MP_ROM_INT((int)st3m_gfx_low_latency) }, + { MP_ROM_QSTR(MP_QSTR_direct_ctx), MP_ROM_INT((int)st3m_gfx_direct_ctx) }, + { MP_ROM_QSTR(MP_QSTR_unset), MP_ROM_INT((int)st3m_gfx_unset) }, + { MP_ROM_QSTR(MP_QSTR_force), MP_ROM_INT((int)st3m_gfx_force) }, + { MP_ROM_QSTR(MP_QSTR_x2), MP_ROM_INT((int)st3m_gfx_2x) }, + { MP_ROM_QSTR(MP_QSTR_x3), MP_ROM_INT((int)st3m_gfx_3x) }, + { MP_ROM_QSTR(MP_QSTR_x4), MP_ROM_INT((int)st3m_gfx_4x) }, + { MP_ROM_QSTR(MP_QSTR_bpp1), MP_ROM_INT((int)st3m_gfx_1bpp) }, + { MP_ROM_QSTR(MP_QSTR_bpp2), MP_ROM_INT((int)st3m_gfx_2bpp) }, + { MP_ROM_QSTR(MP_QSTR_bpp4), MP_ROM_INT((int)st3m_gfx_4bpp) }, + { MP_ROM_QSTR(MP_QSTR_bpp8), MP_ROM_INT((int)st3m_gfx_8bpp) }, + { MP_ROM_QSTR(MP_QSTR_bpp16), MP_ROM_INT((int)st3m_gfx_16bpp) }, + { MP_ROM_QSTR(MP_QSTR_bpp24), MP_ROM_INT((int)st3m_gfx_24bpp) }, + { MP_ROM_QSTR(MP_QSTR_osd), MP_ROM_INT((int)st3m_gfx_osd) }, + { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_INT((int)st3m_gfx_palette) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_sys_display_globals, diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c index 23bcfe09d7eba09f993b327a1ca3d097fa7caa41..89c42f52630d09a8ac46ffb1b046458073ba01db 100644 --- a/components/st3m/st3m_gfx.c +++ b/components/st3m/st3m_gfx.c @@ -26,7 +26,14 @@ static st3m_gfx_mode default_mode = ST3M_GFX_DEFAULT_MODE; // if the EXT_RAM_BSS_ATTR is removed 8bit and 16bit modes go // faster but it is not possible to enable wifi + +#if CTX_ST3M_FB_INTERNAL_RAM +static uint16_t st3m_fb[240 * 240]; +uint8_t st3m_pal[256 * 3]; +#else EXT_RAM_BSS_ATTR static uint16_t st3m_fb[240 * 240]; +EXT_RAM_BSS_ATTR uint8_t st3m_pal[256 * 3]; +#endif // Get a free drawlist ctx to draw into. // @@ -58,6 +65,7 @@ EXT_RAM_BSS_ATTR static uint8_t static Ctx *fb_GRAY8_ctx = NULL; static Ctx *fb_GRAYA8_ctx = NULL; static Ctx *fb_RGB565_BS_ctx = NULL; +static Ctx *fb_RGB332_ctx = NULL; static Ctx *fb_RGBA8_ctx = NULL; static Ctx *fb_RGB8_ctx = NULL; @@ -90,6 +98,19 @@ static TaskHandle_t graphics_task; static int _st3m_gfx_low_latency = 0; +static int st3m_gfx_scale(void) { + st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; + switch ((int)(set_mode & st3m_gfx_4x)) { + case st3m_gfx_4x: + return 4; + case st3m_gfx_3x: + return 3; + case st3m_gfx_2x: + return 2; + } + return 1; +} + /////////////////////////////////////////////////////// // get the bits per pixel for a given mode @@ -99,11 +120,12 @@ int st3m_gfx_bpp(st3m_gfx_mode mode) { mode = set_mode; } else if (mode == st3m_gfx_osd) { if ((st3m_gfx_bpp(set_mode) == 16) || (st3m_gfx_bpp(set_mode) == 8)) - return 4; + return 32; else - return 2; + return 16; } - return (mode & (4 | 8 | 16 | 24 | 32)); + if ((mode & 0xf) == 4) return 4; + return (mode & (8 | 16 | 24 | 32)); } static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode) { @@ -131,21 +153,35 @@ static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode) { } return ctx; } + +void st3m_gfx_viewport_transform(Ctx *ctx) { + int scale = st3m_gfx_scale(); + int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2 / scale; + int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2 / scale; + ctx_identity(ctx); // this might break/need revisiting with tiled rendering + ctx_apply_transform(ctx, 1.0 / scale, 0, offset_x, 0, 1.0 / scale, offset_y, + 0, 0, 1); +} + +void st3m_gfx_start_frame(Ctx *ctx) { + int scale = st3m_gfx_scale(); + ctx_save(ctx); + st3m_gfx_viewport_transform(ctx); + if (scale) { + ctx_rectangle(ctx, -120, -120, 240, 240); + ctx_clip(ctx); + } +} + Ctx *st3m_gfx_ctx(st3m_gfx_mode mode) { Ctx *ctx = st3m_gfx_ctx_int(mode); if (mode == st3m_gfx_osd) { pthread_mutex_lock(&st3m_osd_mutex); } + st3m_gfx_start_frame(ctx); return ctx; } -void st3m_gfx_viewport_transform(Ctx *ctx) { - int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2; - int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2; - ctx_identity(ctx); // this might break/need revisiting with tiled rendering - ctx_apply_transform(ctx, 1, 0, offset_x, 0, 1, offset_y, 0, 0, 1); -} - // Attempt to receive from a queue forever, but log an error if it takes longer // than two seconds to get something. static void xQueueReceiveNotifyStarved(QueueHandle_t q, void *dst, @@ -167,72 +203,109 @@ float st3m_gfx_fps(void) { return smoothed_fps; } void st3m_gfx_set_palette(uint8_t *pal_in, int count) { if (count > 256) count = 256; if (count < 0) count = 0; - uint8_t *pal = ((uint8_t *)st3m_fb) + sizeof(st3m_fb) - 256 * 3; - for (int i = 0; i < count * 3; i++) pal[i] = pal_in[i]; -} - -static void ega_palette(void) { - uint8_t pal[16 * 3]; - int idx = 0; - for (int i = 0; i < 2; i++) - for (int r = 0; r < 2; r++) - for (int g = 0; g < 2; g++) - for (int b = 0; b < 2; b++) { - pal[idx++] = (r * 127) * (i * 2); - pal[idx++] = (g * 127) * (i * 2); - pal[idx++] = (b * 127) * (i * 2); - } - st3m_gfx_set_palette(pal, 16); + for (int i = 0; i < count * 3; i++) st3m_pal[i] = pal_in[i]; } -static void gray_palette(void) { - uint8_t pal[256 * 3]; - for (int i = 0; i < 256; i++) { - pal[i * 3 + 0] = i; - pal[i * 3 + 1] = i; - pal[i * 3 + 2] = i; - } - st3m_gfx_set_palette(pal, 256); -} - -static void sepia_palette(void) { - uint8_t pal[256 * 3]; - for (int i = 0; i < 256; i++) { - pal[i * 3 + 0] = i; - pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255; - pal[i * 3 + 2] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255; +void st3m_gfx_set_default_mode(st3m_gfx_mode mode) { + if (mode & st3m_gfx_unset) { + if (mode & st3m_gfx_force) + default_mode &= ~st3m_gfx_force; + else if (mode & st3m_gfx_4x) + default_mode &= ~st3m_gfx_4x; + else if (mode & st3m_gfx_osd) + default_mode &= ~st3m_gfx_osd; + else if (mode & st3m_gfx_low_latency) + default_mode &= ~st3m_gfx_low_latency; + else if (mode & st3m_gfx_direct_ctx) + default_mode &= ~st3m_gfx_direct_ctx; + } else if (mode == st3m_gfx_2x) { + default_mode &= ~st3m_gfx_4x; + default_mode |= st3m_gfx_2x; + } else if (mode == st3m_gfx_3x) { + default_mode &= ~st3m_gfx_4x; + default_mode |= st3m_gfx_3x; + } else if (mode == st3m_gfx_4x) { + default_mode &= ~st3m_gfx_4x; + default_mode |= st3m_gfx_4x; + } else if (mode == st3m_gfx_2x + st3m_gfx_low_latency) { + default_mode |= st3m_gfx_2x; + default_mode |= st3m_gfx_low_latency; + } else if (mode == st3m_gfx_osd + st3m_gfx_low_latency) { + default_mode |= st3m_gfx_osd; + default_mode |= st3m_gfx_low_latency; + } else if (mode == st3m_gfx_osd) { + default_mode |= st3m_gfx_osd; + } else if (mode == st3m_gfx_low_latency) { + default_mode |= st3m_gfx_low_latency; + } else if (mode == st3m_gfx_force) { + default_mode |= st3m_gfx_force; + } else if (mode == st3m_gfx_direct_ctx) { + default_mode |= st3m_gfx_direct_ctx; + } else + default_mode = mode; + + if (default_mode & st3m_gfx_force) { + default_mode &= ~st3m_gfx_force; + _st3m_gfx_mode = default_mode + 1; + st3m_gfx_set_mode(st3m_gfx_default); + default_mode |= st3m_gfx_force; + } else { + _st3m_gfx_mode = default_mode + 1; + st3m_gfx_set_mode(st3m_gfx_default); } - st3m_gfx_set_palette(pal, 256); } -static void cool_palette(void) { - uint8_t pal[256 * 3]; - for (int i = 0; i < 256; i++) { - pal[i * 3 + 0] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255; - pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255; - pal[i * 3 + 2] = i; +static void st3m_gfx_init_palette(st3m_gfx_mode mode) { + switch (mode & 0xf) { + case 4: { + int idx = 0; + for (int i = 0; i < 2; i++) + for (int r = 0; r < 2; r++) + for (int g = 0; g < 2; g++) + for (int b = 0; b < 2; b++) { + st3m_pal[idx++] = (r * 127) * (i * 2); + st3m_pal[idx++] = (g * 127) * (i * 2); + st3m_pal[idx++] = (b * 127) * (i * 2); + } + } break; + case 8: // grayscale + for (int i = 0; i < 256; i++) { + st3m_pal[i * 3 + 0] = i; + st3m_pal[i * 3 + 1] = i; + st3m_pal[i * 3 + 2] = i; + } + break; + case st3m_gfx_rgb332: + for (int i = 0; i < 256; i++) { + st3m_pal[i * 3 + 0] = (((i >> 5) & 7) * 255) / 7; + st3m_pal[i * 3 + 1] = (((i >> 2) & 7) * 255) / 7; + st3m_pal[i * 3 + 2] = + ((((i & 3) << 1) | ((i >> 2) & 1)) * 255) / 7; + } + break; + case st3m_gfx_sepia: + for (int i = 0; i < 256; i++) { + st3m_pal[i * 3 + 0] = i; + st3m_pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255; + st3m_pal[i * 3 + 2] = + (i / 255.0) * (i / 255.0) * (i / 255.0) * 255; + } + break; + case st3m_gfx_cool: + for (int i = 0; i < 256; i++) { + st3m_pal[i * 3 + 0] = + (i / 255.0) * (i / 255.0) * (i / 255.0) * 255; + st3m_pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255; + st3m_pal[i * 3 + 2] = i; + } + break; } - st3m_gfx_set_palette(pal, 256); } -static void red_palette(void) { - uint8_t pal[256 * 3]; - for (int i = 0; i < 256; i++) { - pal[i * 3 + 0] = i < 64 ? (i * 4) : 255; - pal[i * 3 + 1] = (i / 255.0) * (i / 255.0) * 255; - pal[i * 3 + 2] = (i / 255.0) * (i / 255.0) * (i / 255.0) * 255; +st3m_gfx_mode st3m_gfx_set_mode(st3m_gfx_mode mode) { + if ((mode == _st3m_gfx_mode) || (0 != (default_mode & st3m_gfx_force))) { + return (mode ? mode : default_mode); } - st3m_gfx_set_palette(pal, 256); -} - -void st3m_gfx_set_default_mode(st3m_gfx_mode mode) { - default_mode = mode; - _st3m_gfx_mode = default_mode + 1; - st3m_gfx_set_mode(st3m_gfx_default); -} - -void st3m_gfx_set_mode(st3m_gfx_mode mode) { - if (mode == _st3m_gfx_mode) return; memset(st3m_fb, 0, sizeof(st3m_fb)); memset(st3m_osd_fb, 0, sizeof(st3m_osd_fb)); @@ -244,30 +317,9 @@ void st3m_gfx_set_mode(st3m_gfx_mode mode) { else if (mode == st3m_gfx_osd) mode = default_mode | st3m_gfx_osd; - switch (mode & 0xf) { - case 4: - ega_palette(); - break; - case 8: - sepia_palette(); - break; - case 9: - red_palette(); - break; - case 10: - gray_palette(); - break; - case 11: - cool_palette(); - break; - } + st3m_gfx_init_palette(mode); - if (mode == default_mode) - _st3m_gfx_mode = st3m_gfx_default; - else if (mode == (default_mode + st3m_gfx_low_latency)) - _st3m_gfx_mode = st3m_gfx_low_latency; - else - _st3m_gfx_mode = mode; + _st3m_gfx_mode = (mode == default_mode) ? st3m_gfx_default : mode; _st3m_gfx_low_latency = ((mode & st3m_gfx_low_latency) != 0); switch ((int)mode) { @@ -278,13 +330,16 @@ void st3m_gfx_set_mode(st3m_gfx_mode mode) { case st3m_gfx_24bpp_direct_ctx: _st3m_gfx_low_latency = 1; } + return mode; } st3m_gfx_mode st3m_gfx_get_mode(void) { return _st3m_gfx_mode; } uint8_t *st3m_gfx_fb(st3m_gfx_mode mode) { st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - if (mode == st3m_gfx_default) { + if (mode == st3m_gfx_palette) { + return st3m_pal; + } else if (mode == st3m_gfx_default) { if (st3m_gfx_bpp(set_mode) <= 16) return (uint8_t *)st3m_fb; return st3m_osd_fb; } else if (mode == st3m_gfx_osd) { @@ -310,6 +365,7 @@ static void st3m_gfx_task(void *_arg) { ctx_set_textureclock(fb_RGB565_BS_ctx, ctx_textureclock(fb_RGB565_BS_ctx) + 1); ctx_set_textureclock(fb_RGBA8_ctx, ctx_textureclock(fb_RGB565_BS_ctx)); + ctx_set_textureclock(fb_RGB332_ctx, ctx_textureclock(fb_RGB565_BS_ctx)); ctx_set_textureclock(fb_RGB8_ctx, ctx_textureclock(fb_RGB565_BS_ctx)); ctx_set_textureclock(fb_GRAY8_ctx, ctx_textureclock(fb_RGB565_BS_ctx)); ctx_set_textureclock(fb_GRAYA8_ctx, ctx_textureclock(fb_RGB565_BS_ctx)); @@ -320,11 +376,16 @@ static void st3m_gfx_task(void *_arg) { void *user_fb = st3m_fb; void *osd_fb = st3m_osd_fb; int bits = st3m_gfx_bpp(set_mode); + switch (bits) { case 4: break; case 8: - user_target = fb_GRAY8_ctx; + case 9: + if ((set_mode & 0xf) == 9) + user_target = fb_RGB332_ctx; + else + user_target = fb_GRAY8_ctx; break; case 24: user_target = fb_RGB8_ctx; @@ -337,14 +398,26 @@ static void st3m_gfx_task(void *_arg) { osd_fb = st3m_fb; break; } + if ((set_mode & 0xf) == st3m_gfx_rgb332) bits = 9; + + int scale = st3m_gfx_scale(); + static int prev_scale = -1; + if (prev_scale != scale) { + st3m_gfx_viewport_transform(fb_GRAY8_ctx); + st3m_gfx_viewport_transform(fb_GRAYA8_ctx); + st3m_gfx_viewport_transform(fb_RGB565_BS_ctx); + st3m_gfx_viewport_transform(fb_RGB332_ctx); + st3m_gfx_viewport_transform(fb_RGBA8_ctx); + st3m_gfx_viewport_transform(fb_RGB8_ctx); + } if ((set_mode & st3m_gfx_direct_ctx) == 0) ctx_render_ctx(drawlist->user_ctx, user_target); - if ((set_mode & st3m_gfx_osd) && - (drawlist->osd_y0 != drawlist->osd_y1)) { + if (scale || ((set_mode & st3m_gfx_osd) && + (drawlist->osd_y0 != drawlist->osd_y1))) { pthread_mutex_lock(&st3m_osd_mutex); - flow3r_bsp_display_send_fb_osd(user_fb, bits, osd_fb, + flow3r_bsp_display_send_fb_osd(user_fb, bits, scale, osd_fb, drawlist->osd_x0, drawlist->osd_y0, drawlist->osd_x1, drawlist->osd_y1); pthread_mutex_unlock(&st3m_osd_mutex); @@ -618,6 +691,9 @@ void st3m_gfx_init(void) { fb_GRAY8_ctx = ctx_new_for_framebuffer( st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, FLOW3R_BSP_DISPLAY_WIDTH, CTX_FORMAT_GRAY8); + fb_RGB332_ctx = ctx_new_for_framebuffer( + st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, + FLOW3R_BSP_DISPLAY_WIDTH, CTX_FORMAT_RGB332); fb_GRAYA8_ctx = ctx_new_for_framebuffer( st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, FLOW3R_BSP_DISPLAY_WIDTH * 2, CTX_FORMAT_GRAYA8); @@ -635,6 +711,7 @@ void st3m_gfx_init(void) { assert(fb_RGB565_BS_ctx != NULL); assert(fb_RGBA8_ctx != NULL); assert(fb_RGB8_ctx != NULL); + assert(fb_RGB332_ctx != NULL); st3m_gfx_viewport_transform(fb_GRAY8_ctx); st3m_gfx_viewport_transform(fb_GRAYA8_ctx); @@ -642,6 +719,8 @@ void st3m_gfx_init(void) { st3m_gfx_viewport_transform(fb_RGBA8_ctx); st3m_gfx_viewport_transform(fb_RGB8_ctx); + ctx_set_texture_source(fb_RGB332_ctx, fb_RGB565_BS_ctx); + ctx_set_texture_cache(fb_RGB332_ctx, fb_RGB565_BS_ctx); ctx_set_texture_source(fb_RGBA8_ctx, fb_RGB565_BS_ctx); ctx_set_texture_cache(fb_RGBA8_ctx, fb_RGB565_BS_ctx); ctx_set_texture_source(fb_RGB8_ctx, fb_RGB565_BS_ctx); @@ -696,6 +775,7 @@ static void st3m_gfx_pipe_put(void) { static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode); void st3m_gfx_end_frame(Ctx *ctx) { + ctx_restore(ctx); if (ctx == st3m_gfx_ctx_int(st3m_gfx_osd)) { pthread_mutex_unlock(&st3m_osd_mutex); return; diff --git a/components/st3m/st3m_gfx.h b/components/st3m/st3m_gfx.h index 038e072a94db4f7880ef33d26ce8f13b33bd4d36..cd9dcc1aa0672913e7cb9d0db1d6604c8a317168 100644 --- a/components/st3m/st3m_gfx.h +++ b/components/st3m/st3m_gfx.h @@ -17,13 +17,23 @@ typedef enum { // shallower pipeline, in the future might mean immediate mode st3m_gfx_low_latency = 512, st3m_gfx_unset = 1024, + st3m_gfx_force = 8192, + st3m_gfx_2x = 2048, + st3m_gfx_3x = 4096, + st3m_gfx_4x = 6144, // 4 and 8bpp modes use the configured palette, the palette resides // in video ram and is lost upon mode change + st3m_gfx_1bpp = 1, + st3m_gfx_2bpp = 2, st3m_gfx_4bpp = 4, // a flag for modes >4bpp requesting that ctx calls are direct, this is // slower since micropython cannot run in parallell with rasterization. st3m_gfx_8bpp = 8, + st3m_gfx_palette = 10, st3m_gfx_8bpp_osd = 8 + st3m_gfx_osd, + st3m_gfx_rgb332 = 9, + st3m_gfx_sepia = 10, + st3m_gfx_cool = 11, st3m_gfx_8bpp_direct_ctx = 8 + st3m_gfx_direct_ctx, st3m_gfx_8bpp_low_latency = 8 + st3m_gfx_low_latency, st3m_gfx_8bpp_osd_low_latency = 8 + st3m_gfx_osd + st3m_gfx_low_latency, @@ -52,7 +62,7 @@ typedef enum { void st3m_gfx_set_default_mode(st3m_gfx_mode mode); // sets the current graphics mode -void st3m_gfx_set_mode(st3m_gfx_mode mode); +st3m_gfx_mode st3m_gfx_set_mode(st3m_gfx_mode mode); // gets the current graphics mode st3m_gfx_mode st3m_gfx_get_mode(void); diff --git a/python_payload/st3m/run.py b/python_payload/st3m/run.py index 6816ac113d3a30b46854e644fd0e4b7cd87c3e21..24ff5eab2ffc2ca2ede3ed6a98f44c91d4cab107 100644 --- a/python_payload/st3m/run.py +++ b/python_payload/st3m/run.py @@ -135,54 +135,6 @@ def run_app(klass): run_view(klass(ApplicationContext())) -# 256 is overlay -# - - -def _8bpp() -> None: - sys_display.set_default_mode(8 + 256) - - -def _8bpp_pal1() -> None: - sys_display.set_default_mode(9 + 256) - - -def _8bpp_pal2() -> None: - sys_display.set_default_mode(10 + 256) - - -def _8bpp_pal3() -> None: - sys_display.set_default_mode(11 + 256) - - -def _8bpp_RGB332() -> None: - sys_display.set_default_mode(12 + 256) - - -def _8bpp_3x() -> None: - sys_display.set_default_mode(8 + 256 + 4096) - - -def _8bpp_low_latency() -> None: - sys_display.set_default_mode(8 + 256 + 512) - - -def _16bpp_low_latency() -> None: - sys_display.set_default_mode(16 + 256 + 512) - - -def _16bpp() -> None: - sys_display.set_default_mode(16 + 256) - - -def _24bpp() -> None: - sys_display.set_default_mode(24 + 256) - - -def _32bpp() -> None: - sys_display.set_default_mode(32 + 256) - - def _yeet_local_changes() -> None: os.remove("/flash/sys/.sys-installed") machine.reset() @@ -216,17 +168,80 @@ def run_main() -> None: menu_gfx = SimpleMenu( [ MenuItemBack(), - MenuItemForeground("Graphics Mode", menu_settings), - MenuItemAction("8bpp", _8bpp), - MenuItemAction("8bpp-low latency", _8bpp_low_latency), - # MenuItemAction("8bpp_3x", _8bpp_3x), - MenuItemAction("16bpp", _16bpp), - MenuItemAction("16bpp-low latency", _16bpp_low_latency), - MenuItemAction("24bpp", _24bpp), - MenuItemAction("8bpp Red", _8bpp_pal1), - MenuItemAction("8bpp Grayscale", _8bpp_pal2), - MenuItemAction("8bpp Cool", _8bpp_pal3), - MenuItemAction("8bpp RGB332", _8bpp_RGB332), + MenuItemAction( + "RGB565_BS", lambda: sys_display.set_default_mode(16 + sys_display.osd) + ), + MenuItemAction( + "RGB888", lambda: sys_display.set_default_mode(24 + sys_display.osd) + ), + MenuItemAction( + "RGB332", + lambda: sys_display.set_default_mode( + sys_display.rgb332 + sys_display.osd + ), + ), + MenuItemAction( + "gray", lambda: sys_display.set_default_mode(8 + sys_display.osd) + ), + MenuItemAction( + "sepia", + lambda: sys_display.set_default_mode( + sys_display.sepia + sys_display.osd + ), + ), + MenuItemAction( + "cool", + lambda: sys_display.set_default_mode( + sys_display.cool + sys_display.osd + ), + ), + MenuItemAction( + "1x", + lambda: sys_display.set_default_mode( + sys_display.unset + sys_display.x4 + ), + ), + MenuItemAction("2x", lambda: sys_display.set_default_mode(sys_display.x2)), + MenuItemAction("3x", lambda: sys_display.set_default_mode(sys_display.x3)), + MenuItemAction("4x", lambda: sys_display.set_default_mode(sys_display.x4)), + MenuItemAction( + "osd on", lambda: sys_display.set_default_mode(sys_display.osd) + ), + MenuItemAction( + "osd off", + lambda: sys_display.set_default_mode( + sys_display.unset + sys_display.osd + ), + ), + MenuItemAction( + "high fps", + lambda: sys_display.set_default_mode( + sys_display.unset + sys_display.low_latency + ), + ), + MenuItemAction( + "low-latency", + lambda: sys_display.set_default_mode(sys_display.low_latency), + ), + MenuItemAction( + "drawlists", + lambda: sys_display.set_default_mode( + sys_display.unset + sys_display.direct_ctx + ), + ), + MenuItemAction( + "direct ctx", + lambda: sys_display.set_default_mode(sys_display.direct_ctx), + ), + MenuItemAction( + "force mode", lambda: sys_display.set_default_mode(sys_display.force) + ), + MenuItemAction( + "force mode off", + lambda: sys_display.set_default_mode( + sys_display.unset + sys_display.force + ), + ), ], ) menu_system = SimpleMenu(