diff --git a/components/ctx/ctx.c b/components/ctx/ctx.c index 56d8a15..7553cf1 100644 --- a/components/ctx/ctx.c +++ b/components/ctx/ctx.c @@ -11,5 +11,11 @@ #ifdef CONFIG_FLOW3R_CTX_FLAVOUR_FULL #endif +int mp_ctx_vfs_load_file (const char *path, + unsigned char **contents, + long *length, + long max_length); +#define CTX_LOAD_FILE mp_ctx_vfs_load_file + #define CTX_IMPLEMENTATION #include "ctx.h" diff --git a/components/ctx/ctx.h b/components/ctx/ctx.h index 29ea5f4..b0225e7 100644 --- a/components/ctx/ctx.h +++ b/components/ctx/ctx.h @@ -5412,6 +5412,9 @@ static inline CtxList *ctx_list_find_custom (CtxList *list, #define CTX_ENABLE_FLOAT 1 #endif +#ifndef CTX_LOAD_FILE +#define CTX_LOAD_FILE ___ctx_file_get_contents +#endif /* enable cmykf which is cmyk intermediate format */ @@ -34464,14 +34467,6 @@ ___ctx_file_get_contents (const char *path, return 0; } -static int -__ctx_file_get_contents (const char *path, - unsigned char **contents, - long *length) -{ - return ___ctx_file_get_contents (path, contents, length, 1024*1024*1024); -} - #if !__COSMOPOLITAN__ #include #endif @@ -53075,11 +53070,13 @@ ctx_texture_load (Ctx *ctx, const char *path, int *tw, int *th, char *reid) int w, h, components; unsigned char *pixels = NULL; +#if 0 if (path[0] == '/' || !strncmp (path, "file://", 7)) { pixels = stbi_load (path + (path[0]=='/'?0:7), &w, &h, &components, 0); } else +#endif { unsigned char *data = NULL; long length = 0; @@ -54934,7 +54931,7 @@ ctx_get_contents2 (const char *uri, } if (!strncmp (uri, "file://", 7)) - success = ___ctx_file_get_contents (uri + 7, contents, length, max_len); + success = CTX_LOAD_FILE (uri + 7, contents, length, max_len); #ifdef ITK_HAVE_FS else if (!strncmp (uri, "itk:", 4)) { @@ -54973,7 +54970,7 @@ ctx_get_contents2 (const char *uri, success = 0; } #else - success = ___ctx_file_get_contents (uri, contents, length, max_len); + success = CTX_LOAD_FILE (uri, contents, length, max_len); #endif } ctx_free (temp_uri); @@ -54989,7 +54986,7 @@ ctx_get_contents (const char *uri, return ctx_get_contents2 (uri, contents, length, 1024*1024*1024); } - +#if 0 typedef struct CtxMagicEntry { int is_text; @@ -55255,6 +55252,7 @@ CtxMediaTypeClass ctx_media_type_class (const char *media_type) } return ret; } +#endif #else int diff --git a/components/ctx/ctx_config.h b/components/ctx/ctx_config.h index 6da8716..ae6d988 100644 --- a/components/ctx/ctx_config.h +++ b/components/ctx/ctx_config.h @@ -38,6 +38,7 @@ #define CTX_TILED 0 #define CTX_BAREMETAL 1 #define CTX_ONE_FONT_ENGINE 1 +#define CTX_GET_CONTENTS 1 #define CTX_MAX_SCANLINE_LENGTH 960 #define CTX_MAX_JOURNAL_SIZE (1024*512) diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c index 13e3197..563d322 100644 --- a/components/st3m/st3m_gfx.c +++ b/components/st3m/st3m_gfx.c @@ -6,9 +6,6 @@ #include "esp_system.h" #include "esp_task.h" #include "esp_timer.h" -#include "freertos/FreeRTOS.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" // clang-format off #include "ctx_config.h" @@ -20,658 +17,17 @@ #include "st3m_counter.h" #include "st3m_version.h" -#define ST3M_GFX_BLIT_TASK 1 +void tildagon_start_frame (Ctx *ctx); +Ctx *tildagon_gfx_ctx (void); +void tildagon_blit_fb (void); +void tildagon_end_frame (Ctx *ctx); -#if CTX_ST3M_FB_INTERNAL_RAM -#undef ST3M_GFX_BLIT_TASK -#define ST3M_GFX_BLIT_TASK 0 -#endif - - -#define ST3M_GFX_DEFAULT_MODE (16 | st3m_gfx_osd) - -static st3m_gfx_mode default_mode = ST3M_GFX_DEFAULT_MODE; - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL -EXT_RAM_BSS_ATTR static uint8_t - st3m_fb2[FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT * 4]; -#endif - -#if CTX_ST3M_FB_INTERNAL_RAM -// without EXT_RAM_BSS_ATTR is removed 8bit and 16bit modes go -// faster but it is not possible to enable wifi -static uint16_t st3m_fb[FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT]; -uint8_t st3m_pal[256 * 3]; -#else -EXT_RAM_BSS_ATTR uint8_t st3m_pal[256 * 3]; -EXT_RAM_BSS_ATTR static uint8_t - st3m_fb[FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT * 4]; -#endif - -#if ST3M_GFX_BLIT_TASK -EXT_RAM_BSS_ATTR static uint8_t - st3m_fb_copy[FLOW3R_BSP_DISPLAY_WIDTH * FLOW3R_BSP_DISPLAY_HEIGHT * 2]; -#endif - -EXT_RAM_BSS_ATTR static uint8_t scratch[40 * 1024]; - -// Get a free drawlist ctx to draw into. -// -// ticks_to_wait can be used to limit the time to wait for a free ctx -// descriptor, or portDELAY_MAX can be specified to wait forever. If the timeout -// expires, NULL will be returned. -static Ctx *st3m_gfx_drawctx_free_get(TickType_t ticks_to_wait); - -// Submit a filled ctx descriptor to the rasterization pipeline. -static void st3m_gfx_pipe_put(void); - -static const char *TAG = "st3m-gfx"; - -#define N_DRAWLISTS 3 - -// we keep the OSD buffer the same size as the main framebuffer, -// allowing us to do different combos of which buffer is osd and not - -static st3m_gfx_mode _st3m_gfx_mode = st3m_gfx_default + 1; - -static Ctx *ctx = NULL; -// each frame buffer has an associated rasterizer context -static Ctx *fb_ctx = NULL; -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL -static Ctx *osd_ctx = NULL; - -#define ST3M_OSD_LOCK_TIMEOUT 500 -SemaphoreHandle_t st3m_osd_lock; -#endif - -SemaphoreHandle_t st3m_fb_lock; -SemaphoreHandle_t st3m_fb_copy_lock; - -typedef struct { - Ctx *user_ctx; - - int osd_y0; - int osd_x0; - int osd_y1; - int osd_x1; - - int blit_x; // upper left pixel in framebuffer coordinates - int blit_y; // - - st3m_gfx_mode mode; - uint8_t *blit_src; -} st3m_gfx_drawlist; -static st3m_gfx_drawlist drawlists[N_DRAWLISTS]; - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL -static int _st3m_osd_y1 = - 0; // the corner coordinates of the part of osd that needs to -static int _st3m_osd_x1 = 0; // be composited - more might be composited -static int _st3m_osd_y0 = 0; -static int _st3m_osd_x0 = 0; -#endif +uint8_t st3m_pal[256 * 3]; // XXX - unused static float smoothed_fps = 0.0f; -static QueueHandle_t user_ctx_freeq = NULL; -static QueueHandle_t user_ctx_rastq = NULL; -static QueueHandle_t user_ctx_blitq = NULL; - static st3m_counter_rate_t rast_rate; -static TaskHandle_t graphics_rast_task; -#if ST3M_GFX_BLIT_TASK -static TaskHandle_t graphics_blit_task; -#endif - -static int _st3m_gfx_low_latency = 0; - -static int st3m_gfx_fb_width = 0; -static int st3m_gfx_fb_height = 0; -static int st3m_gfx_blit_x = 0; -static int st3m_gfx_blit_y = 0; -static int st3m_gfx_geom_dirty = 0; - -static inline int st3m_gfx_scale(st3m_gfx_mode mode) { - switch ((int)(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 -static inline int _st3m_gfx_bpp(st3m_gfx_mode mode) { - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - if (mode == st3m_gfx_default) { - mode = set_mode; - } else if (mode == st3m_gfx_osd) { - if ((st3m_gfx_bpp(set_mode) == 16) || (st3m_gfx_bpp(set_mode) == 8)) - return 32; - else - return 16; - } - int bpp = (mode & 63); - if (bpp >= 2 && bpp < 4) bpp = 2; - if (bpp >= 4 && bpp < 8) bpp = 4; - if (bpp >= 8 && bpp < 16) bpp = 8; - return bpp; -} -int st3m_gfx_bpp(st3m_gfx_mode mode) { return _st3m_gfx_bpp(mode); } - -static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode) { - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - if (mode == st3m_gfx_osd) { - if ((_st3m_gfx_bpp(set_mode) == 16) || (st3m_gfx_bpp(set_mode) == 8)) - return osd_ctx; - return osd_ctx; - } -#endif - Ctx *ctx = st3m_gfx_drawctx_free_get(1000); - - if (set_mode & st3m_gfx_direct_ctx) { - if (set_mode & st3m_gfx_smart_redraw) return ctx; - return fb_ctx; - } - - if (!ctx) return NULL; - return ctx; -} - -static void st3m_gfx_viewport_transform(Ctx *ctx, int reset) { - int scale = st3m_gfx_scale(_st3m_gfx_mode ? _st3m_gfx_mode : default_mode); - int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2 / scale; - int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2 / scale; - if (reset) - 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); -} - -static void st3m_gfx_start_frame(Ctx *ctx) { - int scale = st3m_gfx_scale(_st3m_gfx_mode); - if (scale > 1) { - 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 CONFIG_FLOW3R_CTX_FLAVOUR_FULL - if (mode == st3m_gfx_osd) { - xSemaphoreTake(st3m_osd_lock, - ST3M_OSD_LOCK_TIMEOUT / portTICK_PERIOD_MS); - } -#endif - ctx_save(ctx); - if (mode != st3m_gfx_osd) st3m_gfx_viewport_transform(ctx, 0); - st3m_gfx_start_frame(ctx); - return ctx; -} - -// 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, - const char *desc) { - uint8_t starved = 0; - for (;;) { - if (xQueueReceive(q, dst, pdMS_TO_TICKS(2000)) == pdTRUE) { - return; - } - if (!starved) { - ESP_LOGI(TAG, "%s", desc); - starved = 1; - } - } -} - -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; - for (int i = 0; i < count * 3; i++) st3m_pal[i] = pal_in[i]; -} - -void st3m_gfx_set_default_mode(st3m_gfx_mode mode) { - if ((mode & (1 | 2 | 4 | 8 | 16 | 32)) == mode) { - default_mode &= ~(1 | 2 | 4 | 8 | 16 | 32); - default_mode |= mode; - } 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_osd) { - default_mode |= st3m_gfx_osd; - } else if (mode == st3m_gfx_low_latency) { - default_mode |= st3m_gfx_low_latency; - } else if (mode == st3m_gfx_lock) { - default_mode |= st3m_gfx_lock; - } else if (mode == st3m_gfx_direct_ctx) { - default_mode |= st3m_gfx_direct_ctx; - } else - default_mode = mode; - - if (default_mode & st3m_gfx_smart_redraw) { - default_mode &= ~63; - default_mode |= 16; - } - - if (default_mode & st3m_gfx_lock) { - default_mode &= ~st3m_gfx_lock; - _st3m_gfx_mode = default_mode + 1; - st3m_gfx_set_mode(st3m_gfx_default); - default_mode |= st3m_gfx_lock; - } else { - _st3m_gfx_mode = default_mode + 1; - st3m_gfx_set_mode(st3m_gfx_default); - } -} - -static void st3m_gfx_init_palette(st3m_gfx_mode mode) { - switch (mode & 0xf) { - case 1: - for (int i = 0; i < 2; i++) { - st3m_pal[i * 3 + 0] = i * 255; - st3m_pal[i * 3 + 1] = i * 255; - st3m_pal[i * 3 + 2] = i * 255; - } - break; - case 2: - for (int i = 0; i < 4; i++) { - st3m_pal[i * 3 + 0] = (i * 255) / 3; - st3m_pal[i * 3 + 1] = (i * 255) / 3; - st3m_pal[i * 3 + 2] = (i * 255) / 3; - } - break; - case 4: { -#if 0 - // ega palette - 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); - } -#else - // night-mode - for (int i = 0; i < 16; i++) { - st3m_pal[i * 3 + 0] = (i * 255) / 15; - st3m_pal[i * 3 + 1] = ((i * 255) / 15) / 3; - st3m_pal[i * 3 + 2] = ((i * 255) / 15) / 5; - } - break; -#endif - } 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_mode st3m_gfx_set_mode(st3m_gfx_mode mode) { - if ((mode == _st3m_gfx_mode) || (0 != (default_mode & st3m_gfx_lock))) { - return (mode ? mode : default_mode); - } - - if (mode == st3m_gfx_default) - mode = default_mode; - else if (mode == st3m_gfx_low_latency) - mode = default_mode | st3m_gfx_low_latency; - else if (mode == st3m_gfx_osd) - mode = default_mode | st3m_gfx_osd; - - _st3m_gfx_mode = (mode == default_mode) ? st3m_gfx_default : mode; - - if (((mode & st3m_gfx_low_latency) != 0) || - ((mode & st3m_gfx_direct_ctx) != 0)) - _st3m_gfx_low_latency = (N_DRAWLISTS - 1); - else - _st3m_gfx_low_latency = 0; - - st3m_gfx_fbconfig(240, 240, 0, 0); - - return mode; -} - -st3m_gfx_mode st3m_gfx_get_mode(void) { - return _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; -} - -uint8_t *st3m_gfx_fb(st3m_gfx_mode mode, int *width, int *height, int *stride) { - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - int bpp = _st3m_gfx_bpp(set_mode); - if (mode == st3m_gfx_palette) { - if (stride) *stride = 3; - if (width) *width = 1; - if (height) *height = 256; - return st3m_pal; - } else if (mode == st3m_gfx_default) { - if (stride) *stride = st3m_gfx_fb_width * bpp / 8; - if (width) *width = FLOW3R_BSP_DISPLAY_WIDTH; - if (height) *height = FLOW3R_BSP_DISPLAY_HEIGHT; - return ((uint8_t *)st3m_fb); - } -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - else if (mode == st3m_gfx_osd) { - if (stride) *stride = FLOW3R_BSP_DISPLAY_WIDTH * bpp / 8; - if (width) *width = FLOW3R_BSP_DISPLAY_WIDTH; - if (height) *height = FLOW3R_BSP_DISPLAY_HEIGHT; - return st3m_fb2; - } - - int scale = st3m_gfx_scale(set_mode); - if (stride) *stride = FLOW3R_BSP_DISPLAY_WIDTH * bpp / 8; - if (width) *width = FLOW3R_BSP_DISPLAY_WIDTH / scale; - if (height) *height = FLOW3R_BSP_DISPLAY_HEIGHT / scale; -#endif - return (uint8_t *)st3m_fb; -} - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL -static void *osd_fb = st3m_fb2; -#endif - -static void st3m_gfx_blit(st3m_gfx_drawlist *drawlist) { - st3m_gfx_mode set_mode = drawlist->mode; - uint8_t *blit_src = drawlist->blit_src; - int bits = _st3m_gfx_bpp(set_mode); - - static st3m_gfx_mode prev_mode; - - - if (set_mode != prev_mode) { - st3m_gfx_init_palette(set_mode); - } - - xSemaphoreTake(st3m_fb_copy_lock, portMAX_DELAY); -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - int scale = st3m_gfx_scale(set_mode); - int osd_x0 = drawlist->osd_x0, osd_x1 = drawlist->osd_x1, - osd_y0 = drawlist->osd_y0, osd_y1 = drawlist->osd_y1; - - if ((scale > 1) || ((set_mode & st3m_gfx_osd) && (osd_y0 != osd_y1))) { - if (((set_mode & st3m_gfx_osd) && (osd_y0 != osd_y1))) { - if ((set_mode & 0xf) == st3m_gfx_rgb332) bits = 9; - xSemaphoreTake(st3m_osd_lock, - ST3M_OSD_LOCK_TIMEOUT / portTICK_PERIOD_MS); - flow3r_bsp_display_send_fb_osd(blit_src, bits, scale, osd_fb, - osd_x0, osd_y0, osd_x1, osd_y1); - xSemaphoreGive(st3m_osd_lock); - } else { - if ((set_mode & 0xf) == st3m_gfx_rgb332) bits = 9; - flow3r_bsp_display_send_fb_osd(blit_src, bits, scale, NULL, 0, 0, 0, - 0); - } - } else -#endif - { - if ((set_mode & 0xf) == st3m_gfx_rgb332) bits = 9; - flow3r_bsp_display_send_fb(blit_src, bits); - } - xSemaphoreGive(st3m_fb_copy_lock); - prev_mode = set_mode; -} - -#if ST3M_GFX_BLIT_TASK -static void st3m_gfx_blit_task(void *_arg) { - while (true) { - int desc_no = 0; - xQueueReceiveNotifyStarved(user_ctx_blitq, &desc_no, - "blit task starved (user_ctx)!"); - st3m_gfx_drawlist *drawlist = &drawlists[desc_no]; - - st3m_gfx_blit(drawlist); - xQueueSend(user_ctx_freeq, &desc_no, portMAX_DELAY); - } -} -#endif - -static void st3m_gfx_rast_task(void *_arg) { - (void)_arg; - st3m_gfx_set_mode(st3m_gfx_default); - - int bits = 0; - st3m_gfx_mode prev_set_mode = ST3M_GFX_DEFAULT_MODE - 1; - -#if ST3M_GFX_BLIT_TASK - int direct_blit = 0; -#endif - - while (true) { - int desc_no = 0; - int tc = ctx_textureclock(fb_ctx) + 1; - xQueueReceiveNotifyStarved(user_ctx_rastq, &desc_no, - "rast task starved (user_ctx)!"); - st3m_gfx_drawlist *drawlist = &drawlists[desc_no]; - st3m_gfx_mode set_mode = drawlist->mode; - - xSemaphoreTake(st3m_fb_lock, portMAX_DELAY); - - ctx_set_textureclock(fb_ctx, tc); -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - ctx_set_textureclock(osd_ctx, tc); - ctx_set_textureclock(ctx, tc); -#endif - if (st3m_gfx_geom_dirty || (prev_set_mode != set_mode)) { - int was_geom_dirty = (prev_set_mode == set_mode); - bits = _st3m_gfx_bpp(set_mode); - st3m_gfx_geom_dirty = 0; - -#if ST3M_GFX_BLIT_TASK - if ((bits > 16)) - direct_blit = 1; - else - direct_blit = 0; -#endif - - int stride = (bits * st3m_gfx_fb_width) / 8; - switch (bits) { -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - case 1: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, - st3m_gfx_fb_width, st3m_gfx_fb_height, - stride, CTX_FORMAT_GRAY1); - break; - case 2: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, - st3m_gfx_fb_width, st3m_gfx_fb_height, - stride, CTX_FORMAT_GRAY2); - break; - case 4: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, - st3m_gfx_fb_width, st3m_gfx_fb_height, - stride, CTX_FORMAT_GRAY4); - break; - case 8: - case 9: - if ((set_mode & 0xf) == 9) - ctx_rasterizer_reinit( - fb_ctx, st3m_fb, 0, 0, st3m_gfx_fb_width, - st3m_gfx_fb_height, stride, CTX_FORMAT_RGB332); - else - ctx_rasterizer_reinit( - fb_ctx, st3m_fb, 0, 0, st3m_gfx_fb_width, - st3m_gfx_fb_height, stride, CTX_FORMAT_GRAY8); - break; -#endif - case 16: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, - st3m_gfx_fb_width, st3m_gfx_fb_height, - stride, - CTX_FORMAT_RGB565_BYTESWAPPED); - break; - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - case 24: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, 240, 240, - 240 * 3, CTX_FORMAT_RGB8); - break; - case 32: - ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, 240, 240, - 240 * 4, CTX_FORMAT_RGBA8); - break; -#endif - } - if ((set_mode & st3m_gfx_smart_redraw) == 0) { - if (!was_geom_dirty) memset(st3m_fb, 0, sizeof(st3m_fb)); - } -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - st3m_gfx_viewport_transform(osd_ctx, 1); - if (!was_geom_dirty) memset(st3m_fb2, 0, sizeof(st3m_fb2)); -#endif - prev_set_mode = set_mode; - } - - if ((set_mode & st3m_gfx_direct_ctx) == 0) { - if ((set_mode & st3m_gfx_smart_redraw)) { - ctx_start_frame(ctx); - ctx_render_ctx(drawlist->user_ctx, ctx); - ctx_end_frame(ctx); - } else { - ctx_save(fb_ctx); - ctx_render_ctx(drawlist->user_ctx, fb_ctx); - ctx_restore(fb_ctx); - } - ctx_drawlist_clear(drawlist->user_ctx); - } -#if ST3M_GFX_BLIT_TASK - if (direct_blit) { -#endif - drawlist->blit_src = st3m_fb; - st3m_gfx_blit(drawlist); - xSemaphoreGive(st3m_fb_lock); - xQueueSend(user_ctx_freeq, &desc_no, portMAX_DELAY); -#if ST3M_GFX_BLIT_TASK - } else { - drawlist->blit_src = st3m_fb_copy; - xSemaphoreTake(st3m_fb_copy_lock, portMAX_DELAY); - int disp_stride = 240 * bits / 8; - if ((st3m_gfx_fb_width == 240) && (drawlist->blit_x == 0)) { - int blit_offset = st3m_gfx_blit_y * 240 * bits / 8; - int overlap = (st3m_gfx_blit_y + 240) - st3m_gfx_fb_height; - - if (overlap > 0) { - // vertical overlap, 2 memcpys - int start_scans = 240 - overlap; - memcpy(st3m_fb_copy, st3m_fb + blit_offset, - start_scans * disp_stride); - memcpy(st3m_fb_copy + start_scans * disp_stride, st3m_fb, - overlap * disp_stride); - } else { // best case - memcpy(st3m_fb_copy, st3m_fb + blit_offset, - 240 * disp_stride); - } - } else { - int fb_stride = st3m_gfx_fb_width * bits / 8; - int scan_offset = drawlist->blit_x * bits / 8; - int scan_overlap = (drawlist->blit_x + 240) - st3m_gfx_fb_width; - if (scan_overlap <= 0) { // only vertical wrap-around - int blit_offset = - (st3m_gfx_blit_y * 240 + drawlist->blit_x) * bits / 8; - int overlap = (st3m_gfx_blit_y + 240) - st3m_gfx_fb_height; - if (overlap <= 0) overlap = 0; - - int start_scans = 240 - overlap; - for (int i = 0; i < start_scans; i++) - memcpy(st3m_fb_copy + i * disp_stride, - st3m_fb + blit_offset + i * fb_stride, - disp_stride); - for (int i = 0; i < overlap; i++) - memcpy(st3m_fb_copy + (i + start_scans) * disp_stride, - st3m_fb + (drawlist->blit_x * bits / 8) + - i * fb_stride, - disp_stride); - } else { // generic case, handles both horizontal and vertical - // wrap-around - int start_bit = 240 - scan_overlap; - - int blit_offset = (st3m_gfx_blit_y)*fb_stride; - int overlap = (st3m_gfx_blit_y + 240) - st3m_gfx_fb_height; - if (overlap <= 0) overlap = 0; - - int start_scans = 240 - overlap; - int start_bytes = start_bit * bits / 8; - int scan_overlap_bytes = scan_overlap * bits / 8; - - for (int i = 0; i < start_scans; i++) - memcpy( - st3m_fb_copy + i * disp_stride, - st3m_fb + blit_offset + i * fb_stride + scan_offset, - start_bytes); - for (int i = 0; i < overlap; i++) - memcpy(st3m_fb_copy + (i + start_scans) * disp_stride, - st3m_fb + scan_offset + i * fb_stride, - start_bytes); - - // second pass over scanlines, filling in second half (which - // is wrapped to start of fb-scans) - for (int i = 0; i < start_scans; i++) - memcpy(st3m_fb_copy + i * disp_stride + start_bytes, - st3m_fb + blit_offset + i * fb_stride, - scan_overlap_bytes); - for (int i = 0; i < overlap; i++) - memcpy(st3m_fb_copy + (i + start_scans) * disp_stride + - start_bytes, - st3m_fb + i * fb_stride, scan_overlap_bytes); - } - } - xSemaphoreGive(st3m_fb_copy_lock); - xSemaphoreGive(st3m_fb_lock); - xQueueSend(user_ctx_blitq, &desc_no, portMAX_DELAY); - } -#endif - - st3m_counter_rate_sample(&rast_rate); - float rate = 1000000.0 / st3m_counter_rate_average(&rast_rate); - smoothed_fps = smoothed_fps * 0.6 + 0.4 * rate; - } -} void st3m_gfx_flow3r_logo(Ctx *ctx, float x, float y, float dim) { static int frameno = 0; @@ -862,9 +218,8 @@ void st3m_gfx_show_textview(st3m_gfx_textview_t *tv) { return; } - Ctx *ctx = st3m_gfx_ctx(st3m_gfx_default); + Ctx *ctx = tildagon_gfx_ctx(); - st3m_gfx_fbconfig(240, 240, 0, 0); ctx_save(ctx); // Draw background. @@ -910,232 +265,19 @@ void st3m_gfx_show_textview(st3m_gfx_textview_t *tv) { ctx_restore(ctx); - st3m_gfx_end_frame(ctx); + tildagon_end_frame(ctx); } -static void set_pixels_ctx(Ctx *ctx, void *user_data, int x, int y, int w, - int h, void *buf) { - uint16_t *src = buf; - for (int scan = y; scan < y + h; scan++) { - uint16_t *dst = (uint16_t *)&st3m_fb[(scan * 240 + x) * 2]; - for (int u = 0; u < w; u++) *(dst++) = *(src++); - } +float st3m_gfx_fps(void) { return smoothed_fps; } +void st3m_gfx_fps_update (void) +{ + st3m_counter_rate_sample(&rast_rate); + float rate = 1000000.0 / st3m_counter_rate_average(&rast_rate); + smoothed_fps = smoothed_fps * 0.6 + 0.4 * rate; } -void st3m_gfx_init(void) { - // Make sure we're not being re-initialized. +void st3m_gfx_init(void) { st3m_counter_rate_init(&rast_rate); - flow3r_bsp_display_init(); - - // Create drawlist ctx queues. - user_ctx_freeq = xQueueCreate(N_DRAWLISTS, sizeof(int)); - assert(user_ctx_freeq != NULL); - user_ctx_rastq = xQueueCreate(1, sizeof(int)); - assert(user_ctx_rastq != NULL); - user_ctx_blitq = xQueueCreate(1, sizeof(int)); - assert(user_ctx_blitq != NULL); - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - st3m_osd_lock = xSemaphoreCreateMutex(); -#endif - st3m_fb_lock = xSemaphoreCreateMutex(); - st3m_fb_copy_lock = xSemaphoreCreateMutex(); - - ctx = ctx_new_cb(FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, - CTX_FORMAT_RGB565_BYTESWAPPED, set_pixels_ctx, NULL, NULL, - NULL, sizeof(scratch), scratch, - CTX_FLAG_HASH_CACHE | CTX_FLAG_KEEP_DATA); - assert(ctx != NULL); - - // Setup rasterizers for frame buffer formats - fb_ctx = ctx_new_for_framebuffer( - st3m_fb, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, - FLOW3R_BSP_DISPLAY_WIDTH * 2, CTX_FORMAT_RGB565_BYTESWAPPED); - assert(fb_ctx != NULL); -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - osd_ctx = ctx_new_for_framebuffer( - st3m_fb2, FLOW3R_BSP_DISPLAY_WIDTH, FLOW3R_BSP_DISPLAY_HEIGHT, - FLOW3R_BSP_DISPLAY_WIDTH * 4, CTX_FORMAT_RGBA8); - assert(osd_ctx != NULL); - - st3m_gfx_viewport_transform(osd_ctx, 0); - - ctx_set_texture_source(osd_ctx, fb_ctx); - ctx_set_texture_cache(osd_ctx, fb_ctx); - ctx_set_texture_source(ctx, fb_ctx); - ctx_set_texture_cache(ctx, fb_ctx); - -#endif - - // Setup user_ctx descriptor. - for (int i = 0; i < N_DRAWLISTS; i++) { - drawlists[i].user_ctx = ctx_new_drawlist(FLOW3R_BSP_DISPLAY_WIDTH, - FLOW3R_BSP_DISPLAY_HEIGHT); - assert(drawlists[i].user_ctx != NULL); - ctx_set_texture_cache(drawlists[i].user_ctx, fb_ctx); - - BaseType_t res = xQueueSend(user_ctx_freeq, &i, 0); - assert(res == pdTRUE); - } - - // Start rasterization, scan-out - BaseType_t res = - xTaskCreatePinnedToCore(st3m_gfx_rast_task, "gfx-rast", 8192, NULL, - ESP_TASK_PRIO_MIN + 1, &graphics_rast_task, 0); - assert(res == pdPASS); - -#if ST3M_GFX_BLIT_TASK - res = xTaskCreate(st3m_gfx_blit_task, "gfx-blit", 2048, NULL, - ESP_TASK_PRIO_MIN + 2, &graphics_blit_task); - assert(res == pdPASS); -#endif -} -static int last_descno = 0; -static Ctx *st3m_gfx_drawctx_free_get(TickType_t ticks_to_wait) { - BaseType_t res = xQueueReceive(user_ctx_freeq, &last_descno, ticks_to_wait); - if (res != pdTRUE) return NULL; - - st3m_gfx_drawlist *drawlist = &drawlists[last_descno]; - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - drawlist->mode = set_mode; - - if (set_mode & st3m_gfx_direct_ctx) { - while (!uxSemaphoreGetCount(st3m_fb_lock)) vTaskDelay(0); - - if ((set_mode & st3m_gfx_smart_redraw)) { - ctx_start_frame(ctx); - ctx_save(ctx); - return ctx; - } - - return fb_ctx; - } - - return drawlist->user_ctx; -} - -static void st3m_gfx_pipe_put(void) { -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - st3m_gfx_drawlist *drawlist = &drawlists[last_descno]; - drawlist->osd_x0 = _st3m_osd_x0; - drawlist->osd_y0 = _st3m_osd_y0; - drawlist->osd_x1 = _st3m_osd_x1; - drawlist->osd_y1 = _st3m_osd_y1; - drawlist->blit_x = st3m_gfx_blit_x; - drawlist->blit_y = st3m_gfx_blit_y; -#endif - xQueueSend(user_ctx_rastq, &last_descno, portMAX_DELAY); -} - -static Ctx *st3m_gfx_ctx_int(st3m_gfx_mode mode); -void st3m_gfx_end_frame(Ctx *ctx) { - ctx_restore(ctx); -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - if (ctx == st3m_gfx_ctx_int(st3m_gfx_osd)) { - xSemaphoreGive(st3m_osd_lock); - return; - } -#endif - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - if ((set_mode & st3m_gfx_smart_redraw) && (set_mode & st3m_gfx_direct_ctx)) - ctx_end_frame(ctx); - - st3m_gfx_pipe_put(); -} - -uint8_t st3m_gfx_pipe_available(void) { - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - if ((set_mode & st3m_gfx_EXPERIMENTAL_think_per_draw) && - (smoothed_fps > 13.0)) - return 1; - return uxQueueMessagesWaiting(user_ctx_freeq) > _st3m_gfx_low_latency; -} - -uint8_t st3m_gfx_pipe_full(void) { - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - if ((set_mode & st3m_gfx_EXPERIMENTAL_think_per_draw) && - (smoothed_fps > 13.0)) - return 0; - return uxQueueSpacesAvailable(user_ctx_rastq) == 0; -} - -void st3m_gfx_flush(int timeout_ms) { - ESP_LOGW(TAG, "Pipeline flush/reset requested..."); - - // Drain all workqs and freeqs. - xQueueReset(user_ctx_freeq); - xQueueReset(user_ctx_rastq); - - // Delay, making sure pipeline tasks have returned all used descriptors. One - // second is enough to make sure we've processed everything. - vTaskDelay(timeout_ms / portTICK_PERIOD_MS); - - // And drain again. - xQueueReset(user_ctx_freeq); - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL - _st3m_osd_x0 = 0; - _st3m_osd_y0 = 0; - _st3m_osd_x1 = 0; - _st3m_osd_y1 = 0; -#endif - - for (int i = 0; i < N_DRAWLISTS; i++) { - ctx_drawlist_clear(drawlists[i].user_ctx); - BaseType_t res = xQueueSend(user_ctx_freeq, &i, 0); - assert(res == pdTRUE); - } - ESP_LOGW(TAG, "Pipeline flush/reset done."); -} - -#if CONFIG_FLOW3R_CTX_FLAVOUR_FULL -void st3m_gfx_overlay_clip(int x0, int y0, int x1, int y1) { - if (y1 < 0) y1 = 0; - if (y1 > FLOW3R_BSP_DISPLAY_HEIGHT) y1 = FLOW3R_BSP_DISPLAY_HEIGHT; - if (y0 < 0) y0 = 0; - if (y0 > FLOW3R_BSP_DISPLAY_HEIGHT) y0 = FLOW3R_BSP_DISPLAY_HEIGHT; - - if (x1 < 0) x1 = 0; - if (x1 > FLOW3R_BSP_DISPLAY_WIDTH) x1 = FLOW3R_BSP_DISPLAY_WIDTH; - if (x0 < 0) x0 = 0; - if (x0 > FLOW3R_BSP_DISPLAY_WIDTH) x0 = FLOW3R_BSP_DISPLAY_WIDTH; - - if ((x1 < x0) || (y1 < y0)) { - _st3m_osd_x0 = _st3m_osd_y0 = _st3m_osd_x1 = _st3m_osd_y1 = 0; - } else { - _st3m_osd_x0 = x0; - _st3m_osd_y0 = y0; - _st3m_osd_x1 = x1; - _st3m_osd_y1 = y1; - } -} -#endif - -void st3m_gfx_fbconfig(int width, int height, int blit_x, int blit_y) { - if (width <= 0) width = st3m_gfx_fb_width; - if (height <= 0) height = st3m_gfx_fb_height; - st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; - int bits = st3m_gfx_bpp(set_mode); - if (width > CTX_MAX_SCANLINE_LENGTH) width = CTX_MAX_SCANLINE_LENGTH; - if ((width * height * bits) / 8 > (240 * 240 * 4)) - height = 240 * 240 * 4 * 8 / (width * bits); - blit_x %= width; - blit_y %= height; - - if ((st3m_gfx_fb_width != width) || (st3m_gfx_fb_height != height)) { - st3m_gfx_fb_width = width; - st3m_gfx_fb_height = height; - st3m_gfx_geom_dirty++; - } - st3m_gfx_blit_x = blit_x; - st3m_gfx_blit_y = blit_y; -} - -void st3m_gfx_get_fbconfig(int *width, int *height, int *blit_x, int *blit_y) { - if (width) *width = st3m_gfx_fb_width; - if (height) *height = st3m_gfx_fb_height; - if (blit_x) *blit_x = st3m_gfx_blit_x; - if (blit_y) *blit_y = st3m_gfx_blit_y; } diff --git a/components/st3m/st3m_gfx.h b/components/st3m/st3m_gfx.h index faf4883..9cbc7a6 100644 --- a/components/st3m/st3m_gfx.h +++ b/components/st3m/st3m_gfx.h @@ -61,6 +61,8 @@ typedef enum { st3m_gfx_32bpp = 32, } st3m_gfx_mode; +void st3m_gfx_fps_update (void); + // sets the system graphics mode, this is the mode you get to // when calling st3m_gfx_set_mode(st3m_gfx_default); void st3m_gfx_set_default_mode(st3m_gfx_mode mode); diff --git a/drivers/gc9a01/display.c b/drivers/gc9a01/display.c index b3e961f..372900a 100644 --- a/drivers/gc9a01/display.c +++ b/drivers/gc9a01/display.c @@ -27,17 +27,55 @@ static mp_obj_t get_fps() { } static MP_DEFINE_CONST_FUN_OBJ_0(get_fps_obj, get_fps); +#define TILDAGON_DISPLAY_WIDTH 240 +#define TILDAGON_DISPLAY_HEIGHT 240 + +EXT_RAM_BSS_ATTR +static uint8_t tildagon_fb[TILDAGON_DISPLAY_WIDTH * TILDAGON_DISPLAY_HEIGHT * 2]; +static Ctx *tildagon_ctx = NULL; + +Ctx *tildagon_gfx_ctx(void) +{ + if (tildagon_ctx == NULL) + { + tildagon_ctx = ctx_new_for_framebuffer (tildagon_fb, TILDAGON_DISPLAY_WIDTH, TILDAGON_DISPLAY_HEIGHT, TILDAGON_DISPLAY_WIDTH * 2, CTX_FORMAT_RGB565_BYTESWAPPED); + } + return tildagon_ctx; +} + +void tildagon_start_frame(Ctx *ctx) +{ + int32_t offset_x = FLOW3R_BSP_DISPLAY_WIDTH / 2; + int32_t offset_y = FLOW3R_BSP_DISPLAY_HEIGHT / 2; + + ctx_save (ctx); + ctx_identity (ctx); + ctx_apply_transform (ctx, 1.0f, 0.0f, offset_x, 0.0f, 1.0f, offset_y, 0.0f, 0.0f, 1.0f); +} static mp_obj_t get_ctx() { - Ctx *ctx = st3m_gfx_ctx(st3m_gfx_default); + Ctx *ctx = tildagon_gfx_ctx(); + assert (ctx); + tildagon_start_frame (ctx); return mp_ctx_from_ctx(ctx); } static MP_DEFINE_CONST_FUN_OBJ_0(get_ctx_obj, get_ctx); +void tildagon_blit_fb (void) +{ + flow3r_bsp_display_send_fb(tildagon_fb, 16); +} + +void tildagon_end_frame(Ctx *ctx) +{ + ctx_restore (ctx); + tildagon_blit_fb (); + st3m_gfx_fps_update (); +} static mp_obj_t end_frame(mp_obj_t ctx) { mp_ctx_obj_t *self = MP_OBJ_TO_PTR(ctx); - st3m_gfx_end_frame(self->ctx); + tildagon_end_frame (self->ctx); return ctx; } static MP_DEFINE_CONST_FUN_OBJ_1(end_frame_obj, end_frame); diff --git a/drivers/gc9a01/mp_uctx.c b/drivers/gc9a01/mp_uctx.c index 29e5a0d..9692ba6 100644 --- a/drivers/gc9a01/mp_uctx.c +++ b/drivers/gc9a01/mp_uctx.c @@ -1061,6 +1061,52 @@ const mp_obj_module_t mp_module_ctx = { .globals = (mp_obj_dict_t *)&mp_ctx_module_globals, }; + +#include "py/stream.h" +#include "extmod/vfs.h" + +int mp_ctx_vfs_load_file (const char *path, + unsigned char **contents, + long *length, + long max_length) +{ + mp_obj_t filename = mp_obj_new_str(path, strlen(path)); + mp_obj_t open_args[2] = {filename, + MP_OBJ_NEW_QSTR(MP_QSTR_rb)}; + mp_obj_t stat = mp_vfs_stat(filename); + mp_obj_tuple_t *l = MP_OBJ_TO_PTR(stat); + mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(open_args), &open_args[0], + (mp_map_t*)&mp_const_empty_map); + const mp_stream_p_t *stream_p = mp_get_stream(file); + if (!stream_p) + { + mp_stream_close (file); + return -1; + } + int errcode = 0; + + long len = mp_obj_get_int(l->items[6]); + if (len > max_length) { + mp_stream_close (file); + return -1; + } + unsigned char *buf = ctx_malloc (len); + if (!buf) + { + mp_stream_close (file); + return -1; + } + mp_stream_rw(file, buf, len, &errcode, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); + if (errcode != 0) { + mp_raise_OSError(errcode); + } + *contents = buf; + *length = len; + mp_stream_close (file); + return 0; +} + + /* This is a special macro that will make MicroPython aware of this module */ /* clang-format off */ -MP_REGISTER_MODULE(MP_QSTR_ctx, mp_module_ctx); \ No newline at end of file +MP_REGISTER_MODULE(MP_QSTR_ctx, mp_module_ctx);