Printing font on a canvas has artifacts

Description

When drawing a label on a canvas I get artifacts on glyphs. In details they have holes on it through which the underlying layer is visible. It happens both with a freetype font and with builtin montserrat.
It looks like the holes all have the same size and form factor, small lines of the same amount of pixels.

What MCU/Processor/Board and compiler are you using?

Custom iMXRT1052-based board with PXP running, working on IAR 9.10 and FreeRTOS Kernel V10.4.3 LTS Patch 2.

What LVGL version are you using?

LVGL 9.1

What do you want to achieve?

I’m trying to draw label on Canvas so that I can shrink text by scaling the resulting buffer.
The attached snippet only includes the main rendering, not the shrinking which is yet to be done.

What have you tried so far?

I tried:

  • not to call fill_bg function
  • init buffer for canvas in several ways
  • moving the canvas on different position
  • resizing the canvas
  • montserrat font

Code to reproduce

This snippet is executed only once in my program.

        //Create Canvas for PI label
        symbolsArea.piLbl = lv_canvas_create(screen);
        AllocateBufferForCanvas(&symbolsArea.piLblBuf, layout->piWidget.sizePos.w, layout->piWidget.sizePos.h); 
        lv_canvas_set_draw_buf(symbolsArea.piLbl, &symbolsArea.piLblBuf);
        lv_obj_set_pos(symbolsArea.piLbl, layout->piWidget.sizePos.x, layout->piWidget.sizePos.y);
        lv_obj_set_size(symbolsArea.piLbl, layout->piWidget.sizePos.w, layout->piWidget.sizePos.h);
        lv_canvas_fill_bg(symbolsArea.piLbl, lv_color_make(0, 0, 0), LV_OPA_TRANSP);
        
        //Init layer
        lv_canvas_init_layer(symbolsArea.piLbl, &symbolsArea.layer);
        
        //Create label descriptor for canvas
        lv_draw_label_dsc_init(&symbolsArea.piLblDsc);
        symbolsArea.piLblDsc.color = lv_color_make(layout->piWidget.foreColor.r, layout->piWidget.foreColor.g, layout->piWidget.foreColor.b);
        symbolsArea.piLblDsc.align = GetHorAlign(layout->piWidget.alignTextH);
        symbolsArea.piLblDsc.font = info->font;
        symbolsArea.piLblDsc.text = "GG";
        lv_area_t piLblArea = { 0, 0, layout->piWidget.sizePos.w - 1, layout->piWidget.sizePos.h - 1 };
        
        lv_draw_label(&symbolsArea.layer, &symbolsArea.piLblDsc, &piLblArea);
        
        lv_canvas_finish_layer(symbolsArea.piLbl, &symbolsArea.layer);

I noticed that:

  • when stepping in debug through the latest 2 lines, and then run the PC, the problems doesn’t appear
  • I have a user menu that can be opened on top of that canvas. If I open it and then close it, the symbols are cleaned from the artifact.

Screenshot and/or video

image

maybe this or this thread can help you

Thanks. It gave me some inputs.

I tried to set the frame buffers memory region as non-cacheable, via MPU. The problem seems gone, but performance obviously degraded a lot.

Attaching my flush callback.

static void disp_flush(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{	
    lv_display_rotation_t lv_or = lv_disp_get_rotation(disp);
	lv_area_t fullscreen = {0, 0, lv_disp_get_hor_res(disp) - 1, lv_disp_get_ver_res(disp) - 1 };
    
    BSP_Cache_CleanInvalidate(buf_0, sizeof(buf_0));
    BSP_Cache_CleanInvalidate(buf_1, sizeof(buf_0));
	
	if(lv_disp_flush_is_last(disp) == false)
	{
		lv_disp_flush_ready(disp);
		return;
	}
	
	lv_coord_t lv_hor = lv_disp_get_hor_res(disp);
	lv_coord_t lv_ver = lv_disp_get_ver_res(disp);
    switch(lv_or)
    {
        default:
        case LV_DISPLAY_ROTATION_0:
            lv_draw_pxp_rotate(px_map, buf_1, 1+(fullscreen.x2-fullscreen.x1), 1+(fullscreen.y2-fullscreen.y1), 2*(1+(fullscreen.x2-fullscreen.x1)), 2*(1+(fullscreen.x2-fullscreen.x1)), lv_or, LV_COLOR_FORMAT_RGB565);
            break;
        case LV_DISPLAY_ROTATION_90:
            blit_90(PXP, buf_1, lv_ver, lv_hor, px_map, 1+(fullscreen.x2-fullscreen.x1), 1+(fullscreen.y2-fullscreen.y1), fullscreen.x1, fullscreen.y1, 2);
            break;
        case LV_DISPLAY_ROTATION_180:
            blit_180(PXP, buf_1, lv_hor, lv_ver, px_map, 1+(fullscreen.x2-fullscreen.x1), 1+(fullscreen.y2-fullscreen.y1), fullscreen.x1, fullscreen.y1, 2);
            break;
        case LV_DISPLAY_ROTATION_270:
            blit_270(PXP, buf_1, lv_ver, lv_hor, px_map, 1+(fullscreen.x2-fullscreen.x1), 1+(fullscreen.y2-fullscreen.y1), fullscreen.x1, fullscreen.y1, 2);
            break;
    }	
    
    BSP_TFT_SetNextFrame(buf_1);
	
    s_framePending = true;

#if defined(SDK_OS_FREE_RTOS)
    if (xSemaphoreTake(s_frameSema, portMAX_DELAY) == pdTRUE)
    {
        /* IMPORTANT!!!
         * Inform the graphics library that you are ready with the flushing*/
        lv_disp_flush_ready(disp);
    }
    else
    {
        BSP_Debug_Print("Display flush failed\r\n");
        APP_assert(0);
    }
#else
    while (s_framePending)
    {
    }

    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready(disp);
#endif
}

I’ll explain it a little.

In my application I need all orientations, so I use PXP to rotate the whole frame buffer.
I have 2 buffers, one used by LVGL and one used as output for PXP operation.

Moreover I use LV_DISPLAY_RENDER_MODE_DIRECT.

Regards

Little update.

I found a workaround.

I use the buffer of the canvas as a source of an image that must be scaled (even a little).
Snippet here:

lv_img_set_src(symbolsArea.finalImage, symbolsArea.piLblBufHidden);
lv_obj_set_pos(symbolsArea.finalImage, t->sizePos.x, t->sizePos.y);
lv_obj_set_size(symbolsArea.finalImage, t->sizePos.w - 1, t->sizePos.h);
lv_image_set_inner_align(symbolsArea.finalImage, LV_IMAGE_ALIGN_STRETCH);

where symbolsArea.piLblBufHidden is the buffer used by the canvas that has the label.

If I remove the -1 at the third line, the problem occurs again.

It’s not a solution, but hopefully it can trigger any ideas to LGVL experienced users? :smiley:

Regards