Writing more than 4k bytes in the drawing instuctions buffer.

FTDI/Bridgetek EVE2 & EVE3 & EVE4 SPI TFT Series by Matrix Orbital

Moderator: Mods

Post Reply
rascalito
LCD Geek
Posts: 38
Joined: Sat Apr 18, 2020 11:22 pm

Writing more than 4k bytes in the drawing instuctions buffer.

Post by rascalito »

Hello!

Right now I'm implementing a HTML text view. Well, it's overstated, let's say it's a subset of HTML allowing to change fonts and colors.
No image yet. I used replies I got in the past (thanks Rudolph!), and could implement a text justification at both side (left AND right
at the same time, like in a book). Basically it works, but I'm hitting the 4k wall. There are more than 4k instructions in the buffer and
it doesn't work. So I need to know a few things:
Is it possible to have more than 4k of instructions between DL_START and DL_END?
In this case, what I would do is:

- Send DL_START
- Send 4K instructions (or a few bytes less to make sure that the EVE doesn't step on its own shoe laces)

- Wait idle

- Send other instructions
- Send DL_END
- Send DL_SWAP

Would this work?
I think the instructions are processed as soon as they are in the buffer, right?
And beside this, I think I have to "cut" the trunks in whole instructions, not in the middle of an instruction, right? Example, a button
needs something like 20 bytes, I can't cut this in the middle of the button code, right?

Thanks!

R

Rudolph
LCD Guru
Posts: 67
Joined: Wed Feb 28, 2018 11:09 am

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by Rudolph »

While this works while not truncating commands, there is a high chance that the generated display list gets larger than 8kiB.

For a simple
CMD_TEXT(300, 322, 28, 0, "Text")
a display list of 9 to 13 commands is generated, depending on the position of the individual characters.

But CMD_TEXT is "only" 3 co-processor 32-bit words plus in this case 2 32-bit words for the text itself.
So you could place 227 of those in the display list and 204 in the FIFO.

Ok, works out, a few more could be pushed.

CMD_TEXT(33, 38, 28, 0, "Hello, my name is Bob.")
This needs 9 32-bit words in the cmd-fifo, so 113 could fit.
And 27 32-bit words to 49 32-bit word in the display-list, so 41 to 75 could fit.

CMD_BUTTON(86, 66, 120, 36, 27, 0, "Button")
This needs 6 32-bit words in the cmd-fifo.
And 55 32-bit words to 67 32-bit word in the display-list.

So there is a very real chance that you run out of display-list space before you run out of space in the cmd-fifo.

rascalito
LCD Geek
Posts: 38
Joined: Sat Apr 18, 2020 11:22 pm

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by rascalito »

Hello Rudolph!

Thanks for your reply. So does this mean that there is no way to have more than 8k in the display
list in any case? The memory space for DL is 8K, ok, but I had the impression that any instruction
received in the DL is converted into pixels in a frame buffer, and then when swapping, it switches
the frame buffer to show it while another frame buffer is about to be written by further DL instructions.
Am I wrong?
-> If 8k is the absolute maximum, I guess I have to forget my HTML parser
Or does it mean that I need to split my commands in smaller buffers, for example
1k bytes, and they will be decoded into larger DL instructions?
-> In this case, I can do it.

R

Rudolph
LCD Guru
Posts: 67
Joined: Wed Feb 28, 2018 11:09 am

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by Rudolph »

>So does this mean that there is no way to have more than 8k in the display list in any case?

Yes, exactly, there is no way around the 8kiB.

>but I had the impression that any instruction received in the DL is converted into pixels in a frame buffer, and then when swapping,
>it switches the frame buffer to show it while another frame buffer is about to be written by further DL instructions.

No, there is no frame buffer, let alone two, as this would require quite a lot of memory.
There are actually two display lists of 8kiB each at the same location and only the inactive one is visible and can be written to.
The active one is processed for every single line over and over again.
The exact details are not documented though.

Unfortunately the co-processor does not seem to optimize the display list in any way.
So 11 buttons fill the display list to 30% although there is a lot of overlap

There are workarounds.
Buttons for example are most of the time just two images anyways.
So you could pre-calculate the images you need and just display these.
I had a project in which I had two images for a button in pressed and normal state and a set of images for
the text on these buttons like "up", "down", "left" and "right".

And instead of displaying ten buttons with their own separate commands I sorted thru the command-list
to remove redundancies.

The result is code like this, no fun to read but efficent on the SPI:

Code: Select all

	EVE_cmd_dl_burst((DL_BEGIN | EVE_POINTS));
	EVE_cmd_dl_burst(POINT_SIZE(150));

	EVE_color_rgb_burst(LIGHT_GREEN);

	if(vl1_delay)
	{
		vl1_delay--;
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(vl2_delay)
	{
		vl2_delay--;
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(vl3_delay)
	{
		vl3_delay--;
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(vl4_delay)
	{
		vl4_delay--;
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(vr1_delay)
	{
		vr1_delay--;
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(vr2_delay)
	{
		vr2_delay--;
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(vr3_delay)
	{
		vr3_delay--;
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(vr4_delay)
	{
		vr4_delay--;
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(hl1_delay)
	{
		hl1_delay--;
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(hl2_delay)
	{
		hl2_delay--;
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(hl3_delay)
	{
		hl3_delay--;
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(hl4_delay)
	{
		hl4_delay--;
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(hr1_delay)
	{
		hr1_delay--;
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(hr2_delay)
	{
		hr2_delay--;
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(hr3_delay)
	{
		hr3_delay--;
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(hr4_delay)
	{
		hr4_delay--;
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_4));
	}
	
	EVE_color_rgb_burst(LIGHT_GREY);

	if(!vl1_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(!vl2_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(!vl3_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(!vl4_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_1));
	}
	if(!vr1_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(!vr2_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(!vr3_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(!vr4_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_2));
	}
	if(!hl1_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(!hl2_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(!hl3_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(!hl4_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_3));
	}
	if(!hr1_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(!hr2_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(370, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(!hr3_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(410, LAYOUT_Y1+STATUS_LINE_4));
	}
	if(!hr4_delay)
	{
		EVE_cmd_dl_burst(VERTEX2F(450, LAYOUT_Y1+STATUS_LINE_4));
	}

	EVE_cmd_dl_burst(DL_END);
This displays just a set of "LEDs" in green or grey and it is more efficent this way than to do it like this:

Code: Select all

if(vl1_delay)
{
  vl1_delay--;
  EVE_color_rgb_burst(LIGHT_GREEN);
}
else
{
  EVE_color_rgb_burst(LIGHT_GREY);
}
EVE_cmd_dl_burst(VERTEX2F(330, LAYOUT_Y1+STATUS_LINE_1));
So yes, the controller has more code and yes it is more difficult to read.
But this is 30 color-commands shorter, this is 120 Bytes less on the SPI.
And yes, I just noticed that there is a bug but it usually only makes the list 1 instruction longer for one frame. :-)

rascalito
LCD Geek
Posts: 38
Joined: Sat Apr 18, 2020 11:22 pm

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by rascalito »

Hello!

Thanks for your reply. Ok, it looks like my HTML decoder was a bad idea.
No, there is no frame buffer, let alone two, as this would require quite a lot of memory.
But I suppose there is a frame buffer somewhere anyway. The TFT has to be refreshed constantly (which
is the role of the FT8x chips). I don't know where it is but it has to be somewhere to send the pixels to
the screen. Displaying a display list requires it to be processed by a decoder of some kind, transforming
the various commands to pixels, and these pixels have to be sent line by line starting top left and ending
bottom right. You cannot do that with a display list directly.

By the way, is it possible to replace the flash attached to the chip? The current flash is 4 MB, and if I have
to convert my help pages into panels, I will need many images, typically about 750 x 400, which will take
a lot of space.
So you could pre-calculate the images you need and just display these.
Is it possible to store a screenshot of a button to the flash? Not necessarily a button, but for instance a
crop area of some part of the display? I do also have a menu bar, so I could have n copies of this menubar,
one per button pressed, and display it as a bitmap with a single command. If cropping and storing an area
is possible, I could develop routines to do that automagically.

R.

Rudolph
LCD Guru
Posts: 67
Joined: Wed Feb 28, 2018 11:09 am

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by Rudolph »

rascalito wrote:
Wed Jan 12, 2022 6:52 pm
But I suppose there is a frame buffer somewhere anyway. The TFT has to be refreshed constantly (which
is the role of the FT8x chips).
No, there really isn't, the raster-engine processes the display-list over and over again to throw pixels line by line at the panel.
Indirect proof for this is the bandwidth issue with images or fonts displayed directly from flash.
With a frame-buffer there would be a short glitch at most if the first processing tooks an abnormal amount of time but after that it would be fine.
By the way, is it possible to replace the flash attached to the chip? The current flash is 4 MB, and if I have
to convert my help pages into panels, I will need many images, typically about 750 x 400, which will take
a lot of space.
Yes, this is possible, I have a list of possible chips here:
http://www.brtcommunity.com/index.php?topic=77.0

This has to be done very carefull though, the old chip really should not be removed with hot air.
I recommend cutting the pins very close to the body of the chip with a fine cutter and then de-solder the pins one by one.
Better lose the chip than the panel.
Is it possible to store a screenshot of a button to the flash? Not necessarily a button, but for instance a
crop area of some part of the display? I do also have a menu bar, so I could have n copies of this menubar,
one per button pressed, and display it as a bitmap with a single command. If cropping and storing an area
is possible, I could develop routines to do that automagically.
Yes and no.
There is CMD_SNAPSHOT2 which can take a snapshot of a part of the current screen and write it to RAM_G.
And you could write a portion of RAM_G to the flash.
But the only formats available that can be used to display this snapshot again are RGB565 and ARGB4 and these can not be
displayed from the flash.
I guess you could in theory transfer the snapshot to your controller, convert it to ASTC and write it back,
but this would take forever.

rascalito
LCD Geek
Posts: 38
Joined: Sat Apr 18, 2020 11:22 pm

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by rascalito »

Hello!

Another question related to the 4k limitation.
Is it possible to store to flash some instructions aimed at drawing par of a screen, and then
call the result directly from flash? I just thought that in this case it could extend the 4K limitation.
Or whatever I do I will bump into this limitation?

Thanks,

R

Rudolph
LCD Guru
Posts: 67
Joined: Wed Feb 28, 2018 11:09 am

Re: Writing more than 4k bytes in the drawing instuctions buffer.

Post by Rudolph »

rascalito wrote:
Sun Mar 27, 2022 8:22 pm
Another question related to the 4k limitation.
Is it possible to store to flash some instructions aimed at drawing par of a screen, and then
call the result directly from flash? I just thought that in this case it could extend the 4K limitation.
Or whatever I do I will bump into this limitation?
No, not really.
There is CMD_APPEND to use snippets of display-list commands from memory.
But this "only" helps with the 4k FIFO but does not solve the underlying issue that the display list
does "only" hold 8k.
This is a nice way to reduce the necessary SPI traffic. which is why I have it in my basic demo.

Also, the 4k limit of the FIFO is not an issue, you could write several times to the FIFO without swapping in the display list.
You could for example decide to only write a fraction of the complete commands every 1ms to the FIFO, like 256 bytes,
well to perhaps get a more even load on the controller.
And finally when everything is transferred and the time for the previous frame has passed, issue a swap command.
But then again, the resulting display list must be shorter than 8k.

Post Reply