cancel
Showing results for 
Search instead for 
Did you mean: 

Is the L8_ARGB8888 image format supported for Shapes widget? If not, will it be in the future?

scottSD
Senior III

Let me preface this question by saying I appreciate the new L8 (indexed) color support for many of the widgets. This includes the support for L8s in dynamic bitmaps.

I attempted to use an image formatted to L8_ARGB8888 in a shape widget. The code compiled, but when running on the simulator I received the following assert:

0690X00000AsD78QAF.png

The painter for the shape is not instantiated as an L8_ARGB8888, but a PainterRGB8888Bitmap as seen in the gui_generated Screen1ViewBase.hpp file:

0690X00000AsDCwQAN.png

Does the shape widget support the PainterARGB8888L8Bitmap? If not will it support it in the future?

36 REPLIES 36

Okay, here's a quick write up - Let me know how you find it!

Here is a guideline on how to use L8 with Dynamic Bitmaps (Since 4.12.1) - Code for using L8 with DMA2D/ChromART attached:

  1. First, you need to replace the STM32DMA class with the ChromArtDMA class (attached), otherwise L8 images will not be drawn using ChromART. Normally, the DMA class to use is specified in the BoardConfiguration.cpp file.
  2. The Palette is allocated 4 bytes after the last 32-bit aligned pixel in the bitmap cache. For RGB565 each color in the palette is 2 bytes. For L8_RGB888 each color is 3 bytes, and otherwise 4 bytes. The general formula for the position of the Pallette would be P = (w * h + 3) & ~3 + 4.
  3. See the code below on how to use L8 with a dynamic bitmap. The application (Screen2) creates a dynamic bitmap of type CLUT_FORMAT_L8_RGB888, initializes all pixels to black and initializing the first color of the palette to black. In each tick the blue color component of the first color of the palette is modified resulting in a dynamically changing 100x100 square.

0690X00000AsZFxQAN.png0690X00000AsZDwQAN.png

#include <gui/screen2_screen/Screen2View.hpp>
#include <touchgfx/Bitmap.hpp>
 
uint32_t bitmapCache[(100*100+2000)/4];
 
Screen2View::Screen2View()
{
 
}
 
void Screen2View::setupScreen()
{
   Screen2ViewBase::setupScreen();
   Bitmap::setCache((uint16_t*)bitmapCache, sizeof(bitmapCache), 1);
 
   BitmapId dynamicBitmap1 = Bitmap::dynamicBitmapCreate(100, 100, Bitmap::L8, Bitmap::CLUT_FORMAT_L8_RGB888);
 
   image1.setBitmap(Bitmap(dynamicBitmap1));
 
   //Get a pointer to the bitmap data (pixels and palette)
   uint8_t* data = Bitmap::dynamicBitmapGetAddress(image1.getBitmap());
 
   //Set all pixels to 0 (they are showing color 0 from the palette)
   for (int i = 0; i <100*100; i++)
   {
       data[i] = 0;
   }
 
   //Palette starts four bytes after the pixels (one byte each)
   uint8_t* pal = (data + 100*100 + 4);
 
   //make color 0 in the palette black
   pal[0] = 0x00; //B
   pal[1] = 0x00; //G
   pal[2] = 0x00; //R
}
 
void Screen2View::tearDownScreen()
{
   Screen2ViewBase::tearDownScreen();
}
 
void Screen2View::handleTickEvent()
{
   static uint8_t count = 0;
   count++;
 
   //Change blue value of color 0
   uint8_t* data = Bitmap::dynamicBitmapGetAddress(image1.getBitmap());
   uint8_t* pal = (data + 100*100 + 4);
 
   pal[0] = count; //B
   pal[1] = 0x00; //G
   pal[2] = 0x00; //R
 
   //Redraw image with new palette
   image1.invalidate();
}

I'll probably generalize this in a separate post, but you'll be the first one to try it - I can't spare any more time right now, so it'll have to be later.

Hope it works for you!

/Martin

Martin, Thanks for taking the time to do this.

However, when I started looking at your post I noticed you said that my HAL needs to be altered to make ChromeART support CLUT.

Maybe I am not understanding correctly, but I thought it WAS already supporting it. Before posting this question, I wrote code to setup a Dynamic Bitmap for L8. Below is the function I wrote to do that. I pass an ID of a source bitmap and create a dynamic bitmap of identical size and format changing bmpIdDyn accordingly:

bool SetupBmpId(BitmapId& bmpIdDyn, BitmapId bmpSrcId)
{
    Bitmap bmpIn(bmpSrcId);
 
    uint16_t bmp_h = bmpIn.getHeight();
    uint16_t bmp_w = bmpIn.getWidth();
    Bitmap::BitmapFormat bmpFormat = bmpIn.getFormat();
    PrintBitmapFormat(bmpFormat);
 
    if (bmpIdDyn != BITMAP_INVALID)
    {
        Bitmap::dynamicBitmapDelete(bmpIdDyn);
    }
    // Create dynamic bitmap matching file dimensions
    if(bmpFormat == Bitmap::L8)
    {
        bmpIdDyn = Bitmap::dynamicBitmapCreate(bmp_w, bmp_h, bmpFormat, 
        Bitmap::CLUT_FORMAT_L8_ARGB8888);
    }
    else
    {
        bmpIdDyn = Bitmap::dynamicBitmapCreate(bmp_w, bmp_h, bmpFormat);
    }
 
    if (bmpIdDyn != BITMAP_INVALID)
    {
	    return true;
    }
    else
    {
        return false;
    }
}

