diff --git a/components/ctx/ctx_config.h b/components/ctx/ctx_config.h index 8f703b800c5acbcaebe348753a7a206427846f1f..11ac7d3dc728df564934a55de71f44c5a1c13a73 100644 --- a/components/ctx/ctx_config.h +++ b/components/ctx/ctx_config.h @@ -45,7 +45,7 @@ #define CTX_BAREMETAL 1 #define CTX_ONE_FONT_ENGINE 1 -#define CTX_MAX_SCANLINE_LENGTH 256 +#define CTX_MAX_SCANLINE_LENGTH 960 #define CTX_MAX_JOURNAL_SIZE (1024*512) // is also max and limits complexity // of paths that can be filled diff --git a/components/st3m/st3m_gfx.c b/components/st3m/st3m_gfx.c index 73637b89b4ed934e4854de346989a9aa4c6d1611..72317b559ce97ba4267fd6b7b6d7b3b4a4e19580 100644 --- a/components/st3m/st3m_gfx.c +++ b/components/st3m/st3m_gfx.c @@ -90,6 +90,9 @@ typedef struct { 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; @@ -117,6 +120,12 @@ static TaskHandle_t graphics_blit_task; 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(void) { st3m_gfx_mode set_mode = _st3m_gfx_mode ? _st3m_gfx_mode : default_mode; switch ((int)(set_mode & st3m_gfx_4x)) { @@ -351,6 +360,8 @@ st3m_gfx_mode st3m_gfx_set_mode(st3m_gfx_mode mode) { ((mode & st3m_gfx_direct_ctx) != 0)) _st3m_gfx_low_latency = (N_DRAWLISTS - 1); + st3m_gfx_fbconfig(240, 240, 0, 0); + return mode; } @@ -367,7 +378,7 @@ uint8_t *st3m_gfx_fb(st3m_gfx_mode mode, int *width, int *height, int *stride) { if (height) *height = 256; return st3m_pal; } else if (mode == st3m_gfx_default) { - if (stride) *stride = FLOW3R_BSP_DISPLAY_WIDTH * bpp / 8; + 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); @@ -465,9 +476,11 @@ static void st3m_gfx_rast_task(void *_arg) { #if CONFIG_FLOW3R_CTX_FLAVOUR_FULL ctx_set_textureclock(osd_ctx, ctx_textureclock(fb_ctx)); #endif - if (prev_set_mode != set_mode) { + 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); prev_set_mode = set_mode; + st3m_gfx_geom_dirty = 0; #if ST3M_GFX_BLIT_TASK if ((bits > 16)) @@ -475,33 +488,40 @@ static void st3m_gfx_rast_task(void *_arg) { else direct_blit = 0; #endif - int stride = (bits * 240) / 8; + + 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, 240, 240, + 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, 240, 240, + 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, 240, 240, + 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, 240, 240, - stride, CTX_FORMAT_RGB332); + 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, 240, 240, - stride, CTX_FORMAT_GRAY8); + 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, 240, 240, + ctx_rasterizer_reinit(fb_ctx, st3m_fb, 0, 0, + st3m_gfx_fb_width, st3m_gfx_fb_height, stride, CTX_FORMAT_RGB565_BYTESWAPPED); break; @@ -518,10 +538,10 @@ static void st3m_gfx_rast_task(void *_arg) { #endif } st3m_gfx_viewport_transform(fb_ctx); - memset(st3m_fb, 0, sizeof(st3m_fb)); + if (!was_geom_dirty) memset(st3m_fb, 0, sizeof(st3m_fb)); #if CONFIG_FLOW3R_CTX_FLAVOUR_FULL st3m_gfx_viewport_transform(osd_ctx); - memset(st3m_fb2, 0, sizeof(st3m_fb2)); + if (!was_geom_dirty) memset(st3m_fb2, 0, sizeof(st3m_fb2)); #endif } @@ -541,7 +561,76 @@ static void st3m_gfx_rast_task(void *_arg) { } else { drawlist->blit_src = st3m_fb_copy; xSemaphoreTake(st3m_fb_copy_lock, portMAX_DELAY); - memcpy(st3m_fb_copy, st3m_fb, 240 * (240 * bits / 8)); + 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); @@ -882,6 +971,8 @@ static void st3m_gfx_pipe_put(void) { 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); } @@ -966,3 +1057,30 @@ void st3m_gfx_overlay_clip(int x0, int y0, int x1, int 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 5e9afde03ad9b53b36ae34b31e0ca2153cb1cd71..2dc6e28d221fc38f83f4bd65696940d5602a0c78 100644 --- a/components/st3m/st3m_gfx.h +++ b/components/st3m/st3m_gfx.h @@ -43,10 +43,10 @@ typedef enum { st3m_gfx_1bpp = 1, st3m_gfx_2bpp = 2, st3m_gfx_4bpp = 4, - st3m_gfx_8bpp = 8, - st3m_gfx_rgb332 = 9, - st3m_gfx_sepia = 10, - st3m_gfx_cool = 11, + st3m_gfx_8bpp = 8, // bare 8bpp mode is grayscale + st3m_gfx_rgb332 = 9, // variant of 8bpp mode using RGB + st3m_gfx_sepia = 10, // grayscale rendering with sepia palette + st3m_gfx_cool = 11, // grayscale rendering with cool palette st3m_gfx_palette = 15, // 16bpp modes have the lowest blit overhead - no osd for now st3m_gfx_16bpp = 16, @@ -136,3 +136,15 @@ void st3m_gfx_splash(const char *text); // Draw the flow3r multi-coloured logo at coordinates x,y and with given // dimension (approx. bounding box size). void st3m_gfx_flow3r_logo(Ctx *ctx, float x, float y, float dim); + +// configure virtual viewport, the default values are 0, 0, 240, 240 which +// also gives room for a copy of the fb for separate rasterize/blit in 16bpp +// +// with, height: width and height of virtual framebuffer +// +// changing the viewport should be done after setting the graphics mode - upon +// graphics mode setting viewport is reset to 240, 240, 0,0,0,0 +void st3m_gfx_fbconfig(int width, int height, int blit_x, int blit_y); + +// get fbconfig values, arguments passed NULL ptrs are ignored. +void st3m_gfx_get_fbconfig(int *width, int *height, int *blit_x, int *blit_y);