I verified that this Dynamic Bitmap was created correctly by adjusting colors of it by calling the Bitmap function getExtraData() and modifying the CLUT table (4 bytes into the extraData). The color of the image on the LCD changed as well as in the TouchGFX Simulator.

Below is the function I wrote do to this:

void ChangeClut(uint8_t* extraDataP, uint16_t redColor, uint16_t greenColor, uint16_t blueColor)
{
	// Get the size of the clut.
	uint16_t clutSize =  (extraDataP[3] << 8 ) |  extraDataP[2];
 
	// Point to the actual colors.
	uint8_t* clut = extraDataP + 4;
 
	for(uint16_t i = 0; i < (clutSize*4); i+=4)
	{
		clut[i + 2] = (unsigned char)(redColor);
		clut[i + 1] = (unsigned char)(greenColor);
		clut[i + 0] = (unsigned char)(blueColor);
	}
}

This works well and I am able to change the colors of the image. But according to you I am not actually using the ChromART with a CLUT. Is it doing without using ChromArt? Note that I am using the STM32F746G-Discovery kit.

My main question is why the Shapes painter does not appear to support L8 images. I ran across this issue inside the TouchGFX Designer not utilizing any Dynamic Bitmaps at that point in time.

Are you saying I need to replace the STM32DMA class with the ChromArtDMA class so that the Shapes painter will function correctly?

I went ahead and tried implementing the replacement of the STM32DMA class with the ChromArtDMA class. I was finally able to get some code to compile with this change. In order to get this to compile I needed to do the following:

1). Remove STM32F7DMA.cpp and STM32F7DMA.hpp from the target folder.

2). Place ChromArtDMA.cpp and ChromArtDMA.hpp in the target folder.

3). Edit BoardConfiguration.cpp to include ChromArtDMA.hpp instead of STM32F7DMA.hpp.

4) Edit BoardConfiguration.cpp to change the dma variable from an STM32F7DMA to a ChromArtDMA.

5). Edit ChromArtDMA.cpp to include "stm32f7xx_hal.h" and "stm32f7xx_hal_dma2d.h" instead of "stm32l4xx_hal.h" and "stm32l4xx_hal_dma2d.h".

6). Edit HW_Init.cpp to make the definition of hdma2d an "extern DMA2D_HandleTypeDef".

7). Edit STM32F7HAL.cpp to include ChromArtDMA.hpp instead of STM32F7DMA.hpp.

The code compiled. However, I am still getting the Assert (see original post) when I attempt to paint an L8_ARGB8888 image into a Shape in the Designer.

You may have thought so, and i would not hold it against you 🙂 But it didn't. The HAL is a part of the application template, and these HAL/DMA classes haven't been updated to reflect ChromART + L8 yet.

If you're not using the DMA classi posted, then it's not using the ChromART to handle L8 because the DMA class only knows how to answer what kind of Blitops it supports and there's no room for L8, bitwise, so we had to do something else.

You can try breaking inside setupDAtaCopy() with your normal DMA class and see if it gets called by your LCD8_* class - (it shouldnt).

/Martin

Martin,

Thanks for the explanation. I appreciate it. I will try the breakpoint inside setupDAtaCopy()

Can you answer my question on whether or not the Shapes widget supports L8?

I created a project that uses a dynamic bitmap to copy a bitmap into an image widget. Then I set a breakpoint in setupDataCopy() in my normal DMA class (STM32F7DMA).

It does indeed break when the copying occurs. It does this when the image is formatted to L8_ARGB8888 or when it is left at default.

You said that "it shouldn't". Am I doing something wrong?

As stated earlier in this thread, when the image is formatted to an L8_ARGB8888, I create the Dynamic Bitmap with the CLUT format parameter. When it is not, I create it without the clut format parameter.

At the breakpoint, I see that in both ways the image is formatted, the value of blitOp.operation is 64 (BLIT_OP_COPY_ARGB8888_WITH_ALPHA). Is there something ahead of setupDataCopy() that is converting the image?

I tried following the code back to where setupDataCopy() is called but have been unable to see where that is in the framework.

And....I am still waiting to hear from you on whether or not the Shapes widget supports L8......This is really something I would like support on.

scottSD
Senior III

Bringing to the top

Still waiting for an answer on whether or not the Shapes widget supports L8......

They do in the sense that we have the following painters:

PainterRGB565L8Bitmap
PainterRGB888L8Bitmap

Martin, I noticed you did not include L8 with alpha (L8_ARGB8888). Will this be supported for the Shape widget in the future?

Is there an example available of PainterRGB565L8Bitmap or PainterRGB888L8Bitmap being used with the Shape widget?

I formatted an image to L8RGB565 using the TouchGFX Designer. Then I used this image in a Shape widget (within the Designer). However, in the gui_generated Screen1ViewBase.hpp file, it is creating an instance of PainterRGB565Bitmap (not PainterRGB565L8Bitmap setup in the Designer):

touchgfx::Shape<4> shape1;
    touchgfx::PainterRGB565Bitmap shape1Painter;

I do not understand why it is creating a PainterRGB565Bitmap when the image is formatted to L8RGB565. Can you explain this?